Mapbox Vector Tiles are awesome — and conceptually fascinating. They allow us to create lightning-fast maps with enormous amounts of data while providing for dynamic styling and interactivity.
But, you know what they say: with great power, comes …mo’ problems…? Um, anyways, here’s a little gotcha with mapping vector tiles:
Mapbox Vector Tiles, or MVT, fragment vector data across grid and zoom level, meaning information is only provided precisely where and when it’s needed. So, it’s not necessary to load all the data for administrative boundaries — the MVT specification provides only the fragments necessary for a given zoom level, latitude, and longitude.
The problem here, however, is with client-side interactivity, specifically in the implementation of a common UX pattern for highlighting geometries as a mouse pointer moves across it:
Why is this happening? As our mouse pointer moves across the screen, MapboxGL continuously fires events that provide information about the hovered geometry. Intuitively, one would simply add this geometric data to the map to provide a “styled” geometry for the hovered boundary, but as Exhibit B demonstrates, this data is fragmented, as we should expect.
In comes query source features, which we run to pick up all relevant geometric data. This step allows us to gather not just geometric information on a single tile — which may be split across several tiles — but also all tiles loaded presently on the map:
Stitching, however, is expensive, and requires some checks. In our implementation, we run the geometric union in a cancellable “task”, a pattern for managing asynchrony. The task lightly debounces the operation to prevent the machine from being overloaded. It also prevents the union from occurring if there are way too many fragments to union. Finally, once it passes these checks, the task returns the union of fragments and overwrites the initial feature fragment with a more complete geometry. There is still the immediate feedback of a hovered feature fragment which is then backfilled once the stitching procedure finishes.
Note, of course, that this data is never reliable, even after stitching. It’s possible that there is some geometric data missing from the map view. This means that this map data should only ever be relied on for presentation concerns rather than data itself.
After coming up with this solution, we were able to bake it in to our shared mapping library and easily update most of our projects with the new feature.
How have you approached this problem? Let us know in the comments below!