maplibre-gl-nasa-earthdata 0.1.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/LICENSE +21 -0
- package/README.md +341 -0
- package/dist/NasaEarthdataControl-Bb3Evjmo.js +1482 -0
- package/dist/NasaEarthdataControl-Bb3Evjmo.js.map +1 -0
- package/dist/NasaEarthdataControl-BtND3ufy.cjs +1553 -0
- package/dist/NasaEarthdataControl-BtND3ufy.cjs.map +1 -0
- package/dist/index.cjs +14 -0
- package/dist/index.mjs +2 -0
- package/dist/maplibre-gl-nasa-earthdata.css +727 -0
- package/dist/react.cjs +157 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.mjs +155 -0
- package/dist/react.mjs.map +1 -0
- package/dist/types/index.d.cts +747 -0
- package/dist/types/index.d.ts +747 -0
- package/dist/types/react.d.cts +326 -0
- package/dist/types/react.d.ts +326 -0
- package/package.json +113 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Qiusheng Wu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# maplibre-gl-nasa-earthdata
|
|
2
|
+
|
|
3
|
+
A [MapLibre GL JS](https://maplibre.org/) plugin for searching and adding [NASA GIBS](https://earthdata.nasa.gov/gibs) (Global Imagery Browse Services) Earthdata imagery layers to a map.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/maplibre-gl-nasa-earthdata)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
The plugin adds a collapsible map control that fetches the GIBS WMTS capabilities document, lets users search the catalog of 1,100+ raster layers by name, and add imagery layers to the map with per-layer date and opacity controls.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Layer Search** - Search 1,100+ NASA GIBS raster layers by title or identifier
|
|
13
|
+
- **Category Browser** - Layers grouped into collapsible categories by platform/instrument (MODIS, VIIRS, MERRA2, ...)
|
|
14
|
+
- **Layer Management** - Added-layers panel with visibility toggle, legend display, opacity slider, and removal
|
|
15
|
+
- **Insert Before** - Choose where new layers are inserted in the map's layer stack (e.g. below labels)
|
|
16
|
+
- **Time Dimension Support** - Date picker for time-enabled layers (daily/monthly imagery); add the same layer multiple times with different dates to compare
|
|
17
|
+
- **Collapsible Control** - Compact 29x29 button that expands into a floating panel
|
|
18
|
+
- **Resizable Panel** - Drag the panel edge to adjust its width in any corner
|
|
19
|
+
- **Dark and Light Mode** - Follows the OS preference, or force a theme via the `theme` option
|
|
20
|
+
- **Small Screen Friendly** - Panel fits the viewport with a vertical scrollbar
|
|
21
|
+
- **TypeScript Support** - Full type definitions for all public APIs
|
|
22
|
+
- **React Integration** - React wrapper component and custom hook
|
|
23
|
+
- **Programmatic API** - Search and add/remove layers from code
|
|
24
|
+
- **GeoLibre Bundle Output** - Builds a zip plugin bundle for GeoLibre Desktop
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install maplibre-gl-nasa-earthdata
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
### Vanilla JavaScript/TypeScript
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import maplibregl from "maplibre-gl";
|
|
38
|
+
import { NasaEarthdataControl } from "maplibre-gl-nasa-earthdata";
|
|
39
|
+
import "maplibre-gl-nasa-earthdata/style.css";
|
|
40
|
+
|
|
41
|
+
const map = new maplibregl.Map({
|
|
42
|
+
container: "map",
|
|
43
|
+
style: "https://tiles.openfreemap.org/styles/liberty",
|
|
44
|
+
center: [0, 20],
|
|
45
|
+
zoom: 2,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
map.on("load", () => {
|
|
49
|
+
const control = new NasaEarthdataControl({
|
|
50
|
+
title: "NASA Earthdata",
|
|
51
|
+
collapsed: false,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
map.addControl(control, "top-right");
|
|
55
|
+
|
|
56
|
+
control.on("layeradd", (event) => {
|
|
57
|
+
console.log("Added layer:", event.layer?.id);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Programmatic layer management
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
const control = new NasaEarthdataControl();
|
|
66
|
+
map.addControl(control, "top-right");
|
|
67
|
+
|
|
68
|
+
// Load the GIBS catalog, then add a layer by identifier
|
|
69
|
+
await control.getCapabilities();
|
|
70
|
+
control.addLayer("MODIS_Terra_CorrectedReflectance_TrueColor", {
|
|
71
|
+
date: "2024-06-01",
|
|
72
|
+
opacity: 0.8,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Update or remove later
|
|
76
|
+
control.setLayerDate("MODIS_Terra_CorrectedReflectance_TrueColor", "2024-07-01");
|
|
77
|
+
control.setLayerOpacity("MODIS_Terra_CorrectedReflectance_TrueColor", 0.5);
|
|
78
|
+
control.removeLayer("MODIS_Terra_CorrectedReflectance_TrueColor");
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### React
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import { useEffect, useRef, useState } from "react";
|
|
85
|
+
import maplibregl, { Map } from "maplibre-gl";
|
|
86
|
+
import {
|
|
87
|
+
NasaEarthdataControlReact,
|
|
88
|
+
useNasaEarthdata,
|
|
89
|
+
} from "maplibre-gl-nasa-earthdata/react";
|
|
90
|
+
import "maplibre-gl-nasa-earthdata/style.css";
|
|
91
|
+
|
|
92
|
+
function App() {
|
|
93
|
+
const mapContainer = useRef<HTMLDivElement>(null);
|
|
94
|
+
const [map, setMap] = useState<Map | null>(null);
|
|
95
|
+
const { state, setState, toggle } = useNasaEarthdata();
|
|
96
|
+
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (!mapContainer.current) return;
|
|
99
|
+
|
|
100
|
+
const mapInstance = new maplibregl.Map({
|
|
101
|
+
container: mapContainer.current,
|
|
102
|
+
style: "https://tiles.openfreemap.org/styles/liberty",
|
|
103
|
+
center: [0, 20],
|
|
104
|
+
zoom: 2,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
mapInstance.on("load", () => setMap(mapInstance));
|
|
108
|
+
|
|
109
|
+
return () => mapInstance.remove();
|
|
110
|
+
}, []);
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div style={{ width: "100%", height: "100vh" }}>
|
|
114
|
+
<div ref={mapContainer} style={{ width: "100%", height: "100%" }} />
|
|
115
|
+
{map && (
|
|
116
|
+
<NasaEarthdataControlReact
|
|
117
|
+
map={map}
|
|
118
|
+
collapsed={state.collapsed}
|
|
119
|
+
onStateChange={setState}
|
|
120
|
+
onLayerAdd={(layer) => console.log("Added:", layer.id)}
|
|
121
|
+
/>
|
|
122
|
+
)}
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## API
|
|
129
|
+
|
|
130
|
+
### NasaEarthdataControl
|
|
131
|
+
|
|
132
|
+
The main control class implementing MapLibre's `IControl` interface.
|
|
133
|
+
|
|
134
|
+
#### Constructor Options
|
|
135
|
+
|
|
136
|
+
| Option | Type | Default | Description |
|
|
137
|
+
| ----------------- | ------------------------------- | ---------------------- | ------------------------------------------------------------------------- |
|
|
138
|
+
| `collapsed` | `boolean` | `true` | Whether the panel starts collapsed (showing only the 29x29 toggle button) |
|
|
139
|
+
| `position` | `string` | `'top-right'` | Control position on the map |
|
|
140
|
+
| `title` | `string` | `'NASA Earthdata'` | Title displayed in the header |
|
|
141
|
+
| `panelWidth` | `number` | `320` | Initial width of the dropdown panel in pixels (drag the edge to resize) |
|
|
142
|
+
| `className` | `string` | `''` | Custom CSS class name |
|
|
143
|
+
| `capabilitiesUrl` | `string` | GIBS EPSG:3857 best | URL of the WMTS capabilities document |
|
|
144
|
+
| `includeVector` | `boolean` | `false` | Include vector-tile (MVT) layers in search results |
|
|
145
|
+
| `showOpacity` | `boolean` | `true` | Show an opacity slider for added layers |
|
|
146
|
+
| `attribution` | `string` | NASA EOSDIS GIBS link | Attribution applied to added raster sources |
|
|
147
|
+
| `theme` | `'auto' \| 'light' \| 'dark'` | `'auto'` | Color theme; `'auto'` follows the OS preference |
|
|
148
|
+
|
|
149
|
+
#### Methods
|
|
150
|
+
|
|
151
|
+
- `getCapabilities(force?)` - Fetch and cache the GIBS layer catalog
|
|
152
|
+
- `search(query)` - Search loaded layers by title or identifier
|
|
153
|
+
- `addLayer(layerId, { date?, opacity?, visible?, before? })` - Add a GIBS layer to the map. Time-enabled layers can be added multiple times with different dates; each addition is an instance with a unique `key` (see `AddedLayerState`)
|
|
154
|
+
- `removeLayer(keyOrId)` - Remove an instance by key, or all instances of a layer by its GIBS identifier
|
|
155
|
+
- `setLayerDate(keyOrId, date)` - Change the date of a time-enabled layer instance
|
|
156
|
+
- `setLayerOpacity(keyOrId, opacity)` - Change an instance's opacity (0 to 1)
|
|
157
|
+
- `setLayerVisibility(keyOrId, visible)` - Show or hide an added instance
|
|
158
|
+
- `getAddedLayers()` - Get the state of all added layers
|
|
159
|
+
- `toggle()` / `expand()` / `collapse()` - Control the panel
|
|
160
|
+
- `getState()` / `setState(state)` - Read or reconcile the control state
|
|
161
|
+
- `on(event, handler)` / `off(event, handler)` - Manage event handlers
|
|
162
|
+
- `getMap()` / `getContainer()` - Access the map instance and container element
|
|
163
|
+
|
|
164
|
+
#### Events
|
|
165
|
+
|
|
166
|
+
- `collapse` / `expand` - Panel visibility changed
|
|
167
|
+
- `statechange` - State changed (query, added layers, etc.)
|
|
168
|
+
- `layeradd` / `layerremove` - A GIBS layer was added or removed (payload includes `layer`)
|
|
169
|
+
- `capabilitiesload` - The GIBS catalog finished loading
|
|
170
|
+
- `error` - An error occurred (payload includes `error`)
|
|
171
|
+
|
|
172
|
+
### NasaEarthdataControlReact
|
|
173
|
+
|
|
174
|
+
React wrapper component for `NasaEarthdataControl`.
|
|
175
|
+
|
|
176
|
+
#### Props
|
|
177
|
+
|
|
178
|
+
All `NasaEarthdataControl` options plus:
|
|
179
|
+
|
|
180
|
+
| Prop | Type | Description |
|
|
181
|
+
| --------------- | ---------- | -------------------------------------- |
|
|
182
|
+
| `map` | `Map` | MapLibre GL map instance (required) |
|
|
183
|
+
| `onStateChange` | `function` | Callback fired when state changes |
|
|
184
|
+
| `onLayerAdd` | `function` | Callback fired when a layer is added |
|
|
185
|
+
| `onLayerRemove` | `function` | Callback fired when a layer is removed |
|
|
186
|
+
|
|
187
|
+
### useNasaEarthdata
|
|
188
|
+
|
|
189
|
+
Custom React hook for managing control state.
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
const {
|
|
193
|
+
state, // Current state
|
|
194
|
+
setState, // Update entire state
|
|
195
|
+
setCollapsed, // Set collapsed state
|
|
196
|
+
setPanelWidth, // Set panel width
|
|
197
|
+
setQuery, // Set the search query
|
|
198
|
+
setAddedLayers, // Set the added layers list
|
|
199
|
+
reset, // Reset to initial state
|
|
200
|
+
toggle, // Toggle collapsed state
|
|
201
|
+
} = useNasaEarthdata(initialState);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### GIBS helpers
|
|
205
|
+
|
|
206
|
+
Lower-level building blocks are exported for advanced use:
|
|
207
|
+
|
|
208
|
+
- `GibsClient` - Fetches, parses, and caches the capabilities document
|
|
209
|
+
- `parseCapabilities(xml, options?)` - Parse a WMTS capabilities XML string
|
|
210
|
+
- `buildTileUrl(layer, time?)` - Build an XYZ tile URL template for a layer
|
|
211
|
+
- `searchLayers(layers, query)` - Filter layers by title or identifier
|
|
212
|
+
- `DEFAULT_CAPABILITIES_URL` - The default GIBS capabilities URL
|
|
213
|
+
|
|
214
|
+
### Exported Types
|
|
215
|
+
|
|
216
|
+
`NasaEarthdataControlOptions`, `NasaEarthdataState`, `AddedLayerState`, `NasaEarthdataEvent`, `NasaEarthdataEventPayload`, `NasaEarthdataEventHandler`, `NasaEarthdataReactProps`, `GibsLayer`, `GibsLayerFormat`, `GibsTimeDimension`, `GibsCapabilities`, `ParseOptions`, `GibsClientOptions`
|
|
217
|
+
|
|
218
|
+
## Theming
|
|
219
|
+
|
|
220
|
+
The control renders properly in both light and dark mode:
|
|
221
|
+
|
|
222
|
+
- By default (`theme: 'auto'`), colors follow the OS `prefers-color-scheme` setting.
|
|
223
|
+
- Pass `theme: 'dark'` or `theme: 'light'` to force a theme.
|
|
224
|
+
- All colors are driven by CSS custom properties (prefixed `--ne-`) on the
|
|
225
|
+
`.maplibre-gl-nasa-earthdata` class, so they can be overridden in your own CSS.
|
|
226
|
+
|
|
227
|
+
## Build a GeoLibre plugin zip
|
|
228
|
+
|
|
229
|
+
GeoLibre Desktop loads external plugins from an app data `plugins/` directory. The zip must contain `plugin.json` at the root, plus a bundled ESM entry and optional CSS file.
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
npm install
|
|
233
|
+
npm run package:geolibre
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
This creates:
|
|
237
|
+
|
|
238
|
+
```text
|
|
239
|
+
geolibre-plugin/maplibre-gl-nasa-earthdata-0.1.0.zip
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Copy the zip into GeoLibre Desktop's app data `plugins/` directory and restart GeoLibre. On Linux with the default app identifier, that directory is usually:
|
|
243
|
+
|
|
244
|
+
```text
|
|
245
|
+
~/.local/share/org.geolibre.desktop/plugins/
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
For the GeoLibre web app, serve the unpacked plugin with CORS enabled:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
npm run package:geolibre
|
|
252
|
+
npm run serve:geolibre -- 8000
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Then add `http://localhost:8000/plugin.json` in GeoLibre Settings > Plugins.
|
|
256
|
+
|
|
257
|
+
## Development
|
|
258
|
+
|
|
259
|
+
### Setup
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
# Clone the repository
|
|
263
|
+
git clone https://github.com/opengeos/maplibre-gl-nasa-earthdata.git
|
|
264
|
+
cd maplibre-gl-nasa-earthdata
|
|
265
|
+
|
|
266
|
+
# Install dependencies
|
|
267
|
+
npm install
|
|
268
|
+
|
|
269
|
+
# Start development server
|
|
270
|
+
npm run dev
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Scripts
|
|
274
|
+
|
|
275
|
+
| Script | Description |
|
|
276
|
+
| -------------------------- | ---------------------------------------- |
|
|
277
|
+
| `npm run dev` | Start development server |
|
|
278
|
+
| `npm run build` | Build the library and GeoLibre bundle |
|
|
279
|
+
| `npm run build:lib` | Build the standalone MapLibre library |
|
|
280
|
+
| `npm run build:geolibre` | Build the GeoLibre ESM and CSS bundle |
|
|
281
|
+
| `npm run package:geolibre` | Build and zip the GeoLibre plugin bundle |
|
|
282
|
+
| `npm run build:examples` | Build examples for deployment |
|
|
283
|
+
| `npm run test` | Run tests |
|
|
284
|
+
| `npm run test:ui` | Run tests with UI |
|
|
285
|
+
| `npm run test:coverage` | Run tests with coverage |
|
|
286
|
+
| `npm run lint` | Lint the code |
|
|
287
|
+
| `npm run format` | Format the code |
|
|
288
|
+
|
|
289
|
+
### Project Structure
|
|
290
|
+
|
|
291
|
+
```text
|
|
292
|
+
maplibre-gl-nasa-earthdata/
|
|
293
|
+
├── geolibre-plugin/
|
|
294
|
+
│ └── plugin.json # GeoLibre external plugin manifest
|
|
295
|
+
├── scripts/
|
|
296
|
+
│ └── package-geolibre-plugin.mjs
|
|
297
|
+
├── src/
|
|
298
|
+
│ ├── index.ts # Main entry point
|
|
299
|
+
│ ├── geolibre.ts # GeoLibre plugin wrapper entry point
|
|
300
|
+
│ ├── react.ts # React entry point
|
|
301
|
+
│ ├── index.css # Root styles
|
|
302
|
+
│ └── lib/
|
|
303
|
+
│ ├── core/ # Control class, React wrapper, and types
|
|
304
|
+
│ ├── gibs/ # GIBS capabilities parsing and tile URLs
|
|
305
|
+
│ ├── hooks/ # React hooks
|
|
306
|
+
│ ├── utils/ # Utility functions
|
|
307
|
+
│ └── styles/ # Component styles
|
|
308
|
+
├── tests/ # Test files
|
|
309
|
+
├── examples/ # Example applications
|
|
310
|
+
│ ├── basic/ # Vanilla JS example
|
|
311
|
+
│ └── react/ # React example
|
|
312
|
+
└── .github/workflows/ # CI/CD workflows
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Docker
|
|
316
|
+
|
|
317
|
+
The examples can be run using Docker. The image is automatically built and published to GitHub Container Registry.
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
# Pull the latest image
|
|
321
|
+
docker pull ghcr.io/opengeos/maplibre-gl-nasa-earthdata:latest
|
|
322
|
+
|
|
323
|
+
# Run the container
|
|
324
|
+
docker run -p 8080:80 ghcr.io/opengeos/maplibre-gl-nasa-earthdata:latest
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Then open http://localhost:8080/maplibre-gl-nasa-earthdata/ in your browser to view the examples.
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
# Or build locally
|
|
331
|
+
docker build -t maplibre-gl-nasa-earthdata .
|
|
332
|
+
docker run -p 8080:80 maplibre-gl-nasa-earthdata
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Attribution
|
|
336
|
+
|
|
337
|
+
Imagery provided by services from NASA's [Global Imagery Browse Services (GIBS)](https://earthdata.nasa.gov/gibs), part of NASA's Earth Observing System Data and Information System (EOSDIS). The plugin applies a NASA EOSDIS GIBS attribution to added raster sources by default.
|
|
338
|
+
|
|
339
|
+
## License
|
|
340
|
+
|
|
341
|
+
MIT License - see [LICENSE](LICENSE) for details.
|