socib / Leaflet.TimeDimension

Add time dimension capabilities on a Leaflet map.
MIT License
434 stars 138 forks source link

Performance with many markers #58

Open jekuno opened 8 years ago

jekuno commented 8 years ago

I have a performance issue when Leaflet.TimeDimension shows many markers. To demonstrate this I created a jsbin which draws circleMarkers on a single canvas: http://playground-leaflet.rhcloud.com/rus/1/edit?html,output

If you have a look at the time display of the player UI element you can see that the performance initially is good. It significantly drops when you move the slider to the end of the timeline.

For my use case I need to show ALL previous markers (as in the jsbin example). I suppose that Leaflet.TimeDimensiom currently keeps some stateful information for each marker it displays which results in this performance drop. Can you help me locating the according bottleneck?

I would expect that Leaflet.TimeDimension only draws the according marker to the canvas and then forgets everything about it when it advances to the next step.

r1m commented 8 years ago

For each time, it will recreate a new layer that contains only the features that are returned by _getFeatureBetweenDates see L.TimeDimension.Layer.GeoJson

Returning null in that function will remove the feature. One improvement will be to use a LineString instead of a feature collection. You can specify a time for each coordinates along the path. This is what is used in the Hiking example.

In any case rendering 2000 markers in leaflet is pretty intensive. They are all rendered as div. If you use a linestring, leaflet will render the path in svg or canvas.

jekuno commented 8 years ago

In the linked jsbin I already set window.L_PREFER_CANVAS=true for perfmance reasons so that all markers are painted in the same canvas without adding separate divs. Unfortunately this didn't help.

Also as I need some additional properties for each geoposition I unfortunately have to use feature objects and cannot switch to LineString.

For me it looks as if I the _update function should be tweaked so that it does not create a new layer with all the previous features on each tick but simply adds the new marker (of the current tick) to the already existing _currentLayer. However if the user manually moves the slider of the player control a new layer with all previous markers needs to be created.

Does this sound reasonable to you?

r1m commented 8 years ago

You can try that, but the actual code deal with one other thing : remove obsolete features. Not useful in your case but still allow to display only the last 5min for example. Don't forget the case when the user come back in time. you need to remove all future points. LineString are something else because they are not add/removed their path is modified.

You can still go the shorter path and change this function only for your need. This is complex to optimized, and I feel you will end up with some sort of a reverse map time->feature

PS : profiler on chrome says it's spending 46% of time in drawing strokes. That may be better with Leaflet 1.0

jekuno commented 8 years ago

Update: I already did a quick test with the new strategy which looks promising: There isn't any notable performance drop with 2000 markers.

My strategy would be as follows: When minTime is 0 and the current time directly follows the last time which has been displayed (i.e. during playback but not when the user jumps back or forward in time) the new feature gets added to the already existing _currentLayer instead of removing the previous _currentLayer and readding a new layer with all the previous markers.