Skip to content

Conversation

@lucaswoj
Copy link
Contributor

@lucaswoj lucaswoj commented Oct 14, 2025

This PR speeds up GeoJSONSource#updateData when called with small diffs. Now we only reload tiles affected by the diff, rather than reloading all tiles. This significantly improves performance when making small changes to large GeoJSON datasets.

Performance Impact

  • 50% faster against my benchmark updating 1 point in a 100k point dataset
  • Some use cases may benefit or more less, depending on specifics
  • No performance regression expected for any use case

Implementation

When updateData is called with a diff, the source now determines which tiles need reloading by:

  • Checking if tiles contain features being updated or removed
  • Testing if added/updated geometries intersect with tile bounds
  • Falls back to full reload for large diffs (1000+ changes)

Additional Changes

  • Add LngLatBounds.intersects() method for bounds overlap testing
  • Add CanonicalTileID.toLngLatBounds() to convert tile coordinates to geographic bounds
  • Add benchmark to track updateData performance

Related to #4364

Launch Checklist

  • Confirm your changes do not include backports from Mapbox projects (unless with compliant license) - if you are not sure about this, please ask!
  • Briefly describe the changes in this PR.
  • Link to related issues.
  • Include before/after visuals or gifs if this PR includes visual changes.
  • Write tests for all new functionality.
  • Document any changes to public APIs.
  • Post benchmark scores.
  • Add an entry to CHANGELOG.md under the ## main section.

@lucaswoj
Copy link
Contributor Author

not the one you "mid-commit" one

This was posted by @wayofthefuture, not me.

I can't help but wonder if there's no part of the logic that we can do in the worker? doesn't have to be all the work, but maybe just part of it, as it has the geometry data already parsed.

In eb69274 I moved the calculation of nextBounds to the worker.

This does not make the code measurably faster in any benchmark I have run. It does make the code harder to read and harder to test.

it has the geometry data already parsed.

There is no "parsed geometry data" on the worker that we can reuse. For the purposes of this feature, the worker has exactly the same data as the main thread.

@lucaswoj lucaswoj requested a review from HarelM October 28, 2025 21:20
@wayofthefuture
Copy link
Collaborator

wayofthefuture commented Oct 28, 2025

Oh well, now I'm just confused. In a perfect world geojson source would always control source but it doesn't. That's our reality. Source cache does the controlling. reloadTile, loadTile, addTile lives in source cache. The decision to reload is currently in source cache, splitting that decision and creating types to transport a function is confusing. The hodgepodge that is source cache is a problem for another day. I'm not a fan of shouldReloadTile in the current form... and I'm definitely not a fan of shouldReloadTileOptions so that a function can be passed... respectfully... my opinion. Sorry

@HarelM
Copy link
Collaborator

HarelM commented Oct 28, 2025

This does not make the code measurably faster in any benchmark I have run. It does make the code harder to read and harder to test.

I tend to agree, sorry for pushing in the wrong direction, I think this can be reverted if it's not a big ask.
Otherwise, this looks good.
Thanks!

@HarelM
Copy link
Collaborator

HarelM commented Oct 28, 2025

I meant the last change with the worker, the rest is ok.
Source cache is a mess, we'll eventually need to confront with, but not today...

@lucaswoj
Copy link
Contributor Author

I meant the last change with the worker, the rest is ok. Source cache is a mess, we'll eventually need to confront with, but not today...

Reverted in cea0e71

@HarelM
Copy link
Collaborator

HarelM commented Oct 28, 2025

Added a few last final comments, and I'll merge this afterwards.
Thanks for all the hard work on this!

@lucaswoj lucaswoj requested a review from HarelM October 28, 2025 23:47
@HarelM HarelM merged commit 897cff1 into maplibre:main Oct 29, 2025
26 checks passed
@wayofthefuture
Copy link
Collaborator

@lucaswoj I'm not sure if this PR is the cause, but see the behavior difference between 5.10.0 and 5.11.0 where this commit was merged. Notice how the extruded boxes are sticking around and not being removed...

Before:

before.mov

After:

after.mov

All you have to do is change the version number in this codepen to reproduce:
https://codepen.io/wayofthefuture/pen/JoGRwKE?editors=1000

melitele pushed a commit to melitele/maplibre-gl-js that referenced this pull request Jan 8, 2026
* Add geojson diff benchmark

* Update geojson_diff.ts

* Update geojson_diff.ts

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* Self code reivew

* Self code reivew

* Self code reivew

* WIP

* WIP

* Update geojson_diff.ts

* Refactor

* Update min.test.ts

* Fix CI

* WIP

* Add unit tests

* Self code reivew

* Add tests for LngLatBounds#intersects

* WIP

* Update geojson_source.test.ts

* Add more tests

* Fix eslint

* Add large diff bail

* Update display-a-map.html

* Update geojson_diff.ts

* Update CHANGELOG.md

* Self PR review

bump CI

* Memoize some operations on _getShoudReloadTile

* Add failing dateline wrap test

* WIP

* Update lng_lat_bounds.ts

* Update geojson_source.ts

* Self PR review

* Update lng_lat_bounds.ts

* PR review

* Self PR review

* Fix tests

* Self code review

* Remove 1000 feature heuristic

* Update source_cache.ts

* Move tileIdToLngLatBounds to standalone util

* Remove 'extent' parameter from tileIdToLngLatBounds

* Rename "shared" to "shouldReloadTile"

* Remove "else if" statements

* Update geojson_source.test.ts

* Refactor to use MapSourceDataEvent#shouldReloadTileOptions

* Fix CI

* Self code review

* Self code review

* Move getGeoJSONBounds to separate util file

* Fix error

* Calculate 'nextBounds' on the worker

* Revert "Calculate 'nextBounds' on the worker"

This reverts commit eb69274.

* Restore bug fix from eb69274

* Fix typo

* Add doc link

* Don't use  to hide GeoJSONSourceShouldReloadTileOptions

* Update display-a-map.html
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants