maplibre-gl-raster 0.11.0 → 0.12.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,122 @@ 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
167
  curve, gamma, nodata, opacity) map directly onto its render parameters.
168
+ - **`titiler`** - a server-side dynamic tiler
169
+ ([TiTiler](https://developmentseed.org/titiler/)). Tiles are rendered by a
170
+ remote TiTiler instance and drawn as native MapLibre raster layers, so
171
+ nothing is decoded in the browser. It renders a
172
+ [MosaicJSON](https://developmentseed.org/titiler/examples/notebooks/Working_with_MosaicJSON)
173
+ server-side through TiTiler's `/mosaicjson` router, so it reaches assets a
174
+ browser cannot (e.g. non-CORS or `s3://` buckets). Bands, rescale, colormap,
175
+ and a numeric nodata map onto TiTiler's tile parameters (index mode uses a
176
+ server-side band-math `expression`, so the real normalized-difference index
177
+ is rendered). The `stretch` and `gamma` controls have no standard TiTiler
178
+ parameter and are ignored. Only remote sources work (TiTiler reads over
179
+ HTTP), so local files and `.vrt` mosaics render on the other engines.
180
+
181
+ The default instance is `https://titiler.d2s.org`; point it at your own
182
+ deployment with the `titilerEndpoint` option, the `setTitilerEndpoint()` API,
183
+ or the **TiTiler server** input the panel shows while the `titiler` engine is
184
+ selected (clearing it restores the default):
185
+
186
+ ```typescript
187
+ const control = new RasterControl({
188
+ engine: "titiler",
189
+ titilerEndpoint: "https://titiler.example.com",
190
+ });
191
+ await control.addRaster("https://example.com/cog.tif");
192
+ // Switch the server at runtime (the panel input stays in sync):
193
+ control.setTitilerEndpoint("https://titiler.xyz");
194
+ ```
195
+
196
+ > Because TiTiler is a *dynamic* tiler, the plugin does not cap the MapLibre
197
+ > source at a MosaicJSON's advertised `minzoom` (that would leave a small,
198
+ > high-resolution source blank until you zoomed in) - instead the initial fit
199
+ > is floored to that zoom so the view lands where tiles exist.
200
+
201
+ ### Mosaics
202
+
203
+ A **mosaic** is a `.json` manifest of many COGs rendered as one layer. Two
204
+ shapes are accepted:
205
+
206
+ - **[MosaicJSON](https://github.com/developmentseed/mosaicjson-spec)** - `tiles`
207
+ maps web-mercator quadkeys to the covering COGs; each asset's extent is
208
+ derived from those quadkeys.
209
+ - **STAC `FeatureCollection`** - each feature carries its own `bbox` and an
210
+ `assets` map (the shape the
211
+ [deck.gl-raster NAIP example](https://developmentseed.org/deck.gl-raster/examples/naip-mosaic/)
212
+ renders); the COG URL is read from the `visual`/`image` asset.
213
+
214
+ ```typescript
215
+ // Renders on the deck.gl engine by default:
216
+ await control.addRaster("https://example.com/mosaic.json");
217
+ await control.addRaster(
218
+ "https://data.source.coop/giswqs/opengeos/naip_nd_2023_stac.json",
219
+ );
220
+ ```
221
+
222
+ To build a STAC `FeatureCollection` from your own COGs (local or remote), use
223
+ the `make_stac.py` helper in this repo:
224
+
225
+ ```bash
226
+ # A directory of local COGs, hosted under a public base URL:
227
+ python python/make_stac.py ./tiles -o mosaic.json --href-base https://data.example.com/tiles
228
+ # ...or explicit remote COG URLs (add --full for complete STAC Items):
229
+ python python/make_stac.py https://data.example.com/a.tif https://data.example.com/b.tif -o mosaic.json
230
+ ```
231
+
232
+ To build the same `FeatureCollection` from imagery you *don't* host — by
233
+ searching a STAC API such as the
234
+ [Planetary Computer](https://planetarycomputer.microsoft.com/) — use
235
+ `search_stac.py` (standard library only):
236
+
237
+ ```bash
238
+ # NAIP over a bbox, one year:
239
+ python python/search_stac.py -c naip -b -99.3759,46.8959,-98.8825,47.1299 -d 2023 -o naip.json
240
+ # Least-cloudy Sentinel-2 scenes, with SAS-signed hrefs for browser access:
241
+ 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 \
242
+ --query '{"eo:cloud_cover":{"lt":10}}' --sortby eo:cloud_cover \
243
+ --max-items 20 --asset visual --sign -o s2.json
244
+ ```
245
+
246
+ Both scripts pretty-print with a 2-space indent by default; pass `--compact` to
247
+ write the document on a single line instead (about a third smaller, and the
248
+ shape the deck.gl-raster example ships).
249
+
250
+ Point `--api` at any other STAC API (e.g. Earth Search) to search it instead.
251
+ Planetary Computer collections whose blobs are not anonymously readable need
252
+ `--sign`; those tokens expire, so re-run the search rather than reusing an old
253
+ file.
254
+
255
+ On the default **`maplibre-gl-raster`** engine the mosaic is a deck.gl
256
+ `MosaicLayer`: a spatial index culls to the viewport and renders one on-GPU
257
+ `COGLayer` per visible asset (each read directly over HTTP and reprojected by
258
+ its own header), all sharing one visualization state. Both mosaic kinds also
259
+ render on the **`cog-tiler-wasm`** engine, which composites them per tile: for
260
+ each tile it picks the assets whose bbox covers it, decodes each on the CPU, and
261
+ paints them into one tile (stopping as soon as the tile is opaque, so a tile
262
+ inside a single asset costs one decode). A **MosaicJSON** can additionally render
263
+ on the **`titiler`** engine (server-side); a **STAC** mosaic has no TiTiler
264
+ equivalent. Adding a mosaic keeps the active engine when it can draw it, and
265
+ otherwise falls back to the deck.gl engine.
266
+
267
+ A large mosaic (more than ~48 assets) opens on a capped, centred view and hides
268
+ below a `minZoom` derived from the asset size, so a low/world view never spins
269
+ up a `COGLayer` for every asset at once — zoom in to explore, and pan to stream
270
+ in neighbours. A small mosaic always draws its full extent.
271
+
272
+ > Client-side rendering reads each COG directly, so the assets must be
273
+ > **CORS-enabled** and `https` (an `s3://` asset is rewritten to its
274
+ > virtual-hosted `https` form, but the bucket must still allow browser access).
275
+ > For assets a browser cannot reach, use the `titiler` engine instead. The band
276
+ > count, colormap and rescale window are taken from the first asset's header.
164
277
 
165
278
  `cog-tiler-wasm` is an **optional peer dependency**, loaded lazily the first
166
279
  time the engine is selected, so it never enters the default bundle. To use it,