umap-project 2.6.0__py3-none-any.whl → 2.6.0b1__py3-none-any.whl

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.

Potentially problematic release.


This version of umap-project might be problematic. Click here for more details.

Files changed (31) hide show
  1. umap/__init__.py +1 -1
  2. umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
  3. umap/locale/fa_IR/LC_MESSAGES/django.po +9 -9
  4. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  5. umap/locale/hu/LC_MESSAGES/django.po +18 -18
  6. umap/static/umap/js/modules/data/features.js +5 -10
  7. umap/static/umap/js/modules/data/layer.js +1 -1
  8. umap/static/umap/js/modules/rendering/ui.js +4 -25
  9. umap/static/umap/js/modules/rules.js +3 -16
  10. umap/static/umap/locale/en.js +1 -3
  11. umap/static/umap/locale/en.json +1 -3
  12. umap/static/umap/locale/eu.js +6 -8
  13. umap/static/umap/locale/eu.json +6 -8
  14. umap/static/umap/locale/fa_IR.js +12 -14
  15. umap/static/umap/locale/fa_IR.json +12 -14
  16. umap/static/umap/locale/fr.js +1 -3
  17. umap/static/umap/locale/fr.json +1 -3
  18. umap/static/umap/locale/hu.js +12 -14
  19. umap/static/umap/locale/hu.json +12 -14
  20. umap/static/umap/map.css +2 -2
  21. umap/static/umap/vars.css +0 -1
  22. umap/static/umap/vendors/editable/Leaflet.Editable.js +1937 -2079
  23. umap/static/umap/vendors/markercluster/MarkerCluster.Default.css +1 -1
  24. umap/tests/integration/test_browser.py +0 -20
  25. umap/tests/integration/test_conditional_rules.py +17 -102
  26. umap/tests/integration/test_draw_polygon.py +0 -28
  27. {umap_project-2.6.0.dist-info → umap_project-2.6.0b1.dist-info}/METADATA +6 -6
  28. {umap_project-2.6.0.dist-info → umap_project-2.6.0b1.dist-info}/RECORD +31 -31
  29. {umap_project-2.6.0.dist-info → umap_project-2.6.0b1.dist-info}/WHEEL +0 -0
  30. {umap_project-2.6.0.dist-info → umap_project-2.6.0b1.dist-info}/entry_points.txt +0 -0
  31. {umap_project-2.6.0.dist-info → umap_project-2.6.0b1.dist-info}/licenses/LICENSE +0 -0
