nebula.gl icon indicating copy to clipboard operation
nebula.gl copied to clipboard

Poor panning-by-dragging performance with multiple layers

Open timnyborg opened this issue 3 years ago • 4 comments

Describe the bug

When working with large data sets (10,000s of features across multiple EditableGeoJson layers), panning [edit: by dragging] slows to a crawl, because each layer calls this.getPicks(...) whether its mode needs picking data or not. Worse, it's called both in _onpointermove and _onpanmove which both fire.

I suspect the picks object passed to all should be replaced with a lazy object / callable function, so it can be invoked only when needed.

Actual Result

Panning can slow down to a few FPS

Expected Result

Panning FPS is unaffected by large datasets

timnyborg avatar Dec 01 '22 10:12 timnyborg

Some notes that might help your investigations:

In deck.gl, layers have a pickable property that can be set to false to exclude them from the picking process. Then you can call the various deck.pick... functions yourself when you do what to pick.

Another thought is that the auto highlighting feature does require picking on mouse move, you can also turn that off via the autoHighlight layer prop.

ibgreen avatar Dec 01 '22 11:12 ibgreen

Thanks @ibgreen.

The issue I have is that I do want all of my EditableGeoJsonLayers to be pickable, for using getTooltip, selecting features on click, etc. If I convert the layers to vanilla GeoJsonLayers, or disable _onpointermove and _onpanmove by monkey-patching, the drag-to-pan and deck.gl picking performance is fantastic, even with >100k features on >40 layers.

When dragging with multiple large EditableGeoJsonLayers, all the processing time is spent in per-layer calls of pickMultipleObjects: image

I've yet to find an approach that allows me to avoid those unnecessary computationally-expensive hooks, while preserving standard EditableGeoJsonLayer picking functionality.

timnyborg avatar Feb 22 '23 12:02 timnyborg

Had a brainwave re. a workaround right after posting: a layer subclass which disables the offending hooks, swapped in when they're unneeded (e.g. when the mode is ViewMode:

class ViewOnlyEditableGeoJsonLayer extends EditableGeoJsonLayer {
  _onpointermove() { }
  _onpanmove() { }
}

// in my deck-updating logic:
const layerClass = mode == ViewMode ? ViewOnlyEditableGeoJsonLayer : EditableGeoJsonLayer;
layers.push(new layerClass(layerProps));
deckInstance.setProps({ 'layers': layers });

This seems to fix performance while preserving layer state, but is limited to my use case, so I'm inclined to leave the issue open, as I think this affects the library's ability to scale.

timnyborg avatar Feb 22 '23 12:02 timnyborg

pickMultipleObjects is very expensive as it requires multiple GPU readouts. It should not be called on pans, just on clicks. If I was looking at making changes to the code that would be my starting point.

ibgreen avatar Feb 22 '23 20:02 ibgreen