maplibre-gl-raster 0.11.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,6 +11,8 @@ A MapLibre GL JS plugin for visualizing local and remote raster datasets (GeoTIF
11
11
 
12
12
  - **Local and remote rasters** - Load Cloud Optimized GeoTIFFs from any CORS-enabled URL, or drag-and-drop local GeoTIFF files
13
13
  - **Mosaic VRTs** - Load a `.vrt` that mosaics COGs; its sources are rendered as one layer with a single shared stretch ([details and limits](#mosaic-vrt-support))
14
+ - **Three rendering backends** - Switch at runtime between the deck.gl GPU pipeline (default), a serverless WASM tiler, and a remote [TiTiler](https://developmentseed.org/titiler/) server ([details](#rendering-engines))
15
+ - **Mosaics** - Render a [MosaicJSON](https://github.com/developmentseed/mosaicjson-spec) or STAC `FeatureCollection` of COGs as one layer: client-side on the GPU (deck.gl) by default, or server-side via TiTiler ([details](#rendering-engines))
14
16
  - **Multiple layers** - Layer list with visibility toggles, reordering, zoom-to, and per-layer settings
15
17
  - **GPU rendering pipeline** - Band compositing, per-band rescale, 90+ colormaps, nodata filtering, linear/sqrt/log stretch, and gamma correction as deck.gl shader modules; parameter changes re-render without re-fetching tiles
16
18
  - **Auto statistics** - Per-band min/max and histograms sampled from COG overviews (or GDAL metadata), with draggable histogram handles for the rescale range
@@ -119,10 +121,11 @@ The main control class implementing MapLibre's `IControl` interface.
119
121
  | `sampleDataLabel` | `string` | `'Load sample data...'` | Placeholder shown in the sample-data dropdown |
120
122
  | `closeOnOutsideClick` | `boolean` | `true` | Collapse the panel when clicking outside it; set `false` to close only via the header button |
121
123
  | `engine` | `RenderEngine` | `'maplibre-gl-raster'` | Initial rendering backend; switchable at runtime from the panel |
124
+ | `titilerEndpoint` | `string` | `'https://titiler.d2s.org'` | TiTiler instance used by the `'titiler'` engine (COG + MosaicJSON) |
122
125
 
123
126
  #### Raster Methods
124
127
 
125
- - `addRaster(source, options?)` - Add a raster from a COG or [mosaic `.vrt`](#mosaic-vrt-support) URL (`string`), or a local GeoTIFF / `.vrt` `File` (a local `.vrt` must name its sources as absolute URLs); resolves with the layer id
128
+ - `addRaster(source, options?)` - Add a raster from a COG, [mosaic `.vrt`](#mosaic-vrt-support), or [mosaic `.json`](#rendering-engines) (MosaicJSON or STAC `FeatureCollection`) URL (`string`), or a local GeoTIFF / `.vrt` `File` (a local `.vrt` must name its sources as absolute URLs); resolves with the layer id. A mosaic `.json` renders on the deck.gl engine by default, and also on [`cog-tiler-wasm`](#rendering-engines) (a MosaicJSON additionally on [`titiler`](#rendering-engines))
126
129
  - `removeRaster(id)` - Remove a raster layer
127
130
  - `getRaster(id)` / `getRasters()` - Get layer snapshots (`RasterLayerInfo`); for a mosaic VRT, `memberUrls` lists the COGs it expanded to
128
131
  - `setRasterState(id, patch)` - Update visualization state (mode, bands, rescale, colormap, reversed, nodata, opacity, gamma, stretch, visible)
@@ -155,12 +158,125 @@ layer:
155
158
 
156
159
  - **`maplibre-gl-raster`** (default) - the GPU pipeline described above: a
157
160
  deck.gl `COGLayer` on a shared `MapboxOverlay`. Parameter changes re-render
158
- without re-fetching tiles.
161
+ without re-fetching tiles. It also renders a **mosaic** client-side (see
162
+ [Mosaics](#mosaics) below).
159
163
  - **`cog-tiler-wasm`** - a serverless CPU/WASM XYZ tiler
160
164
  ([cog-tiler-wasm](https://github.com/opengeos/cog-tiler-wasm)) wired to a
161
165
  MapLibre custom protocol. Tiles are rendered on the CPU and served as native
162
166
  MapLibre raster layers. The panel's settings (bands, rescale, colormap,
163
- curve, gamma, nodata, opacity) map directly onto its render parameters.
167
+ curve, gamma, nodata, opacity) map directly onto its render parameters. This
168
+ tiler ships a shorter colormap list than the deck.gl sprite, so while it is
169
+ active the panel's colormap picker narrows to the ramps it can actually draw
170
+ (a name it does not know renders black rather than falling back).
171
+ - **`titiler`** - a server-side dynamic tiler
172
+ ([TiTiler](https://developmentseed.org/titiler/)). Tiles are rendered by a
173
+ remote TiTiler instance and drawn as native MapLibre raster layers, so
174
+ nothing is decoded in the browser. It renders a
175
+ [MosaicJSON](https://developmentseed.org/titiler/examples/notebooks/Working_with_MosaicJSON)
176
+ server-side through TiTiler's `/mosaicjson` router, so it reaches assets a
177
+ browser cannot (e.g. non-CORS or `s3://` buckets). Bands, rescale, colormap,
178
+ and a numeric nodata map onto TiTiler's tile parameters (index mode uses a
179
+ server-side band-math `expression`, so the real normalized-difference index
180
+ is rendered). The `stretch` and `gamma` controls have no standard TiTiler
181
+ parameter and are ignored. Only remote sources work (TiTiler reads over
182
+ HTTP), so local files and `.vrt` mosaics render on the other engines.
183
+
184
+ The default instance is `https://titiler.d2s.org`; point it at your own
185
+ deployment with the `titilerEndpoint` option, the `setTitilerEndpoint()` API,
186
+ or the **TiTiler server** input the panel shows while the `titiler` engine is
187
+ selected (clearing it restores the default):
188
+
189
+ ```typescript
190
+ const control = new RasterControl({
191
+ engine: "titiler",
192
+ titilerEndpoint: "https://titiler.example.com",
193
+ });
194
+ await control.addRaster("https://example.com/cog.tif");
195
+ // Switch the server at runtime (the panel input stays in sync):
196
+ control.setTitilerEndpoint("https://titiler.xyz");
197
+ ```
198
+
199
+ > Because TiTiler is a *dynamic* tiler, the plugin does not cap the MapLibre
200
+ > source at a MosaicJSON's advertised `minzoom` (that would leave a small,
201
+ > high-resolution source blank until you zoomed in) - instead the initial fit
202
+ > is floored to that zoom so the view lands where tiles exist.
203
+
204
+ ### Mosaics
205
+
206
+ A **mosaic** is a `.json` manifest of many COGs rendered as one layer. Two
207
+ shapes are accepted:
208
+
209
+ - **[MosaicJSON](https://github.com/developmentseed/mosaicjson-spec)** - `tiles`
210
+ maps web-mercator quadkeys to the covering COGs; each asset's extent is
211
+ derived from those quadkeys.
212
+ - **STAC `FeatureCollection`** - each feature carries its own `bbox` and an
213
+ `assets` map (the shape the
214
+ [deck.gl-raster NAIP example](https://developmentseed.org/deck.gl-raster/examples/naip-mosaic/)
215
+ renders); the COG URL is read from the `visual`/`image` asset.
216
+
217
+ ```typescript
218
+ // Renders on the deck.gl engine by default:
219
+ await control.addRaster("https://example.com/mosaic.json");
220
+ await control.addRaster(
221
+ "https://data.source.coop/giswqs/opengeos/naip_nd_2023_stac.json",
222
+ );
223
+ ```
224
+
225
+ To build a STAC `FeatureCollection` from your own COGs (local or remote), use
226
+ the `make_stac.py` helper in this repo:
227
+
228
+ ```bash
229
+ # A directory of local COGs, hosted under a public base URL:
230
+ python python/make_stac.py ./tiles -o mosaic.json --href-base https://data.example.com/tiles
231
+ # ...or explicit remote COG URLs (add --full for complete STAC Items):
232
+ python python/make_stac.py https://data.example.com/a.tif https://data.example.com/b.tif -o mosaic.json
233
+ ```
234
+
235
+ To build the same `FeatureCollection` from imagery you *don't* host — by
236
+ searching a STAC API such as the
237
+ [Planetary Computer](https://planetarycomputer.microsoft.com/) — use
238
+ `search_stac.py` (standard library only):
239
+
240
+ ```bash
241
+ # NAIP over a bbox, one year:
242
+ python python/search_stac.py -c naip -b -99.3759,46.8959,-98.8825,47.1299 -d 2023 -o naip.json
243
+ # Least-cloudy Sentinel-2 scenes, with SAS-signed hrefs for browser access:
244
+ python python/search_stac.py -c sentinel-2-l2a -b 5.6,45.8,6.2,46.1 -d 2024-06-01/2024-09-01 \
245
+ --query '{"eo:cloud_cover":{"lt":10}}' --sortby eo:cloud_cover \
246
+ --max-items 20 --asset visual --sign -o s2.json
247
+ ```
248
+
249
+ Both scripts pretty-print with a 2-space indent by default; pass `--compact` to
250
+ write the document on a single line instead (about a third smaller, and the
251
+ shape the deck.gl-raster example ships).
252
+
253
+ Point `--api` at any other STAC API (e.g. Earth Search) to search it instead.
254
+ Planetary Computer collections whose blobs are not anonymously readable need
255
+ `--sign`; those tokens expire, so re-run the search rather than reusing an old
256
+ file.
257
+
258
+ On the default **`maplibre-gl-raster`** engine the mosaic is a deck.gl
259
+ `MosaicLayer`: a spatial index culls to the viewport and renders one on-GPU
260
+ `COGLayer` per visible asset (each read directly over HTTP and reprojected by
261
+ its own header), all sharing one visualization state. Both mosaic kinds also
262
+ render on the **`cog-tiler-wasm`** engine, which composites them per tile: for
263
+ each tile it picks the assets whose bbox covers it, decodes each on the CPU, and
264
+ paints them into one tile (stopping as soon as the tile is opaque, so a tile
265
+ inside a single asset costs one decode). A **MosaicJSON** can additionally render
266
+ on the **`titiler`** engine (server-side); a **STAC** mosaic has no TiTiler
267
+ equivalent. Adding a mosaic keeps the active engine when it can draw it, and
268
+ otherwise falls back to the deck.gl engine.
269
+
270
+ A large mosaic (more than ~48 assets) opens on a capped, centred view and hides
271
+ below a `minZoom` derived from the asset size, so a low/world view never spins
272
+ up a `COGLayer` for every asset at once — zoom in to explore, and pan to stream
273
+ in neighbours. A small mosaic always draws its full extent.
274
+
275
+ > Client-side rendering reads each COG directly, so the assets must be
276
+ > **CORS-enabled** and `https` (an `s3://` asset is rewritten to its
277
+ > virtual-hosted `https` form, but the bucket must still allow browser access).
278
+ > For assets a browser cannot reach, use the `titiler` engine instead. The band
279
+ > count, colormap and rescale window are taken from the first asset's header.
164
280
 
165
281
  `cog-tiler-wasm` is an **optional peer dependency**, loaded lazily the first
166
282
  time the engine is selected, so it never enters the default bundle. To use it,