developmentseed / developmentseed/deck.gl-raster

Support debounceTime in MosaicLayer (flat tile model breaks deck.gl's debounced scheduler)

Open
#562 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
228
Forks
29
Avg merge
12h 27m
Merged PRs (30d)
4

Description

## Summary

`MosaicLayer` does not support a non-zero `debounceTime`. Setting one causes source tiles to never load. The prop is therefore intentionally **not** exposed on `MosaicLayer` (removed in #557). It continues to work on `COGLayer` / `MultiCOGLayer`, which are normal hierarchical `RasterTileLayer` tile pyramids.

## Motivation

For a mosaic of many COGs, panning sweeps the viewport across lots of sources and opens GeoTIFFs for every intermediate viewport. A debounce would let us open sources only for where the user *stops*, instead of churning through everything passed over. deck.gl's `TileLayer` exposes `debounceTime` for exactly this, but it's incompatible with `MosaicLayer`'s tile model (see below).

## What we found

`MosaicTileset2D` uses a flat, zoomless tile model: every source is a tile at zoom 0, and `getParentIndex` returns the tile itself, so there is no parent/child hierarchy.

- A **single static** `update()` actually loads fine with a non-zero `debounceTime` — verified by tracing: `_getTile` enqueues the request, `updateTileStates()` sets `isSelected = true`, and when the debounce timer fires the scheduler sees priority `isSelected ? 1 : -1 === 1` and grants it.
- The failure appears under **repeated** `update()` calls (viewport churn from panning, map settle, and/or the interleaved overlay's per-frame repaints). deck.gl's `RequestScheduler` re-evaluates `isSelected ? 1 : -1` at issue time and **cancels** any tile not selected at that instant; a cancelled tile's `needsReload` becomes true, so it's re-`scheduleRequest`ed as a new handle, which **resets** the debounce timer (`clearTimeout` + `setTimeout`). The net effect is that the debounce window never closes on a stable selected set, so requests are never issued.
- The flat model also removes deck.gl's normal cushion: with no ancestor/child tree, unloaded tiles never get `isVisible: true` and there are no lower-res placeholders to show while debouncing.

Relevant source:
- `Tile2DHeader._loadData` priority `tile => tile.isSelected ? 1 : -1` (no token ⇒ cancelled)
- `RequestScheduler._issueNewRequests` (`clearTimeout`/`setTimeout(debounceTime)` on every new enqueue)
- `Tileset2D._getTile` re-loads tiles whose `needsReload` (incl. `_isCancelled`) is true
- `MosaicTileset2D` (`getTileZoom` → 0, `getParentIndex` → self)

**Caveat:** the single-update path was traced from source; the exact dominant trigger under the live render loop (initial-settle churn vs. the cancel→reschedule loop) was not instrumented.

## Possible directions

- Implement debouncing at the `MosaicLayer` `getSource` level instead of forwarding to deck.gl's scheduler.
- Give `MosaicTileset2D` a stable selection / a non-degenerate tree so deck.gl's debounced scheduler behaves.
- Upstream: a deck.gl scheduler mode that doesn't reset the debounce timer for already-queued handles, or doesn't cancel on transient deselection.

Context: split out of #557.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.