fix(deck.gl-geotiff): Honor extent in MosaicLayer - #688
Open
kylebarron wants to merge 1 commit into
Open
kylebarron wants to merge 1 commit into
kylebarron wants to merge 1 commit into
Conversation
MosaicLayer forwards `extent` to its tileset, but MosaicTileset2D overrides `getTileIndices` without reading it, so every source in view still loaded. Keep only the sources whose bbox overlaps the extent (not just touching it, as in deck.gl's TileLayer), reading it on every call so prop updates apply. `extent` is now documented on MosaicLayerProps as WGS84 `[minLng, minLat, maxLng, maxLat]`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
This PR was written by Claude (Claude Code), not by @kylebarron.
MosaicLayeracceptsextentand passes it to its innerTileLayer, which hands it toMosaicTileset2D. ButMosaicTileset2DoverridesgetTileIndicesand never readsthis.opts.extent, so the prop does nothing. Every source whose bbox meets the viewport is still fetched, rendered and reported byonViewportLoad, with no warning. It has been this way sinceMosaicLayerwas added in #184.#684 makes the same fix for
RasterTileset2D, the repo's only otherTileset2Dsubclass, and its description listsMosaicTileset2Das not changed there. Ref #684Reproduction
In a viewport that shows all three sources (longitude 25, latitude 5, zoom 3, 512×512),
mainfetches all three. I ran a version of this with named sources and anonViewportLoadcallback through deck.gl'sLayerManagerin vitest (no GPU device, public API only), logging whatgetSourcefetched and whatonViewportLoadreported:On
main, changingextenton later renders (none, then[15,-5,35,5], then[5,-5,25,5], then none) never changes the selection. With this PR,onViewportLoadreports["A","B","C"],["B"],["A","B"], then["A","B","C"].Fix
MosaicTileset2D.getTileIndiceskeeps its zoom gate and its Flatbush search of the viewport, then drops the hits whose bbox doesn't overlapextent. It readsthis.opts.extenton every call, becauseTileLayerupdates it throughsetOptions. The filter runs before the hits are mapped, so a source's default tile id is still its position insources.TileLayer(OSMNode.update'sinsideBounds) and fix(deck.gl-raster): Infer missing TileMatrixSet bounds and honorextent#684. The overlap is strict, so a source that only touches the extent at an edge or a corner is skipped. Each source is tested against the whole extent, not against the part of it in view, so a source that is on screen and overlaps the extent off-screen still loads (it is drawn in full).extentis no longer picked fromTileLayerProps.MosaicLayerPropsnow declares it with TSDoc, which covers:[minLng, minLat, maxLng, maxLat]extentto the layersrenderSourcereturnsTileLayer, it doesn't keep sources loading belowminZoomTests
There's a new
MosaicTileset2D extentblock intests/mosaic-tileset-2d.test.ts. Its tests check that the tileset:setOptionson the next callRed/green: with only
mosaic-tileset-2d.tsandmosaic-layer.tsreverted tomain, all 5 new tests fail (Tests 5 failed | 6 passed (11)). With this PR,Tests 11 passed (11). I also tried these wrong versions of the fix, and each one fails at least one test:Checks:
pnpm --filter @developmentseed/deck.gl-geotiff test:Test Files 7 passed (7),Tests 38 passed (38).pnpm --filter @developmentseed/deck.gl-geotiff typecheckpasses under TypeScript 6.0.3. I haven't run it under TypeScript 7 (chore(deps-dev): upgrade to TypeScript 7 #685); CI will.pnpm exec biome ci .:Checked 385 files ... No fixes applied.Open questions and judgment calls
extent#684? The TSDoc tells users to passextentto the layersrenderSourcereturns. That only limits what aCOGLayerloads once fix(deck.gl-raster): Infer missing TileMatrixSet bounds and honorextent#684 makesRasterTileset2Dreadextent. If this PR lands first, that sentence is ahead of the code until fix(deck.gl-raster): Infer missing TileMatrixSet bounds and honorextent#684 does.minZoom. I kept the existing zoom gate, so settingextentdoes not keep sources loading belowminZoom, unlike in deck.gl'sTileLayer. fix(deck.gl-raster): Infer missing TileMatrixSet bounds and honorextent#684 makes the same choice.MosaicLayer-level test? This PR doesn't change howMosaicLayerforwardsextent, and no test covers that forwarding yet. A test thatrenderTileLayer(...)passesextentto the innerTileLayerneeds noLayerManager. Turning the end-to-end reproduction above into a test would make it the repo's firstLayerManagertest. Without a device, deck.gl swallowsupdateStateerrors there, so it could only assert positive outcomes.getTileIndices, so whichever lands second needs a manual merge. In feat: antimeridian support #673 the check moves into its per-source loop, as acontinuewhenextentis set and!overlaps(source.bbox, extent), after thesource === undefinedguard. In fix(mosaic): Make MosaicLayer repeat over world copies (antimeridian) #639 it stays a.filteron[...matched]before the.map. Since feat: antimeridian support #673 shifts antimeridian-crossing bboxes so thatmaxX > 180, should the check also test each bbox shifted by ±360? Otherwise a source stored as[178, -10, 182, 10]misses an extent like[-179, -10, -175, 10]. An extent that itself crosses the antimeridian isn't supported, as in deck.gl.Related bug, not fixed here
MosaicLayer'sgetSourcesclosure (() => this.props.sources) stays bound to the first layer instance.TileLayercreates the tileset once, and deck.gl movesstateto each new layer instance but leaves the old instance'spropsas they were. So after the first render, the tileset pairs the rebuilt spatial index with the firstsourcesarray. In the sameLayerManagersetup, with noextent(maingives the same results):So filtering
sourcesyourself is not a reliable substitute forextentonce the layer has rendered. #673 switches the closure tothis.state.sources, which would fix this; it probably deserves its own issue. The new filter assumes, like the existing.map, that every index hit has a matching entry insources, so it doesn't make this worse.🤖 Written by Claude Code