Skip to content

Commit 0503503

Browse files
committed
Add support for COG and Zarr
1 parent 6d58331 commit 0503503

18 files changed

Lines changed: 3370 additions & 41 deletions

README.md

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Extended functionality for MapLibre GL JS with convenient methods for basemaps,
1212
- **Basemap Support**: 35+ free basemap providers including OpenStreetMap, CartoDB, Esri, Google, Stadia, USGS, and more
1313
- **GeoJSON Layers**: Easy-to-use methods for adding GeoJSON data with auto-detection of geometry types
1414
- **Raster Layers**: Support for XYZ tile layers, WMS services, and Cloud Optimized GeoTIFFs (COG)
15+
- **GPU COG Layers**: GPU-accelerated Cloud Optimized GeoTIFF rendering using deck.gl for large rasters
16+
- **Zarr Layers**: Multi-dimensional array data visualization (climate data, satellite imagery time series)
1517
- **Layer Management**: Toggle visibility, adjust opacity, reorder layers, and more
1618
- **Map State**: Capture and restore complete map state (camera, style, terrain, sky, layers, controls)
1719
- **TypeScript First**: Full TypeScript support with module augmentation for type-safe Map methods
@@ -198,14 +200,71 @@ map.addWmsLayer('https://example.com/wms', {
198200
opacity: 0.7,
199201
});
200202