@@ -1,2088 +1,1946 @@
1
- ;((factory, window) => {
2
- /*globals define, module, require*/
1
+ 'use strict';
2
+ (function (factory, window) {
3
+ /*globals define, module, require*/
4
+
5
+ // define an AMD module that relies on 'leaflet'
6
+ if (typeof define === 'function' && define.amd) {
7
+ define(['leaflet'], factory);
3
8
 
4
- // define an AMD module that relies on 'leaflet'
5
- if (typeof define === 'function' && define.amd) {
6
- define(['leaflet'], factory)
7
9
 
8
10
  // define a Common JS module that relies on 'leaflet'
9
- } else if (typeof exports === 'object') {
10
- module.exports = factory(require('leaflet'))
11
- }
12
-
13
- // attach your plugin to the global 'L' variable
14
- if (typeof window !== 'undefined' && window.L) {
15
- factory(window.L)
16
- }
17
- })((L) => {
18
- // 🍂miniclass CancelableEvent (Event objects)
19
- // 🍂method cancel()
20
- // Cancel any subsequent action.
21
-
22
- // 🍂miniclass VertexEvent (Event objects)
23
- // 🍂property vertex: VertexMarker
24
- // The vertex that fires the event.
25
-
26
- // 🍂miniclass ShapeEvent (Event objects)
27
- // 🍂property shape: Array
28
- // The shape (LatLngs array) subject of the action.
29
-
30
- // 🍂miniclass CancelableVertexEvent (Event objects)
31
- // 🍂inherits VertexEvent
32
- // 🍂inherits CancelableEvent
33
-
34
- // 🍂miniclass CancelableShapeEvent (Event objects)
35
- // 🍂inherits ShapeEvent
36
- // 🍂inherits CancelableEvent
37
-
38
- // 🍂miniclass LayerEvent (Event objects)
39
- // 🍂property layer: object
40
- // The Layer (Marker, Polyline…) subject of the action.
41
-
42
- // 🍂namespace Editable; 🍂class Editable; 🍂aka L.Editable
43
- // Main edition handler. By default, it is attached to the map
44
- // as `map.editTools` property.
45
- // Leaflet.Editable is made to be fully extendable. You have three ways to customize
46
- // the behaviour: using options, listening to events, or extending.
47
- L.Editable = L.Evented.extend({
48
- statics: {
49
- FORWARD: 1,
50
- BACKWARD: -1,
51
- },
52
-
53
- options: {
54
- // You can pass them when creating a map using the `editOptions` key.
55
- // 🍂option zIndex: int = 1000
56
- // The default zIndex of the editing tools.
57
- zIndex: 1000,
58
-
59
- // 🍂option polygonClass: class = L.Polygon
60
- // Class to be used when creating a new Polygon.
61
- polygonClass: L.Polygon,
62
-
63
- // 🍂option polylineClass: class = L.Polyline
64
- // Class to be used when creating a new Polyline.
65
- polylineClass: L.Polyline,
66
-
67
- // 🍂option markerClass: class = L.Marker
68
- // Class to be used when creating a new Marker.
69
- markerClass: L.Marker,
70
-
71
- // 🍂option circleMarkerClass: class = L.CircleMarker
72
- // Class to be used when creating a new CircleMarker.
73
- circleMarkerClass: L.CircleMarker,
74
-
75
- // 🍂option rectangleClass: class = L.Rectangle
76
- // Class to be used when creating a new Rectangle.
77
- rectangleClass: L.Rectangle,
78
-
79
- // 🍂option circleClass: class = L.Circle
80
- // Class to be used when creating a new Circle.
81
- circleClass: L.Circle,
82
-
83
- // 🍂option drawingCSSClass: string = 'leaflet-editable-drawing'
84
- // CSS class to be added to the map container while drawing.
85
- drawingCSSClass: 'leaflet-editable-drawing',
86
-
87
- // 🍂option drawingCursor: const = 'crosshair'
88
- // Cursor mode set to the map while drawing.
89
- drawingCursor: 'crosshair',
90
-
91
- // 🍂option editLayer: Layer = new L.LayerGroup()
92
- // Layer used to store edit tools (vertex, line guide…).
93
- editLayer: undefined,
94
-
95
- // 🍂option featuresLayer: Layer = new L.LayerGroup()
96
- // Default layer used to store drawn features (Marker, Polyline…).
97
- featuresLayer: undefined,
98
-
99
- // 🍂option polylineEditorClass: class = PolylineEditor
100
- // Class to be used as Polyline editor.
101
- polylineEditorClass: undefined,
102
-
103
- // 🍂option polygonEditorClass: class = PolygonEditor
104
- // Class to be used as Polygon editor.
105
- polygonEditorClass: undefined,
106
-
107
- // 🍂option markerEditorClass: class = MarkerEditor
108
- // Class to be used as Marker editor.
109
- markerEditorClass: undefined,
110
-
111
- // 🍂option circleMarkerEditorClass: class = CircleMarkerEditor
112
- // Class to be used as CircleMarker editor.
113
- circleMarkerEditorClass: undefined,
114
-
115
- // 🍂option rectangleEditorClass: class = RectangleEditor
116
- // Class to be used as Rectangle editor.
117
- rectangleEditorClass: undefined,
118
-
119
- // 🍂option circleEditorClass: class = CircleEditor
120
- // Class to be used as Circle editor.
121
- circleEditorClass: undefined,
122
-
123
- // 🍂option lineGuideOptions: hash = {}
124
- // Options to be passed to the line guides.
125
- lineGuideOptions: {},
126
-
127
- // 🍂option skipMiddleMarkers: boolean = false
128
- // Set this to true if you don't want middle markers.
129
- skipMiddleMarkers: false,
130
- },
131
-
132
- initialize: function (map, options) {
133
- L.setOptions(this, options)
134
- this._lastZIndex = this.options.zIndex
135
- this.map = map
136
- this.editLayer = this.createEditLayer()
137
- this.featuresLayer = this.createFeaturesLayer()
138
- this.forwardLineGuide = this.createLineGuide()
139
- this.backwardLineGuide = this.createLineGuide()
140
- },
141
-
142
- fireAndForward: function (type, e) {
143
- e = e || {}
144
- e.editTools = this
145
- this.fire(type, e)
146
- this.map.fire(type, e)
147
- },
148
-
149
- createLineGuide: function () {
150
- const options = L.extend(
151
- { dashArray: '5,10', weight: 1, interactive: false },
152
- this.options.lineGuideOptions
153
- )
154
- return L.polyline([], options)
155
- },
156
-
157
- createVertexIcon: (options) =>
158
- L.Browser.mobile && L.Browser.touch
159
- ? new L.Editable.TouchVertexIcon(options)
160
- : new L.Editable.VertexIcon(options),
161
-
162
- createEditLayer: function () {
163
- return this.options.editLayer || new L.LayerGroup().addTo(this.map)
164
- },
165
-
166
- createFeaturesLayer: function () {
167
- return this.options.featuresLayer || new L.LayerGroup().addTo(this.map)
168
- },
169
-
170
- moveForwardLineGuide: function (latlng) {
171
- if (this.forwardLineGuide._latlngs.length) {
172
- this.forwardLineGuide._latlngs[1] = latlng
173
- this.forwardLineGuide._bounds.extend(latlng)
174
- this.forwardLineGuide.redraw()
175
- }
176
- },
177
-
178
- moveBackwardLineGuide: function (latlng) {
179
- if (this.backwardLineGuide._latlngs.length) {
180
- this.backwardLineGuide._latlngs[1] = latlng
181
- this.backwardLineGuide._bounds.extend(latlng)
182
- this.backwardLineGuide.redraw()
183
- }
184
- },
185
-
186
- anchorForwardLineGuide: function (latlng) {
187
- this.forwardLineGuide._latlngs[0] = latlng
188
- this.forwardLineGuide._bounds.extend(latlng)
189
- this.forwardLineGuide.redraw()
190
- },
191
-
192
- anchorBackwardLineGuide: function (latlng) {
193
- this.backwardLineGuide._latlngs[0] = latlng
194
- this.backwardLineGuide._bounds.extend(latlng)
195
- this.backwardLineGuide.redraw()
196
- },
197
-
198
- attachForwardLineGuide: function () {
199
- this.editLayer.addLayer(this.forwardLineGuide)
200
- },
201
-
202
- attachBackwardLineGuide: function () {
203
- this.editLayer.addLayer(this.backwardLineGuide)
204
- },
205
-
206
- detachForwardLineGuide: function () {
207
- this.forwardLineGuide.setLatLngs([])
208
- this.editLayer.removeLayer(this.forwardLineGuide)
209
- },
210
-
211
- detachBackwardLineGuide: function () {
212
- this.backwardLineGuide.setLatLngs([])
213
- this.editLayer.removeLayer(this.backwardLineGuide)
214
- },
215
-
216
- blockEvents: function () {
217
- // Hack: force map not to listen to other layers events while drawing.
218
- if (!this._oldTargets) {
219
- this._oldTargets = this.map._targets
220
- this.map._targets = {}
221
- }
222
- },
223
-
224
- unblockEvents: function () {
225
- if (this._oldTargets) {
226
- // Reset, but keep targets created while drawing.
227
- this.map._targets = L.extend(this.map._targets, this._oldTargets)
228
- delete this._oldTargets
229
- }
230
- },
231
-
232
- registerForDrawing: function (editor) {
233
- if (this._drawingEditor) this.unregisterForDrawing(this._drawingEditor)
234
- this.blockEvents()
235
- editor.reset() // Make sure editor tools still receive events.
236
- this._drawingEditor = editor
237
- this.map.on('mousemove touchmove', editor.onDrawingMouseMove, editor)
238
- this.map.on('mousedown', this.onMousedown, this)
239
- this.map.on('mouseup', this.onMouseup, this)
240
- L.DomUtil.addClass(this.map._container, this.options.drawingCSSClass)
241
- this.defaultMapCursor = this.map._container.style.cursor
242
- this.map._container.style.cursor = this.options.drawingCursor
243
- },
244
-
245
- unregisterForDrawing: function (editor) {
246
- this.unblockEvents()
247
- L.DomUtil.removeClass(this.map._container, this.options.drawingCSSClass)
248
- this.map._container.style.cursor = this.defaultMapCursor
249
- editor = editor || this._drawingEditor
250
- if (!editor) return
251
- this.map.off('mousemove touchmove', editor.onDrawingMouseMove, editor)
252
- this.map.off('mousedown', this.onMousedown, this)
253
- this.map.off('mouseup', this.onMouseup, this)
254
- if (editor !== this._drawingEditor) return
255
- delete this._drawingEditor
256
- if (editor._drawing) editor.cancelDrawing()
257
- },
258
-
259
- onMousedown: function (e) {
260
- if (e.originalEvent.which != 1) return
261
- this._mouseDown = e
262
- this._drawingEditor.onDrawingMouseDown(e)
263
- },
264
-
265
- onMouseup: function (e) {
266
- if (this._mouseDown) {
267
- const editor = this._drawingEditor
268
- const mouseDown = this._mouseDown
269
- this._mouseDown = null
270
- editor.onDrawingMouseUp(e)
271
- if (this._drawingEditor !== editor) return // onDrawingMouseUp may call unregisterFromDrawing.
272
- const origin = L.point(
273
- mouseDown.originalEvent.clientX,
274
- mouseDown.originalEvent.clientY
275
- )
276
- const distance = L.point(
277
- e.originalEvent.clientX,
278
- e.originalEvent.clientY
279
- ).distanceTo(origin)
280
- if (Math.abs(distance) < 9 * (window.devicePixelRatio || 1))
281
- this._drawingEditor.onDrawingClick(e)
282
- }
283
- },
284
-
285
- // 🍂section Public methods
286
- // You will generally access them by the `map.editTools`
287
- // instance:
11
+ } else if (typeof exports === 'object') {
12
+ module.exports = factory(require('leaflet'));
13
+ }
14
+
15
+ // attach your plugin to the global 'L' variable
16
+ if(typeof window !== 'undefined' && window.L){
17
+ factory(window.L);
18
+ }
19
+
20
+ }(function (L) {
21
+ // 🍂miniclass CancelableEvent (Event objects)
22
+ // 🍂method cancel()
23
+ // Cancel any subsequent action.
24
+
25
+ // 🍂miniclass VertexEvent (Event objects)
26
+ // 🍂property vertex: VertexMarker
27
+ // The vertex that fires the event.
28
+
29
+ // 🍂miniclass ShapeEvent (Event objects)
30
+ // 🍂property shape: Array
31
+ // The shape (LatLngs array) subject of the action.
32
+
33
+ // 🍂miniclass CancelableVertexEvent (Event objects)
34
+ // 🍂inherits VertexEvent
35
+ // 🍂inherits CancelableEvent
36
+
37
+ // 🍂miniclass CancelableShapeEvent (Event objects)
38
+ // 🍂inherits ShapeEvent
39
+ // 🍂inherits CancelableEvent
40
+
41
+ // 🍂miniclass LayerEvent (Event objects)
42
+ // 🍂property layer: object
43
+ // The Layer (Marker, Polyline…) subject of the action.
44
+
45
+ // 🍂namespace Editable; 🍂class Editable; 🍂aka L.Editable
46
+ // Main edition handler. By default, it is attached to the map
47
+ // as `map.editTools` property.
48
+ // Leaflet.Editable is made to be fully extendable. You have three ways to customize
49
+ // the behaviour: using options, listening to events, or extending.
50
+ L.Editable = L.Evented.extend({
51
+
52
+ statics: {
53
+ FORWARD: 1,
54
+ BACKWARD: -1
55
+ },
56
+
57
+ options: {
58
+
59
+ // You can pass them when creating a map using the `editOptions` key.
60
+ // 🍂option zIndex: int = 1000
61
+ // The default zIndex of the editing tools.
62
+ zIndex: 1000,
63
+
64
+ // 🍂option polygonClass: class = L.Polygon
65
+ // Class to be used when creating a new Polygon.
66
+ polygonClass: L.Polygon,
67
+
68
+ // 🍂option polylineClass: class = L.Polyline
69
+ // Class to be used when creating a new Polyline.
70
+ polylineClass: L.Polyline,
71
+
72
+ // 🍂option markerClass: class = L.Marker
73
+ // Class to be used when creating a new Marker.
74
+ markerClass: L.Marker,
75
+
76
+ // 🍂option rectangleClass: class = L.Rectangle
77
+ // Class to be used when creating a new Rectangle.
78
+ rectangleClass: L.Rectangle,
79
+
80
+ // 🍂option circleClass: class = L.Circle
81
+ // Class to be used when creating a new Circle.
82
+ circleClass: L.Circle,
83
+
84
+ // 🍂option drawingCSSClass: string = 'leaflet-editable-drawing'
85
+ // CSS class to be added to the map container while drawing.
86
+ drawingCSSClass: 'leaflet-editable-drawing',
87
+
88
+ // 🍂option drawingCursor: const = 'crosshair'
89
+ // Cursor mode set to the map while drawing.
90
+ drawingCursor: 'crosshair',
91
+
92
+ // 🍂option editLayer: Layer = new L.LayerGroup()
93
+ // Layer used to store edit tools (vertex, line guide…).
94
+ editLayer: undefined,
95
+
96
+ // 🍂option featuresLayer: Layer = new L.LayerGroup()
97
+ // Default layer used to store drawn features (Marker, Polyline…).
98
+ featuresLayer: undefined,
99
+
100
+ // 🍂option polylineEditorClass: class = PolylineEditor
101
+ // Class to be used as Polyline editor.
102
+ polylineEditorClass: undefined,
103
+
104
+ // 🍂option polygonEditorClass: class = PolygonEditor
105
+ // Class to be used as Polygon editor.
106
+ polygonEditorClass: undefined,
107
+
108
+ // 🍂option markerEditorClass: class = MarkerEditor
109
+ // Class to be used as Marker editor.
110
+ markerEditorClass: undefined,
111
+
112
+ // 🍂option rectangleEditorClass: class = RectangleEditor
113
+ // Class to be used as Rectangle editor.
114
+ rectangleEditorClass: undefined,
115
+
116
+ // 🍂option circleEditorClass: class = CircleEditor
117
+ // Class to be used as Circle editor.
118
+ circleEditorClass: undefined,
119
+
120
+ // 🍂option lineGuideOptions: hash = {}
121
+ // Options to be passed to the line guides.
122
+ lineGuideOptions: {},
123
+
124
+ // 🍂option skipMiddleMarkers: boolean = false
125
+ // Set this to true if you don't want middle markers.
126
+ skipMiddleMarkers: false
127
+
128
+ },
129
+
130
+ initialize: function (map, options) {
131
+ L.setOptions(this, options);
132
+ this._lastZIndex = this.options.zIndex;
133
+ this.map = map;
134
+ this.editLayer = this.createEditLayer();
135
+ this.featuresLayer = this.createFeaturesLayer();
136
+ this.forwardLineGuide = this.createLineGuide();
137
+ this.backwardLineGuide = this.createLineGuide();
138
+ },
139
+
140
+ fireAndForward: function (type, e) {
141
+ e = e || {};
142
+ e.editTools = this;
143
+ this.fire(type, e);
144
+ this.map.fire(type, e);
145
+ },
146
+
147
+ createLineGuide: function () {
148
+ var options = L.extend({dashArray: '5,10', weight: 1, interactive: false}, this.options.lineGuideOptions);
149
+ return L.polyline([], options);
150
+ },
151
+
152
+ createVertexIcon: function (options) {
153
+ return L.Browser.mobile && L.Browser.touch ? new L.Editable.TouchVertexIcon(options) : new L.Editable.VertexIcon(options);
154
+ },
155
+
156
+ createEditLayer: function () {
157
+ return this.options.editLayer || new L.LayerGroup().addTo(this.map);
158
+ },
159
+
160
+ createFeaturesLayer: function () {
161
+ return this.options.featuresLayer || new L.LayerGroup().addTo(this.map);
162
+ },
163
+
164
+ moveForwardLineGuide: function (latlng) {
165
+ if (this.forwardLineGuide._latlngs.length) {
166
+ this.forwardLineGuide._latlngs[1] = latlng;
167
+ this.forwardLineGuide._bounds.extend(latlng);
168
+ this.forwardLineGuide.redraw();
169
+ }
170
+ },
171
+
172
+ moveBackwardLineGuide: function (latlng) {
173
+ if (this.backwardLineGuide._latlngs.length) {
174
+ this.backwardLineGuide._latlngs[1] = latlng;
175
+ this.backwardLineGuide._bounds.extend(latlng);
176
+ this.backwardLineGuide.redraw();
177
+ }
178
+ },
179
+
180
+ anchorForwardLineGuide: function (latlng) {
181
+ this.forwardLineGuide._latlngs[0] = latlng;
182
+ this.forwardLineGuide._bounds.extend(latlng);
183
+ this.forwardLineGuide.redraw();
184
+ },
185
+
186
+ anchorBackwardLineGuide: function (latlng) {
187
+ this.backwardLineGuide._latlngs[0] = latlng;
188
+ this.backwardLineGuide._bounds.extend(latlng);
189
+ this.backwardLineGuide.redraw();
190
+ },
191
+
192
+ attachForwardLineGuide: function () {
193
+ this.editLayer.addLayer(this.forwardLineGuide);
194
+ },
195
+
196
+ attachBackwardLineGuide: function () {
197
+ this.editLayer.addLayer(this.backwardLineGuide);
198
+ },
199
+
200
+ detachForwardLineGuide: function () {
201
+ this.forwardLineGuide.setLatLngs([]);
202
+ this.editLayer.removeLayer(this.forwardLineGuide);
203
+ },
204
+
205
+ detachBackwardLineGuide: function () {
206
+ this.backwardLineGuide.setLatLngs([]);
207
+ this.editLayer.removeLayer(this.backwardLineGuide);
208
+ },
209
+
210
+ blockEvents: function () {
211
+ // Hack: force map not to listen to other layers events while drawing.
212
+ if (!this._oldTargets) {
213
+ this._oldTargets = this.map._targets;
214
+ this.map._targets = {};
215
+ }
216
+ },
217
+
218
+ unblockEvents: function () {
219
+ if (this._oldTargets) {
220
+ // Reset, but keep targets created while drawing.
221
+ this.map._targets = L.extend(this.map._targets, this._oldTargets);
222
+ delete this._oldTargets;
223
+ }
224
+ },
225
+
226
+ registerForDrawing: function (editor) {
227
+ if (this._drawingEditor) this.unregisterForDrawing(this._drawingEditor);
228
+ this.blockEvents();
229
+ editor.reset(); // Make sure editor tools still receive events.
230
+ this._drawingEditor = editor;
231
+ this.map.on('mousemove touchmove', editor.onDrawingMouseMove, editor);
232
+ this.map.on('mousedown', this.onMousedown, this);
233
+ this.map.on('mouseup', this.onMouseup, this);
234
+ L.DomUtil.addClass(this.map._container, this.options.drawingCSSClass);
235
+ this.defaultMapCursor = this.map._container.style.cursor;
236
+ this.map._container.style.cursor = this.options.drawingCursor;
237
+ },
238
+
239
+ unregisterForDrawing: function (editor) {
240
+ this.unblockEvents();
241
+ L.DomUtil.removeClass(this.map._container, this.options.drawingCSSClass);
242
+ this.map._container.style.cursor = this.defaultMapCursor;
243
+ editor = editor || this._drawingEditor;
244
+ if (!editor) return;
245
+ this.map.off('mousemove touchmove', editor.onDrawingMouseMove, editor);
246
+ this.map.off('mousedown', this.onMousedown, this);
247
+ this.map.off('mouseup', this.onMouseup, this);
248
+ if (editor !== this._drawingEditor) return;
249
+ delete this._drawingEditor;
250
+ if (editor._drawing) editor.cancelDrawing();
251
+ },
252
+
253
+ onMousedown: function (e) {
254
+ if (e.originalEvent.which != 1) return;
255
+ this._mouseDown = e;
256
+ this._drawingEditor.onDrawingMouseDown(e);
257
+ },
258
+
259
+ onMouseup: function (e) {
260
+ if (this._mouseDown) {
261
+ var editor = this._drawingEditor,
262
+ mouseDown = this._mouseDown;
263
+ this._mouseDown = null;
264
+ editor.onDrawingMouseUp(e);
265
+ if (this._drawingEditor !== editor) return; // onDrawingMouseUp may call unregisterFromDrawing.
266
+ var origin = L.point(mouseDown.originalEvent.clientX, mouseDown.originalEvent.clientY);
267
+ var distance = L.point(e.originalEvent.clientX, e.originalEvent.clientY).distanceTo(origin);
268
+ if (Math.abs(distance) < 9 * (window.devicePixelRatio || 1)) this._drawingEditor.onDrawingClick(e);
269
+ }
270
+ },
271
+
272
+ // 🍂section Public methods
273
+ // You will generally access them by the `map.editTools`
274
+ // instance:
275
+ //
276
+ // `map.editTools.startPolyline();`
277
+
278
+ // 🍂method drawing(): boolean
279
+ // Return true if any drawing action is ongoing.
280
+ drawing: function () {
281
+ return this._drawingEditor && this._drawingEditor.drawing();
282
+ },
283
+
284
+ // 🍂method stopDrawing()
285
+ // When you need to stop any ongoing drawing, without needing to know which editor is active.
286
+ stopDrawing: function () {
287
+ this.unregisterForDrawing();
288
+ },
289
+
290
+ // 🍂method commitDrawing()
291
+ // When you need to commit any ongoing drawing, without needing to know which editor is active.
292
+ commitDrawing: function (e) {
293
+ if (!this._drawingEditor) return;
294
+ this._drawingEditor.commitDrawing(e);
295
+ },
296
+
297
+ connectCreatedToMap: function (layer) {
298
+ return this.featuresLayer.addLayer(layer);
299
+ },
300
+
301
+ // 🍂method startPolyline(latlng: L.LatLng, options: hash): L.Polyline
302
+ // Start drawing a Polyline. If `latlng` is given, a first point will be added. In any case, continuing on user click.
303
+ // If `options` is given, it will be passed to the Polyline class constructor.
304
+ startPolyline: function (latlng, options) {
305
+ var line = this.createPolyline([], options);
306
+ line.enableEdit(this.map).newShape(latlng);
307
+ return line;
308
+ },
309
+
310
+ // 🍂method startPolygon(latlng: L.LatLng, options: hash): L.Polygon
311
+ // Start drawing a Polygon. If `latlng` is given, a first point will be added. In any case, continuing on user click.
312
+ // If `options` is given, it will be passed to the Polygon class constructor.
313
+ startPolygon: function (latlng, options) {
314
+ var polygon = this.createPolygon([], options);
315
+ polygon.enableEdit(this.map).newShape(latlng);
316
+ return polygon;
317
+ },
318
+
319
+ // 🍂method startMarker(latlng: L.LatLng, options: hash): L.Marker
320
+ // Start adding a Marker. If `latlng` is given, the Marker will be shown first at this point.
321
+ // In any case, it will follow the user mouse, and will have a final `latlng` on next click (or touch).
322
+ // If `options` is given, it will be passed to the Marker class constructor.
323
+ startMarker: function (latlng, options) {
324
+ latlng = latlng || this.map.getCenter().clone();
325
+ var marker = this.createMarker(latlng, options);
326
+ marker.enableEdit(this.map).startDrawing();
327
+ return marker;
328
+ },
329
+
330
+ // 🍂method startRectangle(latlng: L.LatLng, options: hash): L.Rectangle
331
+ // Start drawing a Rectangle. If `latlng` is given, the Rectangle anchor will be added. In any case, continuing on user drag.
332
+ // If `options` is given, it will be passed to the Rectangle class constructor.
333
+ startRectangle: function(latlng, options) {
334
+ var corner = latlng || L.latLng([0, 0]);
335
+ var bounds = new L.LatLngBounds(corner, corner);
336
+ var rectangle = this.createRectangle(bounds, options);
337
+ rectangle.enableEdit(this.map).startDrawing();
338
+ return rectangle;
339
+ },
340
+
341
+ // 🍂method startCircle(latlng: L.LatLng, options: hash): L.Circle
342
+ // Start drawing a Circle. If `latlng` is given, the Circle anchor will be added. In any case, continuing on user drag.
343
+ // If `options` is given, it will be passed to the Circle class constructor.
344
+ startCircle: function (latlng, options) {
345
+ latlng = latlng || this.map.getCenter().clone();
346
+ var circle = this.createCircle(latlng, options);
347
+ circle.enableEdit(this.map).startDrawing();
348
+ return circle;
349
+ },
350
+
351
+ startHole: function (editor, latlng) {
352
+ editor.newHole(latlng);
353
+ },
354
+
355
+ createLayer: function (klass, latlngs, options) {
356
+ options = L.Util.extend({editOptions: {editTools: this}}, options);
357
+ var layer = new klass(latlngs, options);
358
+ // 🍂namespace Editable
359
+ // 🍂event editable:created: LayerEvent
360
+ // Fired when a new feature (Marker, Polyline…) is created.
361
+ this.fireAndForward('editable:created', {layer: layer});
362
+ return layer;
363
+ },
364
+
365
+ createPolyline: function (latlngs, options) {
366
+ return this.createLayer(options && options.polylineClass || this.options.polylineClass, latlngs, options);
367
+ },
368
+
369
+ createPolygon: function (latlngs, options) {
370
+ return this.createLayer(options && options.polygonClass || this.options.polygonClass, latlngs, options);
371
+ },
372
+
373
+ createMarker: function (latlng, options) {
374
+ return this.createLayer(options && options.markerClass || this.options.markerClass, latlng, options);
375
+ },
376
+
377
+ createRectangle: function (bounds, options) {
378
+ return this.createLayer(options && options.rectangleClass || this.options.rectangleClass, bounds, options);
379
+ },
380
+
381
+ createCircle: function (latlng, options) {
382
+ return this.createLayer(options && options.circleClass || this.options.circleClass, latlng, options);
383
+ }
384
+
385
+ });
386
+
387
+ L.extend(L.Editable, {
388
+
389
+ makeCancellable: function (e) {
390
+ e.cancel = function () {
391
+ e._cancelled = true;
392
+ };
393
+ }
394
+
395
+ });
396
+
397
+ // 🍂namespace Map; 🍂class Map
398
+ // Leaflet.Editable add options and events to the `L.Map` object.
399
+ // See `Editable` events for the list of events fired on the Map.
400
+ // 🍂example
288
401
  //
289
- // `map.editTools.startPolyline();`
290
-
291
- // 🍂method drawing(): boolean
292
- // Return true if any drawing action is ongoing.
293
- drawing: function () {
294
- return this._drawingEditor?.drawing()
295
- },
296
-
297
- // 🍂method stopDrawing()
298
- // When you need to stop any ongoing drawing, without needing to know which editor is active.
299
- stopDrawing: function () {
300
- this.unregisterForDrawing()
301
- },
302
-
303
- // 🍂method commitDrawing()
304
- // When you need to commit any ongoing drawing, without needing to know which editor is active.
305
- commitDrawing: function (e) {
306
- if (!this._drawingEditor) return
307
- this._drawingEditor.commitDrawing(e)
308
- },
309
-
310
- connectCreatedToMap: function (layer) {
311
- return this.featuresLayer.addLayer(layer)
312
- },
313
-
314
- // 🍂method startPolyline(latlng: L.LatLng, options: hash): L.Polyline
315
- // Start drawing a Polyline. If `latlng` is given, a first point will be added. In any case, continuing on user click.
316
- // If `options` is given, it will be passed to the Polyline class constructor.
317
- startPolyline: function (latlng, options) {
318
- const line = this.createPolyline([], options)
319
- line.enableEdit(this.map).newShape(latlng)
320
- return line
321
- },
322
-
323
- // 🍂method startPolygon(latlng: L.LatLng, options: hash): L.Polygon
324
- // Start drawing a Polygon. If `latlng` is given, a first point will be added. In any case, continuing on user click.
325
- // If `options` is given, it will be passed to the Polygon class constructor.
326
- startPolygon: function (latlng, options) {
327
- const polygon = this.createPolygon([], options)
328
- polygon.enableEdit(this.map).newShape(latlng)
329
- return polygon
330
- },
331
-
332
- // 🍂method startMarker(latlng: L.LatLng, options: hash): L.Marker
333
- // Start adding a Marker. If `latlng` is given, the Marker will be shown first at this point.
334
- // In any case, it will follow the user mouse, and will have a final `latlng` on next click (or touch).
335
- // If `options` is given, it will be passed to the Marker class constructor.
336
- startMarker: function (latlng, options) {
337
- latlng = latlng || this.map.getCenter().clone()
338
- const marker = this.createMarker(latlng, options)
339
- marker.enableEdit(this.map).startDrawing()
340
- return marker
341
- },
342
-
343
- // 🍂method startCircleMarker(latlng: L.LatLng, options: hash): L.CircleMarker
344
- // Start adding a CircleMarker. If `latlng` is given, the CircleMarker will be shown first at this point.
345
- // In any case, it will follow the user mouse, and will have a final `latlng` on next click (or touch).
346
- // If `options` is given, it will be passed to the CircleMarker class constructor.
347
- startCircleMarker: function (latlng, options) {
348
- latlng = latlng || this.map.getCenter().clone()
349
- const marker = this.createCircleMarker(latlng, options)
350
- marker.enableEdit(this.map).startDrawing()
351
- return marker
352
- },
353
-
354
- // 🍂method startRectangle(latlng: L.LatLng, options: hash): L.Rectangle
355
- // Start drawing a Rectangle. If `latlng` is given, the Rectangle anchor will be added. In any case, continuing on user drag.
356
- // If `options` is given, it will be passed to the Rectangle class constructor.
357
- startRectangle: function (latlng, options) {
358
- const corner = latlng || L.latLng([0, 0])
359
- const bounds = new L.LatLngBounds(corner, corner)
360
- const rectangle = this.createRectangle(bounds, options)
361
- rectangle.enableEdit(this.map).startDrawing()
362
- return rectangle
363
- },
364
-
365
- // 🍂method startCircle(latlng: L.LatLng, options: hash): L.Circle
366
- // Start drawing a Circle. If `latlng` is given, the Circle anchor will be added. In any case, continuing on user drag.
367
- // If `options` is given, it will be passed to the Circle class constructor.
368
- startCircle: function (latlng, options) {
369
- latlng = latlng || this.map.getCenter().clone()
370
- const circle = this.createCircle(latlng, options)
371
- circle.enableEdit(this.map).startDrawing()
372
- return circle
373
- },
374
-
375
- startHole: (editor, latlng) => {
376
- editor.newHole(latlng)
377
- },
378
-
379
- createLayer: function (klass, latlngs, options) {
380
- options = L.Util.extend({ editOptions: { editTools: this } }, options)
381
- const layer = new klass(latlngs, options)
382
- // 🍂namespace Editable
383
- // 🍂event editable:created: LayerEvent
384
- // Fired when a new feature (Marker, Polyline…) is created.
385
- this.fireAndForward('editable:created', { layer: layer })
386
- return layer
387
- },
388
-
389
- createPolyline: function (latlngs, options) {
390
- return this.createLayer(
391
- options?.polylineClass || this.options.polylineClass,
392
- latlngs,
393
- options
394
- )
395
- },
396
-
397
- createPolygon: function (latlngs, options) {
398
- return this.createLayer(
399
- options?.polygonClass || this.options.polygonClass,
400
- latlngs,
401
- options
402
- )
403
- },
404
-
405
- createMarker: function (latlng, options) {
406
- return this.createLayer(
407
- options?.markerClass || this.options.markerClass,
408
- latlng,
409
- options
410
- )
411
- },
412
-
413
- createCircleMarker: function (latlng, options) {
414
- return this.createLayer(
415
- options?.circleMarkerClass || this.options.circleMarkerClass,
416
- latlng,
417
- options
418
- )
419
- },
420
-
421
- createRectangle: function (bounds, options) {
422
- return this.createLayer(
423
- options?.rectangleClass || this.options.rectangleClass,
424
- bounds,
425
- options
426
- )
427
- },
428
-
429
- createCircle: function (latlng, options) {
430
- return this.createLayer(
431
- options?.circleClass || this.options.circleClass,
432
- latlng,
433
- options
434
- )
435
- },
436
- })
437
-
438
- L.extend(L.Editable, {
439
- makeCancellable: (e) => {
440
- e.cancel = () => {
441
- e._cancelled = true
442
- }
443
- },
444
- })
445
-
446
- // 🍂namespace Map; 🍂class Map
447
- // Leaflet.Editable add options and events to the `L.Map` object.
448
- // See `Editable` events for the list of events fired on the Map.
449
- // 🍂example
450
- //
451
- // ```js
452
- // var map = L.map('map', {
453
- // editable: true,
454
- // editOptions: {
455
- //
456
- // }
457
- // });
458
- // ```
459
- // 🍂section Editable Map Options
460
- L.Map.mergeOptions({
461
- // 🍂namespace Map
462
- // 🍂section Map Options
463
- // 🍂option editToolsClass: class = L.Editable
464
- // Class to be used as vertex, for path editing.
465
- editToolsClass: L.Editable,
466
-
467
- // 🍂option editable: boolean = false
468
- // Whether to create a L.Editable instance at map init.
469
- editable: false,
470
-
471
- // 🍂option editOptions: hash = {}
472
- // Options to pass to L.Editable when instantiating.
473
- editOptions: {},
474
- })
475
-
476
- L.Map.addInitHook(function () {
477
- this.whenReady(function () {
478
- if (this.options.editable) {
479
- this.editTools = new this.options.editToolsClass(this, this.options.editOptions)
480
- }
481
- })
482
- })
483
-
484
- L.Editable.VertexIcon = L.DivIcon.extend({
485
- options: {
486
- iconSize: new L.Point(8, 8),
487
- },
488
- })
489
-
490
- L.Editable.TouchVertexIcon = L.Editable.VertexIcon.extend({
491
- options: {
492
- iconSize: new L.Point(20, 20),
493
- },
494
- })
495
-
496
- // 🍂namespace Editable; 🍂class VertexMarker; Handler for dragging path vertices.
497
- L.Editable.VertexMarker = L.Marker.extend({
498
- options: {
499
- draggable: true,
500
- className: 'leaflet-div-icon leaflet-vertex-icon',
501
- },
502
-
503
- // 🍂section Public methods
504
- // The marker used to handle path vertex. You will usually interact with a `VertexMarker`
505
- // instance when listening for events like `editable:vertex:ctrlclick`.
506
-
507
- initialize: function (latlng, latlngs, editor, options) {
508
- // We don't use this._latlng, because on drag Leaflet replace it while
509
- // we want to keep reference.
510
- this.latlng = latlng
511
- this.latlngs = latlngs
512
- this.editor = editor
513
- L.Marker.prototype.initialize.call(this, latlng, options)
514
- this.options.icon = this.editor.tools.createVertexIcon({
515
- className: this.options.className,
516
- })
517
- this.latlng.__vertex = this
518
- this.connect()
519
- this.setZIndexOffset(editor.tools._lastZIndex + 1)
520
- },
521
-
522
- connect: function () {
523
- this.editor.editLayer.addLayer(this)
524
- },
525
-
526
- onAdd: function (map) {
527
- L.Marker.prototype.onAdd.call(this, map)
528
- this.on('drag', this.onDrag)
529
- this.on('dragstart', this.onDragStart)
530
- this.on('dragend', this.onDragEnd)
531
- this.on('mouseup', this.onMouseup)
532
- this.on('click', this.onClick)
533
- this.on('contextmenu', this.onContextMenu)
534
- this.on('mousedown touchstart', this.onMouseDown)
535
- this.on('mouseover', this.onMouseOver)
536
- this.on('mouseout', this.onMouseOut)
537
- this.addMiddleMarkers()
538
- },
539
-
540
- onRemove: function (map) {
541
- if (this.middleMarker) this.middleMarker.delete()
542
- delete this.latlng.__vertex
543
- this.off('drag', this.onDrag)
544
- this.off('dragstart', this.onDragStart)
545
- this.off('dragend', this.onDragEnd)
546
- this.off('mouseup', this.onMouseup)
547
- this.off('click', this.onClick)
548
- this.off('contextmenu', this.onContextMenu)
549
- this.off('mousedown touchstart', this.onMouseDown)
550
- this.off('mouseover', this.onMouseOver)
551
- this.off('mouseout', this.onMouseOut)
552
- L.Marker.prototype.onRemove.call(this, map)
553
- },
554
-
555
- onDrag: function (e) {
556
- e.vertex = this
557
- this.editor.onVertexMarkerDrag(e)
558
- const iconPos = L.DomUtil.getPosition(this._icon)
559
- const latlng = this._map.layerPointToLatLng(iconPos)
560
- this.latlng.update(latlng)
561
- this._latlng = this.latlng // Push back to Leaflet our reference.
562
- this.editor.refresh()
563
- if (this.middleMarker) this.middleMarker.updateLatLng()
564
- const next = this.getNext()
565
- if (next?.middleMarker) next.middleMarker.updateLatLng()
566
- },
567
-
568
- onDragStart: function (e) {
569
- e.vertex = this
570
- this.editor.onVertexMarkerDragStart(e)
571
- },
572
-
573
- onDragEnd: function (e) {
574
- e.vertex = this
575
- this.editor.onVertexMarkerDragEnd(e)
576
- },
577
-
578
- onClick: function (e) {
579
- e.vertex = this
580
- this.editor.onVertexMarkerClick(e)
581
- },
582
-
583
- onMouseup: function (e) {
584
- L.DomEvent.stop(e)
585
- e.vertex = this
586
- this.editor.map.fire('mouseup', e)
587
- },
588
-
589
- onContextMenu: function (e) {
590
- e.vertex = this
591
- this.editor.onVertexMarkerContextMenu(e)
592
- },
593
-
594
- onMouseDown: function (e) {
595
- e.vertex = this
596
- this.editor.onVertexMarkerMouseDown(e)
597
- },
598
-
599
- onMouseOver: function (e) {
600
- e.vertex = this
601
- this.editor.onVertexMarkerMouseOver(e)
602
- },
603
-
604
- onMouseOut: function (e) {
605
- e.vertex = this
606
- this.editor.onVertexMarkerMouseOut(e)
607
- },
608
-
609
- // 🍂method delete()
610
- // Delete a vertex and the related LatLng.
611
- delete: function () {
612
- const next = this.getNext() // Compute before changing latlng
613
- this.latlngs.splice(this.getIndex(), 1)
614
- this.editor.editLayer.removeLayer(this)
615
- this.editor.onVertexDeleted({ latlng: this.latlng, vertex: this })
616
- if (!this.latlngs.length) this.editor.deleteShape(this.latlngs)
617
- if (next) next.resetMiddleMarker()
618
- this.editor.refresh()
619
- },
620
-
621
- // 🍂method getIndex(): int
622
- // Get the index of the current vertex among others of the same LatLngs group.
623
- getIndex: function () {
624
- return this.latlngs.indexOf(this.latlng)
625
- },
626
-
627
- // 🍂method getLastIndex(): int
628
- // Get last vertex index of the LatLngs group of the current vertex.
629
- getLastIndex: function () {
630
- return this.latlngs.length - 1
631
- },
632
-
633
- // 🍂method getPrevious(): VertexMarker
634
- // Get the previous VertexMarker in the same LatLngs group.
635
- getPrevious: function () {
636
- if (this.latlngs.length < 2) return
637
- const index = this.getIndex()
638
- let previousIndex = index - 1
639
- if (index === 0 && this.editor.CLOSED) previousIndex = this.getLastIndex()
640
- const previous = this.latlngs[previousIndex]
641
- if (previous) return previous.__vertex
642
- },
643
-
644
- // 🍂method getNext(): VertexMarker
645
- // Get the next VertexMarker in the same LatLngs group.
646
- getNext: function () {
647
- if (this.latlngs.length < 2) return
648
- const index = this.getIndex()
649
- let nextIndex = index + 1
650
- if (index === this.getLastIndex() && this.editor.CLOSED) nextIndex = 0
651
- const next = this.latlngs[nextIndex]
652
- if (next) return next.__vertex
653
- },
654
-
655
- addMiddleMarker: function (previous) {
656
- if (!this.editor.hasMiddleMarkers()) return
657
- previous = previous || this.getPrevious()
658
- if (previous && !this.middleMarker)
659
- this.middleMarker = this.editor.addMiddleMarker(
660
- previous,
661
- this,
662
- this.latlngs,
663
- this.editor
664
- )
665
- },
666
-
667
- addMiddleMarkers: function () {
668
- if (!this.editor.hasMiddleMarkers()) return
669
- const previous = this.getPrevious()
670
- if (previous) this.addMiddleMarker(previous)
671
- const next = this.getNext()
672
- if (next) next.resetMiddleMarker()
673
- },
674
-
675
- resetMiddleMarker: function () {
676
- if (this.middleMarker) this.middleMarker.delete()
677
- this.addMiddleMarker()
678
- },
679
-
680
- // 🍂method split()
681
- // Split the vertex LatLngs group at its index, if possible.
682
- split: function () {
683
- if (!this.editor.splitShape) return // Only for PolylineEditor
684
- this.editor.splitShape(this.latlngs, this.getIndex())
685
- },
686
-
687
- // 🍂method continue()
688
- // Continue the vertex LatLngs from this vertex. Only active for first and last vertices of a Polyline.
689
- continue: function () {
690
- if (!this.editor.continueBackward) return // Only for PolylineEditor
691
- const index = this.getIndex()
692
- if (index === 0) this.editor.continueBackward(this.latlngs)
693
- else if (index === this.getLastIndex()) this.editor.continueForward(this.latlngs)
694
- },
695
- })
696
-
697
- L.Editable.mergeOptions({
698
- // 🍂namespace Editable
699
- // 🍂option vertexMarkerClass: class = VertexMarker
700
- // Class to be used as vertex, for path editing.
701
- vertexMarkerClass: L.Editable.VertexMarker,
702
- })
703
-
704
- L.Editable.MiddleMarker = L.Marker.extend({
705
- options: {
706
- opacity: 0.5,
707
- className: 'leaflet-div-icon leaflet-middle-icon',
708
- draggable: true,
709
- },
710
-
711
- initialize: function (left, right, latlngs, editor, options) {
712
- this.left = left
713
- this.right = right
714
- this.editor = editor
715
- this.latlngs = latlngs
716
- L.Marker.prototype.initialize.call(this, this.computeLatLng(), options)
717
- this._opacity = this.options.opacity
718
- this.options.icon = this.editor.tools.createVertexIcon({
719
- className: this.options.className,
720
- })
721
- this.editor.editLayer.addLayer(this)
722
- this.setVisibility()
723
- },
724
-
725
- setVisibility: function () {
726
- const leftPoint = this._map.latLngToContainerPoint(this.left.latlng)
727
- const rightPoint = this._map.latLngToContainerPoint(this.right.latlng)
728
- const size = L.point(this.options.icon.options.iconSize)
729
- if (leftPoint.distanceTo(rightPoint) < size.x * 3) this.hide()
730
- else this.show()
731
- },
732
-
733
- show: function () {
734
- this.setOpacity(this._opacity)
735
- },
736
-
737
- hide: function () {
738
- this.setOpacity(0)
739
- },
740
-
741
- updateLatLng: function () {
742
- this.setLatLng(this.computeLatLng())
743
- this.setVisibility()
744
- },
745
-
746
- computeLatLng: function () {
747
- const leftPoint = this.editor.map.latLngToContainerPoint(this.left.latlng)
748
- const rightPoint = this.editor.map.latLngToContainerPoint(this.right.latlng)
749
- const y = (leftPoint.y + rightPoint.y) / 2
750
- const x = (leftPoint.x + rightPoint.x) / 2
751
- return this.editor.map.containerPointToLatLng([x, y])
752
- },
753
-
754
- onAdd: function (map) {
755
- L.Marker.prototype.onAdd.call(this, map)
756
- L.DomEvent.on(this._icon, 'mousedown touchstart', this.onMouseDown, this)
757
- map.on('zoomend', this.setVisibility, this)
758
- },
759
-
760
- onRemove: function (map) {
761
- delete this.right.middleMarker
762
- L.DomEvent.off(this._icon, 'mousedown touchstart', this.onMouseDown, this)
763
- map.off('zoomend', this.setVisibility, this)
764
- L.Marker.prototype.onRemove.call(this, map)
765
- },
766
-
767
- onMouseDown: function (e) {
768
- const iconPos = L.DomUtil.getPosition(this._icon)
769
- const latlng = this.editor.map.layerPointToLatLng(iconPos)
770
- e = {
771
- originalEvent: e,
772
- latlng: latlng,
773
- }
774
- if (this.options.opacity === 0) return
775
- L.Editable.makeCancellable(e)
776
- this.editor.onMiddleMarkerMouseDown(e)
777
- if (e._cancelled) return
778
- this.latlngs.splice(this.index(), 0, e.latlng)
779
- this.editor.refresh()
780
- const icon = this._icon
781
- const marker = this.editor.addVertexMarker(e.latlng, this.latlngs)
782
- this.editor.onNewVertex(marker)
783
- /* Hack to workaround browser not firing touchend when element is no more on DOM */
784
- const parent = marker._icon.parentNode
785
- parent.removeChild(marker._icon)
786
- marker._icon = icon
787
- parent.appendChild(marker._icon)
788
- marker._initIcon()
789
- marker._initInteraction()
790
- marker.setOpacity(1)
791
- /* End hack */
792
- // Transfer ongoing dragging to real marker
793
- L.Draggable._dragging = false
794
- marker.dragging._draggable._onDown(e.originalEvent)
795
- this.delete()
796
- },
797
-
798
- delete: function () {
799
- this.editor.editLayer.removeLayer(this)
800
- },
801
-
802
- index: function () {
803
- return this.latlngs.indexOf(this.right.latlng)
804
- },
805
- })
806
-
807
- L.Editable.mergeOptions({
808
- // 🍂namespace Editable
809
- // 🍂option middleMarkerClass: class = VertexMarker
810
- // Class to be used as middle vertex, pulled by the user to create a new point in the middle of a path.
811
- middleMarkerClass: L.Editable.MiddleMarker,
812
- })
813
-
814
- // 🍂namespace Editable; 🍂class BaseEditor; 🍂aka L.Editable.BaseEditor
815
- // When editing a feature (Marker, Polyline…), an editor is attached to it. This
816
- // editor basically knows how to handle the edition.
817
- L.Editable.BaseEditor = L.Handler.extend({
818
- initialize: function (map, feature, options) {
819
- L.setOptions(this, options)
820
- this.map = map
821
- this.feature = feature
822
- this.feature.editor = this
823
- this.editLayer = new L.LayerGroup()
824
- this.tools = this.options.editTools || map.editTools
825
- },
826
-
827
- // 🍂method enable(): this
828
- // Set up the drawing tools for the feature to be editable.
829
- addHooks: function () {
830
- if (this.isConnected()) this.onFeatureAdd()
831
- else this.feature.once('add', this.onFeatureAdd, this)
832
- this.onEnable()
833
- this.feature.on(this._getEvents(), this)
834
- },
835
-
836
- // 🍂method disable(): this
837
- // Remove the drawing tools for the feature.
838
- removeHooks: function () {
839
- this.feature.off(this._getEvents(), this)
840
- if (this.feature.dragging) this.feature.dragging.disable()
841
- this.editLayer.clearLayers()
842
- this.tools.editLayer.removeLayer(this.editLayer)
843
- this.onDisable()
844
- if (this._drawing) this.cancelDrawing()
845
- },
846
-
847
- // 🍂method drawing(): boolean
848
- // Return true if any drawing action is ongoing with this editor.
849
- drawing: function () {
850
- return !!this._drawing
851
- },
852
-
853
- reset: () => {},
854
-
855
- onFeatureAdd: function () {
856
- this.tools.editLayer.addLayer(this.editLayer)
857
- if (this.feature.dragging) this.feature.dragging.enable()
858
- },
859
-
860
- hasMiddleMarkers: function () {
861
- return !this.options.skipMiddleMarkers && !this.tools.options.skipMiddleMarkers
862
- },
863
-
864
- fireAndForward: function (type, e) {
865
- e = e || {}
866
- e.layer = this.feature
867
- this.feature.fire(type, e)
868
- this.tools.fireAndForward(type, e)
869
- },
870
-
871
- onEnable: function () {
872
- // 🍂namespace Editable
873
- // 🍂event editable:enable: Event
874
- // Fired when an existing feature is ready to be edited.
875
- this.fireAndForward('editable:enable')
876
- },
877
-
878
- onDisable: function () {
879
- // 🍂namespace Editable
880
- // 🍂event editable:disable: Event
881
- // Fired when an existing feature is not ready anymore to be edited.
882
- this.fireAndForward('editable:disable')
883
- },
884
-
885
- onEditing: function () {
886
- // 🍂namespace Editable
887
- // 🍂event editable:editing: Event
888
- // Fired as soon as any change is made to the feature geometry.
889
- this.fireAndForward('editable:editing')
890
- },
891
-
892
- onEdited: function () {
893
- // 🍂namespace Editable
894
- // 🍂event editable:edited: Event
895
- // Fired after any change is made to the feature geometry.
896
- this.fireAndForward('editable:edited')
897
- },
898
-
899
- onStartDrawing: function () {
900
- // 🍂namespace Editable
901
- // 🍂section Drawing events
902
- // 🍂event editable:drawing:start: Event
903
- // Fired when a feature is to be drawn.
904
- this.fireAndForward('editable:drawing:start')
905
- },
906
-
907
- onEndDrawing: function () {
908
- // 🍂namespace Editable
909
- // 🍂section Drawing events
910
- // 🍂event editable:drawing:end: Event
911
- // Fired when a feature is not drawn anymore.
912
- this.fireAndForward('editable:drawing:end')
913
- },
914
-
915
- onCancelDrawing: function () {
916
- // 🍂namespace Editable
917
- // 🍂section Drawing events
918
- // 🍂event editable:drawing:cancel: Event
919
- // Fired when user cancel drawing while a feature is being drawn.
920
- this.fireAndForward('editable:drawing:cancel')
921
- },
922
-
923
- onCommitDrawing: function (e) {
924
- // 🍂namespace Editable
925
- // 🍂section Drawing events
926
- // 🍂event editable:drawing:commit: Event
927
- // Fired when user finish drawing a feature.
928
- this.fireAndForward('editable:drawing:commit', e)
929
- this.onEdited()
930
- },
931
-
932
- onDrawingMouseDown: function (e) {
933
- // 🍂namespace Editable
934
- // 🍂section Drawing events
935
- // 🍂event editable:drawing:mousedown: Event
936
- // Fired when user `mousedown` while drawing.
937
- this.fireAndForward('editable:drawing:mousedown', e)
938
- },
939
-
940
- onDrawingMouseUp: function (e) {
941
- // 🍂namespace Editable
942
- // 🍂section Drawing events
943
- // 🍂event editable:drawing:mouseup: Event
944
- // Fired when user `mouseup` while drawing.
945
- this.fireAndForward('editable:drawing:mouseup', e)
946
- },
947
-
948
- startDrawing: function () {
949
- if (!this._drawing) this._drawing = L.Editable.FORWARD
950
- this.tools.registerForDrawing(this)
951
- this.onStartDrawing()
952
- },
953
-
954
- commitDrawing: function (e) {
955
- this.onCommitDrawing(e)
956
- this.endDrawing()
957
- },
958
-
959
- cancelDrawing: function () {
960
- // If called during a vertex drag, the vertex will be removed before
961
- // the mouseup fires on it. This is a workaround. Maybe better fix is
962
- // To have L.Draggable reset it's status on disable (Leaflet side).
963
- L.Draggable._dragging = false
964
- this.onCancelDrawing()
965
- this.endDrawing()
966
- },
967
-
968
- endDrawing: function () {
969
- this._drawing = false
970
- this.tools.unregisterForDrawing(this)
971
- this.onEndDrawing()
972
- },
973
-
974
- onDrawingClick: function (e) {
975
- if (!this.drawing()) return
976
- L.Editable.makeCancellable(e)
977
- // 🍂namespace Editable
978
- // 🍂section Drawing events
979
- // 🍂event editable:drawing:click: CancelableEvent
980
- // Fired when user `click` while drawing, before any internal action is being processed.
981
- this.fireAndForward('editable:drawing:click', e)
982
- if (e._cancelled) return
983
- if (!this.isConnected()) this.connect(e)
984
- this.processDrawingClick(e)
985
- },
986
-
987
- isConnected: function () {
988
- return this.map.hasLayer(this.feature)
989
- },
990
-
991
- connect: function () {
992
- this.tools.connectCreatedToMap(this.feature)
993
- this.tools.editLayer.addLayer(this.editLayer)
994
- },
995
-
996
- onMove: function (e) {
997
- // 🍂namespace Editable
998
- // 🍂section Drawing events
999
- // 🍂event editable:drawing:move: Event
1000
- // Fired when `move` mouse while drawing, while dragging a marker, and while dragging a vertex.
1001
- this.fireAndForward('editable:drawing:move', e)
1002
- },
1003
-
1004
- onDrawingMouseMove: function (e) {
1005
- this.onMove(e)
1006
- },
1007
-
1008
- _getEvents: function () {
1009
- return {
1010
- dragstart: this.onDragStart,
1011
- drag: this.onDrag,
1012
- dragend: this.onDragEnd,
1013
- remove: this.disable,
1014
- }
1015
- },
1016
-
1017
- onDragStart: function (e) {
1018
- this.onEditing()
1019
- // 🍂namespace Editable
1020
- // 🍂event editable:dragstart: Event
1021
- // Fired before a path feature is dragged.
1022
- this.fireAndForward('editable:dragstart', e)
1023
- },
1024
-
1025
- onDrag: function (e) {
1026
- this.onMove(e)
1027
- // 🍂namespace Editable
1028
- // 🍂event editable:drag: Event
1029
- // Fired when a path feature is being dragged.
1030
- this.fireAndForward('editable:drag', e)
1031
- },
1032
-
1033
- onDragEnd: function (e) {
1034
- // 🍂namespace Editable
1035
- // 🍂event editable:dragend: Event
1036
- // Fired after a path feature has been dragged.
1037
- this.fireAndForward('editable:dragend', e)
1038
- this.onEdited()
1039
- },
1040
- })
1041
-
1042
- // 🍂namespace Editable; 🍂class MarkerEditor; 🍂aka L.Editable.MarkerEditor
1043
- // 🍂inherits BaseEditor
1044
- // Editor for Marker.
1045
- L.Editable.MarkerEditor = L.Editable.BaseEditor.extend({
1046
- onDrawingMouseMove: function (e) {
1047
- L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e)
1048
- if (this._drawing) this.feature.setLatLng(e.latlng)
1049
- },
1050
-
1051
- processDrawingClick: function (e) {
1052
- // 🍂namespace Editable
1053
- // 🍂section Drawing events
1054
- // 🍂event editable:drawing:clicked: Event
1055
- // Fired when user `click` while drawing, after all internal actions.
1056
- this.fireAndForward('editable:drawing:clicked', e)
1057
- this.commitDrawing(e)
1058
- },
1059
-
1060
- connect: function (e) {
1061
- // On touch, the latlng has not been updated because there is
1062
- // no mousemove.
1063
- if (e) this.feature._latlng = e.latlng
1064
- L.Editable.BaseEditor.prototype.connect.call(this, e)
1065
- },
1066
- })
1067
-
1068
- // 🍂namespace Editable; 🍂class CircleMarkerEditor; 🍂aka L.Editable.CircleMarkerEditor
1069
- // 🍂inherits BaseEditor
1070
- // Editor for CircleMarker.
1071
- L.Editable.CircleMarkerEditor = L.Editable.BaseEditor.extend({
1072
- onDrawingMouseMove: function (e) {
1073
- L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e)
1074
- if (this._drawing) this.feature.setLatLng(e.latlng)
1075
- },
1076
-
1077
- processDrawingClick: function (e) {
1078
- // 🍂namespace Editable
1079
- // 🍂section Drawing events
1080
- // 🍂event editable:drawing:clicked: Event
1081
- // Fired when user `click` while drawing, after all internal actions.
1082
- this.fireAndForward('editable:drawing:clicked', e)
1083
- this.commitDrawing(e)
1084
- },
1085
-
1086
- connect: function (e) {
1087
- // On touch, the latlng has not been updated because there is
1088
- // no mousemove.
1089
- if (e) this.feature._latlng = e.latlng
1090
- L.Editable.BaseEditor.prototype.connect.call(this, e)
1091
- },
1092
- })
1093
-
1094
- // 🍂namespace Editable; 🍂class PathEditor; 🍂aka L.Editable.PathEditor
1095
- // 🍂inherits BaseEditor
1096
- // Base class for all path editors.
1097
- L.Editable.PathEditor = L.Editable.BaseEditor.extend({
1098
- CLOSED: false,
1099
- MIN_VERTEX: 2,
1100
-
1101
- addHooks: function () {
1102
- L.Editable.BaseEditor.prototype.addHooks.call(this)
1103
- if (this.feature) {
1104
- this.initVertexMarkers()
1105
- this.map.on('moveend', this.onMoveEnd, this)
1106
- }
1107
- return this
1108
- },
1109
-
1110
- removeHooks: function () {
1111
- L.Editable.BaseEditor.prototype.removeHooks.call(this)
1112
- if (this.feature) {
1113
- this.map.off('moveend', this.onMoveEnd, this)
1114
- }
1115
- },
1116
-
1117
- onMoveEnd: function () {
1118
- this.initVertexMarkers()
1119
- },
1120
-
1121
- initVertexMarkers: function (latlngs) {
1122
- if (!this.enabled()) return
1123
- latlngs = latlngs || this.getLatLngs()
1124
- if (isFlat(latlngs)) {
1125
- this.addVertexMarkers(latlngs)
1126
- } else {
1127
- for (const member of latlngs) {
1128
- this.initVertexMarkers(member)
402
+ // ```js
403
+ // var map = L.map('map', {
404
+ // editable: true,
405
+ // editOptions: {
406
+ // …
407
+ // }
408
+ // });
409
+ // ```
410
+ // 🍂section Editable Map Options
411
+ L.Map.mergeOptions({
412
+
413
+ // 🍂namespace Map
414
+ // 🍂section Map Options
415
+ // 🍂option editToolsClass: class = L.Editable
416
+ // Class to be used as vertex, for path editing.
417
+ editToolsClass: L.Editable,
418
+
419
+ // 🍂option editable: boolean = false
420
+ // Whether to create a L.Editable instance at map init.
421
+ editable: false,
422
+
423
+ // 🍂option editOptions: hash = {}
424
+ // Options to pass to L.Editable when instantiating.
425
+ editOptions: {}
426
+
427
+ });
428
+
429
+ L.Map.addInitHook(function () {
430
+
431
+ this.whenReady(function () {
432
+ if (this.options.editable) {
433
+ this.editTools = new this.options.editToolsClass(this, this.options.editOptions);
434
+ }
435
+ });
436
+
437
+ });
438
+
439
+ L.Editable.VertexIcon = L.DivIcon.extend({
440
+
441
+ options: {
442
+ iconSize: new L.Point(8, 8)
443
+ }
444
+
445
+ });
446
+
447
+ L.Editable.TouchVertexIcon = L.Editable.VertexIcon.extend({
448
+
449
+ options: {
450
+ iconSize: new L.Point(20, 20)
451
+ }
452
+
453
+ });
454
+
455
+
456
+ // 🍂namespace Editable; 🍂class VertexMarker; Handler for dragging path vertices.
457
+ L.Editable.VertexMarker = L.Marker.extend({
458
+
459
+ options: {
460
+ draggable: true,
461
+ className: 'leaflet-div-icon leaflet-vertex-icon'
462
+ },
463
+
464
+
465
+ // 🍂section Public methods
466
+ // The marker used to handle path vertex. You will usually interact with a `VertexMarker`
467
+ // instance when listening for events like `editable:vertex:ctrlclick`.
468
+
469
+ initialize: function (latlng, latlngs, editor, options) {
470
+ // We don't use this._latlng, because on drag Leaflet replace it while
471
+ // we want to keep reference.
472
+ this.latlng = latlng;
473
+ this.latlngs = latlngs;
474
+ this.editor = editor;
475
+ L.Marker.prototype.initialize.call(this, latlng, options);
476
+ this.options.icon = this.editor.tools.createVertexIcon({className: this.options.className});
477
+ this.latlng.__vertex = this;
478
+ this.editor.editLayer.addLayer(this);
479
+ this.setZIndexOffset(editor.tools._lastZIndex + 1);
480
+ },
481
+
482
+ onAdd: function (map) {
483
+ L.Marker.prototype.onAdd.call(this, map);
484
+ this.on('drag', this.onDrag);
485
+ this.on('dragstart', this.onDragStart);
486
+ this.on('dragend', this.onDragEnd);
487
+ this.on('mouseup', this.onMouseup);
488
+ this.on('click', this.onClick);
489
+ this.on('contextmenu', this.onContextMenu);
490
+ this.on('mousedown touchstart', this.onMouseDown);
491
+ this.on('mouseover', this.onMouseOver);
492
+ this.on('mouseout', this.onMouseOut);
493
+ this.addMiddleMarkers();
494
+ },
495
+
496
+ onRemove: function (map) {
497
+ if (this.middleMarker) this.middleMarker.delete();
498
+ delete this.latlng.__vertex;
499
+ this.off('drag', this.onDrag);
500
+ this.off('dragstart', this.onDragStart);
501
+ this.off('dragend', this.onDragEnd);
502
+ this.off('mouseup', this.onMouseup);
503
+ this.off('click', this.onClick);
504
+ this.off('contextmenu', this.onContextMenu);
505
+ this.off('mousedown touchstart', this.onMouseDown);
506
+ this.off('mouseover', this.onMouseOver);
507
+ this.off('mouseout', this.onMouseOut);
508
+ L.Marker.prototype.onRemove.call(this, map);
509
+ },
510
+
511
+ onDrag: function (e) {
512
+ e.vertex = this;
513
+ this.editor.onVertexMarkerDrag(e);
514
+ var iconPos = L.DomUtil.getPosition(this._icon),
515
+ latlng = this._map.layerPointToLatLng(iconPos);
516
+ this.latlng.update(latlng);
517
+ this._latlng = this.latlng; // Push back to Leaflet our reference.
518
+ this.editor.refresh();
519
+ if (this.middleMarker) this.middleMarker.updateLatLng();
520
+ var next = this.getNext();
521
+ if (next && next.middleMarker) next.middleMarker.updateLatLng();
522
+ },
523
+
524
+ onDragStart: function (e) {
525
+ e.vertex = this;
526
+ this.editor.onVertexMarkerDragStart(e);
527
+ },
528
+
529
+ onDragEnd: function (e) {
530
+ e.vertex = this;
531
+ this.editor.onVertexMarkerDragEnd(e);
532
+ },
533
+
534
+ onClick: function (e) {
535
+ e.vertex = this;
536
+ this.editor.onVertexMarkerClick(e);
537
+ },
538
+
539
+ onMouseup: function (e) {
540
+ L.DomEvent.stop(e);
541
+ e.vertex = this;
542
+ this.editor.map.fire('mouseup', e);
543
+ },
544
+
545
+ onContextMenu: function (e) {
546
+ e.vertex = this;
547
+ this.editor.onVertexMarkerContextMenu(e);
548
+ },
549
+
550
+ onMouseDown: function (e) {
551
+ e.vertex = this;
552
+ this.editor.onVertexMarkerMouseDown(e);
553
+ },
554
+
555
+ onMouseOver: function (e) {
556
+ e.vertex = this;
557
+ this.editor.onVertexMarkerMouseOver(e);
558
+ },
559
+
560
+ onMouseOut: function (e) {
561
+ e.vertex = this;
562
+ this.editor.onVertexMarkerMouseOut(e);
563
+ },
564
+
565
+ // 🍂method delete()
566
+ // Delete a vertex and the related LatLng.
567
+ delete: function () {
568
+ var next = this.getNext(); // Compute before changing latlng
569
+ this.latlngs.splice(this.getIndex(), 1);
570
+ this.editor.editLayer.removeLayer(this);
571
+ this.editor.onVertexDeleted({latlng: this.latlng, vertex: this});
572
+ if (!this.latlngs.length) this.editor.deleteShape(this.latlngs);
573
+ if (next) next.resetMiddleMarker();
574
+ this.editor.refresh();
575
+ },
576
+
577
+ // 🍂method getIndex(): int
578
+ // Get the index of the current vertex among others of the same LatLngs group.
579
+ getIndex: function () {
580
+ return this.latlngs.indexOf(this.latlng);
581
+ },
582
+
583
+ // 🍂method getLastIndex(): int
584
+ // Get last vertex index of the LatLngs group of the current vertex.
585
+ getLastIndex: function () {
586
+ return this.latlngs.length - 1;
587
+ },
588
+
589
+ // 🍂method getPrevious(): VertexMarker
590
+ // Get the previous VertexMarker in the same LatLngs group.
591
+ getPrevious: function () {
592
+ if (this.latlngs.length < 2) return;
593
+ var index = this.getIndex(),
594
+ previousIndex = index - 1;
595
+ if (index === 0 && this.editor.CLOSED) previousIndex = this.getLastIndex();
596
+ var previous = this.latlngs[previousIndex];
597
+ if (previous) return previous.__vertex;
598
+ },
599
+
600
+ // 🍂method getNext(): VertexMarker
601
+ // Get the next VertexMarker in the same LatLngs group.
602
+ getNext: function () {
603
+ if (this.latlngs.length < 2) return;
604
+ var index = this.getIndex(),
605
+ nextIndex = index + 1;
606
+ if (index === this.getLastIndex() && this.editor.CLOSED) nextIndex = 0;
607
+ var next = this.latlngs[nextIndex];
608
+ if (next) return next.__vertex;
609
+ },
610
+
611
+ addMiddleMarker: function (previous) {
612
+ if (!this.editor.hasMiddleMarkers()) return;
613
+ previous = previous || this.getPrevious();
614
+ if (previous && !this.middleMarker) this.middleMarker = this.editor.addMiddleMarker(previous, this, this.latlngs, this.editor);
615
+ },
616
+
617
+ addMiddleMarkers: function () {
618
+ if (!this.editor.hasMiddleMarkers()) return;
619
+ var previous = this.getPrevious();
620
+ if (previous) this.addMiddleMarker(previous);
621
+ var next = this.getNext();
622
+ if (next) next.resetMiddleMarker();
623
+ },
624
+
625
+ resetMiddleMarker: function () {
626
+ if (this.middleMarker) this.middleMarker.delete();
627
+ this.addMiddleMarker();
628
+ },
629
+
630
+ // 🍂method split()
631
+ // Split the vertex LatLngs group at its index, if possible.
632
+ split: function () {
633
+ if (!this.editor.splitShape) return; // Only for PolylineEditor
634
+ this.editor.splitShape(this.latlngs, this.getIndex());
635
+ },
636
+
637
+ // 🍂method continue()
638
+ // Continue the vertex LatLngs from this vertex. Only active for first and last vertices of a Polyline.
639
+ continue: function () {
640
+ if (!this.editor.continueBackward) return; // Only for PolylineEditor
641
+ var index = this.getIndex();
642
+ if (index === 0) this.editor.continueBackward(this.latlngs);
643
+ else if (index === this.getLastIndex()) this.editor.continueForward(this.latlngs);
644
+ }
645
+
646
+ });
647
+
648
+ L.Editable.mergeOptions({
649
+
650
+ // 🍂namespace Editable
651
+ // 🍂option vertexMarkerClass: class = VertexMarker
652
+ // Class to be used as vertex, for path editing.
653
+ vertexMarkerClass: L.Editable.VertexMarker
654
+
655
+ });
656
+
657
+ L.Editable.MiddleMarker = L.Marker.extend({
658
+
659
+ options: {
660
+ opacity: 0.5,
661
+ className: 'leaflet-div-icon leaflet-middle-icon',
662
+ draggable: true
663
+ },
664
+
665
+ initialize: function (left, right, latlngs, editor, options) {
666
+ this.left = left;
667
+ this.right = right;
668
+ this.editor = editor;
669
+ this.latlngs = latlngs;
670
+ L.Marker.prototype.initialize.call(this, this.computeLatLng(), options);
671
+ this._opacity = this.options.opacity;
672
+ this.options.icon = this.editor.tools.createVertexIcon({className: this.options.className});
673
+ this.editor.editLayer.addLayer(this);
674
+ this.setVisibility();
675
+ },
676
+
677
+ setVisibility: function () {
678
+ var leftPoint = this._map.latLngToContainerPoint(this.left.latlng),
679
+ rightPoint = this._map.latLngToContainerPoint(this.right.latlng),
680
+ size = L.point(this.options.icon.options.iconSize);
681
+ if (leftPoint.distanceTo(rightPoint) < size.x * 3) this.hide();
682
+ else this.show();
683
+ },
684
+
685
+ show: function () {
686
+ this.setOpacity(this._opacity);
687
+ },
688
+
689
+ hide: function () {
690
+ this.setOpacity(0);
691
+ },
692
+
693
+ updateLatLng: function () {
694
+ this.setLatLng(this.computeLatLng());
695
+ this.setVisibility();
696
+ },
697
+
698
+ computeLatLng: function () {
699
+ var leftPoint = this.editor.map.latLngToContainerPoint(this.left.latlng),
700
+ rightPoint = this.editor.map.latLngToContainerPoint(this.right.latlng),
701
+ y = (leftPoint.y + rightPoint.y) / 2,
702
+ x = (leftPoint.x + rightPoint.x) / 2;
703
+ return this.editor.map.containerPointToLatLng([x, y]);
704
+ },
705
+
706
+ onAdd: function (map) {
707
+ L.Marker.prototype.onAdd.call(this, map);
708
+ L.DomEvent.on(this._icon, 'mousedown touchstart', this.onMouseDown, this);
709
+ map.on('zoomend', this.setVisibility, this);
710
+ },
711
+
712
+ onRemove: function (map) {
713
+ delete this.right.middleMarker;
714
+ L.DomEvent.off(this._icon, 'mousedown touchstart', this.onMouseDown, this);
715
+ map.off('zoomend', this.setVisibility, this);
716
+ L.Marker.prototype.onRemove.call(this, map);
717
+ },
718
+
719
+ onMouseDown: function (e) {
720
+ var iconPos = L.DomUtil.getPosition(this._icon),
721
+ latlng = this.editor.map.layerPointToLatLng(iconPos);
722
+ e = {
723
+ originalEvent: e,
724
+ latlng: latlng
725
+ };
726
+ if (this.options.opacity === 0) return;
727
+ L.Editable.makeCancellable(e);
728
+ this.editor.onMiddleMarkerMouseDown(e);
729
+ if (e._cancelled) return;
730
+ this.latlngs.splice(this.index(), 0, e.latlng);
731
+ this.editor.refresh();
732
+ var icon = this._icon;
733
+ var marker = this.editor.addVertexMarker(e.latlng, this.latlngs);
734
+ this.editor.onNewVertex(marker);
735
+ /* Hack to workaround browser not firing touchend when element is no more on DOM */
736
+ var parent = marker._icon.parentNode;
737
+ parent.removeChild(marker._icon);
738
+ marker._icon = icon;
739
+ parent.appendChild(marker._icon);
740
+ marker._initIcon();
741
+ marker._initInteraction();
742
+ marker.setOpacity(1);
743
+ /* End hack */
744
+ // Transfer ongoing dragging to real marker
745
+ L.Draggable._dragging = false;
746
+ marker.dragging._draggable._onDown(e.originalEvent);
747
+ this.delete();
748
+ },
749
+
750
+ delete: function () {
751
+ this.editor.editLayer.removeLayer(this);
752
+ },
753
+
754
+ index: function () {
755
+ return this.latlngs.indexOf(this.right.latlng);
756
+ }
757
+
758
+ });
759
+
760
+ L.Editable.mergeOptions({
761
+
762
+ // 🍂namespace Editable
763
+ // 🍂option middleMarkerClass: class = VertexMarker
764
+ // Class to be used as middle vertex, pulled by the user to create a new point in the middle of a path.
765
+ middleMarkerClass: L.Editable.MiddleMarker
766
+
767
+ });
768
+
769
+ // 🍂namespace Editable; 🍂class BaseEditor; 🍂aka L.Editable.BaseEditor
770
+ // When editing a feature (Marker, Polyline…), an editor is attached to it. This
771
+ // editor basically knows how to handle the edition.
772
+ L.Editable.BaseEditor = L.Handler.extend({
773
+
774
+ initialize: function (map, feature, options) {
775
+ L.setOptions(this, options);
776
+ this.map = map;
777
+ this.feature = feature;
778
+ this.feature.editor = this;
779
+ this.editLayer = new L.LayerGroup();
780
+ this.tools = this.options.editTools || map.editTools;
781
+ },
782
+
783
+ // 🍂method enable(): this
784
+ // Set up the drawing tools for the feature to be editable.
785
+ addHooks: function () {
786
+ if (this.isConnected()) this.onFeatureAdd();
787
+ else this.feature.once('add', this.onFeatureAdd, this);
788
+ this.onEnable();
789
+ this.feature.on(this._getEvents(), this);
790
+ },
791
+
792
+ // 🍂method disable(): this
793
+ // Remove the drawing tools for the feature.
794
+ removeHooks: function () {
795
+ this.feature.off(this._getEvents(), this);
796
+ if (this.feature.dragging) this.feature.dragging.disable();
797
+ this.editLayer.clearLayers();
798
+ this.tools.editLayer.removeLayer(this.editLayer);
799
+ this.onDisable();
800
+ if (this._drawing) this.cancelDrawing();
801
+ },
802
+
803
+ // 🍂method drawing(): boolean
804
+ // Return true if any drawing action is ongoing with this editor.
805
+ drawing: function () {
806
+ return !!this._drawing;
807
+ },
808
+
809
+ reset: function () {},
810
+
811
+ onFeatureAdd: function () {
812
+ this.tools.editLayer.addLayer(this.editLayer);
813
+ if (this.feature.dragging) this.feature.dragging.enable();
814
+ },
815
+
816
+ hasMiddleMarkers: function () {
817
+ return !this.options.skipMiddleMarkers && !this.tools.options.skipMiddleMarkers;
818
+ },
819
+
820
+ fireAndForward: function (type, e) {
821
+ e = e || {};
822
+ e.layer = this.feature;
823
+ this.feature.fire(type, e);
824
+ this.tools.fireAndForward(type, e);
825
+ },
826
+
827
+ onEnable: function () {
828
+ // 🍂namespace Editable
829
+ // 🍂event editable:enable: Event
830
+ // Fired when an existing feature is ready to be edited.
831
+ this.fireAndForward('editable:enable');
832
+ },
833
+
834
+ onDisable: function () {
835
+ // 🍂namespace Editable
836
+ // 🍂event editable:disable: Event
837
+ // Fired when an existing feature is not ready anymore to be edited.
838
+ this.fireAndForward('editable:disable');
839
+ },
840
+
841
+ onEditing: function () {
842
+ // 🍂namespace Editable
843
+ // 🍂event editable:editing: Event
844
+ // Fired as soon as any change is made to the feature geometry.
845
+ this.fireAndForward('editable:editing');
846
+ },
847
+
848
+ onStartDrawing: function () {
849
+ // 🍂namespace Editable
850
+ // 🍂section Drawing events
851
+ // 🍂event editable:drawing:start: Event
852
+ // Fired when a feature is to be drawn.
853
+ this.fireAndForward('editable:drawing:start');
854
+ },
855
+
856
+ onEndDrawing: function () {
857
+ // 🍂namespace Editable
858
+ // 🍂section Drawing events
859
+ // 🍂event editable:drawing:end: Event
860
+ // Fired when a feature is not drawn anymore.
861
+ this.fireAndForward('editable:drawing:end');
862
+ },
863
+
864
+ onCancelDrawing: function () {
865
+ // 🍂namespace Editable
866
+ // 🍂section Drawing events
867
+ // 🍂event editable:drawing:cancel: Event
868
+ // Fired when user cancel drawing while a feature is being drawn.
869
+ this.fireAndForward('editable:drawing:cancel');
870
+ },
871
+
872
+ onCommitDrawing: function (e) {
873
+ // 🍂namespace Editable
874
+ // 🍂section Drawing events
875
+ // 🍂event editable:drawing:commit: Event
876
+ // Fired when user finish drawing a feature.
877
+ this.fireAndForward('editable:drawing:commit', e);
878
+ },
879
+
880
+ onDrawingMouseDown: function (e) {
881
+ // 🍂namespace Editable
882
+ // 🍂section Drawing events
883
+ // 🍂event editable:drawing:mousedown: Event
884
+ // Fired when user `mousedown` while drawing.
885
+ this.fireAndForward('editable:drawing:mousedown', e);
886
+ },
887
+
888
+ onDrawingMouseUp: function (e) {
889
+ // 🍂namespace Editable
890
+ // 🍂section Drawing events
891
+ // 🍂event editable:drawing:mouseup: Event
892
+ // Fired when user `mouseup` while drawing.
893
+ this.fireAndForward('editable:drawing:mouseup', e);
894
+ },
895
+
896
+ startDrawing: function () {
897
+ if (!this._drawing) this._drawing = L.Editable.FORWARD;
898
+ this.tools.registerForDrawing(this);
899
+ this.onStartDrawing();
900
+ },
901
+
902
+ commitDrawing: function (e) {
903
+ this.onCommitDrawing(e);
904
+ this.endDrawing();
905
+ },
906
+
907
+ cancelDrawing: function () {
908
+ // If called during a vertex drag, the vertex will be removed before
909
+ // the mouseup fires on it. This is a workaround. Maybe better fix is
910
+ // To have L.Draggable reset it's status on disable (Leaflet side).
911
+ L.Draggable._dragging = false;
912
+ this.onCancelDrawing();
913
+ this.endDrawing();
914
+ },
915
+
916
+ endDrawing: function () {
917
+ this._drawing = false;
918
+ this.tools.unregisterForDrawing(this);
919
+ this.onEndDrawing();
920
+ },
921
+
922
+ onDrawingClick: function (e) {
923
+ if (!this.drawing()) return;
924
+ L.Editable.makeCancellable(e);
925
+ // 🍂namespace Editable
926
+ // 🍂section Drawing events
927
+ // 🍂event editable:drawing:click: CancelableEvent
928
+ // Fired when user `click` while drawing, before any internal action is being processed.
929
+ this.fireAndForward('editable:drawing:click', e);
930
+ if (e._cancelled) return;
931
+ if (!this.isConnected()) this.connect(e);
932
+ this.processDrawingClick(e);
933
+ },
934
+
935
+ isConnected: function () {
936
+ return this.map.hasLayer(this.feature);
937
+ },
938
+
939
+ connect: function () {
940
+ this.tools.connectCreatedToMap(this.feature);
941
+ this.tools.editLayer.addLayer(this.editLayer);
942
+ },
943
+
944
+ onMove: function (e) {
945
+ // 🍂namespace Editable
946
+ // 🍂section Drawing events
947
+ // 🍂event editable:drawing:move: Event
948
+ // Fired when `move` mouse while drawing, while dragging a marker, and while dragging a vertex.
949
+ this.fireAndForward('editable:drawing:move', e);
950
+ },
951
+
952
+ onDrawingMouseMove: function (e) {
953
+ this.onMove(e);
954
+ },
955
+
956
+ _getEvents: function () {
957
+ return {
958
+ dragstart: this.onDragStart,
959
+ drag: this.onDrag,
960
+ dragend: this.onDragEnd,
961
+ remove: this.disable
962
+ };
963
+ },
964
+
965
+ onDragStart: function (e) {
966
+ this.onEditing();
967
+ // 🍂namespace Editable
968
+ // 🍂event editable:dragstart: Event
969
+ // Fired before a path feature is dragged.
970
+ this.fireAndForward('editable:dragstart', e);
971
+ },
972
+
973
+ onDrag: function (e) {
974
+ this.onMove(e);
975
+ // 🍂namespace Editable
976
+ // 🍂event editable:drag: Event
977
+ // Fired when a path feature is being dragged.
978
+ this.fireAndForward('editable:drag', e);
979
+ },
980
+
981
+ onDragEnd: function (e) {
982
+ // 🍂namespace Editable
983
+ // 🍂event editable:dragend: Event
984
+ // Fired after a path feature has been dragged.
985
+ this.fireAndForward('editable:dragend', e);
986
+ }
987
+
988
+ });
989
+
990
+ // 🍂namespace Editable; 🍂class MarkerEditor; 🍂aka L.Editable.MarkerEditor
991
+ // 🍂inherits BaseEditor
992
+ // Editor for Marker.
993
+ L.Editable.MarkerEditor = L.Editable.BaseEditor.extend({
994
+
995
+ onDrawingMouseMove: function (e) {
996
+ L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e);
997
+ if (this._drawing) this.feature.setLatLng(e.latlng);
998
+ },
999
+
1000
+ processDrawingClick: function (e) {
1001
+ // 🍂namespace Editable
1002
+ // 🍂section Drawing events
1003
+ // 🍂event editable:drawing:clicked: Event
1004
+ // Fired when user `click` while drawing, after all internal actions.
1005
+ this.fireAndForward('editable:drawing:clicked', e);
1006
+ this.commitDrawing(e);
1007
+ },
1008
+
1009
+ connect: function (e) {
1010
+ // On touch, the latlng has not been updated because there is
1011
+ // no mousemove.
1012
+ if (e) this.feature._latlng = e.latlng;
1013
+ L.Editable.BaseEditor.prototype.connect.call(this, e);
1014
+ }
1015
+
1016
+ });
1017
+
1018
+ // 🍂namespace Editable; 🍂class PathEditor; 🍂aka L.Editable.PathEditor
1019
+ // 🍂inherits BaseEditor
1020
+ // Base class for all path editors.
1021
+ L.Editable.PathEditor = L.Editable.BaseEditor.extend({
1022
+
1023
+ CLOSED: false,
1024
+ MIN_VERTEX: 2,
1025
+
1026
+ addHooks: function () {
1027
+ L.Editable.BaseEditor.prototype.addHooks.call(this);
1028
+ if (this.feature) this.initVertexMarkers();
1029
+ return this;
1030
+ },
1031
+
1032
+ initVertexMarkers: function (latlngs) {
1033
+ if (!this.enabled()) return;
1034
+ latlngs = latlngs || this.getLatLngs();
1035
+ if (isFlat(latlngs)) this.addVertexMarkers(latlngs);
1036
+ else for (var i = 0; i < latlngs.length; i++) this.initVertexMarkers(latlngs[i]);
1037
+ },
1038
+
1039
+ getLatLngs: function () {
1040
+ return this.feature.getLatLngs();
1041
+ },
1042
+
1043
+ // 🍂method reset()
1044
+ // Rebuild edit elements (Vertex, MiddleMarker, etc.).
1045
+ reset: function () {
1046
+ this.editLayer.clearLayers();
1047
+ this.initVertexMarkers();
1048
+ },
1049
+
1050
+ addVertexMarker: function (latlng, latlngs) {
1051
+ return new this.tools.options.vertexMarkerClass(latlng, latlngs, this);
1052
+ },
1053
+
1054
+ onNewVertex: function (vertex) {
1055
+ // 🍂namespace Editable
1056
+ // 🍂section Vertex events
1057
+ // 🍂event editable:vertex:new: VertexEvent
1058
+ // Fired when a new vertex is created.
1059
+ this.fireAndForward('editable:vertex:new', {latlng: vertex.latlng, vertex: vertex});
1060
+ },
1061
+
1062
+ addVertexMarkers: function (latlngs) {
1063
+ for (var i = 0; i < latlngs.length; i++) {
1064
+ this.addVertexMarker(latlngs[i], latlngs);
1065
+ }
1066
+ },
1067
+
1068
+ refreshVertexMarkers: function (latlngs) {
1069
+ latlngs = latlngs || this.getDefaultLatLngs();
1070
+ for (var i = 0; i < latlngs.length; i++) {
1071
+ latlngs[i].__vertex.update();
1072
+ }
1073
+ },
1074
+
1075
+ addMiddleMarker: function (left, right, latlngs) {
1076
+ return new this.tools.options.middleMarkerClass(left, right, latlngs, this);
1077
+ },
1078
+
1079
+ onVertexMarkerClick: function (e) {
1080
+ L.Editable.makeCancellable(e);
1081
+ // 🍂namespace Editable
1082
+ // 🍂section Vertex events
1083
+ // 🍂event editable:vertex:click: CancelableVertexEvent
1084
+ // Fired when a `click` is issued on a vertex, before any internal action is being processed.
1085
+ this.fireAndForward('editable:vertex:click', e);
1086
+ if (e._cancelled) return;
1087
+ if (this.tools.drawing() && this.tools._drawingEditor !== this) return;
1088
+ var index = e.vertex.getIndex(), commit;
1089
+ if (e.originalEvent.ctrlKey) {
1090
+ this.onVertexMarkerCtrlClick(e);
1091
+ } else if (e.originalEvent.altKey) {
1092
+ this.onVertexMarkerAltClick(e);
1093
+ } else if (e.originalEvent.shiftKey) {
1094
+ this.onVertexMarkerShiftClick(e);
1095
+ } else if (e.originalEvent.metaKey) {
1096
+ this.onVertexMarkerMetaKeyClick(e);
1097
+ } else if (index === e.vertex.getLastIndex() && this._drawing === L.Editable.FORWARD) {
1098
+ if (index >= this.MIN_VERTEX - 1) commit = true;
1099
+ } else if (index === 0 && this._drawing === L.Editable.BACKWARD && this._drawnLatLngs.length >= this.MIN_VERTEX) {
1100
+ commit = true;
1101
+ } else if (index === 0 && this._drawing === L.Editable.FORWARD && this._drawnLatLngs.length >= this.MIN_VERTEX && this.CLOSED) {
1102
+ commit = true; // Allow to close on first point also for polygons
1103
+ } else {
1104
+ this.onVertexRawMarkerClick(e);
1105
+ }
1106
+ // 🍂namespace Editable
1107
+ // 🍂section Vertex events
1108
+ // 🍂event editable:vertex:clicked: VertexEvent
1109
+ // Fired when a `click` is issued on a vertex, after all internal actions.
1110
+ this.fireAndForward('editable:vertex:clicked', e);
1111
+ if (commit) this.commitDrawing(e);
1112
+ },
1113
+
1114
+ onVertexRawMarkerClick: function (e) {
1115
+ // 🍂namespace Editable
1116
+ // 🍂section Vertex events
1117
+ // 🍂event editable:vertex:rawclick: CancelableVertexEvent
1118
+ // Fired when a `click` is issued on a vertex without any special key and without being in drawing mode.
1119
+ this.fireAndForward('editable:vertex:rawclick', e);
1120
+ if (e._cancelled) return;
1121
+ if (!this.vertexCanBeDeleted(e.vertex)) return;
1122
+ e.vertex.delete();
1123
+ },
1124
+
1125
+ vertexCanBeDeleted: function (vertex) {
1126
+ return vertex.latlngs.length > this.MIN_VERTEX;
1127
+ },
1128
+
1129
+ onVertexDeleted: function (e) {
1130
+ // 🍂namespace Editable
1131
+ // 🍂section Vertex events
1132
+ // 🍂event editable:vertex:deleted: VertexEvent
1133
+ // Fired after a vertex has been deleted by user.
1134
+ this.fireAndForward('editable:vertex:deleted', e);
1135
+ },
1136
+
1137
+ onVertexMarkerCtrlClick: function (e) {
1138
+ // 🍂namespace Editable
1139
+ // 🍂section Vertex events
1140
+ // 🍂event editable:vertex:ctrlclick: VertexEvent
1141
+ // Fired when a `click` with `ctrlKey` is issued on a vertex.
1142
+ this.fireAndForward('editable:vertex:ctrlclick', e);
1143
+ },
1144
+
1145
+ onVertexMarkerShiftClick: function (e) {
1146
+ // 🍂namespace Editable
1147
+ // 🍂section Vertex events
1148
+ // 🍂event editable:vertex:shiftclick: VertexEvent
1149
+ // Fired when a `click` with `shiftKey` is issued on a vertex.
1150
+ this.fireAndForward('editable:vertex:shiftclick', e);
1151
+ },
1152
+
1153
+ onVertexMarkerMetaKeyClick: function (e) {
1154
+ // 🍂namespace Editable
1155
+ // 🍂section Vertex events
1156
+ // 🍂event editable:vertex:metakeyclick: VertexEvent
1157
+ // Fired when a `click` with `metaKey` is issued on a vertex.
1158
+ this.fireAndForward('editable:vertex:metakeyclick', e);
1159
+ },
1160
+
1161
+ onVertexMarkerAltClick: function (e) {
1162
+ // 🍂namespace Editable
1163
+ // 🍂section Vertex events
1164
+ // 🍂event editable:vertex:altclick: VertexEvent
1165
+ // Fired when a `click` with `altKey` is issued on a vertex.
1166
+ this.fireAndForward('editable:vertex:altclick', e);
1167
+ },
1168
+
1169
+ onVertexMarkerContextMenu: function (e) {
1170
+ // 🍂namespace Editable
1171
+ // 🍂section Vertex events
1172
+ // 🍂event editable:vertex:contextmenu: VertexEvent
1173
+ // Fired when a `contextmenu` is issued on a vertex.
1174
+ this.fireAndForward('editable:vertex:contextmenu', e);
1175
+ },
1176
+
1177
+ onVertexMarkerMouseDown: function (e) {
1178
+ // 🍂namespace Editable
1179
+ // 🍂section Vertex events
1180
+ // 🍂event editable:vertex:mousedown: VertexEvent
1181
+ // Fired when user `mousedown` a vertex.
1182
+ this.fireAndForward('editable:vertex:mousedown', e);
1183
+ },
1184
+
1185
+ onVertexMarkerMouseOver: function (e) {
1186
+ // 🍂namespace Editable
1187
+ // 🍂section Vertex events
1188
+ // 🍂event editable:vertex:mouseover: VertexEvent
1189
+ // Fired when a user's mouse enters the vertex
1190
+ this.fireAndForward('editable:vertex:mouseover', e);
1191
+ },
1192
+
1193
+ onVertexMarkerMouseOut: function (e) {
1194
+ // 🍂namespace Editable
1195
+ // 🍂section Vertex events
1196
+ // 🍂event editable:vertex:mouseout: VertexEvent
1197
+ // Fired when a user's mouse leaves the vertex
1198
+ this.fireAndForward('editable:vertex:mouseout', e);
1199
+ },
1200
+
1201
+ onMiddleMarkerMouseDown: function (e) {
1202
+ // 🍂namespace Editable
1203
+ // 🍂section MiddleMarker events
1204
+ // 🍂event editable:middlemarker:mousedown: VertexEvent
1205
+ // Fired when user `mousedown` a middle marker.
1206
+ this.fireAndForward('editable:middlemarker:mousedown', e);
1207
+ },
1208
+
1209
+ onVertexMarkerDrag: function (e) {
1210
+ this.onMove(e);
1211
+ if (this.feature._bounds) this.extendBounds(e);
1212
+ // 🍂namespace Editable
1213
+ // 🍂section Vertex events
1214
+ // 🍂event editable:vertex:drag: VertexEvent
1215
+ // Fired when a vertex is dragged by user.
1216
+ this.fireAndForward('editable:vertex:drag', e);
1217
+ },
1218
+
1219
+ onVertexMarkerDragStart: function (e) {
1220
+ // 🍂namespace Editable
1221
+ // 🍂section Vertex events
1222
+ // 🍂event editable:vertex:dragstart: VertexEvent
1223
+ // Fired before a vertex is dragged by user.
1224
+ this.fireAndForward('editable:vertex:dragstart', e);
1225
+ },
1226
+
1227
+ onVertexMarkerDragEnd: function (e) {
1228
+ // 🍂namespace Editable
1229
+ // 🍂section Vertex events
1230
+ // 🍂event editable:vertex:dragend: VertexEvent
1231
+ // Fired after a vertex is dragged by user.
1232
+ this.fireAndForward('editable:vertex:dragend', e);
1233
+ },
1234
+
1235
+ setDrawnLatLngs: function (latlngs) {
1236
+ this._drawnLatLngs = latlngs || this.getDefaultLatLngs();
1237
+ },
1238
+
1239
+ startDrawing: function () {
1240
+ if (!this._drawnLatLngs) this.setDrawnLatLngs();
1241
+ L.Editable.BaseEditor.prototype.startDrawing.call(this);
1242
+ },
1243
+
1244
+ startDrawingForward: function () {
1245
+ this.startDrawing();
1246
+ },
1247
+
1248
+ endDrawing: function () {
1249
+ this.tools.detachForwardLineGuide();
1250
+ this.tools.detachBackwardLineGuide();
1251
+ if (this._drawnLatLngs && this._drawnLatLngs.length < this.MIN_VERTEX) this.deleteShape(this._drawnLatLngs);
1252
+ L.Editable.BaseEditor.prototype.endDrawing.call(this);
1253
+ delete this._drawnLatLngs;
1254
+ },
1255
+
1256
+ addLatLng: function (latlng) {
1257
+ if (this._drawing === L.Editable.FORWARD) this._drawnLatLngs.push(latlng);
1258
+ else this._drawnLatLngs.unshift(latlng);
1259
+ this.feature._bounds.extend(latlng);
1260
+ var vertex = this.addVertexMarker(latlng, this._drawnLatLngs);
1261
+ this.onNewVertex(vertex);
1262
+ this.refresh();
1263
+ },
1264
+
1265
+ newPointForward: function (latlng) {
1266
+ this.addLatLng(latlng);
1267
+ this.tools.attachForwardLineGuide();
1268
+ this.tools.anchorForwardLineGuide(latlng);
1269
+ },
1270
+
1271
+ newPointBackward: function (latlng) {
1272
+ this.addLatLng(latlng);
1273
+ this.tools.anchorBackwardLineGuide(latlng);
1274
+ },
1275
+
1276
+ // 🍂namespace PathEditor
1277
+ // 🍂method push()
1278
+ // Programmatically add a point while drawing.
1279
+ push: function (latlng) {
1280
+ if (!latlng) return console.error('L.Editable.PathEditor.push expect a valid latlng as parameter');
1281
+ if (this._drawing === L.Editable.FORWARD) this.newPointForward(latlng);
1282
+ else this.newPointBackward(latlng);
1283
+ },
1284
+
1285
+ removeLatLng: function (latlng) {
1286
+ latlng.__vertex.delete();
1287
+ this.refresh();
1288
+ },
1289
+
1290
+ // 🍂method pop(): L.LatLng or null
1291
+ // Programmatically remove last point (if any) while drawing.
1292
+ pop: function () {
1293
+ if (this._drawnLatLngs.length <= 1) return;
1294
+ var latlng;
1295
+ if (this._drawing === L.Editable.FORWARD) latlng = this._drawnLatLngs[this._drawnLatLngs.length - 1];
1296
+ else latlng = this._drawnLatLngs[0];
1297
+ this.removeLatLng(latlng);
1298
+ if (this._drawing === L.Editable.FORWARD) this.tools.anchorForwardLineGuide(this._drawnLatLngs[this._drawnLatLngs.length - 1]);
1299
+ else this.tools.anchorForwardLineGuide(this._drawnLatLngs[0]);
1300
+ return latlng;
1301
+ },
1302
+
1303
+ processDrawingClick: function (e) {
1304
+ if (e.vertex && e.vertex.editor === this) return;
1305
+ if (this._drawing === L.Editable.FORWARD) this.newPointForward(e.latlng);
1306
+ else this.newPointBackward(e.latlng);
1307
+ this.fireAndForward('editable:drawing:clicked', e);
1308
+ },
1309
+
1310
+ onDrawingMouseMove: function (e) {
1311
+ L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e);
1312
+ if (this._drawing) {
1313
+ this.tools.moveForwardLineGuide(e.latlng);
1314
+ this.tools.moveBackwardLineGuide(e.latlng);
1315
+ }
1316
+ },
1317
+
1318
+ refresh: function () {
1319
+ this.feature.redraw();
1320
+ this.onEditing();
1321
+ },
1322
+
1323
+ // 🍂namespace PathEditor
1324
+ // 🍂method newShape(latlng?: L.LatLng)
1325
+ // Add a new shape (Polyline, Polygon) in a multi, and setup up drawing tools to draw it;
1326
+ // if optional `latlng` is given, start a path at this point.
1327
+ newShape: function (latlng) {
1328
+ var shape = this.addNewEmptyShape();
1329
+ if (!shape) return;
1330
+ this.setDrawnLatLngs(shape[0] || shape); // Polygon or polyline
1331
+ this.startDrawingForward();
1332
+ // 🍂namespace Editable
1333
+ // 🍂section Shape events
1334
+ // 🍂event editable:shape:new: ShapeEvent
1335
+ // Fired when a new shape is created in a multi (Polygon or Polyline).
1336
+ this.fireAndForward('editable:shape:new', {shape: shape});
1337
+ if (latlng) this.newPointForward(latlng);
1338
+ },
1339
+
1340
+ deleteShape: function (shape, latlngs) {
1341
+ var e = {shape: shape};
1342
+ L.Editable.makeCancellable(e);
1343
+ // 🍂namespace Editable
1344
+ // 🍂section Shape events
1345
+ // 🍂event editable:shape:delete: CancelableShapeEvent
1346
+ // Fired before a new shape is deleted in a multi (Polygon or Polyline).
1347
+ this.fireAndForward('editable:shape:delete', e);
1348
+ if (e._cancelled) return;
1349
+ shape = this._deleteShape(shape, latlngs);
1350
+ if (this.ensureNotFlat) this.ensureNotFlat(); // Polygon.
1351
+ this.feature.setLatLngs(this.getLatLngs()); // Force bounds reset.
1352
+ this.refresh();
1353
+ this.reset();
1354
+ // 🍂namespace Editable
1355
+ // 🍂section Shape events
1356
+ // 🍂event editable:shape:deleted: ShapeEvent
1357
+ // Fired after a new shape is deleted in a multi (Polygon or Polyline).
1358
+ this.fireAndForward('editable:shape:deleted', {shape: shape});
1359
+ return shape;
1360
+ },
1361
+
1362
+ _deleteShape: function (shape, latlngs) {
1363
+ latlngs = latlngs || this.getLatLngs();
1364
+ if (!latlngs.length) return;
1365
+ var self = this,
1366
+ inplaceDelete = function (latlngs, shape) {
1367
+ // Called when deleting a flat latlngs
1368
+ shape = latlngs.splice(0, Number.MAX_VALUE);
1369
+ return shape;
1370
+ },
1371
+ spliceDelete = function (latlngs, shape) {
1372
+ // Called when removing a latlngs inside an array
1373
+ latlngs.splice(latlngs.indexOf(shape), 1);
1374
+ if (!latlngs.length) self._deleteShape(latlngs);
1375
+ return shape;
1376
+ };
1377
+ if (latlngs === shape) return inplaceDelete(latlngs, shape);
1378
+ for (var i = 0; i < latlngs.length; i++) {
1379
+ if (latlngs[i] === shape) return spliceDelete(latlngs, shape);
1380
+ else if (latlngs[i].indexOf(shape) !== -1) return spliceDelete(latlngs[i], shape);
1381
+ }
1382
+ },
1383
+
1384
+ // 🍂namespace PathEditor
1385
+ // 🍂method deleteShapeAt(latlng: L.LatLng): Array
1386
+ // Remove a path shape at the given `latlng`.
1387
+ deleteShapeAt: function (latlng) {
1388
+ var shape = this.feature.shapeAt(latlng);
1389
+ if (shape) return this.deleteShape(shape);
1390
+ },
1391
+
1392
+ // 🍂method appendShape(shape: Array)
1393
+ // Append a new shape to the Polygon or Polyline.
1394
+ appendShape: function (shape) {
1395
+ this.insertShape(shape);
1396
+ },
1397
+
1398
+ // 🍂method prependShape(shape: Array)
1399
+ // Prepend a new shape to the Polygon or Polyline.
1400
+ prependShape: function (shape) {
1401
+ this.insertShape(shape, 0);
1402
+ },
1403
+
1404
+ // 🍂method insertShape(shape: Array, index: int)
1405
+ // Insert a new shape to the Polygon or Polyline at given index (default is to append).
1406
+ insertShape: function (shape, index) {
1407
+ this.ensureMulti();
1408
+ shape = this.formatShape(shape);
1409
+ if (typeof index === 'undefined') index = this.feature._latlngs.length;
1410
+ this.feature._latlngs.splice(index, 0, shape);
1411
+ this.feature.redraw();
1412
+ if (this._enabled) this.reset();
1413
+ },
1414
+
1415
+ extendBounds: function (e) {
1416
+ this.feature._bounds.extend(e.vertex.latlng);
1417
+ },
1418
+
1419
+ onDragStart: function (e) {
1420
+ this.editLayer.clearLayers();
1421
+ L.Editable.BaseEditor.prototype.onDragStart.call(this, e);
1422
+ },
1423
+
1424
+ onDragEnd: function (e) {
1425
+ this.initVertexMarkers();
1426
+ L.Editable.BaseEditor.prototype.onDragEnd.call(this, e);
1427
+ }
1428
+
1429
+ });
1430
+
1431
+ // 🍂namespace Editable; 🍂class PolylineEditor; 🍂aka L.Editable.PolylineEditor
1432
+ // 🍂inherits PathEditor
1433
+ L.Editable.PolylineEditor = L.Editable.PathEditor.extend({
1434
+
1435
+ startDrawingBackward: function () {
1436
+ this._drawing = L.Editable.BACKWARD;
1437
+ this.startDrawing();
1438
+ },
1439
+
1440
+ // 🍂method continueBackward(latlngs?: Array)
1441
+ // Set up drawing tools to continue the line backward.
1442
+ continueBackward: function (latlngs) {
1443
+ if (this.drawing()) return;
1444
+ latlngs = latlngs || this.getDefaultLatLngs();
1445
+ this.setDrawnLatLngs(latlngs);
1446
+ if (latlngs.length > 0) {
1447
+ this.tools.attachBackwardLineGuide();
1448
+ this.tools.anchorBackwardLineGuide(latlngs[0]);
1449
+ }
1450
+ this.startDrawingBackward();
1451
+ },
1452
+
1453
+ // 🍂method continueForward(latlngs?: Array)
1454
+ // Set up drawing tools to continue the line forward.
1455
+ continueForward: function (latlngs) {
1456
+ if (this.drawing()) return;
1457
+ latlngs = latlngs || this.getDefaultLatLngs();
1458
+ this.setDrawnLatLngs(latlngs);
1459
+ if (latlngs.length > 0) {
1460
+ this.tools.attachForwardLineGuide();
1461
+ this.tools.anchorForwardLineGuide(latlngs[latlngs.length - 1]);
1462
+ }
1463
+ this.startDrawingForward();
1464
+ },
1465
+
1466
+ getDefaultLatLngs: function (latlngs) {
1467
+ latlngs = latlngs || this.feature._latlngs;
1468
+ if (!latlngs.length || latlngs[0] instanceof L.LatLng) return latlngs;
1469
+ else return this.getDefaultLatLngs(latlngs[0]);
1470
+ },
1471
+
1472
+ ensureMulti: function () {
1473
+ if (this.feature._latlngs.length && isFlat(this.feature._latlngs)) {
1474
+ this.feature._latlngs = [this.feature._latlngs];
1475
+ }
1476
+ },
1477
+
1478
+ addNewEmptyShape: function () {
1479
+ if (this.feature._latlngs.length) {
1480
+ var shape = [];
1481
+ this.appendShape(shape);
1482
+ return shape;
1483
+ } else {
1484
+ return this.feature._latlngs;
1485
+ }
1486
+ },
1487
+
1488
+ formatShape: function (shape) {
1489
+ if (isFlat(shape)) return shape;
1490
+ else if (shape[0]) return this.formatShape(shape[0]);
1491
+ },
1492
+
1493
+ // 🍂method splitShape(latlngs?: Array, index: int)
1494
+ // Split the given `latlngs` shape at index `index` and integrate new shape in instance `latlngs`.
1495
+ splitShape: function (shape, index) {
1496
+ if (!index || index >= shape.length - 1) return;
1497
+ this.ensureMulti();
1498
+ var shapeIndex = this.feature._latlngs.indexOf(shape);
1499
+ if (shapeIndex === -1) return;
1500
+ var first = shape.slice(0, index + 1),
1501
+ second = shape.slice(index);
1502
+ // We deal with reference, we don't want twice the same latlng around.
1503
+ second[0] = L.latLng(second[0].lat, second[0].lng, second[0].alt);
1504
+ this.feature._latlngs.splice(shapeIndex, 1, first, second);
1505
+ this.refresh();
1506
+ this.reset();
1507
+ }
1508
+
1509
+ });
1510
+
1511
+ // 🍂namespace Editable; 🍂class PolygonEditor; 🍂aka L.Editable.PolygonEditor
1512
+ // 🍂inherits PathEditor
1513
+ L.Editable.PolygonEditor = L.Editable.PathEditor.extend({
1514
+
1515
+ CLOSED: true,
1516
+ MIN_VERTEX: 3,
1517
+
1518
+ newPointForward: function (latlng) {
1519
+ L.Editable.PathEditor.prototype.newPointForward.call(this, latlng);
1520
+ if (!this.tools.backwardLineGuide._latlngs.length) this.tools.anchorBackwardLineGuide(latlng);
1521
+ if (this._drawnLatLngs.length === 2) this.tools.attachBackwardLineGuide();
1522
+ },
1523
+
1524
+ addNewEmptyHole: function (latlng) {
1525
+ this.ensureNotFlat();
1526
+ var latlngs = this.feature.shapeAt(latlng);
1527
+ if (!latlngs) return;
1528
+ var holes = [];
1529
+ latlngs.push(holes);
1530
+ return holes;
1531
+ },
1532
+
1533
+ // 🍂method newHole(latlng?: L.LatLng, index: int)
1534
+ // Set up drawing tools for creating a new hole on the Polygon. If the `latlng` param is given, a first point is created.
1535
+ newHole: function (latlng) {
1536
+ var holes = this.addNewEmptyHole(latlng);
1537
+ if (!holes) return;
1538
+ this.setDrawnLatLngs(holes);
1539
+ this.startDrawingForward();
1540
+ if (latlng) this.newPointForward(latlng);
1541
+ },
1542
+
1543
+ addNewEmptyShape: function () {
1544
+ if (this.feature._latlngs.length && this.feature._latlngs[0].length) {
1545
+ var shape = [];
1546
+ this.appendShape(shape);
1547
+ return shape;
1548
+ } else {
1549
+ return this.feature._latlngs;
1550
+ }
1551
+ },
1552
+
1553
+ ensureMulti: function () {
1554
+ if (this.feature._latlngs.length && isFlat(this.feature._latlngs[0])) {
1555
+ this.feature._latlngs = [this.feature._latlngs];
1556
+ }
1557
+ },
1558
+
1559
+ ensureNotFlat: function () {
1560
+ if (!this.feature._latlngs.length || isFlat(this.feature._latlngs)) this.feature._latlngs = [this.feature._latlngs];
1561
+ },
1562
+
1563
+ vertexCanBeDeleted: function (vertex) {
1564
+ var parent = this.feature.parentShape(vertex.latlngs),
1565
+ idx = L.Util.indexOf(parent, vertex.latlngs);
1566
+ if (idx > 0) return true; // Holes can be totally deleted without removing the layer itself.
1567
+ return L.Editable.PathEditor.prototype.vertexCanBeDeleted.call(this, vertex);
1568
+ },
1569
+
1570
+ getDefaultLatLngs: function () {
1571
+ if (!this.feature._latlngs.length) this.feature._latlngs.push([]);
1572
+ return this.feature._latlngs[0];
1573
+ },
1574
+
1575
+ formatShape: function (shape) {
1576
+ // [[1, 2], [3, 4]] => must be nested
1577
+ // [] => must be nested
1578
+ // [[]] => is already nested
1579
+ if (isFlat(shape) && (!shape[0] || shape[0].length !== 0)) return [shape];
1580
+ else return shape;
1129
1581
  }
1130
- }
1131
- },
1132
-
1133
- getLatLngs: function () {
1134
- return this.feature.getLatLngs()
1135
- },
1136
-
1137
- // 🍂method reset()
1138
- // Rebuild edit elements (Vertex, MiddleMarker, etc.).
1139
- reset: function () {
1140
- this.editLayer.clearLayers()
1141
- this.initVertexMarkers()
1142
- },
1143
-
1144
- addVertexMarker: function (latlng, latlngs) {
1145
- if (latlng.__vertex) {
1146
- latlng.__vertex.connect()
1147
- return latlng.__vertex
1148
- }
1149
- return new this.tools.options.vertexMarkerClass(latlng, latlngs, this)
1150
- },
1151
-
1152
- onNewVertex: function (vertex) {
1153
- // 🍂namespace Editable
1154
- // 🍂section Vertex events
1155
- // 🍂event editable:vertex:new: VertexEvent
1156
- // Fired when a new vertex is created.
1157
- this.fireAndForward('editable:vertex:new', {
1158
- latlng: vertex.latlng,
1159
- vertex: vertex,
1160
- })
1161
- },
1162
-
1163
- addVertexMarkers: function (latlngs) {
1164
- const bounds = this.map.getBounds()
1165
- for (const latlng of latlngs) {
1166
- if (!bounds.contains(latlng)) continue
1167
- this.addVertexMarker(latlng, latlngs)
1168
- }
1169
- },
1170
-
1171
- refreshVertexMarkers: function (latlngs) {
1172
- latlngs = latlngs || this.getDefaultLatLngs()
1173
- for (const latlng of latlngs) {
1174
- latlng.__vertex.update()
1175
- }
1176
- },
1177
-
1178
- addMiddleMarker: function (left, right, latlngs) {
1179
- return new this.tools.options.middleMarkerClass(left, right, latlngs, this)
1180
- },
1181
-
1182
- onVertexMarkerClick: function (e) {
1183
- L.Editable.makeCancellable(e)
1184
- // 🍂namespace Editable
1185
- // 🍂section Vertex events
1186
- // 🍂event editable:vertex:click: CancelableVertexEvent
1187
- // Fired when a `click` is issued on a vertex, before any internal action is being processed.
1188
- this.fireAndForward('editable:vertex:click', e)
1189
- if (e._cancelled) return
1190
- if (this.tools.drawing() && this.tools._drawingEditor !== this) return
1191
- const index = e.vertex.getIndex()
1192
- let commit
1193
- if (e.originalEvent.ctrlKey) {
1194
- this.onVertexMarkerCtrlClick(e)
1195
- } else if (e.originalEvent.altKey) {
1196
- this.onVertexMarkerAltClick(e)
1197
- } else if (e.originalEvent.shiftKey) {
1198
- this.onVertexMarkerShiftClick(e)
1199
- } else if (e.originalEvent.metaKey) {
1200
- this.onVertexMarkerMetaKeyClick(e)
1201
- } else if (
1202
- index === e.vertex.getLastIndex() &&
1203
- this._drawing === L.Editable.FORWARD
1204
- ) {
1205
- if (index >= this.MIN_VERTEX - 1) commit = true
1206
- } else if (
1207
- index === 0 &&
1208
- this._drawing === L.Editable.BACKWARD &&
1209
- this._drawnLatLngs.length >= this.MIN_VERTEX
1210
- ) {
1211
- commit = true
1212
- } else if (
1213
- index === 0 &&
1214
- this._drawing === L.Editable.FORWARD &&
1215
- this._drawnLatLngs.length >= this.MIN_VERTEX &&
1216
- this.CLOSED
1217
- ) {
1218
- commit = true // Allow to close on first point also for polygons
1219
- } else {
1220
- this.onVertexRawMarkerClick(e)
1221
- }
1222
- // 🍂namespace Editable
1223
- // 🍂section Vertex events
1224
- // 🍂event editable:vertex:clicked: VertexEvent
1225
- // Fired when a `click` is issued on a vertex, after all internal actions.
1226
- this.fireAndForward('editable:vertex:clicked', e)
1227
- if (commit) this.commitDrawing(e)
1228
- },
1229
-
1230
- onVertexRawMarkerClick: function (e) {
1231
- // 🍂namespace Editable
1232
- // 🍂section Vertex events
1233
- // 🍂event editable:vertex:rawclick: CancelableVertexEvent
1234
- // Fired when a `click` is issued on a vertex without any special key and without being in drawing mode.
1235
- this.fireAndForward('editable:vertex:rawclick', e)
1236
- if (e._cancelled) return
1237
- if (!this.vertexCanBeDeleted(e.vertex)) return
1238
- e.vertex.delete()
1239
- },
1240
-
1241
- vertexCanBeDeleted: function (vertex) {
1242
- return vertex.latlngs.length > this.MIN_VERTEX
1243
- },
1244
-
1245
- onVertexDeleted: function (e) {
1246
- // 🍂namespace Editable
1247
- // 🍂section Vertex events
1248
- // 🍂event editable:vertex:deleted: VertexEvent
1249
- // Fired after a vertex has been deleted by user.
1250
- this.fireAndForward('editable:vertex:deleted', e)
1251
- },
1252
-
1253
- onVertexMarkerCtrlClick: function (e) {
1254
- // 🍂namespace Editable
1255
- // 🍂section Vertex events
1256
- // 🍂event editable:vertex:ctrlclick: VertexEvent
1257
- // Fired when a `click` with `ctrlKey` is issued on a vertex.
1258
- this.fireAndForward('editable:vertex:ctrlclick', e)
1259
- },
1260
-
1261
- onVertexMarkerShiftClick: function (e) {
1262
- // 🍂namespace Editable
1263
- // 🍂section Vertex events
1264
- // 🍂event editable:vertex:shiftclick: VertexEvent
1265
- // Fired when a `click` with `shiftKey` is issued on a vertex.
1266
- this.fireAndForward('editable:vertex:shiftclick', e)
1267
- },
1268
-
1269
- onVertexMarkerMetaKeyClick: function (e) {
1270
- // 🍂namespace Editable
1271
- // 🍂section Vertex events
1272
- // 🍂event editable:vertex:metakeyclick: VertexEvent
1273
- // Fired when a `click` with `metaKey` is issued on a vertex.
1274
- this.fireAndForward('editable:vertex:metakeyclick', e)
1275
- },
1276
-
1277
- onVertexMarkerAltClick: function (e) {
1278
- // 🍂namespace Editable
1279
- // 🍂section Vertex events
1280
- // 🍂event editable:vertex:altclick: VertexEvent
1281
- // Fired when a `click` with `altKey` is issued on a vertex.
1282
- this.fireAndForward('editable:vertex:altclick', e)
1283
- },
1284
-
1285
- onVertexMarkerContextMenu: function (e) {
1286
- // 🍂namespace Editable
1287
- // 🍂section Vertex events
1288
- // 🍂event editable:vertex:contextmenu: VertexEvent
1289
- // Fired when a `contextmenu` is issued on a vertex.
1290
- this.fireAndForward('editable:vertex:contextmenu', e)
1291
- },
1292
-
1293
- onVertexMarkerMouseDown: function (e) {
1294
- // 🍂namespace Editable
1295
- // 🍂section Vertex events
1296
- // 🍂event editable:vertex:mousedown: VertexEvent
1297
- // Fired when user `mousedown` a vertex.
1298
- this.fireAndForward('editable:vertex:mousedown', e)
1299
- },
1300
-
1301
- onVertexMarkerMouseOver: function (e) {
1302
- // 🍂namespace Editable
1303
- // 🍂section Vertex events
1304
- // 🍂event editable:vertex:mouseover: VertexEvent
1305
- // Fired when a user's mouse enters the vertex
1306
- this.fireAndForward('editable:vertex:mouseover', e)
1307
- },
1308
-
1309
- onVertexMarkerMouseOut: function (e) {
1310
- // 🍂namespace Editable
1311
- // 🍂section Vertex events
1312
- // 🍂event editable:vertex:mouseout: VertexEvent
1313
- // Fired when a user's mouse leaves the vertex
1314
- this.fireAndForward('editable:vertex:mouseout', e)
1315
- },
1316
-
1317
- onMiddleMarkerMouseDown: function (e) {
1318
- // 🍂namespace Editable
1319
- // 🍂section MiddleMarker events
1320
- // 🍂event editable:middlemarker:mousedown: VertexEvent
1321
- // Fired when user `mousedown` a middle marker.
1322
- this.fireAndForward('editable:middlemarker:mousedown', e)
1323
- },
1324
-
1325
- onVertexMarkerDrag: function (e) {
1326
- this.onMove(e)
1327
- if (this.feature._bounds) this.extendBounds(e)
1328
- // 🍂namespace Editable
1329
- // 🍂section Vertex events
1330
- // 🍂event editable:vertex:drag: VertexEvent
1331
- // Fired when a vertex is dragged by user.
1332
- this.fireAndForward('editable:vertex:drag', e)
1333
- },
1334
-
1335
- onVertexMarkerDragStart: function (e) {
1336
- // 🍂namespace Editable
1337
- // 🍂section Vertex events
1338
- // 🍂event editable:vertex:dragstart: VertexEvent
1339
- // Fired before a vertex is dragged by user.
1340
- this.fireAndForward('editable:vertex:dragstart', e)
1341
- },
1342
-
1343
- onVertexMarkerDragEnd: function (e) {
1344
- // 🍂namespace Editable
1345
- // 🍂section Vertex events
1346
- // 🍂event editable:vertex:dragend: VertexEvent
1347
- // Fired after a vertex is dragged by user.
1348
- this.fireAndForward('editable:vertex:dragend', e)
1349
- this.onEdited()
1350
- },
1351
-
1352
- setDrawnLatLngs: function (latlngs) {
1353
- this._drawnLatLngs = latlngs || this.getDefaultLatLngs()
1354
- },
1355
-
1356
- startDrawing: function () {
1357
- if (!this._drawnLatLngs) this.setDrawnLatLngs()
1358
- L.Editable.BaseEditor.prototype.startDrawing.call(this)
1359
- },
1360
-
1361
- startDrawingForward: function () {
1362
- this.startDrawing()
1363
- },
1364
-
1365
- endDrawing: function () {
1366
- this.tools.detachForwardLineGuide()
1367
- this.tools.detachBackwardLineGuide()
1368
- if (this._drawnLatLngs && this._drawnLatLngs.length < this.MIN_VERTEX)
1369
- this.deleteShape(this._drawnLatLngs)
1370
- L.Editable.BaseEditor.prototype.endDrawing.call(this)
1371
- delete this._drawnLatLngs
1372
- },
1373
-
1374
- addLatLng: function (latlng) {
1375
- if (this._drawing === L.Editable.FORWARD) this._drawnLatLngs.push(latlng)
1376
- else this._drawnLatLngs.unshift(latlng)
1377
- this.feature._bounds.extend(latlng)
1378
- const vertex = this.addVertexMarker(latlng, this._drawnLatLngs)
1379
- this.onNewVertex(vertex)
1380
- this.refresh()
1381
- },
1382
-
1383
- newPointForward: function (latlng) {
1384
- this.addLatLng(latlng)
1385
- this.tools.attachForwardLineGuide()
1386
- this.tools.anchorForwardLineGuide(latlng)
1387
- },
1388
-
1389
- newPointBackward: function (latlng) {
1390
- this.addLatLng(latlng)
1391
- this.tools.anchorBackwardLineGuide(latlng)
1392
- },
1393
-
1394
- // 🍂namespace PathEditor
1395
- // 🍂method push()
1396
- // Programmatically add a point while drawing.
1397
- push: function (latlng) {
1398
- if (!latlng)
1399
- return console.error(
1400
- 'L.Editable.PathEditor.push expect a valid latlng as parameter'
1401
- )
1402
- if (this._drawing === L.Editable.FORWARD) this.newPointForward(latlng)
1403
- else this.newPointBackward(latlng)
1404
- },
1405
-
1406
- removeLatLng: function (latlng) {
1407
- latlng.__vertex.delete()
1408
- this.refresh()
1409
- },
1410
-
1411
- // 🍂method pop(): L.LatLng or null
1412
- // Programmatically remove last point (if any) while drawing.
1413
- pop: function () {
1414
- if (this._drawnLatLngs.length <= 1) return
1415
- let latlng
1416
- if (this._drawing === L.Editable.FORWARD) {
1417
- latlng = this._drawnLatLngs[this._drawnLatLngs.length - 1]
1418
- } else {
1419
- latlng = this._drawnLatLngs[0]
1420
- }
1421
- this.removeLatLng(latlng)
1422
- if (this._drawing === L.Editable.FORWARD) {
1423
- this.tools.anchorForwardLineGuide(
1424
- this._drawnLatLngs[this._drawnLatLngs.length - 1]
1425
- )
1426
- } else {
1427
- this.tools.anchorForwardLineGuide(this._drawnLatLngs[0])
1428
- }
1429
- return latlng
1430
- },
1431
-
1432
- processDrawingClick: function (e) {
1433
- if (e.vertex && e.vertex.editor === this) return
1434
- if (this._drawing === L.Editable.FORWARD) this.newPointForward(e.latlng)
1435
- else this.newPointBackward(e.latlng)
1436
- this.fireAndForward('editable:drawing:clicked', e)
1437
- },
1438
-
1439
- onDrawingMouseMove: function (e) {
1440
- L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e)
1441
- if (this._drawing) {
1442
- this.tools.moveForwardLineGuide(e.latlng)
1443
- this.tools.moveBackwardLineGuide(e.latlng)
1444
- }
1445
- },
1446
-
1447
- refresh: function () {
1448
- this.feature.redraw()
1449
- this.onEditing()
1450
- },
1451
-
1452
- // 🍂namespace PathEditor
1453
- // 🍂method newShape(latlng?: L.LatLng)
1454
- // Add a new shape (Polyline, Polygon) in a multi, and setup up drawing tools to draw it;
1455
- // if optional `latlng` is given, start a path at this point.
1456
- newShape: function (latlng) {
1457
- const shape = this.addNewEmptyShape()
1458
- if (!shape) return
1459
- this.setDrawnLatLngs(shape[0] || shape) // Polygon or polyline
1460
- this.startDrawingForward()
1461
- // 🍂namespace Editable
1462
- // 🍂section Shape events
1463
- // 🍂event editable:shape:new: ShapeEvent
1464
- // Fired when a new shape is created in a multi (Polygon or Polyline).
1465
- this.fireAndForward('editable:shape:new', { shape: shape })
1466
- if (latlng) this.newPointForward(latlng)
1467
- },
1468
-
1469
- deleteShape: function (shape, latlngs) {
1470
- const e = { shape: shape }
1471
- L.Editable.makeCancellable(e)
1472
- // 🍂namespace Editable
1473
- // 🍂section Shape events
1474
- // 🍂event editable:shape:delete: CancelableShapeEvent
1475
- // Fired before a new shape is deleted in a multi (Polygon or Polyline).
1476
- this.fireAndForward('editable:shape:delete', e)
1477
- if (e._cancelled) return
1478
- shape = this._deleteShape(shape, latlngs)
1479
- if (this.ensureNotFlat) this.ensureNotFlat() // Polygon.
1480
- this.feature.setLatLngs(this.getLatLngs()) // Force bounds reset.
1481
- this.refresh()
1482
- this.reset()
1483
- // 🍂namespace Editable
1484
- // 🍂section Shape events
1485
- // 🍂event editable:shape:deleted: ShapeEvent
1486
- // Fired after a new shape is deleted in a multi (Polygon or Polyline).
1487
- this.fireAndForward('editable:shape:deleted', { shape: shape })
1488
- this.onEdited()
1489
- return shape
1490
- },
1491
-
1492
- _deleteShape: function (shape, latlngs) {
1493
- latlngs = latlngs || this.getLatLngs()
1494
- if (!latlngs.length) return
1495
- const inplaceDelete = (latlngs, shape) => {
1496
- // Called when deleting a flat latlngs
1497
- return latlngs.splice(0, Number.MAX_VALUE)
1498
- }
1499
- const spliceDelete = (latlngs, shape) => {
1500
- // Called when removing a latlngs inside an array
1501
- latlngs.splice(latlngs.indexOf(shape), 1)
1502
- if (!latlngs.length) this._deleteShape(latlngs)
1503
- return shape
1504
- }
1505
- if (latlngs === shape) return inplaceDelete(latlngs, shape)
1506
- for (const member of latlngs) {
1507
- if (member === shape) return spliceDelete(latlngs, shape)
1508
- if (member.indexOf(shape) !== -1) return spliceDelete(member, shape)
1509
- }
1510
- },
1511
-
1512
- // 🍂namespace PathEditor
1513
- // 🍂method deleteShapeAt(latlng: L.LatLng): Array
1514
- // Remove a path shape at the given `latlng`.
1515
- deleteShapeAt: function (latlng) {
1516
- const shape = this.feature.shapeAt(latlng)
1517
- if (shape) return this.deleteShape(shape)
1518
- },
1519
-
1520
- // 🍂method appendShape(shape: Array)
1521
- // Append a new shape to the Polygon or Polyline.
1522
- appendShape: function (shape) {
1523
- this.insertShape(shape)
1524
- },
1525
-
1526
- // 🍂method prependShape(shape: Array)
1527
- // Prepend a new shape to the Polygon or Polyline.
1528
- prependShape: function (shape) {
1529
- this.insertShape(shape, 0)
1530
- },
1531
-
1532
- // 🍂method insertShape(shape: Array, index: int)
1533
- // Insert a new shape to the Polygon or Polyline at given index (default is to append).
1534
- insertShape: function (shape, index) {
1535
- this.ensureMulti()
1536
- shape = this.formatShape(shape)
1537
- if (index === undefined) index = this.feature._latlngs.length
1538
- this.feature._latlngs.splice(index, 0, shape)
1539
- this.feature.redraw()
1540
- if (this._enabled) this.reset()
1541
- },
1542
-
1543
- extendBounds: function (e) {
1544
- this.feature._bounds.extend(e.vertex.latlng)
1545
- },
1546
-
1547
- onDragStart: function (e) {
1548
- this.editLayer.clearLayers()
1549
- L.Editable.BaseEditor.prototype.onDragStart.call(this, e)
1550
- },
1551
-
1552
- onDragEnd: function (e) {
1553
- this.initVertexMarkers()
1554
- L.Editable.BaseEditor.prototype.onDragEnd.call(this, e)
1555
- },
1556
- })
1557
-
1558
- // 🍂namespace Editable; 🍂class PolylineEditor; 🍂aka L.Editable.PolylineEditor
1559
- // 🍂inherits PathEditor
1560
- L.Editable.PolylineEditor = L.Editable.PathEditor.extend({
1561
- startDrawingBackward: function () {
1562
- this._drawing = L.Editable.BACKWARD
1563
- this.startDrawing()
1564
- },
1565
-
1566
- // 🍂method continueBackward(latlngs?: Array)
1567
- // Set up drawing tools to continue the line backward.
1568
- continueBackward: function (latlngs) {
1569
- if (this.drawing()) return
1570
- latlngs = latlngs || this.getDefaultLatLngs()
1571
- this.setDrawnLatLngs(latlngs)
1572
- if (latlngs.length > 0) {
1573
- this.tools.attachBackwardLineGuide()
1574
- this.tools.anchorBackwardLineGuide(latlngs[0])
1575
- }
1576
- this.startDrawingBackward()
1577
- },
1578
-
1579
- // 🍂method continueForward(latlngs?: Array)
1580
- // Set up drawing tools to continue the line forward.
1581
- continueForward: function (latlngs) {
1582
- if (this.drawing()) return
1583
- latlngs = latlngs || this.getDefaultLatLngs()
1584
- this.setDrawnLatLngs(latlngs)
1585
- if (latlngs.length > 0) {
1586
- this.tools.attachForwardLineGuide()
1587
- this.tools.anchorForwardLineGuide(latlngs[latlngs.length - 1])
1588
- }
1589
- this.startDrawingForward()
1590
- },
1591
-
1592
- getDefaultLatLngs: function (latlngs) {
1593
- latlngs = latlngs || this.feature._latlngs
1594
- if (!latlngs.length || latlngs[0] instanceof L.LatLng) return latlngs
1595
- return this.getDefaultLatLngs(latlngs[0])
1596
- },
1597
-
1598
- ensureMulti: function () {
1599
- if (this.feature._latlngs.length && isFlat(this.feature._latlngs)) {
1600
- this.feature._latlngs = [this.feature._latlngs]
1601
- }
1602
- },
1603
-
1604
- addNewEmptyShape: function () {
1605
- if (this.feature._latlngs.length) {
1606
- const shape = []
1607
- this.appendShape(shape)
1608
- return shape
1609
- }
1610
- return this.feature._latlngs
1611
- },
1612
-
1613
- formatShape: function (shape) {
1614
- if (isFlat(shape)) return shape
1615
- if (shape[0]) return this.formatShape(shape[0])
1616
- },
1617
-
1618
- // 🍂method splitShape(latlngs?: Array, index: int)
1619
- // Split the given `latlngs` shape at index `index` and integrate new shape in instance `latlngs`.
1620
- splitShape: function (shape, index) {
1621
- if (!index || index >= shape.length - 1) return
1622
- this.ensureMulti()
1623
- const shapeIndex = this.feature._latlngs.indexOf(shape)
1624
- if (shapeIndex === -1) return
1625
- const first = shape.slice(0, index + 1)
1626
- const second = shape.slice(index)
1627
- // We deal with reference, we don't want twice the same latlng around.
1628
- second[0] = L.latLng(second[0].lat, second[0].lng, second[0].alt)
1629
- this.feature._latlngs.splice(shapeIndex, 1, first, second)
1630
- this.refresh()
1631
- this.reset()
1632
- this.onEdited()
1633
- },
1634
- })
1635
-
1636
- // 🍂namespace Editable; 🍂class PolygonEditor; 🍂aka L.Editable.PolygonEditor
1637
- // 🍂inherits PathEditor
1638
- L.Editable.PolygonEditor = L.Editable.PathEditor.extend({
1639
- CLOSED: true,
1640
- MIN_VERTEX: 3,
1641
-
1642
- newPointForward: function (latlng) {
1643
- L.Editable.PathEditor.prototype.newPointForward.call(this, latlng)
1644
- if (!this.tools.backwardLineGuide._latlngs.length)
1645
- this.tools.anchorBackwardLineGuide(latlng)
1646
- if (this._drawnLatLngs.length === 2) this.tools.attachBackwardLineGuide()
1647
- },
1648
-
1649
- addNewEmptyHole: function (latlng) {
1650
- this.ensureNotFlat()
1651
- const latlngs = this.feature.shapeAt(latlng)
1652
- if (!latlngs) return
1653
- const holes = []
1654
- latlngs.push(holes)
1655
- return holes
1656
- },
1657
-
1658
- // 🍂method newHole(latlng?: L.LatLng, index: int)
1659
- // Set up drawing tools for creating a new hole on the Polygon. If the `latlng` param is given, a first point is created.
1660
- newHole: function (latlng) {
1661
- const holes = this.addNewEmptyHole(latlng)
1662
- if (!holes) return
1663
- this.setDrawnLatLngs(holes)
1664
- this.startDrawingForward()
1665
- if (latlng) this.newPointForward(latlng)
1666
- },
1667
-
1668
- addNewEmptyShape: function () {
1669
- if (this.feature._latlngs.length && this.feature._latlngs[0].length) {
1670
- const shape = []
1671
- this.appendShape(shape)
1672
- return shape
1673
- }
1674
- return this.feature._latlngs
1675
- },
1676
-
1677
- ensureMulti: function () {
1678
- if (this.feature._latlngs.length && isFlat(this.feature._latlngs[0])) {
1679
- this.feature._latlngs = [this.feature._latlngs]
1680
- }
1681
- },
1682
-
1683
- ensureNotFlat: function () {
1684
- if (!this.feature._latlngs.length || isFlat(this.feature._latlngs))
1685
- this.feature._latlngs = [this.feature._latlngs]
1686
- },
1687
-
1688
- vertexCanBeDeleted: function (vertex) {
1689
- const parent = this.feature.parentShape(vertex.latlngs)
1690
- const idx = L.Util.indexOf(parent, vertex.latlngs)
1691
- if (idx > 0) return true // Holes can be totally deleted without removing the layer itself.
1692
- return L.Editable.PathEditor.prototype.vertexCanBeDeleted.call(this, vertex)
1693
- },
1694
-
1695
- getDefaultLatLngs: function () {
1696
- if (!this.feature._latlngs.length) this.feature._latlngs.push([])
1697
- return this.feature._latlngs[0]
1698
- },
1699
-
1700
- formatShape: (shape) => {
1701
- // [[1, 2], [3, 4]] => must be nested
1702
- // [] => must be nested
1703
- // [[]] => is already nested
1704
- if (isFlat(shape) && (!shape[0] || shape[0].length !== 0)) return [shape]
1705
- return shape
1706
- },
1707
- })
1708
-
1709
- // 🍂namespace Editable; 🍂class RectangleEditor; 🍂aka L.Editable.RectangleEditor
1710
- // 🍂inherits PathEditor
1711
- L.Editable.RectangleEditor = L.Editable.PathEditor.extend({
1712
- CLOSED: true,
1713
- MIN_VERTEX: 4,
1714
-
1715
- options: {
1716
- skipMiddleMarkers: true,
1717
- },
1718
-
1719
- extendBounds: function (e) {
1720
- const index = e.vertex.getIndex()
1721
- const next = e.vertex.getNext()
1722
- const previous = e.vertex.getPrevious()
1723
- const oppositeIndex = (index + 2) % 4
1724
- const opposite = e.vertex.latlngs[oppositeIndex]
1725
- const bounds = new L.LatLngBounds(e.latlng, opposite)
1726
- // Update latlngs by hand to preserve order.
1727
- previous.latlng.update([e.latlng.lat, opposite.lng])
1728
- next.latlng.update([opposite.lat, e.latlng.lng])
1729
- this.updateBounds(bounds)
1730
- this.refreshVertexMarkers()
1731
- },
1732
-
1733
- onDrawingMouseDown: function (e) {
1734
- L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e)
1735
- this.connect()
1736
- const latlngs = this.getDefaultLatLngs()
1737
- // L.Polygon._convertLatLngs removes last latlng if it equals first point,
1738
- // which is the case here as all latlngs are [0, 0]
1739
- if (latlngs.length === 3) latlngs.push(e.latlng)
1740
- const bounds = new L.LatLngBounds(e.latlng, e.latlng)
1741
- this.updateBounds(bounds)
1742
- this.updateLatLngs(bounds)
1743
- this.refresh()
1744
- this.reset()
1745
- // Stop dragging map.
1746
- // L.Draggable has two workflows:
1747
- // - mousedown => mousemove => mouseup
1748
- // - touchstart => touchmove => touchend
1749
- // Problem: L.Map.Tap does not allow us to listen to touchstart, so we only
1750
- // can deal with mousedown, but then when in a touch device, we are dealing with
1751
- // simulated events (actually simulated by L.Map.Tap), which are no more taken
1752
- // into account by L.Draggable.
1753
- // Ref.: https://github.com/Leaflet/Leaflet.Editable/issues/103
1754
- e.originalEvent._simulated = false
1755
- this.map.dragging._draggable._onUp(e.originalEvent)
1756
- // Now transfer ongoing drag action to the bottom right corner.
1757
- // Should we refine which corner will handle the drag according to
1758
- // drag direction?
1759
- latlngs[3].__vertex.dragging._draggable._onDown(e.originalEvent)
1760
- },
1761
-
1762
- onDrawingMouseUp: function (e) {
1763
- this.commitDrawing(e)
1764
- e.originalEvent._simulated = false
1765
- L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e)
1766
- },
1767
-
1768
- onDrawingMouseMove: function (e) {
1769
- e.originalEvent._simulated = false
1770
- L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e)
1771
- },
1772
-
1773
- getDefaultLatLngs: function (latlngs) {
1774
- return latlngs || this.feature._latlngs[0]
1775
- },
1776
-
1777
- updateBounds: function (bounds) {
1778
- this.feature._bounds = bounds
1779
- },
1780
-
1781
- updateLatLngs: function (bounds) {
1782
- const latlngs = this.getDefaultLatLngs()
1783
- const newLatlngs = this.feature._boundsToLatLngs(bounds)
1784
- // Keep references.
1785
- for (let i = 0; i < latlngs.length; i++) {
1786
- latlngs[i].update(newLatlngs[i])
1787
- }
1788
- },
1789
- })
1790
-
1791
- // 🍂namespace Editable; 🍂class CircleEditor; 🍂aka L.Editable.CircleEditor
1792
- // 🍂inherits PathEditor
1793
- L.Editable.CircleEditor = L.Editable.PathEditor.extend({
1794
- MIN_VERTEX: 2,
1795
-
1796
- options: {
1797
- skipMiddleMarkers: true,
1798
- },
1799
-
1800
- initialize: function (map, feature, options) {
1801
- L.Editable.PathEditor.prototype.initialize.call(this, map, feature, options)
1802
- this._resizeLatLng = this.computeResizeLatLng()
1803
- },
1804
-
1805
- computeResizeLatLng: function () {
1806
- // While circle is not added to the map, _radius is not set.
1807
- const delta =
1808
- (this.feature._radius || this.feature._mRadius) * Math.cos(Math.PI / 4)
1809
- const point = this.map.project(this.feature._latlng)
1810
- return this.map.unproject([point.x + delta, point.y - delta])
1811
- },
1812
-
1813
- updateResizeLatLng: function () {
1814
- this._resizeLatLng.update(this.computeResizeLatLng())
1815
- this._resizeLatLng.__vertex.update()
1816
- },
1817
-
1818
- getLatLngs: function () {
1819
- return [this.feature._latlng, this._resizeLatLng]
1820
- },
1821
-
1822
- getDefaultLatLngs: function () {
1823
- return this.getLatLngs()
1824
- },
1825
-
1826
- onVertexMarkerDrag: function (e) {
1827
- if (e.vertex.getIndex() === 1) this.resize(e)
1828
- else this.updateResizeLatLng(e)
1829
- L.Editable.PathEditor.prototype.onVertexMarkerDrag.call(this, e)
1830
- },
1831
-
1832
- resize: function (e) {
1833
- let radius
1834
- if (this.map.options.crs) {
1835
- radius = this.map.options.crs.distance(this.feature._latlng, e.latlng)
1836
- } else {
1837
- radius = this.feature._latlng.distanceTo(e.latlng)
1838
- }
1839
- this.feature.setRadius(radius)
1840
- },
1841
-
1842
- onDrawingMouseDown: function (e) {
1843
- L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e)
1844
- this._resizeLatLng.update(e.latlng)
1845
- this.feature._latlng.update(e.latlng)
1846
- this.connect()
1847
- // Stop dragging map.
1848
- e.originalEvent._simulated = false
1849
- this.map.dragging._draggable._onUp(e.originalEvent)
1850
- // Now transfer ongoing drag action to the radius handler.
1851
- this._resizeLatLng.__vertex.dragging._draggable._onDown(e.originalEvent)
1852
- },
1853
-
1854
- onDrawingMouseUp: function (e) {
1855
- this.commitDrawing(e)
1856
- e.originalEvent._simulated = false
1857
- L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e)
1858
- },
1859
-
1860
- onDrawingMouseMove: function (e) {
1861
- e.originalEvent._simulated = false
1862
- L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e)
1863
- },
1864
-
1865
- onDrag: function (e) {
1866
- L.Editable.PathEditor.prototype.onDrag.call(this, e)
1867
- this.feature.dragging.updateLatLng(this._resizeLatLng)
1868
- },
1869
- })
1870
-
1871
- // 🍂namespace Editable; 🍂class EditableMixin
1872
- // `EditableMixin` is included to `L.Polyline`, `L.Polygon`, `L.Rectangle`, `L.Circle`
1873
- // and `L.Marker`. It adds some methods to them.
1874
- // *When editing is enabled, the editor is accessible on the instance with the
1875
- // `editor` property.*
1876
- const EditableMixin = {
1877
- createEditor: function (map) {
1878
- map = map || this._map
1879
- const tools = this.options.editOptions?.editTools || map.editTools
1880
- if (!tools) throw Error('Unable to detect Editable instance.')
1881
- const Klass = this.options.editorClass || this.getEditorClass(tools)
1882
- return new Klass(map, this, this.options.editOptions)
1883
- },
1884
-
1885
- // 🍂method enableEdit(map?: L.Map): this.editor
1886
- // Enable editing, by creating an editor if not existing, and then calling `enable` on it.
1887
- enableEdit: function (map) {
1888
- if (!this.editor) this.createEditor(map)
1889
- this.editor.enable()
1890
- return this.editor
1891
- },
1892
-
1893
- // 🍂method editEnabled(): boolean
1894
- // Return true if current instance has an editor attached, and this editor is enabled.
1895
- editEnabled: function () {
1896
- return this.editor?.enabled()
1897
- },
1898
-
1899
- // 🍂method disableEdit()
1900
- // Disable editing, also remove the editor property reference.
1901
- disableEdit: function () {
1902
- if (this.editor) {
1903
- this.editor.disable()
1904
- delete this.editor
1905
- }
1906
- },
1907
-
1908
- // 🍂method toggleEdit()
1909
- // Enable or disable editing, according to current status.
1910
- toggleEdit: function () {
1911
- if (this.editEnabled()) this.disableEdit()
1912
- else this.enableEdit()
1913
- },
1914
-
1915
- _onEditableAdd: function () {
1916
- if (this.editor) this.enableEdit()
1917
- },
1918
- }
1919
-
1920
- const PolylineMixin = {
1921
- getEditorClass: (tools) => {
1922
- return tools?.options?.polylineEditorClass || L.Editable.PolylineEditor
1923
- },
1924
-
1925
- shapeAt: function (latlng, latlngs) {
1926
- // We can have those cases:
1927
- // - latlngs are just a flat array of latlngs, use this
1928
- // - latlngs is an array of arrays of latlngs, loop over
1929
- let shape = null
1930
- latlngs = latlngs || this._latlngs
1931
- if (!latlngs.length) return shape
1932
- if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs
1933
- else {
1934
- for (const member of latlngs) {
1935
- if (this.isInLatLngs(latlng, member)) return member
1582
+
1583
+ });
1584
+
1585
+ // 🍂namespace Editable; 🍂class RectangleEditor; 🍂aka L.Editable.RectangleEditor
1586
+ // 🍂inherits PathEditor
1587
+ L.Editable.RectangleEditor = L.Editable.PathEditor.extend({
1588
+
1589
+ CLOSED: true,
1590
+ MIN_VERTEX: 4,
1591
+
1592
+ options: {
1593
+ skipMiddleMarkers: true
1594
+ },
1595
+
1596
+ extendBounds: function (e) {
1597
+ var index = e.vertex.getIndex(),
1598
+ next = e.vertex.getNext(),
1599
+ previous = e.vertex.getPrevious(),
1600
+ oppositeIndex = (index + 2) % 4,
1601
+ opposite = e.vertex.latlngs[oppositeIndex],
1602
+ bounds = new L.LatLngBounds(e.latlng, opposite);
1603
+ // Update latlngs by hand to preserve order.
1604
+ previous.latlng.update([e.latlng.lat, opposite.lng]);
1605
+ next.latlng.update([opposite.lat, e.latlng.lng]);
1606
+ this.updateBounds(bounds);
1607
+ this.refreshVertexMarkers();
1608
+ },
1609
+
1610
+ onDrawingMouseDown: function (e) {
1611
+ L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e);
1612
+ this.connect();
1613
+ var latlngs = this.getDefaultLatLngs();
1614
+ // L.Polygon._convertLatLngs removes last latlng if it equals first point,
1615
+ // which is the case here as all latlngs are [0, 0]
1616
+ if (latlngs.length === 3) latlngs.push(e.latlng);
1617
+ var bounds = new L.LatLngBounds(e.latlng, e.latlng);
1618
+ this.updateBounds(bounds);
1619
+ this.updateLatLngs(bounds);
1620
+ this.refresh();
1621
+ this.reset();
1622
+ // Stop dragging map.
1623
+ // L.Draggable has two workflows:
1624
+ // - mousedown => mousemove => mouseup
1625
+ // - touchstart => touchmove => touchend
1626
+ // Problem: L.Map.Tap does not allow us to listen to touchstart, so we only
1627
+ // can deal with mousedown, but then when in a touch device, we are dealing with
1628
+ // simulated events (actually simulated by L.Map.Tap), which are no more taken
1629
+ // into account by L.Draggable.
1630
+ // Ref.: https://github.com/Leaflet/Leaflet.Editable/issues/103
1631
+ e.originalEvent._simulated = false;
1632
+ this.map.dragging._draggable._onUp(e.originalEvent);
1633
+ // Now transfer ongoing drag action to the bottom right corner.
1634
+ // Should we refine which corner will handle the drag according to
1635
+ // drag direction?
1636
+ latlngs[3].__vertex.dragging._draggable._onDown(e.originalEvent);
1637
+ },
1638
+
1639
+ onDrawingMouseUp: function (e) {
1640
+ this.commitDrawing(e);
1641
+ e.originalEvent._simulated = false;
1642
+ L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e);
1643
+ },
1644
+
1645
+ onDrawingMouseMove: function (e) {
1646
+ e.originalEvent._simulated = false;
1647
+ L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e);
1648
+ },
1649
+
1650
+
1651
+ getDefaultLatLngs: function (latlngs) {
1652
+ return latlngs || this.feature._latlngs[0];
1653
+ },
1654
+
1655
+ updateBounds: function (bounds) {
1656
+ this.feature._bounds = bounds;
1657
+ },
1658
+
1659
+ updateLatLngs: function (bounds) {
1660
+ var latlngs = this.getDefaultLatLngs(),
1661
+ newLatlngs = this.feature._boundsToLatLngs(bounds);
1662
+ // Keep references.
1663
+ for (var i = 0; i < latlngs.length; i++) {
1664
+ latlngs[i].update(newLatlngs[i]);
1665
+ }
1666
+ }
1667
+
1668
+ });
1669
+
1670
+ // 🍂namespace Editable; 🍂class CircleEditor; 🍂aka L.Editable.CircleEditor
1671
+ // 🍂inherits PathEditor
1672
+ L.Editable.CircleEditor = L.Editable.PathEditor.extend({
1673
+
1674
+ MIN_VERTEX: 2,
1675
+
1676
+ options: {
1677
+ skipMiddleMarkers: true
1678
+ },
1679
+
1680
+ initialize: function (map, feature, options) {
1681
+ L.Editable.PathEditor.prototype.initialize.call(this, map, feature, options);
1682
+ this._resizeLatLng = this.computeResizeLatLng();
1683
+ },
1684
+
1685
+ computeResizeLatLng: function () {
1686
+ // While circle is not added to the map, _radius is not set.
1687
+ var delta = (this.feature._radius || this.feature._mRadius) * Math.cos(Math.PI / 4),
1688
+ point = this.map.project(this.feature._latlng);
1689
+ return this.map.unproject([point.x + delta, point.y - delta]);
1690
+ },
1691
+
1692
+ updateResizeLatLng: function () {
1693
+ this._resizeLatLng.update(this.computeResizeLatLng());
1694
+ this._resizeLatLng.__vertex.update();
1695
+ },
1696
+
1697
+ getLatLngs: function () {
1698
+ return [this.feature._latlng, this._resizeLatLng];
1699
+ },
1700
+
1701
+ getDefaultLatLngs: function () {
1702
+ return this.getLatLngs();
1703
+ },
1704
+
1705
+ onVertexMarkerDrag: function (e) {
1706
+ if (e.vertex.getIndex() === 1) this.resize(e);
1707
+ else this.updateResizeLatLng(e);
1708
+ L.Editable.PathEditor.prototype.onVertexMarkerDrag.call(this, e);
1709
+ },
1710
+
1711
+ resize: function (e) {
1712
+ var radius = this.feature._latlng.distanceTo(e.latlng);
1713
+ this.feature.setRadius(radius);
1714
+ },
1715
+
1716
+ onDrawingMouseDown: function (e) {
1717
+ L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e);
1718
+ this._resizeLatLng.update(e.latlng);
1719
+ this.feature._latlng.update(e.latlng);
1720
+ this.connect();
1721
+ // Stop dragging map.
1722
+ e.originalEvent._simulated = false;
1723
+ this.map.dragging._draggable._onUp(e.originalEvent);
1724
+ // Now transfer ongoing drag action to the radius handler.
1725
+ this._resizeLatLng.__vertex.dragging._draggable._onDown(e.originalEvent);
1726
+ },
1727
+
1728
+ onDrawingMouseUp: function (e) {
1729
+ this.commitDrawing(e);
1730
+ e.originalEvent._simulated = false;
1731
+ L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e);
1732
+ },
1733
+
1734
+ onDrawingMouseMove: function (e) {
1735
+ e.originalEvent._simulated = false;
1736
+ L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e);
1737
+ },
1738
+
1739
+ onDrag: function (e) {
1740
+ L.Editable.PathEditor.prototype.onDrag.call(this, e);
1741
+ this.feature.dragging.updateLatLng(this._resizeLatLng);
1936
1742
  }
