Cause of MapBox GL JS Performance Difference
Asked Answered
B

2

9

This question is for someone who understands the internals of MapBox GL JS.

I'm using MapBox GL JS to render a geographic map of up to 40,000 polygons, each of which is colored based on the "owner" of that polygon. There are typically many polygons per owner and the "owner" of each polygon may change over time. The number of owners can vary from one to around 1,000. I'm having performance problems (which vary depending on how I approach it), so I've tried a few different strategies.

  1. Using data-driven styling for "fill-color", where I have a single source and a single layer. I've tried both the polygon id and the "owner" id as the category for the data-driven styling.
  2. Using filtered layers, where I have a single source and a separate layer for each "owner". Again, I've tried both the polygon id and the "owner" id as the criteria for filtering.
  3. Using a separate source and layer for each "owner".

Option three has the best drawing speed. The layers are rendered very fast as I zoom and pan. But I have to call setData whenever I change the owner of a layer and setData leaks memory so I eventually end up with the page crashing. This issue, 2607, was closed as not actionable, so I don't expect a resolution to this.

Options one and two draw okay with the initial zoom, but when I zoom in they are very slow to re-draw the tiles. I am stuck looking at the jagged, low detail tiles until the rendering catches up after 20-30 seconds. Note that if I use the "owner" id instead of the "polygon" id, I still need to call setData when an "owner" changes which will lead to the memory leak. If I use polygon id, I just need to update the layer filters or fill-color categories when the "owner" changes. However, I don't get a noticeable performance difference if I use "polygon" id so I think that's okay.

So my question is why is option three so much faster to render when I zoom in? Does it have to do with the number of workers assigned to drawing? In options one and two, there is a single source so does that mean the drawing is only using a single worker? Whereas in option three, there is a separate source for each "owner" so I have multiple workers doing the drawing?

Blackheart answered 3/11, 2016 at 15:12 Comment(1)
It appears that the memory leak related to option 3 was fixed in v0.29.0.Blackheart
C
6

I recommend performing a data-join using categorical data-driven styles. This allows you to decouple your data property updates from your geometry.

Check out https://www.mapbox.com/mapbox-gl-js/example/data-join/ for an example of how to join JSON data in the browser to vector tile geometry. This should scale well up to 100+ thousand features.

Caffeine answered 14/1, 2017 at 18:43 Comment(1)
This approach does perform very well. And this is the approach I settled on.Blackheart
W
3

I think you will require a variety of techniques to solve what is essentially a level of detail (LOD) problem. I've done similar work involving drawing poly regions of a country to indicate various Districts within a State and you have to scale data to suit the view.

The first thing I would recommend is creating various levels of detail for your Regions. A first-sweep can be done automatically by removing Region vertices that are aligned (geographically speaking) within a few degrees of a straight line with their neighboring points. Think of this as removing the many small points that don't add detail to a Region boundary as they are on a straight line. As this can be an automated (and even pre-stored) step you can create different levels of detail based on zoom-level.

The second recommendation is view-space culling. That is, if a region is not within the view port, don't render it! If you attempt to do this vertex-perfect you'll end up with the same CPU problems as before so I'd recommend creating a Region bounding-box (if you are using axis-aligned viewing only, a suggestion proposed as it's the easiest solution).

If you need non axis-aligned regions, simply create a bounding circle (with a radius based on the boundary vertex at the greatest distance from the geocentre of the region).

I would suggest that your various difficulties are a derivative of the scene complexity problem. Solve that and you will have a much more efficient system to work with.

Good luck!

Wrongheaded answered 5/12, 2016 at 1:8 Comment(2)
Thanks for the suggestions. But in out case that doesnt seem like a practical solution. We have a structure of map items that are of very different categories and usages and not a massive homogenous amount of similar geometry. Any suggestions for our heterogenous case?Lambrecht
Thank you for the response. I converted my vector polygons to vector-tiles and have seen a huge improvement in the performance of data driven styling and filtered layers. In essence, the vector tiles are doing exactly what you recommend by creating various levels of detail and view-space culling.Blackheart

© 2022 - 2024 — McMap. All rights reserved.