maplibre-gl-national-map 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 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,298 @@
1
+ # MapLibre GL National Map
2
+
3
+ A [MapLibre GL JS](https://maplibre.org) plugin for searching and adding [USGS National Map web services](https://apps.nationalmap.gov/services/) to a map. It ships as a standard MapLibre `IControl` with a React wrapper, and also builds as a GeoLibre Desktop plugin bundle.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/maplibre-gl-national-map.svg)](https://www.npmjs.com/package/maplibre-gl-national-map)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![Open in CodeSandbox](https://img.shields.io/badge/Open%20in-CodeSandbox-blue?logo=codesandbox)](https://codesandbox.io/p/github/opengeos/maplibre-gl-national-map)
8
+ [![Open in StackBlitz](https://img.shields.io/badge/Open%20in-StackBlitz-blue?logo=stackblitz)](https://stackblitz.com/github/opengeos/maplibre-gl-national-map)
9
+
10
+ ## Features
11
+
12
+ - **Service Catalog** - Browse 20+ USGS National Map services grouped by collapsible categories (Basemaps, Hydrography, Elevation, Cartography, Indexes)
13
+ - **Search** - Filter services by name, title, description, or category; matching categories expand automatically
14
+ - **Layer Insertion Point** - An "Insert before" selector in the panel (or the `beforeId` option) inserts added layers beneath an existing layer (e.g. labels); changing it re-anchors layers already added
15
+ - **Resizable Panel** - Drag the panel edge to resize; works from left and right corner placements
16
+ - **Live Catalog Refresh** - Fetches the latest service listings from the National Map ArcGIS REST endpoints at runtime, with a built-in static catalog as an instant-render fallback (works offline)
17
+ - **Layer Management** - Toggle visibility, adjust opacity, and remove added layers from an "Active layers" section
18
+ - **Light/Dark Theme** - Follows `prefers-color-scheme` by default, with a `theme` option to force light or dark
19
+ - **Small-Screen Friendly** - The panel constrains itself to the map height and scrolls vertically
20
+ - **Collapsible Control** - 29x29 toggle button matching MapLibre's navigation control, with a floating panel
21
+ - **TypeScript Support** - All public types exported from the package root
22
+ - **React Integration** - React wrapper component and custom hook
23
+ - **GeoLibre Bundle Output** - Builds a zip with root `plugin.json`, bundled ESM, and CSS for GeoLibre Desktop
24
+
25
+ ## Supported Services
26
+
27
+ The catalog mirrors the map services listed at [apps.nationalmap.gov/services](https://apps.nationalmap.gov/services/). All endpoints are CORS-enabled ArcGIS REST services and need no API key:
28
+
29
+ | Category | Services | Rendering |
30
+ | ----------- | ----------------------------------------------------------------------------------------------------- | -------------------------- |
31
+ | Basemaps | USGS Topo, Imagery Only, Imagery Topo, Shaded Relief, Hydro Cached | Cached XYZ tiles |
32
+ | Hydrography | 3DHP, NHD, NHDPlus HR, Watershed Boundary Dataset | Dynamic map export |
33
+ | Elevation | 3DEP Elevation (hillshade) | ImageServer export |
34
+ | Imagery | NAIP Plus, NAIP False Color Imagery, NAIP NDVI | ImageServer export |
35
+ | Cartography | Contours, Geographic Names, Governmental Units, Map Indices, Selectable Polygons, Structures, Transportation, USGS Trails | Dynamic map export |
36
+ | Hazards | FEMA National Flood Hazard Layer | Dynamic map export |
37
+ | Other Data | Scanned USA Topo Maps, BLM PLSS, FWS National Wetlands Inventory | Cached tiles / map export |
38
+ | Indexes | 3DEP Elevation Index, NHDPlus HR Index, Seamless 1m DEM Index, NAIP Imagery Index, US Topo Availability, Special Edition 250K Maps, 3DEP Acquisition Grid | Dynamic map export |
39
+
40
+ A few services from the page are intentionally excluded: WFS/WCS endpoints and FeatureServers (not raster-displayable), NLCD land cover (WMS landing page only), and partner endpoints that were unreachable at testing time (ScienceBase geology, USGS ecosystems, GAP land cover, earthquake faults, mine symbols, NPS boundaries).
41
+
42
+ Note: layers added later render on top of earlier ones (or beneath the `beforeId` layer when configured). Remove and re-add layers to change stacking.
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ npm install maplibre-gl-national-map
48
+ ```
49
+
50
+ ## Quick Start
51
+
52
+ ### Vanilla JavaScript/TypeScript
53
+
54
+ ```typescript
55
+ import maplibregl from "maplibre-gl";
56
+ import { NationalMapControl } from "maplibre-gl-national-map";
57
+ import "maplibre-gl-national-map/style.css";
58
+
59
+ const map = new maplibregl.Map({
60
+ container: "map",
61
+ style: "https://tiles.openfreemap.org/styles/positron",
62
+ center: [-98.5, 39.8],
63
+ zoom: 4,
64
+ });
65
+
66
+ map.on("load", () => {
67
+ const control = new NationalMapControl({
68
+ title: "USGS National Map",
69
+ collapsed: false,
70
+ theme: "auto",
71
+ });
72
+
73
+ map.addControl(control, "top-right");
74
+
75
+ // Programmatic layer management
76
+ control.addService("basemap/USGSTopo");
77
+ console.log(control.getActiveLayers());
78
+ });
79
+ ```
80
+
81
+ ### React
82
+
83
+ ```tsx
84
+ import { useEffect, useRef, useState } from "react";
85
+ import maplibregl, { Map } from "maplibre-gl";
86
+ import {
87
+ NationalMapControlReact,
88
+ useNationalMapState,
89
+ } from "maplibre-gl-national-map/react";
90
+ import "maplibre-gl-national-map/style.css";
91
+
92
+ function App() {
93
+ const mapContainer = useRef<HTMLDivElement>(null);
94
+ const [map, setMap] = useState<Map | null>(null);
95
+ const { state, toggle } = useNationalMapState();
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/positron",
103
+ center: [-98.5, 39.8],
104
+ zoom: 4,
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
+ <NationalMapControlReact
117
+ map={map}
118
+ title="National Map"
119
+ collapsed={state.collapsed}
120
+ theme="auto"
121
+ onStateChange={(newState) => console.log(newState)}
122
+ />
123
+ )}
124
+ </div>
125
+ );
126
+ }
127
+ ```
128
+
129
+ ## API
130
+
131
+ ### NationalMapControl
132
+
133
+ The main control class implementing MapLibre's `IControl` interface.
134
+
135
+ #### Constructor Options
136
+
137
+ | Option | Type | Default | Description |
138
+ | ------------ | --------- | ---------------- | -------------------------------------------------------------------------- |
139
+ | `collapsed` | `boolean` | `true` | Whether the panel starts collapsed (showing only the 29x29 toggle button) |
140
+ | `position` | `string` | `'top-right'` | Control position on the map |
141
+ | `title` | `string` | `'USGS National Map'` | Title displayed in the header |
142
+ | `panelWidth` | `number` | `320` | Initial width of the dropdown panel in pixels (user-resizable by dragging the panel edge) |
143
+ | `className` | `string` | `''` | Custom CSS class name |
144
+ | `theme` | `string` | `'auto'` | Color theme: `'light'`, `'dark'`, or `'auto'` (follows `prefers-color-scheme`) |
145
+ | `beforeId` | `string` | `undefined` | Existing layer id to insert added layers before, so services render underneath it (ignored if the layer does not exist). Also adjustable at runtime via the panel's "Insert before" selector |
146
+
147
+ #### Methods
148
+
149
+ - `toggle()` - Toggle the collapsed state
150
+ - `expand()` - Expand the panel
151
+ - `collapse()` - Collapse the panel
152
+ - `getState()` - Get the current state (includes `activeLayerIds`)
153
+ - `setState(state)` - Update the state
154
+ - `addService(serviceId)` - Add a catalog service to the map (e.g. `"basemap/USGSTopo"`)
155
+ - `removeService(serviceId)` - Remove a previously added service
156
+ - `getActiveLayers()` - Get the services currently added to the map
157
+ - `setTheme(theme)` - Change the theme at runtime
158
+ - `on(event, handler)` - Register an event handler
159
+ - `off(event, handler)` - Remove an event handler
160
+ - `getMap()` - Get the map instance
161
+ - `getContainer()` - Get the container element
162
+
163
+ #### Events
164
+
165
+ - `collapse` - Fired when the panel is collapsed
166
+ - `expand` - Fired when the panel is expanded
167
+ - `statechange` - Fired when the state changes
168
+ - `layeradd` - Fired when a service is added to the map (`event.service` is the service)
169
+ - `layerremove` - Fired when a service is removed from the map
170
+
171
+ ### NationalMapControlReact
172
+
173
+ React wrapper component for `NationalMapControl`.
174
+
175
+ #### Props
176
+
177
+ All `NationalMapControl` options plus:
178
+
179
+ | Prop | Type | Description |
180
+ | --------------- | ---------- | ----------------------------------- |
181
+ | `map` | `Map` | MapLibre GL map instance (required) |
182
+ | `onStateChange` | `function` | Callback fired when state changes |
183
+
184
+ ### useNationalMapState
185
+
186
+ Custom React hook for managing control state.
187
+
188
+ ```typescript
189
+ const {
190
+ state, // Current state
191
+ setState, // Replace the state
192
+ setCollapsed, // Set collapsed state
193
+ setPanelWidth, // Set panel width
194
+ setData, // Merge custom data
195
+ reset, // Reset to defaults
196
+ toggle, // Toggle collapsed
197
+ } = useNationalMapState({ collapsed: false });
198
+ ```
199
+
200
+ ### Data Layer
201
+
202
+ The catalog and spec builders are exported for advanced use without the UI control:
203
+
204
+ ```typescript
205
+ import {
206
+ STATIC_CATALOG, // Built-in service catalog
207
+ fetchCatalog, // Live catalog fetch with static fallback
208
+ buildLayerSpec, // NationalMapService -> MapLibre source/layer specs
209
+ filterServices, // Search the catalog
210
+ groupByCategory, // Group services for display
211
+ LayerManager, // Add/remove/visibility/opacity on a map
212
+ } from "maplibre-gl-national-map";
213
+
214
+ const spec = buildLayerSpec(STATIC_CATALOG[0]);
215
+ map.addSource(spec.sourceId, spec.source);
216
+ map.addLayer(spec.layer);
217
+ ```
218
+
219
+ Exported types include `NationalMapService`, `NationalMapControlOptions`, `NationalMapState`, `NationalMapTheme`, `NationalMapHost`, `NationalMapCategory`, `ServiceType`, `ServiceRenderMode`, `ActiveLayer`, `LayerSpec`, and `CategoryGroup`.
220
+
221
+ ## Theming
222
+
223
+ The control uses CSS custom properties scoped to `.national-map` and `.national-map-panel`. With `theme: 'auto'` (default), dark colors apply when the OS is in dark mode. Use `theme: 'light'` or `theme: 'dark'` to force a theme, or override the `--nm-*` variables in your own CSS:
224
+
225
+ ```css
226
+ .national-map-panel {
227
+ --nm-accent: #2e7d32;
228
+ --nm-accent-hover: #1b5e20;
229
+ }
230
+ ```
231
+
232
+ ## Examples
233
+
234
+ Run locally:
235
+
236
+ ```bash
237
+ npm install
238
+ npm run dev
239
+ ```
240
+
241
+ - Basic: http://localhost:5173/examples/basic/
242
+ - React (with theme switcher): http://localhost:5173/examples/react/
243
+
244
+ ## Build a GeoLibre plugin zip
245
+
246
+ 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.
247
+
248
+ ```bash
249
+ npm install
250
+ npm run package:geolibre
251
+ ```
252
+
253
+ This creates:
254
+
255
+ ```text
256
+ geolibre-plugin/maplibre-gl-national-map-0.1.0.zip
257
+ ```
258
+
259
+ 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:
260
+
261
+ ```text
262
+ ~/.local/share/org.geolibre.desktop/plugins/
263
+ ```
264
+
265
+ For the GeoLibre web app, serve the unpacked plugin with CORS enabled:
266
+
267
+ ```bash
268
+ npm run package:geolibre
269
+ npm run serve:geolibre -- 8000
270
+ ```
271
+
272
+ Then add this manifest URL in GeoLibre Settings > Plugins:
273
+
274
+ ```text
275
+ http://localhost:8000/plugin.json
276
+ ```
277
+
278
+ ## Development
279
+
280
+ ```bash
281
+ npm install # Install dependencies
282
+ npm run dev # Start the dev server
283
+ npm test # Run the test suite
284
+ npm run lint # Lint
285
+ npm run build # Build the library and GeoLibre bundle
286
+ ```
287
+
288
+ ## Docker
289
+
290
+ ```bash
291
+ docker build -t maplibre-gl-national-map .
292
+ docker run -p 8080:80 maplibre-gl-national-map
293
+ # Open http://localhost:8080/maplibre-gl-national-map/
294
+ ```
295
+
296
+ ## License
297
+
298
+ MIT