maplibre-gl-lidar 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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +395 -0
  3. package/dist/LidarControl-BFJN1DIQ.js +37815 -0
  4. package/dist/LidarControl-BFJN1DIQ.js.map +1 -0
  5. package/dist/LidarControl-CQjIl4U5.cjs +37814 -0
  6. package/dist/LidarControl-CQjIl4U5.cjs.map +1 -0
  7. package/dist/index.cjs +21 -0
  8. package/dist/index.cjs.map +1 -0
  9. package/dist/index.mjs +21 -0
  10. package/dist/index.mjs.map +1 -0
  11. package/dist/laz-perf.wasm +0 -0
  12. package/dist/laz_rs_wasm_bg.wasm +0 -0
  13. package/dist/libs/laz_rs_wasm_bg.wasm +0 -0
  14. package/dist/maplibre-gl-lidar.css +570 -0
  15. package/dist/react.cjs +179 -0
  16. package/dist/react.cjs.map +1 -0
  17. package/dist/react.mjs +179 -0
  18. package/dist/react.mjs.map +1 -0
  19. package/dist/types/index.d.ts +13 -0
  20. package/dist/types/index.d.ts.map +1 -0
  21. package/dist/types/lib/colorizers/ColorScheme.d.ts +60 -0
  22. package/dist/types/lib/colorizers/ColorScheme.d.ts.map +1 -0
  23. package/dist/types/lib/colorizers/index.d.ts +3 -0
  24. package/dist/types/lib/colorizers/index.d.ts.map +1 -0
  25. package/dist/types/lib/colorizers/types.d.ts +17 -0
  26. package/dist/types/lib/colorizers/types.d.ts.map +1 -0
  27. package/dist/types/lib/core/DeckOverlay.d.ts +64 -0
  28. package/dist/types/lib/core/DeckOverlay.d.ts.map +1 -0
  29. package/dist/types/lib/core/LidarControl.d.ts +318 -0
  30. package/dist/types/lib/core/LidarControl.d.ts.map +1 -0
  31. package/dist/types/lib/core/LidarControlReact.d.ts +35 -0
  32. package/dist/types/lib/core/LidarControlReact.d.ts.map +1 -0
  33. package/dist/types/lib/core/ViewportManager.d.ts +105 -0
  34. package/dist/types/lib/core/ViewportManager.d.ts.map +1 -0
  35. package/dist/types/lib/core/types.d.ts +235 -0
  36. package/dist/types/lib/core/types.d.ts.map +1 -0
  37. package/dist/types/lib/gui/DualRangeSlider.d.ts +46 -0
  38. package/dist/types/lib/gui/DualRangeSlider.d.ts.map +1 -0
  39. package/dist/types/lib/gui/FileInput.d.ts +44 -0
  40. package/dist/types/lib/gui/FileInput.d.ts.map +1 -0
  41. package/dist/types/lib/gui/PanelBuilder.d.ts +117 -0
  42. package/dist/types/lib/gui/PanelBuilder.d.ts.map +1 -0
  43. package/dist/types/lib/gui/RangeSlider.d.ts +50 -0
  44. package/dist/types/lib/gui/RangeSlider.d.ts.map +1 -0
  45. package/dist/types/lib/gui/index.d.ts +7 -0
  46. package/dist/types/lib/gui/index.d.ts.map +1 -0
  47. package/dist/types/lib/hooks/index.d.ts +3 -0
  48. package/dist/types/lib/hooks/index.d.ts.map +1 -0
  49. package/dist/types/lib/hooks/useLidarState.d.ts +52 -0
  50. package/dist/types/lib/hooks/useLidarState.d.ts.map +1 -0
  51. package/dist/types/lib/hooks/usePointCloud.d.ts +53 -0
  52. package/dist/types/lib/hooks/usePointCloud.d.ts.map +1 -0
  53. package/dist/types/lib/layers/PointCloudManager.d.ts +136 -0
  54. package/dist/types/lib/layers/PointCloudManager.d.ts.map +1 -0
  55. package/dist/types/lib/layers/index.d.ts +3 -0
  56. package/dist/types/lib/layers/index.d.ts.map +1 -0
  57. package/dist/types/lib/layers/types.d.ts +71 -0
  58. package/dist/types/lib/layers/types.d.ts.map +1 -0
  59. package/dist/types/lib/loaders/CopcStreamingLoader.d.ts +217 -0
  60. package/dist/types/lib/loaders/CopcStreamingLoader.d.ts.map +1 -0
  61. package/dist/types/lib/loaders/PointCloudLoader.d.ts +61 -0
  62. package/dist/types/lib/loaders/PointCloudLoader.d.ts.map +1 -0
  63. package/dist/types/lib/loaders/index.d.ts +5 -0
  64. package/dist/types/lib/loaders/index.d.ts.map +1 -0
  65. package/dist/types/lib/loaders/streaming-types.d.ts +122 -0
  66. package/dist/types/lib/loaders/streaming-types.d.ts.map +1 -0
  67. package/dist/types/lib/loaders/types.d.ts +83 -0
  68. package/dist/types/lib/loaders/types.d.ts.map +1 -0
  69. package/dist/types/lib/utils/helpers.d.ts +91 -0
  70. package/dist/types/lib/utils/helpers.d.ts.map +1 -0
  71. package/dist/types/lib/utils/index.d.ts +2 -0
  72. package/dist/types/lib/utils/index.d.ts.map +1 -0
  73. package/dist/types/react.d.ts +6 -0
  74. package/dist/types/react.d.ts.map +1 -0
  75. package/package.json +118 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Open Geospatial Solutions
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,395 @@
1
+ # maplibre-gl-lidar
2
+
3
+ A MapLibre GL JS plugin for visualizing LiDAR point clouds using deck.gl.
4
+
5
+ ## Features
6
+
7
+ - Load and visualize LAS/LAZ/COPC point cloud files (LAS 1.0 - 1.4)
8
+ - **Dynamic COPC streaming** - viewport-based loading for large cloud-optimized point clouds
9
+ - Multiple color schemes: elevation, intensity, classification, RGB
10
+ - **Percentile-based coloring** - use 2-98% percentile range for better color distribution (clips outliers)
11
+ - Interactive GUI control panel with scrollable content
12
+ - **Point picking** - hover over points to see all available attributes (coordinates, elevation, intensity, classification, RGB, GPS time, return number, etc.)
13
+ - **Z offset adjustment** - shift point clouds vertically for alignment
14
+ - **Elevation filtering** - filter points by elevation range
15
+ - Automatic coordinate transformation (projected CRS to WGS84)
16
+ - Programmatic API for loading and styling
17
+ - React integration with hooks
18
+ - deck.gl PointCloudLayer with optimized chunking for large datasets
19
+ - TypeScript support
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install maplibre-gl-lidar
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### Basic Usage (Vanilla JS/TypeScript)
30
+
31
+ ```typescript
32
+ import maplibregl from 'maplibre-gl';
33
+ import { LidarControl } from 'maplibre-gl-lidar';
34
+ import 'maplibre-gl-lidar/style.css';
35
+ import 'maplibre-gl/dist/maplibre-gl.css';
36
+
37
+ const map = new maplibregl.Map({
38
+ container: 'map',
39
+ style: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',
40
+ center: [-122.4, 37.8],
41
+ zoom: 12,
42
+ pitch: 60,
43
+ maxPitch: 85, // Allow higher pitch for better 3D viewing
44
+ });
45
+
46
+ map.on('load', () => {
47
+ // Add the LiDAR control
48
+ const lidarControl = new LidarControl({
49
+ title: 'LiDAR Viewer',
50
+ collapsed: true,
51
+ pointSize: 2,
52
+ colorScheme: 'elevation',
53
+ pickable: true, // Enable point picking for hover tooltips
54
+ });
55
+
56
+ map.addControl(lidarControl, 'top-right');
57
+
58
+ // Listen for events
59
+ lidarControl.on('load', (event) => {
60
+ console.log('Point cloud loaded:', event.pointCloud);
61
+ lidarControl.flyToPointCloud();
62
+ });
63
+
64
+ // Load a point cloud programmatically
65
+ lidarControl.loadPointCloud('https://s3.amazonaws.com/hobu-lidar/autzen-classified.copc.laz');
66
+ });
67
+ ```
68
+
69
+ ### React Usage
70
+
71
+ ```tsx
72
+ import { useEffect, useRef, useState } from 'react';
73
+ import maplibregl, { Map } from 'maplibre-gl';
74
+ import { LidarControlReact, useLidarState } from 'maplibre-gl-lidar/react';
75
+ import 'maplibre-gl-lidar/style.css';
76
+ import 'maplibre-gl/dist/maplibre-gl.css';
77
+
78
+ function App() {
79
+ const mapContainer = useRef<HTMLDivElement>(null);
80
+ const [map, setMap] = useState<Map | null>(null);
81
+ const { state, setColorScheme, setPointSize } = useLidarState();
82
+
83
+ useEffect(() => {
84
+ if (!mapContainer.current) return;
85
+
86
+ const mapInstance = new maplibregl.Map({
87
+ container: mapContainer.current,
88
+ style: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',
89
+ center: [-122.4, 37.8],
90
+ zoom: 12,
91
+ pitch: 60,
92
+ maxPitch: 85, // Allow higher pitch for better 3D viewing
93
+ });
94
+
95
+ mapInstance.on('load', () => setMap(mapInstance));
96
+
97
+ return () => mapInstance.remove();
98
+ }, []);
99
+
100
+ return (
101
+ <div style={{ width: '100%', height: '100vh' }}>
102
+ <div ref={mapContainer} style={{ width: '100%', height: '100%' }} />
103
+ {map && (
104
+ <LidarControlReact
105
+ map={map}
106
+ title="LiDAR Viewer"
107
+ pointSize={state.pointSize}
108
+ colorScheme={state.colorScheme}
109
+ onLoad={(pc) => console.log('Loaded:', pc)}
110
+ />
111
+ )}
112
+ </div>
113
+ );
114
+ }
115
+ ```
116
+
117
+ ## API Reference
118
+
119
+ ### LidarControl
120
+
121
+ The main control class implementing MapLibre's `IControl` interface.
122
+
123
+ #### Constructor Options
124
+
125
+ ```typescript
126
+ interface LidarControlOptions {
127
+ // Panel settings
128
+ collapsed?: boolean; // Start collapsed (default: true)
129
+ position?: string; // 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
130
+ title?: string; // Panel title (default: 'LiDAR Viewer')
131
+ panelWidth?: number; // Panel width in pixels (default: 365)
132
+ panelMaxHeight?: number; // Panel max height with scrollbar (default: 500)
133
+ className?: string; // Custom CSS class
134
+
135
+ // Point cloud styling
136
+ pointSize?: number; // Point size in pixels (default: 2)
137
+ opacity?: number; // Opacity 0-1 (default: 1.0)
138
+ colorScheme?: ColorScheme; // Color scheme (default: 'elevation')
139
+ usePercentile?: boolean; // Use 2-98% percentile for coloring (default: true)
140
+ pointBudget?: number; // Max points to display (default: 1000000)
141
+
142
+ // Filters and adjustments
143
+ elevationRange?: [number, number] | null; // Elevation filter
144
+ zOffsetEnabled?: boolean; // Enable Z offset adjustment (default: false)
145
+ zOffset?: number; // Z offset in meters (default: 0)
146
+
147
+ // Interaction
148
+ pickable?: boolean; // Enable point picking/hover tooltips (default: false)
149
+ pickInfoFields?: string[]; // Fields to show in tooltip (default: all)
150
+
151
+ // Behavior
152
+ autoZoom?: boolean; // Auto zoom to data after loading (default: true)
153
+
154
+ // COPC Streaming (dynamic loading)
155
+ copcLoadingMode?: 'full' | 'dynamic'; // Loading mode for COPC files (default: 'dynamic')
156
+ streamingPointBudget?: number; // Max points for streaming (default: 5000000)
157
+ streamingMaxConcurrentRequests?: number; // Concurrent node requests (default: 4)
158
+ streamingViewportDebounceMs?: number; // Viewport change debounce (default: 150)
159
+ }
160
+ ```
161
+
162
+ #### Methods
163
+
164
+ ```typescript
165
+ // Loading
166
+ loadPointCloud(source: string | File | ArrayBuffer, options?: { loadingMode?: 'full' | 'dynamic' }): Promise<PointCloudInfo>
167
+ loadPointCloudStreaming(source: string | File | ArrayBuffer, options?: StreamingLoaderOptions): Promise<PointCloudInfo>
168
+ stopStreaming(): void // Stop dynamic loading and clean up
169
+ unloadPointCloud(id?: string): void
170
+ getPointClouds(): PointCloudInfo[]
171
+ flyToPointCloud(id?: string): void
172
+
173
+ // Styling
174
+ setPointSize(size: number): void
175
+ setOpacity(opacity: number): void
176
+ setColorScheme(scheme: ColorScheme): void
177
+ setUsePercentile(usePercentile: boolean): void
178
+ getUsePercentile(): boolean
179
+ setElevationRange(min: number, max: number): void
180
+ clearElevationRange(): void
181
+ setPickable(pickable: boolean): void
182
+
183
+ // Z Offset
184
+ setZOffsetEnabled(enabled: boolean): void
185
+ setZOffset(offset: number): void
186
+ getZOffset(): number
187
+
188
+ // Pick info customization
189
+ setPickInfoFields(fields?: string[]): void
190
+ getPickInfoFields(): string[] | undefined
191
+
192
+ // Panel control
193
+ toggle(): void
194
+ expand(): void
195
+ collapse(): void
196
+
197
+ // Events
198
+ on(event: LidarControlEvent, handler: LidarControlEventHandler): void
199
+ off(event: LidarControlEvent, handler: LidarControlEventHandler): void
200
+
201
+ // State
202
+ getState(): LidarState
203
+ getMap(): MapLibreMap | undefined
204
+ ```
205
+
206
+ #### Events
207
+
208
+ - `load` - Point cloud loaded successfully
209
+ - `loadstart` - Loading started
210
+ - `loaderror` - Loading failed
211
+ - `unload` - Point cloud unloaded
212
+ - `statechange` - Control state changed
213
+ - `stylechange` - Styling changed
214
+ - `collapse` - Panel collapsed
215
+ - `expand` - Panel expanded
216
+ - `streamingstart` - Dynamic streaming started
217
+ - `streamingstop` - Dynamic streaming stopped
218
+ - `streamingprogress` - Streaming progress update
219
+ - `budgetreached` - Point budget limit reached
220
+
221
+ ### Color Schemes
222
+
223
+ - `'elevation'` - Viridis-like color ramp based on Z values
224
+ - `'intensity'` - Grayscale based on intensity attribute
225
+ - `'classification'` - ASPRS standard classification colors
226
+ - `'rgb'` - Use embedded RGB colors (if available)
227
+
228
+ ### Percentile-Based Coloring
229
+
230
+ By default, elevation and intensity coloring uses the 2nd-98th percentile range instead of the full min-max range. This clips outliers and provides better color distribution across the point cloud.
231
+
232
+ ```typescript
233
+ // Percentile coloring is enabled by default
234
+ const control = new LidarControl({
235
+ colorScheme: 'elevation',
236
+ usePercentile: true, // default
237
+ });
238
+
239
+ // Disable to use full value range (min-max)
240
+ control.setUsePercentile(false);
241
+
242
+ // Check current setting
243
+ console.log(control.getUsePercentile()); // true or false
244
+ ```
245
+
246
+ The percentile toggle is also available in the GUI panel when using "Elevation" or "Intensity" color schemes. Uncheck "Use percentile range (2-98%)" to use the full value range.
247
+
248
+ ### Point Picking
249
+
250
+ When `pickable` is enabled, hovering over points displays a tooltip with all available attributes:
251
+
252
+ - **X, Y, Z** - Coordinates and elevation
253
+ - **Intensity** - Reflectance value
254
+ - **Classification** - ASPRS class name (Ground, Building, Vegetation, etc.)
255
+ - **Red, Green, Blue** - RGB color values (if available)
256
+ - **GpsTime** - GPS timestamp
257
+ - **ReturnNumber / NumberOfReturns** - Return information
258
+ - **PointSourceId** - Scanner source ID
259
+ - **ScanAngle** - Scan angle
260
+ - And more (EdgeOfFlightLine, ScanDirectionFlag, UserData, etc.)
261
+
262
+ Enable via constructor option or toggle in the GUI panel:
263
+
264
+ ```typescript
265
+ // Via constructor
266
+ const control = new LidarControl({ pickable: true });
267
+
268
+ // Or programmatically
269
+ control.setPickable(true);
270
+
271
+ // Optionally filter which fields to display
272
+ control.setPickInfoFields(['Classification', 'Intensity', 'GpsTime', 'ReturnNumber']);
273
+ ```
274
+
275
+ ### Z Offset
276
+
277
+ Shift point clouds vertically for alignment with terrain or other data:
278
+
279
+ ```typescript
280
+ // Via constructor
281
+ const control = new LidarControl({
282
+ zOffsetEnabled: true,
283
+ zOffset: 50, // Shift up 50 meters
284
+ });
285
+
286
+ // Or programmatically
287
+ control.setZOffsetEnabled(true);
288
+ control.setZOffset(50);
289
+
290
+ // Get current offset
291
+ console.log(control.getZOffset()); // 50
292
+ ```
293
+
294
+ The Z offset can also be adjusted interactively via the "Z Offset" checkbox and slider in the GUI panel.
295
+
296
+ ### Dynamic COPC Streaming
297
+
298
+ For large COPC (Cloud Optimized Point Cloud) files, dynamic streaming loads only the points visible in the current viewport, dramatically reducing initial load time and memory usage.
299
+
300
+ **Key features:**
301
+ - **Viewport-based loading** - Only loads octree nodes visible in the current map view
302
+ - **Level-of-detail (LOD)** - Automatically selects appropriate detail level based on zoom
303
+ - **Center-first priority** - Points near the viewport center load first
304
+ - **Point budget** - Limits total points in memory (default: 5 million)
305
+
306
+ **How it works:**
307
+ 1. When loading a COPC file (from URL or local file), dynamic mode is used by default
308
+ 2. As you pan/zoom the map, new nodes are streamed based on viewport
309
+ 3. Deeper octree levels (more detail) load as you zoom in
310
+ 4. Parent nodes provide coverage where child nodes don't exist
311
+
312
+ ```typescript
313
+ // Dynamic loading is the default for COPC files
314
+ const control = new LidarControl();
315
+ control.loadPointCloud('https://example.com/large-pointcloud.copc.laz');
316
+
317
+ // Explicitly set loading mode
318
+ const control = new LidarControl({
319
+ copcLoadingMode: 'dynamic', // or 'full' for complete load
320
+ streamingPointBudget: 10_000_000, // 10 million points max
321
+ });
322
+
323
+ // Override per-load
324
+ control.loadPointCloud(file, { loadingMode: 'full' }); // Force full load
325
+ control.loadPointCloud(url, { loadingMode: 'dynamic' }); // Force streaming
326
+ ```
327
+
328
+ **Loading modes:**
329
+ - `'dynamic'` (default for COPC) - Stream nodes based on viewport, ideal for large files
330
+ - `'full'` - Load entire point cloud upfront, better for small files
331
+
332
+ **Note:** Non-COPC files (regular LAS/LAZ) always use full loading mode since they don't have the octree structure required for streaming.
333
+
334
+ ### React Hooks
335
+
336
+ #### useLidarState
337
+
338
+ ```typescript
339
+ const {
340
+ state,
341
+ setState,
342
+ setPointSize,
343
+ setOpacity,
344
+ setColorScheme,
345
+ setUsePercentile,
346
+ setElevationRange,
347
+ setZOffsetEnabled,
348
+ setZOffset,
349
+ toggle,
350
+ reset,
351
+ } = useLidarState(initialState?);
352
+ ```
353
+
354
+ #### usePointCloud
355
+
356
+ ```typescript
357
+ const { data, loading, error, progress, load, reset } = usePointCloud();
358
+
359
+ // Load a file
360
+ await load(file);
361
+ console.log(`Loaded ${data.pointCount} points`);
362
+ ```
363
+
364
+ ## Supported Formats
365
+
366
+ - LAS 1.0 - 1.4 (all versions supported via copc.js + loaders.gl fallback)
367
+ - LAZ (compressed LAS)
368
+ - COPC (Cloud Optimized Point Cloud) - with dynamic streaming support
369
+
370
+ **Note:** LAS 1.2 and 1.4 are loaded using copc.js for optimal performance. LAS 1.0, 1.1, and 1.3 files automatically fall back to @loaders.gl/las.
371
+
372
+ ## Coordinate Systems
373
+
374
+ Point clouds are automatically transformed to WGS84 (EPSG:4326) for display on the map. The loader reads the WKT coordinate reference system from the file and uses proj4 to transform coordinates. Supported features:
375
+
376
+ - Projected coordinate systems (State Plane, UTM, etc.)
377
+ - Compound coordinate systems (horizontal + vertical)
378
+ - Automatic unit conversion (feet to meters for elevation)
379
+
380
+ ## Dependencies
381
+
382
+ - [deck.gl](https://deck.gl/) - WebGL visualization layers
383
+ - [copc.js](https://github.com/connormanning/copc.js) - COPC/LAS/LAZ parsing (LAS 1.2/1.4)
384
+ - [@loaders.gl/las](https://loaders.gl/modules/las/docs) - LAS parsing fallback (LAS 1.0/1.1/1.3)
385
+ - [laz-perf](https://github.com/hobu/laz-perf) - LAZ decompression
386
+ - [proj4](http://proj4js.org/) - Coordinate transformation
387
+ - [maplibre-gl](https://maplibre.org/) - Map rendering
388
+
389
+ ## License
390
+
391
+ MIT
392
+
393
+ ## Credits
394
+
395
+ The sample dataset [autzen-classified.copc.laz](https://s3.amazonaws.com/hobu-lidar/autzen-classified.copc.laz) is from [Hobu, Inc.](https://hobu.co). Credits to [Howard Butler](https://github.com/hobu).