maplibre / maplibre-gl-js

MapLibre GL JS - Interactive vector tile maps in the browser
https://maplibre.org/maplibre-gl-js/docs/
Other
6.41k stars 689 forks source link

Performance issue on large FeatureCollection GeoJSON source updates #4364

Open zxwild opened 3 months ago

zxwild commented 3 months ago

User Story

Greetings, I'm building a geojson drawing tool with maplibre and encounter a performance issue when I try to move/update a GeoJSON shape when there are a lot of shapes on the map.

Rationale

I'm trying to offer a high performance for end users, so I want to be able to handle a few thousands of GeoJSON shapes and update them with my tool.

On the screenshot you can see the example how my map could look (it contains 2278 GeoJSON shapes).

For the first I had very slow performance when I used a source for each of these shapes. This case I needed to have "a source + 1-2 layers" for a shape, now I switched to a FeatureCollection source + limited number of sources (I have 5 overall).

Now performance is OK, it's possible to move, zoom a map without issues.

BUT, when I try to update a source, for example to move a shape, maplibre handles it very slow. It seems the whole canvas is rerendered or something like this (I use updateData to update source partially).

The question/offer: is it possible to have another canvas?

This case I'll be able:

2278-shapes

Impact

Maplibre performance is OK when shapes are static, but shapes updating is a huge trouble.

HarelM commented 3 months ago

Updating a geojson source rebuilds the tile pyramid every update, improving the performance will need to dive into the geojson-vt package I believe in order to solve this. I'm not sure I can think of a better solution, but different sources might be the right solution. I would recommend sharing a minimal reproduction, otherwise it's hard to really understand the problem.

zxwild commented 3 months ago

Ok, I'll implement a demo, it would be something like 3000 GeoJSON features bundled in one FeatureCollection source, with a few layers.

I think dragging should be enougth: mousedown to select a Feature, mousemove to move it, mouseup to release.

zxwild commented 3 months ago

Here is the demo, try to zoom, move map, and then drag any polygon (I adjusted feature amount to m1-max mac performance).

github repository: https://github.com/zxwild/maplibre-performance

codepen: https://codepen.io/zxwild/pen/WNqeaZM

It's very fast on map move/zoom-in/zoom-out with 5000 geojson subfeatures, but it's slow when I try to update one, even if only a few polygons are visible.

PS: throttling for 30ms is used on the mousemove event handler

HarelM commented 3 months ago

The update process of geojson is heavy and is not actually incremental. I think you have two options here:

  1. Dig into the geojson-vt code and allow incremental updates
  2. Split the sources on the fly and keep the currently updating feature in one geojson source and the others in a different one, making the updates fast on the dynamic source while keeping the rest of the data on the static source.

I don't know if any of these options will actually work though...

zxwild commented 3 months ago

Ok thanks, I'll try the second way for the first. Actually previously I had a dedicated source for each GeoJSON, but it works incredibly slow (it seems hundreds of layers impact performance a lot). But I hope 2 sources shouldn't be a trouble.

zxwild commented 2 months ago

@HarelM it seems a second source works OK, thanks!

Single source (slow with ~5k features): https://codepen.io/zxwild/pen/WNqeaZM

With a tmp source (much faster even with ~20k features): https://codepen.io/zxwild/pen/NWZWjQz

The Github branch for the demo https://github.com/zxwild/maplibre-performance/tree/second-source