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

efficiently updating data in the labels layer #38

Open FrissAnalytics opened 3 years ago

FrissAnalytics commented 3 years ago

Hi Vasco!

Hope you are doing well!

For a corona tracking visualization that I'm working on (work in progress) I use pointsData and labelsData. In the app (see screenshot below) there is a timeline and a globe, in which the globe shows a series of data points e.g. number of deaths for a given lat/lng coordinate. The size of the points is proportional to the number of deaths and if the number is above some threshold the count is shown as a label as well. The idea is that when the user hovers over the timeline the counts for that particular point in time are shown and that the globe points and labels update quickly.

What would you advise to be the best way to efficiently update labels (if any)? Preferably I like to animate the numbers in when the globe data is initially shown and to update the labels on timeline hover.

For the customLayerData there is the customThreeObjectUpdate method that allows one to efficiently update the data. However, for the other layers these options do not exist currently.

Say you have some points data e.g. gPointsData and we want to update this efficiently. I had hoped that the globe instance would take a reference and that updating gPointsData without rebinding would suffice for updating the globe view. Turns out this doesn't work, but fortunately re-binding data via globe.pointsData(gPointsData) works and is quick enough.

However, for the labels data updating in a similar way is too slow and does not work well for quick updates for sizes of a few hundred labels and more. To reduce the work load on timeline hover I'm already throttling the hover events. Clearly I can debounce as well but that would make the timeline hover experience much less fluent.

What would you say is the best way to go here?

kind regards, Herman

image

image

vasturiano commented 3 years ago

Hi Herman, first of all those screenshots look great. You've done a really awesome job in representing that data!

About data updates, you're right it's not enough to simply update the data structures, the component needs to be told when some property is updated so it can run its digest cycle. This is by design, and for performance reasons actually, because the alternative would be to continuously run full digests to pick up any alterations to the data items. It's more efficient to put that control in the hands of the consumer.

Regarding the labels update, that can become a heavy operation if you have many labels, specially because three's TextGeometry can be a complex geometry to generate and manipulate, and that gets multiplied by all of the visible labels.

But perhaps there's a more direct way if all you want is to affect a single label. Associated with each of your (bound) labelData items, there is a __threeObj attribute, that points to the corresponding three object in the scene representing the given label.

Just setting the visible attribute of this object to false will cause it to hide. So you could potentially render all the labels onto the scene and selectively hide/show them on interaction, by manipulating the visible attribute.

Let me know if you manage to get it to work that way, and if it addresses all the performance issues.

gnowland commented 3 years ago

@vasturiano unfortunately

Just setting the visible attribute of this object to false will cause it to hide. So you could potentially render all the ~labels~ arcs onto the scene and selectively hide/show them on interaction, by manipulating the visible attribute.

still shows the mouse hover tooltips on the invisible elements... do you know how to avoid that? Thanks for your help!!

EDIT: Worked around it using this method: .arcLabel((d) => { return d.__threeObj.visible ? d.properties.name : null })