leaflet-polydraw 0.8.5

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 (59) hide show
  1. package/LICENCE +21 -0
  2. package/README.md +1006 -0
  3. package/dist/icons/icon-activate.svg +1 -0
  4. package/dist/icons/icon-add-elbow.svg +128 -0
  5. package/dist/icons/icon-bbox.svg +47 -0
  6. package/dist/icons/icon-bezier.svg +132 -0
  7. package/dist/icons/icon-draw.svg +1 -0
  8. package/dist/icons/icon-erase.svg +3 -0
  9. package/dist/icons/icon-info-white.svg +25 -0
  10. package/dist/icons/icon-settings-white.svg +15 -0
  11. package/dist/icons/icon-simplify.svg +61 -0
  12. package/dist/icons/icon-simplify2.svg +46 -0
  13. package/dist/icons/icon-subtract.svg +1 -0
  14. package/dist/icons/icon-trash-hover-white.svg +16 -0
  15. package/dist/icons/icon-trash-white.svg +16 -0
  16. package/dist/leaflet-polydraw.css +1 -0
  17. package/dist/polydraw.es.js +20688 -0
  18. package/dist/polydraw.es.js.map +1 -0
  19. package/dist/polydraw.umd.min.js +2 -0
  20. package/dist/polydraw.umd.min.js.map +1 -0
  21. package/dist/styles/polydraw.css +419 -0
  22. package/dist/types/buttons.d.ts +14 -0
  23. package/dist/types/buttons.d.ts.map +1 -0
  24. package/dist/types/coordinate-utils.d.ts +21 -0
  25. package/dist/types/coordinate-utils.d.ts.map +1 -0
  26. package/dist/types/enums.d.ts +27 -0
  27. package/dist/types/enums.d.ts.map +1 -0
  28. package/dist/types/geometry-utils.d.ts +24 -0
  29. package/dist/types/geometry-utils.d.ts.map +1 -0
  30. package/dist/types/icon-factory.d.ts +13 -0
  31. package/dist/types/icon-factory.d.ts.map +1 -0
  32. package/dist/types/index.d.ts +1 -0
  33. package/dist/types/managers/mode-manager.d.ts +91 -0
  34. package/dist/types/managers/mode-manager.d.ts.map +1 -0
  35. package/dist/types/managers/polygon-draw-manager.d.ts +88 -0
  36. package/dist/types/managers/polygon-draw-manager.d.ts.map +1 -0
  37. package/dist/types/managers/polygon-geometry-manager.d.ts +75 -0
  38. package/dist/types/managers/polygon-geometry-manager.d.ts.map +1 -0
  39. package/dist/types/managers/polygon-interaction-manager.d.ts +116 -0
  40. package/dist/types/managers/polygon-interaction-manager.d.ts.map +1 -0
  41. package/dist/types/managers/polygon-mutation-manager.d.ts +163 -0
  42. package/dist/types/managers/polygon-mutation-manager.d.ts.map +1 -0
  43. package/dist/types/map-state.d.ts +22 -0
  44. package/dist/types/map-state.d.ts.map +1 -0
  45. package/dist/types/polydraw.d.ts +87 -0
  46. package/dist/types/polydraw.d.ts.map +1 -0
  47. package/dist/types/polygon-helpers.d.ts +35 -0
  48. package/dist/types/polygon-helpers.d.ts.map +1 -0
  49. package/dist/types/polygon-information.service.d.ts +27 -0
  50. package/dist/types/polygon-information.service.d.ts.map +1 -0
  51. package/dist/types/polygon.util.d.ts +32 -0
  52. package/dist/types/polygon.util.d.ts.map +1 -0
  53. package/dist/types/turf-helper.d.ts +141 -0
  54. package/dist/types/turf-helper.d.ts.map +1 -0
  55. package/dist/types/types/polydraw-interfaces.d.ts +351 -0
  56. package/dist/types/types/polydraw-interfaces.d.ts.map +1 -0
  57. package/dist/types/utils.d.ts +57 -0
  58. package/dist/types/utils.d.ts.map +1 -0
  59. package/package.json +79 -0