1937
- }
1938
- return shape
1939
- },
1940
-
1941
- isInLatLngs: function (l, latlngs) {
1942
- if (!latlngs) return false
1943
- let i
1944
- let k
1945
- let len
1946
- let part = []
1947
- let p
1948
- const w = this._clickTolerance()
1949
- this._projectLatlngs(latlngs, part, this._pxBounds)
1950
- part = part[0]
1951
- p = this._map.latLngToLayerPoint(l)
1952
-
1953
- if (!this._pxBounds.contains(p)) {
1954
- return false
1955
- }
1956
- for (i = 1, len = part.length, k = 0; i < len; k = i++) {
1957
- if (L.LineUtil.pointToSegmentDistance(p, part[k], part[i]) <= w) {
1958
- return true
1743
+
1744
+ });
1745
+
1746
+ // 🍂namespace Editable; 🍂class EditableMixin
1747
+ // `EditableMixin` is included to `L.Polyline`, `L.Polygon`, `L.Rectangle`, `L.Circle`
1748
+ // and `L.Marker`. It adds some methods to them.
1749
+ // *When editing is enabled, the editor is accessible on the instance with the
1750
+ // `editor` property.*
1751
+ var EditableMixin = {
1752
+
1753
+ createEditor: function (map) {
1754
+ map = map || this._map;
1755
+ var tools = (this.options.editOptions || {}).editTools || map.editTools;
1756
+ if (!tools) throw Error('Unable to detect Editable instance.');
1757
+ var Klass = this.options.editorClass || this.getEditorClass(tools);
1758
+ return new Klass(map, this, this.options.editOptions);
1759
+ },
1760
+
1761
+ // 🍂method enableEdit(map?: L.Map): this.editor
1762
+ // Enable editing, by creating an editor if not existing, and then calling `enable` on it.
1763
+ enableEdit: function (map) {
1764
+ if (!this.editor) this.createEditor(map);
1765
+ this.editor.enable();
1766
+ return this.editor;
1767
+ },
1768
+
1769
+ // 🍂method editEnabled(): boolean
1770
+ // Return true if current instance has an editor attached, and this editor is enabled.
1771
+ editEnabled: function () {
1772
+ return this.editor && this.editor.enabled();
1773
+ },
1774
+
1775
+ // 🍂method disableEdit()
1776
+ // Disable editing, also remove the editor property reference.
1777
+ disableEdit: function () {
1778
+ if (this.editor) {
1779
+ this.editor.disable();
1780
+ delete this.editor;
1781
+ }
1782
+ },
1783
+
1784
+ // 🍂method toggleEdit()
1785
+ // Enable or disable editing, according to current status.
1786
+ toggleEdit: function () {
1787
+ if (this.editEnabled()) this.disableEdit();
1788
+ else this.enableEdit();
1789
+ },
1790
+
1791
+ _onEditableAdd: function () {
1792
+ if (this.editor) this.enableEdit();
1959
1793
  }
1960
- }
1961
- return false
1962
- },
1963
- }
1964
-
1965
- const PolygonMixin = {
1966
- getEditorClass: (tools) => {
1967
- return tools?.options?.polygonEditorClass || L.Editable.PolygonEditor
1968
- },
1969
-
1970
- shapeAt: function (latlng, latlngs) {
1971
- // We can have those cases:
1972
- // - latlngs are just a flat array of latlngs, use this
1973
- // - latlngs is an array of arrays of latlngs, this is a simple polygon (maybe with holes), use the first
1974
- // - latlngs is an array of arrays of arrays, this is a multi, loop over
1975
- let shape = null
1976
- latlngs = latlngs || this._latlngs
1977
- if (!latlngs.length) return shape
1978
- if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs
1979
- if (isFlat(latlngs[0]) && this.isInLatLngs(latlng, latlngs[0])) {
1980
- shape = latlngs
1981
- } else {
1982
- for (const member of latlngs) {
1983
- if (this.isInLatLngs(latlng, member[0])) return member
1794
+
1795
+ };
1796
+
1797
+ var PolylineMixin = {
1798
+
1799
+ getEditorClass: function (tools) {
1800
+ return (tools && tools.options.polylineEditorClass) ? tools.options.polylineEditorClass : L.Editable.PolylineEditor;
1801
+ },
1802
+
1803
+ shapeAt: function (latlng, latlngs) {
1804
+ // We can have those cases:
1805
+ // - latlngs are just a flat array of latlngs, use this
1806
+ // - latlngs is an array of arrays of latlngs, loop over
1807
+ var shape = null;
1808
+ latlngs = latlngs || this._latlngs;
1809
+ if (!latlngs.length) return shape;
1810
+ else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs;
1811
+ else for (var i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i])) return latlngs[i];
1812
+ return shape;
1813
+ },
1814
+
1815
+ isInLatLngs: function (l, latlngs) {
1816
+ if (!latlngs) return false;
1817
+ var i, k, len, part = [], p,
1818
+ w = this._clickTolerance();
1819
+ this._projectLatlngs(latlngs, part, this._pxBounds);
1820
+ part = part[0];
1821
+ p = this._map.latLngToLayerPoint(l);
1822
+
1823
+ if (!this._pxBounds.contains(p)) { return false; }
1824
+ for (i = 1, len = part.length, k = 0; i < len; k = i++) {
1825
+
1826
+ if (L.LineUtil.pointToSegmentDistance(p, part[k], part[i]) <= w) {
1827
+ return true;
1828
+ }
1829
+ }
1830
+ return false;
1984
1831
  }
1985
- }
1986
- return shape
1987
- },
1988
-
1989
- isInLatLngs: (l, latlngs) => {
1990
- let inside = false
1991
- let l1
1992
- let l2
1993
- let j
1994
- let k
1995
- let len2
1996
-
1997
- for (j = 0, len2 = latlngs.length, k = len2 - 1; j < len2; k = j++) {
1998
- l1 = latlngs[j]
1999
- l2 = latlngs[k]
2000
-
2001
- if (
2002
- l1.lat > l.lat !== l2.lat > l.lat &&
2003
- l.lng < ((l2.lng - l1.lng) * (l.lat - l1.lat)) / (l2.lat - l1.lat) + l1.lng
2004
- ) {
2005
- inside = !inside
1832
+
1833
+ };
1834
+
1835
+ var PolygonMixin = {
1836
+
1837
+ getEditorClass: function (tools) {
1838
+ return (tools && tools.options.polygonEditorClass) ? tools.options.polygonEditorClass : L.Editable.PolygonEditor;
1839
+ },
1840
+
1841
+ shapeAt: function (latlng, latlngs) {
1842
+ // We can have those cases:
1843
+ // - latlngs are just a flat array of latlngs, use this
1844
+ // - latlngs is an array of arrays of latlngs, this is a simple polygon (maybe with holes), use the first
1845
+ // - latlngs is an array of arrays of arrays, this is a multi, loop over
1846
+ var shape = null;
1847
+ latlngs = latlngs || this._latlngs;
1848
+ if (!latlngs.length) return shape;
1849
+ else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs;
1850
+ else if (isFlat(latlngs[0]) && this.isInLatLngs(latlng, latlngs[0])) shape = latlngs;
1851
+ else for (var i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i][0])) return latlngs[i];
1852
+ return shape;
1853
+ },
1854
+
1855
+ isInLatLngs: function (l, latlngs) {
1856
+ var inside = false, l1, l2, j, k, len2;
1857
+
1858
+ for (j = 0, len2 = latlngs.length, k = len2 - 1; j < len2; k = j++) {
1859
+ l1 = latlngs[j];
1860
+ l2 = latlngs[k];
1861
+
1862
+ if (((l1.lat > l.lat) !== (l2.lat > l.lat)) &&
1863
+ (l.lng < (l2.lng - l1.lng) * (l.lat - l1.lat) / (l2.lat - l1.lat) + l1.lng)) {
1864
+ inside = !inside;
1865
+ }
1866
+ }
1867
+
1868
+ return inside;
1869
+ },
1870
+
1871
+ parentShape: function (shape, latlngs) {
1872
+ latlngs = latlngs || this._latlngs;
1873
+ if (!latlngs) return;
1874
+ var idx = L.Util.indexOf(latlngs, shape);
1875
+ if (idx !== -1) return latlngs;
1876
+ for (var i = 0; i < latlngs.length; i++) {
1877
+ idx = L.Util.indexOf(latlngs[i], shape);
1878
+ if (idx !== -1) return latlngs[i];
1879
+ }
2006
1880
  }
2007
- }
2008
-
2009
- return inside
2010
- },
2011
-
2012
- parentShape: function (shape, latlngs) {
2013
- latlngs = latlngs || this._latlngs
2014
- if (!latlngs) return
2015
- let idx = L.Util.indexOf(latlngs, shape)
2016
- if (idx !== -1) return latlngs
2017
- for (const member of latlngs) {
2018
- idx = L.Util.indexOf(member, shape)
2019
- if (idx !== -1) return member
2020
- }
2021
- },
2022
- }
2023
-
2024
- const MarkerMixin = {
2025
- getEditorClass: (tools) => {
2026
- return tools?.options?.markerEditorClass || L.Editable.MarkerEditor
2027
- },
2028
- }
2029
-
2030
- const CircleMarkerMixin = {
2031
- getEditorClass: (tools) => {
2032
- return tools?.options?.circleMarkerEditorClass || L.Editable.CircleMarkerEditor
2033
- },
2034
- }
2035
-
2036
- const RectangleMixin = {
2037
- getEditorClass: (tools) => {
2038
- return tools?.options?.rectangleEditorClass || L.Editable.RectangleEditor
2039
- },
2040
- }
2041
-
2042
- const CircleMixin = {
2043
- getEditorClass: (tools) => {
2044
- return tools?.options?.circleEditorClass || L.Editable.CircleEditor
2045
- },
2046
- }
2047
-
2048
- const keepEditable = function () {
2049
- // Make sure you can remove/readd an editable layer.
2050
- this.on('add', this._onEditableAdd)
2051
- }
2052
-
2053
- const isFlat = L.LineUtil.isFlat || L.LineUtil._flat || L.Polyline._flat // <=> 1.1 compat.
2054
-
2055
- if (L.Polyline) {
2056
- L.Polyline.include(EditableMixin)
2057
- L.Polyline.include(PolylineMixin)
2058
- L.Polyline.addInitHook(keepEditable)
2059
- }
2060
- if (L.Polygon) {
2061
- L.Polygon.include(EditableMixin)
2062
- L.Polygon.include(PolygonMixin)
2063
- }
2064
- if (L.Marker) {
2065
- L.Marker.include(EditableMixin)
2066
- L.Marker.include(MarkerMixin)
2067
- L.Marker.addInitHook(keepEditable)
2068
- }
2069
- if (L.CircleMarker) {
2070
- L.CircleMarker.include(EditableMixin)
2071
- L.CircleMarker.include(CircleMarkerMixin)
2072
- L.CircleMarker.addInitHook(keepEditable)
2073
- }
2074
- if (L.Rectangle) {
2075
- L.Rectangle.include(EditableMixin)
2076
- L.Rectangle.include(RectangleMixin)
2077
- }
2078
- if (L.Circle) {
2079
- L.Circle.include(EditableMixin)
2080
- L.Circle.include(CircleMixin)
2081
- }
2082
-
2083
- L.LatLng.prototype.update = function (latlng) {
2084
- latlng = L.latLng(latlng)
2085
- this.lat = latlng.lat
2086
- this.lng = latlng.lng
2087
- }
2088
- }, window)
1881
+
1882
+ };
1883
+
1884
+
1885
+ var MarkerMixin = {
1886
+
1887
+ getEditorClass: function (tools) {
1888
+ return (tools && tools.options.markerEditorClass) ? tools.options.markerEditorClass : L.Editable.MarkerEditor;
1889
+ }
1890
+
1891
+ };
1892
+
1893
+ var RectangleMixin = {
1894
+
1895
+ getEditorClass: function (tools) {
1896
+ return (tools && tools.options.rectangleEditorClass) ? tools.options.rectangleEditorClass : L.Editable.RectangleEditor;
1897
+ }
1898
+
1899
+ };
1900
+
1901
+ var CircleMixin = {
1902
+
1903
+ getEditorClass: function (tools) {
1904
+ return (tools && tools.options.circleEditorClass) ? tools.options.circleEditorClass : L.Editable.CircleEditor;
1905
+ }
1906
+
1907
+ };
1908
+
1909
+ var keepEditable = function () {
1910
+ // Make sure you can remove/readd an editable layer.
1911
+ this.on('add', this._onEditableAdd);
1912
+ };
1913
+
1914
+ var isFlat = L.LineUtil.isFlat || L.LineUtil._flat || L.Polyline._flat; // <=> 1.1 compat.
1915
+
1916
+
1917
+ if (L.Polyline) {
1918
+ L.Polyline.include(EditableMixin);
1919
+ L.Polyline.include(PolylineMixin);
1920
+ L.Polyline.addInitHook(keepEditable);
1921
+ }
1922
+ if (L.Polygon) {
1923
+ L.Polygon.include(EditableMixin);
1924
+ L.Polygon.include(PolygonMixin);
1925
+ }
1926
+ if (L.Marker) {
1927
+ L.Marker.include(EditableMixin);
1928
+ L.Marker.include(MarkerMixin);
1929
+ L.Marker.addInitHook(keepEditable);
1930
+ }
1931
+ if (L.Rectangle) {
1932
+ L.Rectangle.include(EditableMixin);
1933
+ L.Rectangle.include(RectangleMixin);
1934
+ }
1935
+ if (L.Circle) {
1936
+ L.Circle.include(EditableMixin);
1937
+ L.Circle.include(CircleMixin);
1938
+ }
1939
+
1940
+ L.LatLng.prototype.update = function (latlng) {
1941
+ latlng = L.latLng(latlng);
1942
+ this.lat = latlng.lat;
1943
+ this.lng = latlng.lng;
1944
+ }
1945
+
1946
+ }, window));