maplibre-gl-geo-editor 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,286 @@
1
+ # maplibre-gl-geo-editor
2
+
3
+ A powerful MapLibre GL plugin for creating and editing geometries. Extends the free [Geoman](https://geoman.io/docs/maplibre/) control with advanced editing features including Union, Split, Scale, Difference, Simplify, Copy, and Lasso selection.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/maplibre-gl-geo-editor.svg)](https://www.npmjs.com/package/maplibre-gl-geo-editor)
6
+ [![npm downloads](https://img.shields.io/npm/dm/maplibre-gl-geo-editor.svg)](https://www.npmjs.com/package/maplibre-gl-geo-editor)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ ## Features
10
+
11
+ ### Draw Tools
12
+ - **Polygon** - Draw polygons by clicking points
13
+ - **Line** - Draw polylines
14
+ - **Rectangle** - Draw rectangles
15
+ - **Circle** - Draw circles
16
+ - **Marker** - Place point markers
17
+
18
+ ### Basic Edit Tools (via Geoman Free)
19
+ - **Drag** - Move features on the map
20
+ - **Edit** - Modify feature vertices
21
+ - **Rotate** - Rotate features
22
+ - **Cut** - Cut holes in polygons
23
+ - **Delete** - Remove selected features (supports multi-select)
24
+
25
+ ### Advanced Edit Tools (Custom Implementation)
26
+ - **Scale** - Resize features with interactive handles
27
+ - **Copy** - Duplicate features (Ctrl+C/V support)
28
+ - **Split** - Split polygons/lines with a drawn line
29
+ - **Union** - Merge multiple polygons into one
30
+ - **Difference** - Subtract one polygon from another
31
+ - **Simplify** - Reduce vertices using Douglas-Peucker algorithm
32
+ - **Lasso** - Select multiple features by drawing a polygon (supports union/difference/drag)
33
+ - **Reset** - Clear selection and disable active tools (toolbar button)
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ npm install maplibre-gl-geo-editor @geoman-io/maplibre-geoman-free maplibre-gl
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ ### Basic Usage (Vanilla JS/TS)
44
+
45
+ ```typescript
46
+ import 'maplibre-gl/dist/maplibre-gl.css';
47
+ import '@geoman-io/maplibre-geoman-free/dist/maplibre-geoman.css';
48
+ import 'maplibre-gl-geo-editor/style.css';
49
+
50
+ import maplibregl from 'maplibre-gl';
51
+ import { Geoman } from '@geoman-io/maplibre-geoman-free';
52
+ import { GeoEditor } from 'maplibre-gl-geo-editor';
53
+
54
+ // Create the map
55
+ const map = new maplibregl.Map({
56
+ container: 'map',
57
+ style: 'https://demotiles.maplibre.org/style.json',
58
+ center: [0, 0],
59
+ zoom: 2,
60
+ });
61
+
62
+ map.on('load', () => {
63
+ // Initialize Geoman
64
+ const geoman = new Geoman(map, {});
65
+
66
+ map.on('gm:loaded', () => {
67
+ // Create GeoEditor
68
+ const geoEditor = new GeoEditor({
69
+ position: 'top-left',
70
+ toolbarOrientation: 'vertical',
71
+ drawModes: ['polygon', 'line', 'rectangle', 'circle', 'marker'],
72
+ editModes: [
73
+ 'drag', 'change', 'rotate', 'cut', 'delete',
74
+ 'scale', 'copy', 'split', 'union', 'difference', 'simplify', 'lasso'
75
+ ],
76
+ onFeatureCreate: (feature) => console.log('Created:', feature),
77
+ onSelectionChange: (features) => console.log('Selected:', features.length),
78
+ });
79
+
80
+ // Connect with Geoman
81
+ geoEditor.setGeoman(geoman);
82
+
83
+ // Add to map
84
+ map.addControl(geoEditor, 'top-left');
85
+ });
86
+ });
87
+ ```
88
+
89
+ ### React Usage
90
+
91
+ ```tsx
92
+ import { useEffect, useRef, useState } from 'react';
93
+ import maplibregl from 'maplibre-gl';
94
+ import { Geoman } from '@geoman-io/maplibre-geoman-free';
95
+ import { GeoEditorReact } from 'maplibre-gl-geo-editor/react';
96
+
97
+ import 'maplibre-gl/dist/maplibre-gl.css';
98
+ import '@geoman-io/maplibre-geoman-free/dist/maplibre-geoman.css';
99
+ import 'maplibre-gl-geo-editor/style.css';
100
+
101
+ function App() {
102
+ const mapContainer = useRef(null);
103
+ const [map, setMap] = useState(null);
104
+ const [geoman, setGeoman] = useState(null);
105
+
106
+ useEffect(() => {
107
+ const newMap = new maplibregl.Map({
108
+ container: mapContainer.current,
109
+ style: 'https://demotiles.maplibre.org/style.json',
110
+ center: [0, 0],
111
+ zoom: 2,
112
+ });
113
+
114
+ newMap.on('load', () => {
115
+ const gm = new Geoman(newMap, {});
116
+ newMap.on('gm:loaded', () => {
117
+ setMap(newMap);
118
+ setGeoman(gm);
119
+ });
120
+ });
121
+
122
+ return () => newMap.remove();
123
+ }, []);
124
+
125
+ return (
126
+ <div style={{ width: '100%', height: '100vh' }}>
127
+ <div ref={mapContainer} style={{ width: '100%', height: '100%' }} />
128
+ {map && geoman && (
129
+ <GeoEditorReact
130
+ map={map}
131
+ geoman={geoman}
132
+ position="top-left"
133
+ drawModes={['polygon', 'line', 'marker']}
134
+ editModes={['drag', 'change', 'scale', 'copy', 'union', 'split']}
135
+ />
136
+ )}
137
+ </div>
138
+ );
139
+ }
140
+ ```
141
+
142
+ ## API Reference
143
+
144
+ ### GeoEditorOptions
145
+
146
+ | Option | Type | Default | Description |
147
+ |--------|------|---------|-------------|
148
+ | `position` | `'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right'` | `'top-left'` | Position of the control |
149
+ | `collapsed` | `boolean` | `false` | Start with toolbar collapsed |
150
+ | `drawModes` | `DrawMode[]` | All modes | Draw modes to enable |
151
+ | `editModes` | `EditMode[]` | All modes | Edit modes to enable |
152
+ | `toolbarOrientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Toolbar layout |
153
+ | `showLabels` | `boolean` | `false` | Show text labels on buttons |
154
+ | `simplifyTolerance` | `number` | `0.001` | Default simplification tolerance |
155
+ | `onFeatureCreate` | `(feature) => void` | - | Callback when feature is created |
156
+ | `onFeatureEdit` | `(feature, oldFeature) => void` | - | Callback when feature is edited |
157
+ | `onFeatureDelete` | `(featureId) => void` | - | Callback when feature is deleted |
158
+ | `onSelectionChange` | `(features) => void` | - | Callback when selection changes |
159
+ | `onModeChange` | `(mode) => void` | - | Callback when mode changes |
160
+
161
+ ### Methods
162
+
163
+ ```typescript
164
+ // Mode management
165
+ geoEditor.enableDrawMode('polygon');
166
+ geoEditor.enableEditMode('scale');
167
+ geoEditor.disableAllModes();
168
+
169
+ // Selection
170
+ geoEditor.selectFeatures(features);
171
+ geoEditor.clearSelection();
172
+ geoEditor.getSelectedFeatures();
173
+ geoEditor.getSelectedFeatureCollection();
174
+
175
+ // Clipboard
176
+ geoEditor.copySelectedFeatures();
177
+ geoEditor.pasteFeatures();
178
+ geoEditor.deleteSelectedFeatures();
179
+
180
+ // Get all features
181
+ geoEditor.getFeatures();
182
+ geoEditor.getAllFeatureCollection();
183
+
184
+ // Operation snapshots
185
+ geoEditor.getLastCreatedFeature();
186
+ geoEditor.getLastEditedFeature();
187
+ geoEditor.getLastDeletedFeature();
188
+ geoEditor.getLastDeletedFeatureId();
189
+
190
+ // Get state
191
+ geoEditor.getState();
192
+ ```
193
+
194
+ ### Events
195
+
196
+ Listen for events on the map container:
197
+
198
+ ```typescript
199
+ map.getContainer().addEventListener('gm:union', (e) => {
200
+ console.log('Union result:', e.detail);
201
+ });
202
+
203
+ map.getContainer().addEventListener('gm:split', (e) => {
204
+ console.log('Split result:', e.detail);
205
+ });
206
+
207
+ map.getContainer().addEventListener('gm:simplify', (e) => {
208
+ console.log('Simplify result:', e.detail);
209
+ });
210
+
211
+ map.getContainer().addEventListener('gm:lassoend', (e) => {
212
+ console.log('Lasso selection:', e.detail);
213
+ });
214
+ ```
215
+
216
+ ## Keyboard Shortcuts
217
+
218
+ | Shortcut | Action |
219
+ |----------|--------|
220
+ | `Ctrl+C` | Copy selected features |
221
+ | `Ctrl+V` | Paste features |
222
+ | `Delete` | Delete selected features |
223
+ | `Escape` | Cancel operation / Clear selection |
224
+
225
+ ## Logging
226
+
227
+ GeoEditor logs the current selected FeatureCollection to the console whenever a feature is selected, created, edited, or deleted.
228
+
229
+ ## Standalone Feature Classes
230
+
231
+ You can also use the feature classes directly:
232
+
233
+ ```typescript
234
+ import {
235
+ CopyFeature,
236
+ SimplifyFeature,
237
+ UnionFeature,
238
+ DifferenceFeature,
239
+ ScaleFeature,
240
+ SplitFeature,
241
+ } from 'maplibre-gl-geo-editor';
242
+
243
+ // Union polygons
244
+ const union = new UnionFeature();
245
+ const result = union.union([polygon1, polygon2]);
246
+
247
+ // Simplify a feature
248
+ const simplify = new SimplifyFeature();
249
+ const simplified = simplify.simplify(feature, { tolerance: 0.01 });
250
+
251
+ // Get simplification stats
252
+ const stats = simplify.getSimplificationStats(feature, 0.01);
253
+ console.log(`Reduced vertices by ${stats.reduction}%`);
254
+ ```
255
+
256
+ ## Development
257
+
258
+ ```bash
259
+ # Install dependencies
260
+ npm install
261
+
262
+ # Start development server
263
+ npm run dev
264
+
265
+ # Run tests
266
+ npm test
267
+
268
+ # Build
269
+ npm run build
270
+ ```
271
+
272
+ ## Dependencies
273
+
274
+ - [MapLibre GL JS](https://maplibre.org/) - Map rendering
275
+ - [@geoman-io/maplibre-geoman-free](https://geoman.io/) - Basic drawing/editing
276
+ - [@turf/turf](https://turfjs.org/) - Geometry operations
277
+
278
+ ## License
279
+
280
+ MIT License - see [LICENSE](LICENSE) for details.
281
+
282
+ ## Credits
283
+
284
+ - [Geoman](https://geoman.io/) for the excellent free drawing/editing plugin
285
+ - [Turf.js](https://turfjs.org/) for powerful geometry operations
286
+ - Inspired by [maplibre-gl-layer-control](https://github.com/opengeos/maplibre-gl-layer-control)