201-
// Add Cloud Optimized GeoTIFF
203+
// Add Cloud Optimized GeoTIFF (tile-based)
202204
map.addCogLayer('https://example.com/raster.tif', {
203205
tileServerUrl: 'https://titiler.example.com', // TiTiler server URL
204206
opacity: 0.9,
205207
bounds: [-180, -90, 180, 90],
206208
});
207209
```
208210

211+
### GPU COG Layers
212+
213+
For large Cloud Optimized GeoTIFFs, use GPU-accelerated rendering with deck.gl:
214+
215+
```typescript
216+
// Add GPU-accelerated COG layer
217+
const layerId = await map.addGpuCogLayer('https://example.com/large-raster.tif', {
218+
opacity: 0.8,
219+
fitBounds: true, // Automatically zoom to raster extent
220+
debug: false, // Show debug tiles
221+
debugOpacity: 0.25, // Debug tile opacity
222+
maxError: 0.125, // Maximum terrain mesh error
223+
});
224+
225+
// Control visibility and opacity
226+
map.setLayerVisibility(layerId, false);
227+
map.setLayerOpacity(layerId, 0.5);
228+
229+
// Remove the layer
230+
map.removeLayerById(layerId);
231+
```
232+
233+
### Zarr Layers
234+
235+
Visualize multi-dimensional array data (e.g., climate data, satellite time series):
236+
237+
```typescript
238+
// Add Zarr layer
239+
const layerId = await map.addZarrLayer(
240+
'https://carbonplan-maps.s3.us-west-2.amazonaws.com/v2/demo/4d/tavg-prec-month',
241+
{
242+
variable: 'tavg', // Variable to display
243+
colormap: ['#440154', '#21918c', '#fde725'], // Viridis-like colormap
244+
clim: [0, 30], // Color limits [min, max]
245+
opacity: 0.8,
246+
selector: { month: 6 }, // Dimension selector
247+
fillValue: -9999, // No-data value
248+
}
249+
);
250+
251+
// Update dimension selector (e.g., change month)
252+
map.setZarrSelector(layerId, { month: 9 }); // October
253+
254+
// Update color limits
255+
map.setZarrClim(layerId, [-10, 40]);
256+
257+
// Update colormap
258+
map.setZarrColormap(layerId, ['#3b4cc0', '#f7f7f7', '#b40426']); // Coolwarm
259+
260+
// Control visibility and opacity
261+
map.setLayerVisibility(layerId, false);
262+
map.setLayerOpacity(layerId, 0.5);
263+
264+
// Remove the layer
265+
map.removeZarrLayer(layerId);
266+
```
267+
209268
### Layer Management
210269

211270
```typescript
@@ -351,6 +410,11 @@ const {
351410
addRasterLayer,
352411
addCogLayer,
353412
addWmsLayer,
413+
addGpuCogLayer, // GPU-accelerated COG layers
414+
addZarrLayer, // Zarr multi-dimensional data
415+
setZarrSelector, // Update Zarr dimension selector
416+
setZarrClim, // Update Zarr color limits
417+
setZarrColormap, // Update Zarr colormap
354418
removeLayer,
355419
toggleLayerVisibility,
356420
setLayerOpacity,
@@ -398,6 +462,8 @@ import type {
398462
AddRasterOptions,
399463
AddCogOptions,
400464
AddWmsOptions,
465+
AddGpuCogOptions,
466+
AddZarrOptions,
401467
LayerInfo,
402468
// State types
403469
MapState,

examples/cog/index.html

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>MapLibre GL Extend - GPU COG Layer Example</title>
7+
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@5.0.0/dist/maplibre-gl.css">
8+
<style>
9+
* {
10+
margin: 0;
11+
padding: 0;
12+
box-sizing: border-box;
13+
}
14+
body {
15+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
16+
}
17+
#map {
18+
width: 100vw;
19+
height: 100vh;
20+
}
21+
.controls {
22+
position: absolute;
23+
bottom: 30px;
24+
left: 10px;
25+
background: white;
26+
padding: 15px;
27+
border-radius: 8px;
28+
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
29+
max-width: 320px;
30+
max-height: calc(100vh - 60px);
31+
overflow-y: auto;
32+
z-index: 1000;
33+
}
34+
.controls h3 {
35+
margin: 0 0 10px 0;
36+
font-size: 14px;
37+
color: #333;
38+
}
39+
.control-group {
40+
margin-bottom: 12px;
41+
}
42+
.control-group label {
43+
display: block;
44+
margin-bottom: 4px;
45+
font-size: 12px;
46+
color: #666;
47+
}
48+
.control-group select,
49+
.control-group button,
50+
.control-group input {
51+
width: 100%;
52+
padding: 8px;
53+
border: 1px solid #ddd;
54+
border-radius: 4px;
55+
font-size: 13px;
56+
}
57+
.control-group button {
58+
background: #3388ff;
59+
color: white;
60+
border: none;
61+
cursor: pointer;
62+
margin-top: 4px;
63+
}
64+
.control-group button:hover {
65+
background: #2266cc;
66+
}
67+
.control-group button:disabled {
68+
background: #cccccc;
69+
cursor: not-allowed;
70+
}
71+
.slider-group {
72+
display: flex;
73+
align-items: center;
74+
gap: 10px;
75+
}
76+
.slider-group input[type="range"] {
77+
flex: 1;
78+
}
79+
.slider-group span {
80+
min-width: 40px;
81+
text-align: right;
82+
font-size: 12px;
83+
}
84+
.layer-item {
85+
display: flex;
86+
align-items: center;
87+
justify-content: space-between;
88+
padding: 6px 8px;
89+
background: #f5f5f5;
90+
border-radius: 4px;
91+
margin-top: 4px;
92+
font-size: 12px;
93+
}
94+
.layer-item button {
95+
padding: 4px 8px;
96+
font-size: 11px;
97+
width: auto;
98+
}
99+
.layer-item button.remove {
100+
background: #dc3545;
101+
}
102+
.status {
103+
padding: 8px;
104+
background: #f0f0f0;
105+
border-radius: 4px;
106+
font-size: 12px;
107+
color: #666;
108+
}
109+
.status.loading {
110+
background: #fff3cd;
111+
color: #856404;
112+
}
113+
.status.success {
114+
background: #d4edda;
115+
color: #155724;
116+
}
117+
.status.error {
118+
background: #f8d7da;
119+
color: #721c24;
120+
}
121+
</style>
122+
</head>
123+
<body>
124+
<div id="map"></div>
125+
<div class="controls">
126+
<h3>GPU COG Layer Demo</h3>
127+
128+
<div class="control-group">
129+
<label>Select COG Layer</label>
130+
<select id="cog-select">
131+
<option value="">-- Select a COG --</option>
132+
<option value="https://s3.us-east-1.amazonaws.com/ds-deck.gl-raster-public/cog/Annual_NLCD_LndCov_2024_CU_C1V1.tif">NLCD 2024 Land Cover</option>
133+
<option value="https://s3.us-east-1.amazonaws.com/ds-deck.gl-raster-public/cog/NOAA_GOES_West_201907291630.tif">NOAA GOES West Imagery</option>
134+
</select>
135+
<button id="add-cog" disabled>Add COG Layer</button>
136+
</div>
137+
138+
<div class="control-group">
139+
<label>Opacity</label>
140+
<div class="slider-group">
141+
<input type="range" id="opacity-slider" min="0" max="100" value="100" disabled>
142+
<span id="opacity-value">100%</span>
143+
</div>
144+
</div>
145+
146+
<div class="control-group">
147+
<label>Options</label>
148+
<div style="display: flex; gap: 10px; align-items: center;">
149+
<input type="checkbox" id="fit-bounds" checked>
150+
<label for="fit-bounds" style="margin: 0; font-size: 13px;">Fit to bounds</label>
151+
</div>
152+
</div>
153+
154+
<div class="control-group">
155+
<label>Status</label>
156+
<div id="status" class="status">Ready to load COG layer</div>
157+
</div>
158+
159+
<div class="control-group">
160+
<label>Loaded Layers</label>
161+
<div id="layer-list"></div>
162+
</div>
163+
</div>
164+
<script type="module" src="./main.ts"></script>
165+
</body>
166+
</html>

0 commit comments

Comments
 (0)