package/README.md ADDED
@@ -0,0 +1,1006 @@
1
+ [![Leaflet Polydraw](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/logo.jpg)](https://github.com/AndreasOlausson/leaflet-polydraw)
2
+
3
+ # Leaflet Polydraw
4
+
5
+ > **Advanced Leaflet plugin for interactive polygon drawing with point-to-point creation, smart merging, and comprehensive editing tools**
6
+
7
+ Leaflet Polydraw is a powerful, feature-rich plugin that transforms your Leaflet maps into interactive polygon drawing and editing environments. With intelligent merging, drag-and-drop functionality, and comprehensive editing tools, it's perfect for GIS applications, mapping tools, and spatial data collection.
8
+
9
+ [![npm version](https://badge.fury.io/js/leaflet-polydraw.svg)](https://badge.fury.io/js/leaflet-polydraw)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
12
+ [![CI](https://github.com/AndreasOlausson/leaflet-polydraw/actions/workflows/ci.yml/badge.svg)](https://github.com/AndreasOlausson/leaflet-polydraw/actions/workflows/ci.yml)
13
+
14
+ ## Key Features
15
+
16
+ [![Feature Overview](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/feature-overview.png)](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/feature-overview.png)
17
+
18
+ - **Point-to-Point Drawing**: Precise polygon creation with click-by-click vertex placement
19
+ - **Smart Polygon Merging**: Automatic detection and merging of overlapping polygons (including C-to-O shape completion)
20
+ - **Drag & Drop**: Intuitive polygon repositioning with intelligent spatial interactions
21
+ - **Advanced Editing**: Drag vertices, add/remove points, and reshape polygons
22
+ - **Smart Markers**: Intelligent marker separation prevents overlapping on small polygons
23
+ - **Hole Support**: Create complex polygons with holes and nested shapes
24
+ - **Performance Optimized**: Efficient rendering and interaction handling
25
+ - **Well Tested**: Comprehensive test suite with 167+ passing tests
26
+ - **TypeScript Ready**: Full TypeScript support with type definitions
27
+
28
+ ## Table of Contents
29
+
30
+ 1. [Installation](#installation)
31
+ 2. [Quick Start](#quick-start)
32
+ 3. [Configuration](#configuration)
33
+ 4. [Features](#features)
34
+ 5. [API Reference](#api-reference)
35
+ 6. [Markers](#markers)
36
+ 7. [Events](#events)
37
+ 8. [Examples](#examples)
38
+ 9. [Browser Support](#browser-support)
39
+ 10. [Contributing](#contributing)
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ npm install leaflet-polydraw
45
+ ```
46
+
47
+ ## CDN Usage
48
+
49
+ You can also use Leaflet.Polydraw directly in the browser via a CDN like [jsDelivr](https://www.jsdelivr.com/) or [unpkg](https://unpkg.com/):
50
+
51
+ ### Include via CDN
52
+
53
+ ```html
54
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.css" />
55
+ <link
56
+ rel="stylesheet"
57
+ href="https://cdn.jsdelivr.net/npm/leaflet.polydraw@0.8.0/dist/styles/polydraw.css"
58
+ />
59
+ <script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.js"></script>
60
+ <script src="https://cdn.jsdelivr.net/npm/leaflet.polydraw@0.8.0/dist/polydraw.umd.min.js"></script>
61
+ ```
62
+
63
+ ### Example Usage
64
+
65
+ ```html
66
+ <script>
67
+ const map = L.map('map').setView([58.4, 15.6], 10);
68
+ L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
69
+ attribution: '&copy; OpenStreetMap contributors',
70
+ }).addTo(map);
71
+
72
+ const polydraw = new LeafletPolydraw();
73
+ map.addControl(polydraw);
74
+ </script>
75
+ ```
76
+
77
+ > Note: All icons and styles are included automatically when using the CSS from the CDN.
78
+
79
+ ## Quick Start
80
+
81
+ ### Basic Usage
82
+
83
+ ```javascript
84
+ import * as L from 'leaflet';
85
+ import Polydraw from 'leaflet-polydraw';
86
+
87
+ // Create your map
88
+ const map = L.map('map').setView([58.402514, 15.606188], 10);
89
+ L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
90
+ attribution:
91
+ '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
92
+ }).addTo(map);
93
+
94
+ // Add the PolyDraw control (includes all drawing buttons)
95
+ const polydraw = new Polydraw();
96
+ polydraw.addTo(map);
97
+
98
+ // Optionally add some predefined polygons
99
+ const octagon = [
100
+ [
101
+ [
102
+ L.latLng(58.404493, 15.6),
103
+ L.latLng(58.402928, 15.602928),
104
+ L.latLng(58.4, 15.604493),
105
+ L.latLng(58.397072, 15.602928),
106
+ L.latLng(58.395507, 15.6),
107
+ L.latLng(58.397072, 15.597072),
108
+ L.latLng(58.4, 15.595507),
109
+ L.latLng(58.402928, 15.597072),
110
+ L.latLng(58.404493, 15.6),
111
+ ],
112
+ ],
113
+ ];
114
+
115
+ polydraw.addPredefinedPolygon(octagon);
116
+ ```
117
+
118
+ ### Advanced Configuration
119
+
120
+ ```javascript
121
+ import Polydraw from 'leaflet-polydraw';
122
+
123
+ const polyDrawControl = L.control
124
+ .polydraw({
125
+ position: 'topright',
126
+ config: {
127
+ touchSupport: true,
128
+ mergePolygons: true,
129
+ modes: {
130
+ dragPolygons: true,
131
+ attachElbow: true,
132
+ dragElbow: true,
133
+ },
134
+ dragPolygons: {
135
+ autoMergeOnIntersect: true,
136
+ autoHoleOnContained: true,
137
+ markerBehavior: 'hide',
138
+ },
139
+ markers: {
140
+ deleteMarker: true,
141
+ infoMarker: true,
142
+ menuMarker: true,
143
+ markerDeleteIcon: {
144
+ position: 5, // North
145
+ },
146
+ markerInfoIcon: {
147
+ position: 4, // NorthEast
148
+ useMetrics: true,
149
+ },
150
+ },
151
+ polygonOptions: {
152
+ color: '#ff0000',
153
+ fillColor: '#ff0000',
154
+ fillOpacity: 0.3,
155
+ },
156
+ },
157
+ })
158
+ .addTo(map);
159
+ ```
160
+
161
+ ## Configuration
162
+
163
+ ### Default Configuration
164
+
165
+ ```javascript
166
+ {
167
+ "touchSupport": true,
168
+ "mergePolygons": true,
169
+ "kinks": false,
170
+ "modes": {
171
+ "draw": true,
172
+ "subtract": true,
173
+ "deleteAll": true,
174
+ "p2p": true,
175
+ "attachElbow": true,
176
+ "dragElbow": true,
177
+ "dragPolygons": true,
178
+ "edgeDeletion": true
179
+ },
180
+ "dragPolygons": {
181
+ "realTimeUpdate": false,
182
+ "showDragHandle": false,
183
+ "opacity": 0.7,
184
+ "dragCursor": "move",
185
+ "hoverCursor": "grab",
186
+ "markerBehavior": "hide",
187
+ "markerAnimationDuration": 200,
188
+ "autoMergeOnIntersect": true,
189
+ "autoHoleOnContained": false,
190
+ "dragInteractionBehavior": "auto",
191
+ "modifierSubtract": {
192
+ "enabled": true,
193
+ "keys": {
194
+ "windows": "ctrlKey",
195
+ "mac": "metaKey",
196
+ "linux": "ctrlKey"
197
+ },
198
+ "subtractColor": "#D9460F",
199
+ "hideMarkersOnDrag": true
200
+ }
201
+ },
202
+ "edgeDeletion": {
203
+ "enabled": true,
204
+ "modifierKey": "auto",
205
+ "hoverColor": "#D9460F",
206
+ "confirmDeletion": false,
207
+ "minVertices": 3
208
+ },
209
+ "markers": {
210
+ "deleteMarker": true,
211
+ "infoMarker": true,
212
+ "menuMarker": true,
213
+ "coordsTitle": true,
214
+ "zIndexOffset": 0,
215
+ "markerIcon": {
216
+ "styleClasses": ["polygon-marker"],
217
+ "zIndexOffset": null
218
+ },
219
+ "holeIcon": {
220
+ "styleClasses": ["polygon-marker", "hole"],
221
+ "zIndexOffset": null
222
+ },
223
+ "markerInfoIcon": {
224
+ "position": 3,
225
+ "showArea": true,
226
+ "showPerimeter": true,
227
+ "useMetrics": true,
228
+ "usePerimeterMinValue": false,
229
+ "areaLabel": "Area",
230
+ "perimeterLabel": "Perimeter",
231
+ "values": {
232
+ "min": {
233
+ "metric": "50",
234
+ "imperial": "100"
235
+ },
236
+ "unknown": {
237
+ "metric": "-",
238
+ "imperial": "-"
239
+ }
240
+ },
241
+ "units": {
242
+ "unknownUnit": "",
243
+ "metric": {
244
+ "onlyMetrics": true,
245
+ "perimeter": {
246
+ "m": "m",
247
+ "km": "km"
248
+ },
249
+ "area": {
250
+ "m2": "m²",
251
+ "km2": "km²",
252
+ "daa": "daa",
253
+ "ha": "ha"
254
+ }
255
+ },
256
+ "imperial": {
257
+ "perimeter": {
258
+ "feet": "ft",
259
+ "yards": "yd",
260
+ "miles": "mi"
261
+ },
262
+ "area": {
263
+ "feet2": "ft²",
264
+ "yards2": "yd²",
265
+ "acres": "ac",
266
+ "miles2": "mi²"
267
+ }
268
+ }
269
+ },
270
+ "styleClasses": ["polygon-marker", "info"],
271
+ "zIndexOffset": 10000
272
+ },
273
+ "markerMenuIcon": {
274
+ "position": 7,
275
+ "styleClasses": ["polygon-marker", "menu"],
276
+ "zIndexOffset": 10000
277
+ },
278
+ "markerDeleteIcon": {
279
+ "position": 5,
280
+ "styleClasses": ["polygon-marker", "delete"],
281
+ "zIndexOffset": 10000
282
+ },
283
+ "visualOptimization": {
284
+ "sharpAngleThreshold": 30,
285
+ "thresholdBoundingBox": 0.05,
286
+ "thresholdDistance": 0.05,
287
+ "useDistance": true,
288
+ "useBoundingBox": false,
289
+ "useAngles": false
290
+ }
291
+ },
292
+ "polyLineOptions": {
293
+ "color": "#50622b",
294
+ "opacity": 1,
295
+ "smoothFactor": 0,
296
+ "noClip": true,
297
+ "clickable": false,
298
+ "weight": 2
299
+ },
300
+ "subtractLineOptions": {
301
+ "color": "#50622b",
302
+ "opacity": 1,
303
+ "smoothFactor": 0,
304
+ "noClip": true,
305
+ "clickable": false,
306
+ "weight": 2
307
+ },
308
+ "polygonOptions": {
309
+ "smoothFactor": 0.3,
310
+ "color": "#50622b",
311
+ "fillColor": "#b4cd8a",
312
+ "noClip": true
313
+ },
314
+ "holeOptions": {
315
+ "color": "#aa0000",
316
+ "fillColor": "#ffcccc",
317
+ "weight": 2,
318
+ "opacity": 1,
319
+ "fillOpacity": 0.5
320
+ },
321
+ "polygonCreation": {
322
+ "method": "concaveman",
323
+ "simplification": {
324
+ "mode": "simple",
325
+ "tolerance": 0.0001,
326
+ "highQuality": false
327
+ }
328
+ },
329
+ "simplification": {
330
+ "simplifyTolerance": {
331
+ "tolerance": 0.0001,
332
+ "highQuality": false,
333
+ "mutate": false
334
+ },
335
+ "dynamicMode": {
336
+ "fractionGuard": 0.9,
337
+ "multipiler": 2
338
+ }
339
+ },
340
+ "boundingBox": {
341
+ "addMidPointMarkers": true
342
+ },
343
+ "bezier": {
344
+ "resolution": 10000,
345
+ "sharpness": 0.75
346
+ }
347
+ }
348
+ ```
349
+
350
+ ### Configuration Options
351
+
352
+ | Key | Type | Default | Description |
353
+ | ------------------------------------------------------------------ | ------- | ------------------------------ | --------------------------------------------------------- |
354
+ | **touchSupport** | boolean | `true` | Enable touch support for mobile devices |
355
+ | **mergePolygons** | boolean | `true` | Auto-merge polygons during drawing when they intersect |
356
+ | **kinks** | boolean | `false` | Allow self-intersecting polygons |
357
+ | **modes** | object | | Feature toggles |
358
+ | &nbsp;&nbsp;draw | boolean | `true` | Enable draw mode button |
359
+ | &nbsp;&nbsp;subtract | boolean | `true` | Enable subtract mode button |
360
+ | &nbsp;&nbsp;deleteAll | boolean | `true` | Enable delete all button |
361
+ | &nbsp;&nbsp;p2p | boolean | `true` | Enable point-to-point drawing mode |
362
+ | &nbsp;&nbsp;attachElbow | boolean | `true` | Enable clicking on edges to add vertices |
363
+ | &nbsp;&nbsp;dragElbow | boolean | `true` | Enable dragging vertices |
364
+ | &nbsp;&nbsp;dragPolygons | boolean | `true` | Enable dragging entire polygons |
365
+ | &nbsp;&nbsp;edgeDeletion | boolean | `true` | Enable edge deletion with modifier keys |
366
+ | **dragPolygons** | object | | Polygon dragging configuration |
367
+ | &nbsp;&nbsp;realTimeUpdate | boolean | `false` | Update polygon position in real-time during drag |
368
+ | &nbsp;&nbsp;showDragHandle | boolean | `false` | Show visual drag handle on polygons |
369
+ | &nbsp;&nbsp;opacity | number | `0.7` | Polygon opacity during drag (0-1) |
370
+ | &nbsp;&nbsp;dragCursor | string | `"move"` | Cursor during active dragging |
371
+ | &nbsp;&nbsp;hoverCursor | string | `"grab"` | Cursor when hovering over draggable polygons |
372
+ | &nbsp;&nbsp;markerBehavior | string | `"hide"` | Marker behavior during drag: `"hide"`, `"show"`, `"fade"` |
373
+ | &nbsp;&nbsp;markerAnimationDuration | number | `200` | Duration of marker animations in milliseconds |
374
+ | &nbsp;&nbsp;autoMergeOnIntersect | boolean | `true` | Auto-merge when dragging polygons together |
375
+ | &nbsp;&nbsp;autoHoleOnContained | boolean | `false` | Create holes when dragging inside polygons |
376
+ | &nbsp;&nbsp;dragInteractionBehavior | string | `"auto"` | How drag interactions are handled |
377
+ | &nbsp;&nbsp;**modifierSubtract** | object | | Modifier key subtract configuration |
378
+ | &nbsp;&nbsp;&nbsp;&nbsp;enabled | boolean | `true` | Enable modifier key subtract mode |
379
+ | &nbsp;&nbsp;&nbsp;&nbsp;**keys** | object | | Platform-specific modifier keys |
380
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;windows | string | `"ctrlKey"` | Windows modifier key |
381
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mac | string | `"metaKey"` | Mac modifier key |
382
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;linux | string | `"ctrlKey"` | Linux modifier key |
383
+ | &nbsp;&nbsp;&nbsp;&nbsp;subtractColor | string | `"#D9460F"` | Color for subtract mode visualization |
384
+ | &nbsp;&nbsp;&nbsp;&nbsp;hideMarkersOnDrag | boolean | `true` | Hide markers during subtract drag |
385
+ | **edgeDeletion** | object | | Edge deletion configuration |
386
+ | &nbsp;&nbsp;enabled | boolean | `true` | Enable edge deletion functionality |
387
+ | &nbsp;&nbsp;modifierKey | string | `"auto"` | Modifier key: `"ctrl"`, `"cmd"`, `"auto"` |
388
+ | &nbsp;&nbsp;hoverColor | string | `"#D9460F"` | Color when hovering over deletable edges |
389
+ | &nbsp;&nbsp;confirmDeletion | boolean | `false` | Require confirmation before deleting |
390
+ | &nbsp;&nbsp;minVertices | number | `3` | Minimum vertices required after deletion |
391
+ | **markers** | object | | Marker configuration |
392
+ | &nbsp;&nbsp;deleteMarker | boolean | `true` | Show delete marker |
393
+ | &nbsp;&nbsp;infoMarker | boolean | `true` | Show info marker with area/perimeter |
394
+ | &nbsp;&nbsp;menuMarker | boolean | `true` | Show menu marker with operations |
395
+ | &nbsp;&nbsp;coordsTitle | boolean | `true` | Show coordinate tooltips on markers |
396
+ | &nbsp;&nbsp;zIndexOffset | number | `0` | Global z-index offset for markers |
397
+ | &nbsp;&nbsp;**markerIcon** | object | | Standard marker configuration |
398
+ | &nbsp;&nbsp;&nbsp;&nbsp;styleClasses | array | `["polygon-marker"]` | CSS classes for standard markers |
399
+ | &nbsp;&nbsp;&nbsp;&nbsp;zIndexOffset | number | `null` | Z-index offset override |
400
+ | &nbsp;&nbsp;**holeIcon** | object | | Hole marker configuration |
401
+ | &nbsp;&nbsp;&nbsp;&nbsp;styleClasses | array | `["polygon-marker", "hole"]` | CSS classes for hole markers |
402
+ | &nbsp;&nbsp;&nbsp;&nbsp;zIndexOffset | number | `null` | Z-index offset override |
403
+ | &nbsp;&nbsp;**markerInfoIcon** | object | | Info marker configuration |
404
+ | &nbsp;&nbsp;&nbsp;&nbsp;position | number | `3` | Marker position (see MarkerPosition enum) |
405
+ | &nbsp;&nbsp;&nbsp;&nbsp;showArea | boolean | `true` | Display area information |
406
+ | &nbsp;&nbsp;&nbsp;&nbsp;showPerimeter | boolean | `true` | Display perimeter information |
407
+ | &nbsp;&nbsp;&nbsp;&nbsp;useMetrics | boolean | `true` | Use metric units |
408
+ | &nbsp;&nbsp;&nbsp;&nbsp;usePerimeterMinValue | boolean | `false` | Use minimum value for small perimeters |
409
+ | &nbsp;&nbsp;&nbsp;&nbsp;areaLabel | string | `"Area"` | Label for area display |
410
+ | &nbsp;&nbsp;&nbsp;&nbsp;perimeterLabel | string | `"Perimeter"` | Label for perimeter display |
411
+ | &nbsp;&nbsp;&nbsp;&nbsp;**values** | object | | Default values configuration |
412
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**min** | object | | Minimum value settings |
413
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;metric | string | `"50"` | Minimum metric value |
414
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imperial | string | `"100"` | Minimum imperial value |
415
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**unknown** | object | | Unknown value settings |
416
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;metric | string | `"-"` | Unknown metric placeholder |
417
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imperial | string | `"-"` | Unknown imperial placeholder |
418
+ | &nbsp;&nbsp;&nbsp;&nbsp;**units** | object | | Unit configuration |
419
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unknownUnit | string | `""` | Unknown unit placeholder |
420
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**metric** | object | | Metric units |
421
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;onlyMetrics | boolean | `true` | Use only m² and km² for area |
422
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**perimeter** | object | | Perimeter units |
423
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m | string | `"m"` | Meter unit |
424
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;km | string | `"km"` | Kilometer unit |
425
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**area** | object | | Area units |
426
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m2 | string | `"m²"` | Square meter unit |
427
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;km2 | string | `"km²"` | Square kilometer unit |
428
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;daa | string | `"daa"` | Decare unit |
429
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ha | string | `"ha"` | Hectare unit |
430
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**imperial** | object | | Imperial units |
431
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**perimeter** | object | | Perimeter units |
432
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;feet | string | `"ft"` | Feet unit |
433
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yards | string | `"yd"` | Yards unit |
434
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;miles | string | `"mi"` | Miles unit |
435
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**area** | object | | Area units |
436
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;feet2 | string | `"ft²"` | Square feet unit |
437
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yards2 | string | `"yd²"` | Square yards unit |
438
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;acres | string | `"ac"` | Acres unit |
439
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;miles2 | string | `"mi²"` | Square miles unit |
440
+ | &nbsp;&nbsp;&nbsp;&nbsp;styleClasses | array | `["polygon-marker", "info"]` | CSS classes for info marker |
441
+ | &nbsp;&nbsp;&nbsp;&nbsp;zIndexOffset | number | `10000` | Z-index offset for info marker |
442
+ | &nbsp;&nbsp;**markerMenuIcon** | object | | Menu marker configuration |
443
+ | &nbsp;&nbsp;&nbsp;&nbsp;position | number | `7` | Marker position (see MarkerPosition enum) |
444
+ | &nbsp;&nbsp;&nbsp;&nbsp;styleClasses | array | `["polygon-marker", "menu"]` | CSS classes for menu marker |
445
+ | &nbsp;&nbsp;&nbsp;&nbsp;zIndexOffset | number | `10000` | Z-index offset for menu marker |
446
+ | &nbsp;&nbsp;**markerDeleteIcon** | object | | Delete marker configuration |
447
+ | &nbsp;&nbsp;&nbsp;&nbsp;position | number | `5` | Marker position (see MarkerPosition enum) |
448
+ | &nbsp;&nbsp;&nbsp;&nbsp;styleClasses | array | `["polygon-marker", "delete"]` | CSS classes for delete marker |
449
+ | &nbsp;&nbsp;&nbsp;&nbsp;zIndexOffset | number | `10000` | Z-index offset for delete marker |
450
+ | &nbsp;&nbsp;**visualOptimization** | object | | Visual optimization settings |
451
+ | &nbsp;&nbsp;&nbsp;&nbsp;sharpAngleThreshold | number | `30` | Angle threshold for optimization |
452
+ | &nbsp;&nbsp;&nbsp;&nbsp;thresholdBoundingBox | number | `0.05` | Bounding box threshold |
453
+ | &nbsp;&nbsp;&nbsp;&nbsp;thresholdDistance | number | `0.05` | Distance threshold |
454
+ | &nbsp;&nbsp;&nbsp;&nbsp;useDistance | boolean | `true` | Use distance-based optimization |
455
+ | &nbsp;&nbsp;&nbsp;&nbsp;useBoundingBox | boolean | `false` | Use bounding box optimization |
456
+ | &nbsp;&nbsp;&nbsp;&nbsp;useAngles | boolean | `false` | Use angle-based optimization |
457
+ | **polyLineOptions** | object | | Polyline styling options |
458
+ | &nbsp;&nbsp;color | string | `"#50622b"` | Polyline color |
459
+ | &nbsp;&nbsp;opacity | number | `1` | Polyline opacity |
460
+ | &nbsp;&nbsp;smoothFactor | number | `0` | Polyline smoothing factor |
461
+ | &nbsp;&nbsp;noClip | boolean | `true` | Disable polyline clipping |
462
+ | &nbsp;&nbsp;clickable | boolean | `false` | Make polyline clickable |
463
+ | &nbsp;&nbsp;weight | number | `2` | Polyline weight in pixels |
464
+ | **subtractLineOptions** | object | | Subtract mode polyline styling |
465
+ | &nbsp;&nbsp;color | string | `"#50622b"` | Subtract polyline color |
466
+ | &nbsp;&nbsp;opacity | number | `1` | Subtract polyline opacity |
467
+ | &nbsp;&nbsp;smoothFactor | number | `0` | Subtract polyline smoothing |
468
+ | &nbsp;&nbsp;noClip | boolean | `true` | Disable subtract polyline clipping |
469
+ | &nbsp;&nbsp;clickable | boolean | `false` | Make subtract polyline clickable |
470
+ | &nbsp;&nbsp;weight | number | `2` | Subtract polyline weight |
471
+ | **polygonOptions** | object | | Polygon styling options |
472
+ | &nbsp;&nbsp;smoothFactor | number | `0.3` | Polygon smoothing factor |
473
+ | &nbsp;&nbsp;color | string | `"#50622b"` | Polygon border color |
474
+ | &nbsp;&nbsp;fillColor | string | `"#b4cd8a"` | Polygon fill color |
475
+ | &nbsp;&nbsp;noClip | boolean | `true` | Disable polygon clipping |
476
+ | **holeOptions** | object | | Hole styling options |
477
+ | &nbsp;&nbsp;color | string | `"#aa0000"` | Hole border color |
478
+ | &nbsp;&nbsp;fillColor | string | `"#ffcccc"` | Hole fill color |
479
+ | &nbsp;&nbsp;weight | number | `2` | Hole border weight |
480
+ | &nbsp;&nbsp;opacity | number | `1` | Hole border opacity |
481
+ | &nbsp;&nbsp;fillOpacity | number | `0.5` | Hole fill opacity |
482
+ | **polygonCreation** | object | | Polygon creation settings |
483
+ | &nbsp;&nbsp;method | string | `"concaveman"` | Creation method |
484
+ | &nbsp;&nbsp;**simplification** | object | | Creation simplification |
485
+ | &nbsp;&nbsp;&nbsp;&nbsp;mode | string | `"simple"` | Simplification mode |
486
+ | &nbsp;&nbsp;&nbsp;&nbsp;tolerance | number | `0.0001` | Simplification tolerance |
487
+ | &nbsp;&nbsp;&nbsp;&nbsp;highQuality | boolean | `false` | High quality simplification |
488
+ | **simplification** | object | | General simplification settings |
489
+ | &nbsp;&nbsp;**simplifyTolerance** | object | | Tolerance settings |
490
+ | &nbsp;&nbsp;&nbsp;&nbsp;tolerance | number | `0.0001` | Simplification tolerance |
491
+ | &nbsp;&nbsp;&nbsp;&nbsp;highQuality | boolean | `false` | High quality mode |
492
+ | &nbsp;&nbsp;&nbsp;&nbsp;mutate | boolean | `false` | Allow input mutation |
493
+ | &nbsp;&nbsp;**dynamicMode** | object | | Dynamic simplification |
494
+ | &nbsp;&nbsp;&nbsp;&nbsp;fractionGuard | number | `0.9` | Fraction guard value |
495
+ | &nbsp;&nbsp;&nbsp;&nbsp;multipiler | number | `2` | Tolerance multiplier |
496
+ | **boundingBox** | object | | Bounding box settings |
497
+ | &nbsp;&nbsp;addMidPointMarkers | boolean | `true` | Add midpoint markers to bounding box |
498
+ | **bezier** | object | | Bezier curve settings |
499
+ | &nbsp;&nbsp;resolution | number | `10000` | Bezier curve resolution |
500
+ | &nbsp;&nbsp;sharpness | number | `0.75` | Bezier curve sharpness |
501
+
502
+ ### External Configuration
503
+
504
+ Load configuration from an external JSON file:
505
+
506
+ ```javascript
507
+ const polyDrawControl = L.control.polydraw({
508
+ configPath: 'path/to/your/polydraw.config.json',
509
+ });
510
+ ```
511
+
512
+ You can also combine external configuration with inline configuration. Inline configuration takes precedence:
513
+
514
+ ```javascript
515
+ const polyDrawControl = L.control.polydraw({
516
+ configPath: 'config/polydraw.json',
517
+ config: {
518
+ // These settings will override the external config
519
+ polygonOptions: {
520
+ color: '#ff0000',
521
+ },
522
+ },
523
+ });
524
+ ```
525
+
526
+ **Configuration Priority (highest to lowest):**
527
+
528
+ 1. Inline `config` parameter
529
+ 2. External configuration file
530
+ 3. Default configuration
531
+
532
+ If the external configuration file fails to load, the plugin will fall back to using the default configuration plus any inline configuration provided.
533
+
534
+ ## Features
535
+
536
+ ### Draw Mode
537
+
538
+ [![Draw Mode](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/draw-mode.gif)](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/draw-mode.gif)
539
+
540
+ Create polygons by drawing freehand shapes on the map. Perfect for:
541
+
542
+ - Quick area sketching
543
+ - Rough boundary mapping
544
+ - Freehand polygon creation
545
+ - Natural drawing workflow
546
+
547
+ Simply click the draw button and drag your mouse/finger to create polygon shapes. The plugin automatically converts your drawn path into a clean polygon using advanced algorithms.
548
+
549
+ **Note**: The number of vertices in the final polygon is controlled by the `polygonCreation.simplification` settings in the configuration.
550
+
551
+ ### Subtract Mode
552
+
553
+ [![Subtract Mode](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/subtract-mode.gif)](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/subtract-mode.gif)
554
+
555
+ Create holes and complex shapes by subtracting areas from existing polygons. Ideal for:
556
+
557
+ - Creating holes in polygons
558
+ - Removing unwanted areas
559
+ - Complex shape editing
560
+ - Precision area exclusion
561
+
562
+ Click the subtract button and draw over existing polygons to remove those areas, creating holes or splitting polygons into multiple parts.
563
+
564
+ ### Point-to-Point Drawing
565
+
566
+ [![Point-to-Point Drawing](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/p2p.gif)](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/p2p.gif)
567
+
568
+ Create precise polygons by clicking to place each vertex. Perfect for:
569
+
570
+ - Accurate boundary mapping
571
+ - Property delineation
572
+ - Custom shape creation
573
+
574
+ **How it works:**
575
+
576
+ 1. Click to place the first vertex.
577
+ 2. Continue clicking to add more vertices.
578
+ 3. To complete the polygon (requires minimum 3 points):
579
+ - Click on the first vertex again.
580
+ - **or** Double-click anywhere on the map.
581
+ 4. Press `ESC` to cancel the current drawing.
582
+
583
+ ### Smart Polygon Merging
584
+
585
+ [![Smart Merging](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/merge.gif)](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/merge.gif)
586
+
587
+ The plugin features **two independent merge systems**:
588
+
589
+ #### 1. Drawing Merge (`mergePolygons`)
590
+
591
+ - **When**: During polygon creation
592
+ - **Purpose**: Automatically merge new polygons with existing intersecting ones
593
+ - **Use case**: Streamlined drawing workflow
594
+
595
+ #### 2. Drag Merge (`autoMergeOnIntersect`)
596
+
597
+ - **When**: During polygon dragging
598
+ - **Purpose**: Merge polygons when dragged together
599
+ - **Use case**: Interactive editing and combining
600
+
601
+ ### Drag & Drop Functionality
602
+
603
+ [![Drag and Drop](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/drag-drop.gif)](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/drag-drop.gif)
604
+
605
+ **Drag-to-Merge**: Drag polygons together to automatically merge them
606
+
607
+ **Drag-to-Hole**: Drag a polygon completely inside another to create a hole (requires a modifier key defined in `config.dragPolygons.modifierSubtract.keys`)
608
+
609
+ **Repositioning**: Drag to empty areas to simply reposition polygons
610
+
611
+ ### Drag Elbows (Vertex Editing)
612
+
613
+ [![Drag Elbows](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/drag-elbows.gif)](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/drag-elbows.gif)
614
+
615
+ Fine-tune polygon shapes by dragging individual vertices. Perfect for:
616
+
617
+ - Precision boundary adjustments
618
+ - Shape refinement after initial drawing
619
+ - Correcting polygon edges
620
+ - Detailed polygon editing
621
+
622
+ Click and drag any vertex (elbow) to reshape your polygons. To add a new vertex, click directly on the line between two existing points. To remove a vertex, hold the configured modifier key (defined in `config.dragPolygons.modifierSubtract.keys`) and click the vertex you want to delete. This provides full control over polygon geometry and shape refinement.
623
+
624
+ ### Advanced Editing Tools
625
+
626
+ [![Editing Tools](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/editing-tools.gif)](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/editing-tools.gif)
627
+
628
+ Access operations through the menu marker:
629
+
630
+ - **Simplify**: Reduce polygon complexity using Douglas-Peucker algorithm
631
+ - **Double Elbows**: Add intermediate vertices for higher resolution
632
+ - **Bounding Box**: Convert to rectangular bounds
633
+ - **Bezier Curves**: Apply smooth curve interpolation (alpha)
634
+
635
+ ### Smart Marker System
636
+
637
+ [![Smart Markers](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/smart-markers.png)](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/smart-markers.png)
638
+
639
+ Intelligent marker positioning prevents overlapping on small polygons:
640
+
641
+ - **Automatic separation**: Detects potential overlaps and redistributes markers
642
+ - **Priority-based**: Resolves conflicts using info → delete → menu priority
643
+ - **Smooth animations**: Markers fade during drag operations
644
+
645
+ ## API Reference
646
+
647
+ For most use cases, simply add the plugin and use the built-in buttons. However, these methods are available for programmatic control:
648
+
649
+ ### Essential Methods
650
+
651
+ #### `addPredefinedPolygon(geographicBorders: L.LatLng[][][])`
652
+
653
+ Add polygons programmatically (useful for loading saved data).
654
+
655
+ ```javascript
656
+ const polygon = [
657
+ [
658
+ [
659
+ { lat: 59.903, lng: 10.724 },
660
+ { lat: 59.908, lng: 10.728 },
661
+ { lat: 59.91, lng: 10.72 },
662
+ { lat: 59.903, lng: 10.724 },
663
+ ],
664
+ ],
665
+ ];
666
+ polydraw.addPredefinedPolygon(polygon);
667
+ ```
668
+
669
+ #### `getAllPolygons()`
670
+
671
+ Get all polygons for data export.
672
+
673
+ ```javascript
674
+ const polygons = polydraw.getAllPolygons();
675
+ // Use for saving, exporting, or processing polygon data
676
+ ```
677
+
678
+ ### Advanced Methods (Optional)
679
+
680
+ #### `setDrawMode(mode: DrawMode)` & `getDrawMode()`
681
+
682
+ Programmatically control drawing modes (the buttons do this automatically).
683
+
684
+ ```javascript
685
+ import { DrawMode } from 'leaflet-polydraw';
686
+ polydraw.setDrawMode(DrawMode.Add); // Same as clicking the draw button
687
+ ```
688
+
689
+ #### `configurate(config: any)`
690
+
691
+ Update configuration after initialization.
692
+
693
+ ```javascript
694
+ polydraw.configurate({
695
+ polygonOptions: { color: '#ff0000' },
696
+ });
697
+ ```
698
+
699
+ ## Markers
700
+
701
+ [![Marker Positions](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/marker-positions.png)](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/marker-positions.png)
702
+
703
+ ### Delete Marker (Default: North)
704
+
705
+ - **Purpose**: Delete the entire polygon
706
+ - **Icon**: Trash/delete icon
707
+ - **Behavior**: Fades during drag operations
708
+
709
+ ### Info Marker (Default: East)
710
+
711
+ - **Purpose**: Display polygon metrics
712
+ - **Features**: Area, perimeter, metric/imperial units
713
+ - **Popup**: Shows detailed measurements
714
+
715
+ [![Info Marker Popup](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/info-marker-popup.png)](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/info-marker-popup.png)
716
+
717
+ ### Menu Marker (Default: West)
718
+
719
+ - **Purpose**: Access advanced polygon editing operations
720
+ - **Popup**: Interactive operation menu with the following tools:
721
+ - **Simplify**: Reduce polygon complexity by removing unnecessary vertices using Douglas-Peucker algorithm
722
+ - **Double Elbows**: Add intermediate vertices between existing points for higher resolution editing
723
+ - **Bounding Box**: Convert polygon to its rectangular bounding box
724
+ - **Bezier**: Apply smooth curve interpolation to polygon edges _(alpha feature)_
725
+
726
+ [![Menu Marker Popup](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/menu-marker-popup.png)](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/menu-marker-popup.png)
727
+
728
+ ### Marker Positioning
729
+
730
+ Customize marker positions using the `MarkerPosition` enum:
731
+
732
+ ```javascript
733
+ const polyDrawControl = L.control.polydraw({
734
+ config: {
735
+ markers: {
736
+ markerDeleteIcon: {
737
+ position: MarkerPosition.North,
738
+ styleClasses: ['custom-delete-marker'],
739
+ },
740
+ markerInfoIcon: {
741
+ position: MarkerPosition.East,
742
+ useMetrics: true,
743
+ areaLabel: 'Area',
744
+ perimeterLabel: 'Perimeter',
745
+ },
746
+ markerMenuIcon: {
747
+ position: MarkerPosition.West,
748
+ styleClasses: ['custom-menu-marker'],
749
+ },
750
+ },
751
+ },
752
+ });
753
+ ```
754
+
755
+ This configuration gives this result.
756
+
757
+ ![Marker Positions](https://raw.githubusercontent.com/AndreasOlausson/leaflet-polydraw/main/Leaflet.Polydraw/docs/images/star.png)
758
+
759
+ ```javascript
760
+ MarkerPosition {
761
+ SouthWest = 0,
762
+ South = 1,
763
+ SouthEast = 2,
764
+ East = 3,
765
+ NorthEast = 4,
766
+ North = 5,
767
+ NorthWest = 6,
768
+ West = 7
769
+ }
770
+ ```
771
+
772
+ ## Events
773
+
774
+ Polydraw emits various events that allow you to respond to user interactions and polygon changes. These events are useful for implementing features like auto-save, validation, analytics, or custom UI updates.
775
+
776
+ ### Draw Mode Events
777
+
778
+ Listen for drawing mode changes to update your UI or trigger specific behaviors:
779
+
780
+ ```javascript
781
+ polydraw.onDrawModeChanged((mode) => {
782
+ console.log('Draw mode changed to:', mode);
783
+
784
+ // Update UI based on current mode
785
+ switch (mode) {
786
+ case DrawMode.Add:
787
+ updateStatusBar('Drawing mode: Add polygons');
788
+ break;
789
+ case DrawMode.Subtract:
790
+ updateStatusBar('Drawing mode: Create holes');
791
+ break;
792
+ case DrawMode.Off:
793
+ updateStatusBar('Drag mode: Move polygons');
794
+ break;
795
+ }
796
+ });
797
+ ```
798
+
799
+ ### Polygon Lifecycle Events
800
+
801
+ Track polygon creation, modification, and deletion:
802
+
803
+ ```javascript
804
+ // Polygon created
805
+ map.on('polygon:created', (e) => {
806
+ console.log('New polygon created:', e.polygon);
807
+ // Auto-save, validate, or log the new polygon
808
+ savePolygonToDatabase(e.polygon);
809
+ });
810
+
811
+ // Polygon modified (vertices moved, simplified, etc.)
812
+ map.on('polygon:modified', (e) => {
813
+ console.log('Polygon modified:', e.polygon);
814
+ // Mark as unsaved, trigger validation
815
+ markAsUnsaved(e.polygon);
816
+ });
817
+
818
+ // Polygon deleted
819
+ map.on('polygon:deleted', (e) => {
820
+ console.log('Polygon deleted:', e.polygon);
821
+ // Remove from database, update counters
822
+ removeFromDatabase(e.polygonId);
823
+ });
824
+ ```
825
+
826
+ ### Drag & Drop Events
827
+
828
+ Monitor polygon dragging for real-time updates or validation:
829
+
830
+ ```javascript
831
+ // Drag start - useful for showing drag indicators
832
+ map.on('polygon:dragstart', (e) => {
833
+ console.log('Drag started:', e.polygon);
834
+ showDragIndicator(true);
835
+ logUserAction('drag_start', e.polygon.id);
836
+ });
837
+
838
+ // Drag end - perfect for auto-save or validation
839
+ map.on('polygon:dragend', (e) => {
840
+ console.log('Drag ended:', e.polygon);
841
+ console.log('Moved from:', e.oldPosition, 'to:', e.newPosition);
842
+
843
+ showDragIndicator(false);
844
+ autoSavePolygon(e.polygon);
845
+ validatePolygonPosition(e.polygon);
846
+ });
847
+
848
+ // Real-time drag updates (if realTimeUpdate is enabled)
849
+ map.on('polygon:drag', (e) => {
850
+ console.log('Dragging:', e.polygon);
851
+ updateCoordinateDisplay(e.polygon.getLatLngs());
852
+ });
853
+ ```
854
+
855
+ ### Merge & Hole Events
856
+
857
+ Track automatic merging and hole creation:
858
+
859
+ ```javascript
860
+ // Polygons merged automatically
861
+ map.on('polygons:merged', (e) => {
862
+ console.log('Polygons merged:', e.originalPolygons, '→', e.resultPolygon);
863
+ updatePolygonCount(-e.originalPolygons.length + 1);
864
+ });
865
+
866
+ // Hole created by dragging polygon inside another
867
+ map.on('polygon:hole-created', (e) => {
868
+ console.log('Hole created in:', e.parentPolygon, 'by:', e.holePolygon);
869
+ notifyUser('Hole created in polygon');
870
+ });
871
+ ```
872
+
873
+ ### Practical Use Cases
874
+
875
+ **Auto-save functionality:**
876
+
877
+ ```javascript
878
+ map.on('polygon:created polygon:modified polygon:dragend', (e) => {
879
+ debounce(() => saveToLocalStorage(polydraw.getAllPolygons()), 1000);
880
+ });
881
+ ```
882
+
883
+ **Validation and feedback:**
884
+
885
+ ```javascript
886
+ map.on('polygon:created', (e) => {
887
+ const area = calculateArea(e.polygon);
888
+ if (area < MIN_AREA) {
889
+ showWarning('Polygon too small');
890
+ e.polygon.setStyle({ color: 'red' });
891
+ }
892
+ });
893
+ ```
894
+
895
+ **Analytics tracking:**
896
+
897
+ ```javascript
898
+ polydraw.onDrawModeChanged((mode) => {
899
+ analytics.track('draw_mode_changed', { mode: mode });
900
+ });
901
+
902
+ map.on('polygon:created', (e) => {
903
+ analytics.track('polygon_created', {
904
+ vertices: e.polygon.getLatLngs()[0].length,
905
+ area: calculateArea(e.polygon),
906
+ });
907
+ });
908
+ ```
909
+
910
+ ## Browser Support
911
+
912
+ - **Modern Browsers**: Chrome 60+, Firefox 55+, Safari 12+, Edge 79+
913
+ - **Mobile**: iOS Safari 12+, Chrome Mobile 60+
914
+ - **Requirements**: ES6+ support, Leaflet 1.9+, Touch events, CSS transitions
915
+
916
+ ## Demo
917
+
918
+ A local demo is included in the `demo/` directory for testing and development purposes.
919
+
920
+ ### Running the Demo
921
+
922
+ To run the local demo:
923
+
924
+ 1. **Build the main library and types**:
925
+
926
+ ```bash
927
+ cd Leaflet.Polydraw
928
+ npm run build
929
+ npm run build:types
930
+ ```
931
+
932
+ 2. **Run the demo**:
933
+ ```bash
934
+ cd demo
935
+ npm install
936
+ npm run dev
937
+ ```
938
+
939
+ The demo will be available at `http://localhost:5173/` and includes examples of all major features.
940
+
941
+ ## Contributing
942
+
943
+ Contributions are welcome! Please feel free to submit a Pull Request.
944
+
945
+ ### Development Setup
946
+
947
+ ```bash
948
+ # Clone the repository
949
+ git clone https://github.com/AndreasOlausson/leaflet-polydraw.git
950
+ cd leaflet-polydraw
951
+
952
+ # Install dependencies
953
+ npm install
954
+
955
+ # Run tests
956
+ npm test
957
+
958
+ # Build the project
959
+ npm run build
960
+ npm run build:types
961
+
962
+ # For development with the demo project
963
+ cd demo
964
+ npm install
965
+ npm run dev # Automatically builds plugin, generates typings, and installs them
966
+ ```
967
+
968
+ **Note**: The demo's `npm run dev` command automatically rebuilds the main plugin and type definitions, then installs them locally for immediate testing of your changes.
969
+
970
+ ### Guidelines
971
+
972
+ - Follow the existing coding style
973
+ - Add tests for new features
974
+ - Update documentation when relevant
975
+ - Ensure all tests pass before submitting
976
+
977
+ ## License
978
+
979
+ This project is licensed under the [MIT License](./LICENSE).
980
+
981
+ ## Acknowledgments
982
+
983
+ PolyDraw was initially inspired by:
984
+
985
+ - [Leaflet.FreeDraw](https://github.com/Wildhoney/Leaflet.FreeDraw) by Adam Timberlake "Wildhoney"
986
+ - [leaflet-freehandshapes](https://github.com/bozdoz/leaflet-freehandshapes) by Benjamin DeLong "bozdoz"
987
+
988
+ Big thank you and kudos to these amazing developers!
989
+
990
+ ## Changelog
991
+
992
+ ### v0.8.0 (Initial release)
993
+
994
+ - **Polygon Dragging**: Complete drag-and-drop functionality
995
+ - **Smart Merging**: Dual merge systems for drawing and dragging
996
+ - **Marker Separation**: Intelligent positioning prevents overlaps
997
+ - **Enhanced Events**: Comprehensive event system
998
+ - **Production Ready**: 167+ passing tests, full TypeScript support
999
+ - **Performance Optimized**: Efficient geometric operations
1000
+
1001
+ ---
1002
+
1003
+ **Created and maintained by [Andreas Olausson](https://github.com/AndreasOlausson)**
1004
+
1005
+ [![GitHub stars](https://img.shields.io/github/stars/AndreasOlausson/leaflet-polydraw.svg?style=social&label=Star)](https://github.com/AndreasOlausson/leaflet-polydraw)
1006
+ [![GitHub forks](https://img.shields.io/github/forks/AndreasOlausson/leaflet-polydraw.svg?style=social&label=Fork)](https://github.com/AndreasOlausson/leaflet-polydraw/fork)