vasturiano / globe.gl

UI component for Globe Data Visualization using ThreeJS/WebGL
https://vasturiano.github.io/globe.gl/example/world-population/
MIT License
2.03k stars 301 forks source link

[Feature suggestion] add filter in customLayerData() to improve performance #17

Closed lslzl3000 closed 3 years ago

lslzl3000 commented 4 years ago

Is your feature request related to a problem? Please describe. The customLayerData() will loop all objs and trigger customThreeObjectUpdate for every objs. But with more and more objects in custom layer, the loop for all customThreeObjectUpdate will be slower and slower. But in most of the time, we only want to update one obj. All other loops will be waste of time.

Describe the solution you'd like the customLayer cloud have a second vals to filter objs updating process, such as

    let customData = [.....] // already got many objs

    // if we just updated some of them
    customData[3] = .... 
    customData[5] = .... 
    myGlobe.customLayerData(customData, [3, 5]) // indicate the indexes to update or some other way

or, if you can use observers to watch customLayerData objs, and only update the changed ones with new data

Currently, I have to manually maintain a __update for every custom object, and manually by-pass the update process in customThreeObjectUpdate. Hope it can be done in a better way

lslzl3000 commented 4 years ago

This should be a good improvement for all other layers as well. Changing one point/arc/polgyon/.. will trigger accessor functions for all objects in the array. Which is not an efficient way, especially for functions related to geometry updating process

vasturiano commented 4 years ago

@lslzl3000 thanks for the request.

One way I could imagine an API for this is to have the 2nd argument on customLayerData be an object accessor function that defines whether the update should be invoked for a particular object. Something like:

.customLayerData(customData, d => d.hasOwnProperty('__update'))

But this is really no different (performance or convenience-wise) than applying the filter on the customThreeObjectUpdate method, like you're probably already doing:

.customThreeObjectUpdate((obj, d) => {
  if (d.hasOwnProperty('__update')) { ... }
})

And in this case you can also make more sophisticated conditions against the Three object itself.

A note worth mentioning is that the component already knows how not to re-invoke the object creation function, if it infers that the data point already exists. The creation function is where most of the heavy-lifting ThreeJS operations happen, so the module is already saving performance by doing this diffing mechanism between consecutive data updates.

As for accessor functions in other layers that are invoked during the update digest, it's recommended to keep these methods as lean as possible because the component does not make defensive copies of these values and can re-invoke them any time that is needed. If they are non-efficient, the consumer should apply the necessary caching/memoization logic to ensure that they are optimized, because the module does not have the domain knowledge to do so, and does not know whether the method results might have changed.