Docs add deckgl raster tutorial#530
Conversation
Adds a tutorial walking through Cloud Optimized GeoTIFF rendering in the browser with deck.gl-raster — for building standalone web apps on Planetary Computer data. No companion notebook (TypeScript/React). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The tutorial scaffolded a Vite/React app around APIs that don't work as
written: COGLayer({url}) (the real prop is geotiff:), a backend signing
proxy (the PC sign endpoint is public/anonymous), and colormap/rescale
props COGLayer doesn't have. It also linked a deckgl-raster-example repo
that doesn't exist.
Replace it with a working, committed single index.html: an esm.sh import
map (no build), client-side anonymous signing, COGLayer with a
main-thread DecoderPool (size: 0) to dodge the cross-origin-worker block,
and a MapboxOverlay basemap. Add the rendered-app screenshot and a real
206 range-request log.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace em dashes with sentence splits, commas, and colons, and rename the trailing-ellipsis section header to a plain statement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the developmentseed/deck.gl-raster examples more closely: interleaved MapboxOverlay with beforeId so basemap labels stay on top, and onGeoTIFFLoad -> fitBounds to frame the scene from its own bounds instead of a STAC bbox. Also make the control panel background solid (it was slightly transparent and bled the imagery behind it) and refresh the screenshot. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
This is a nice example of how to have a single-page HTML file with deck.gl-raster! I'll adopt something like this in the deck.gl-raster docs
| // Insert deck layers before the first label layer so basemap text | ||
| // (place names, roads) stays legible on top of the imagery. | ||
| beforeId = map.getStyle().layers.find((l) => l.type === "symbol")?.id; |
There was a problem hiding this comment.
This is too low in the MapLibre layer stack.
If you look at the rendered example:
It's hard to see the image because other layers from the basemap are on top of it.
If you load the map style json (https://basemaps.cartocdn.com/gl/positron-gl-style/style.json), you can try different id values from the layers array.
In my example I use this:
https://github.com/developmentseed/deck.gl-raster/blob/55619f8f15c3e8b8696480f5974d6bd49bcfedf1/examples/naip-mosaic/src/App.tsx#L445
| layers: [ | ||
| new COGLayer({ | ||
| id: "naip", | ||
| geotiff, |
There was a problem hiding this comment.
When you pass in a geotiff as-is, deck.gl-raster uses the "default" styling it can infer. But in this case, the default styling it infers is incorrect. It sees 4 bands but it doesn't have a way to know that the fourth band refers to near-infrared data, instead of an alpha band.
You can use this, which you pass into renderTile to render as RGB
| @@ -0,0 +1,147 @@ | |||
| # Rendering Planetary Computer rasters in the browser with deck.gl-raster | |||
|
|
|||
| [deck.gl-raster](https://github.com/developmentseed/deck.gl-raster) renders Cloud Optimized GeoTIFFs directly in the browser. Its `COGLayer` reads the COG header over HTTP, then streams only the tiles visible in the current viewport, decodes them client-side, reprojects, and renders in WebGL2. No tile server, no intermediate downloads. It's the same model as [Lonboard](./lonboard.md), but in TypeScript for standalone web apps. | |||
There was a problem hiding this comment.
| [deck.gl-raster](https://github.com/developmentseed/deck.gl-raster) renders Cloud Optimized GeoTIFFs directly in the browser. Its `COGLayer` reads the COG header over HTTP, then streams only the tiles visible in the current viewport, decodes them client-side, reprojects, and renders in WebGL2. No tile server, no intermediate downloads. It's the same model as [Lonboard](./lonboard.md), but in TypeScript for standalone web apps. | |
| [deck.gl-raster](https://github.com/developmentseed/deck.gl-raster) renders Cloud Optimized GeoTIFFs directly in the browser. Its `COGLayer` reads the COG header over HTTP, then streams only the tiles visible in the current viewport, decodes them client-side, reprojects, and renders in WebGL2. No tile server, no intermediate downloads. |
I'd take this out or reword it, because generally Lonboard has used Arrow as the reason why it's faster for vector data, but deck.gl-raster doesn't use Arrow at all. The one thing they both share is that they use deck.gl as the underlying engine for powering geospatial visualizations in the browser.
| - Every `@deck.gl/*` and `@luma.gl/core` entry must be the **same version**, since mismatched patch versions throw `deck.gl - multiple versions detected`. | ||
| - The `deck.gl-geotiff` entry marks deck, luma, and geotiff as `external` so they resolve to the singletons above rather than being bundled a second time. |
There was a problem hiding this comment.
yes these are really important things to note! We should add this to the upstream deck.gl-raster docs as well.
| Bbox-search returns many items. Sign each href and pass one `COGLayer` per scene. `overlay.setProps({ layers })` diffs them and only reloads what changed: | ||
|
|
||
| ```js | ||
| const layers = signedHrefs.map((href, i) => new COGLayer({ id: `naip-${i}`, geotiff: href, pool })); | ||
| overlay.setProps({ layers }); | ||
| ``` |
There was a problem hiding this comment.
This is fine for a few scenes, maybe up to 10 or 20, but if you have hundreds of non-overlapping scenes, which fits NAIP perfectly, it's better to use the MosaicLayer, which only loads COGLayers when they're visible currently on the screen. The naip-mosaic example is an example you could point people to
| overlay.setProps({ layers }); | ||
| ``` | ||
|
|
||
| Browser memory is the practical limit. For large mosaics, reach for `MosaicLayer` / `MultiCOGLayer` from the same package, or fall back to a server-side tiler like [titiler](https://developmentseed.org/titiler/). |
There was a problem hiding this comment.
Oh I didn't see this.
It's not necessarily browser memory as the limit, because if you load 100 COG layers and they're all off screen, you'll be using very little browser memory, because only those COG headers will be loaded into memory. but it still forces you to load all those COG headers.
Also, don't suggest the MultiCOGLayer here in the context of a mosaic. That's for cases like landsat/sentinel2 where there are multiple separate COGs that are all referencing the same scene and should be composited together.
Based on the outline here