leaflet-draw-rails 0.0.1
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +23 -0
- data/lib/leaflet-draw-rails/version.rb +7 -0
- data/lib/leaflet-draw-rails.rb +10 -0
- data/vendor/assets/images/images/spritesheet-2x.png +0 -0
- data/vendor/assets/images/images/spritesheet.png +0 -0
- data/vendor/assets/javascripts/leaflet.draw.js +2943 -0
- data/vendor/assets/stylesheets/leaflet.draw.css +303 -0
- metadata +136 -0
@@ -0,0 +1,2943 @@
|
|
1
|
+
|
2
|
+
/*
|
3
|
+
Leaflet.draw, a plugin that adds drawing and editing tools to Leaflet powered maps.
|
4
|
+
(c) 2012-2013, Jacob Toye, Smartrak
|
5
|
+
|
6
|
+
https://github.com/Leaflet/Leaflet.draw
|
7
|
+
http://leafletjs.com
|
8
|
+
https://github.com/jacobtoye
|
9
|
+
*/
|
10
|
+
(function (window, document, undefined) {/*
|
11
|
+
* Leaflet.draw assumes that you have already included the Leaflet library.
|
12
|
+
*/
|
13
|
+
|
14
|
+
L.drawVersion = '0.2.4-dev';
|
15
|
+
|
16
|
+
L.drawLocal = {
|
17
|
+
draw: {
|
18
|
+
toolbar: {
|
19
|
+
actions: {
|
20
|
+
title: 'Cancel drawing',
|
21
|
+
text: 'Cancel'
|
22
|
+
},
|
23
|
+
undo: {
|
24
|
+
title: 'Delete last point drawn',
|
25
|
+
text: 'Delete last point'
|
26
|
+
},
|
27
|
+
buttons: {
|
28
|
+
polyline: 'Draw a polyline',
|
29
|
+
polygon: 'Draw a polygon',
|
30
|
+
rectangle: 'Draw a rectangle',
|
31
|
+
circle: 'Draw a circle',
|
32
|
+
marker: 'Draw a marker'
|
33
|
+
}
|
34
|
+
},
|
35
|
+
handlers: {
|
36
|
+
circle: {
|
37
|
+
tooltip: {
|
38
|
+
start: 'Click and drag to draw circle.'
|
39
|
+
},
|
40
|
+
radius: 'Radius'
|
41
|
+
},
|
42
|
+
marker: {
|
43
|
+
tooltip: {
|
44
|
+
start: 'Click map to place marker.'
|
45
|
+
}
|
46
|
+
},
|
47
|
+
polygon: {
|
48
|
+
tooltip: {
|
49
|
+
start: 'Click to start drawing shape.',
|
50
|
+
cont: 'Click to continue drawing shape.',
|
51
|
+
end: 'Click first point to close this shape.'
|
52
|
+
}
|
53
|
+
},
|
54
|
+
polyline: {
|
55
|
+
error: '<strong>Error:</strong> shape edges cannot cross!',
|
56
|
+
tooltip: {
|
57
|
+
start: 'Click to start drawing line.',
|
58
|
+
cont: 'Click to continue drawing line.',
|
59
|
+
end: 'Click last point to finish line.'
|
60
|
+
}
|
61
|
+
},
|
62
|
+
rectangle: {
|
63
|
+
tooltip: {
|
64
|
+
start: 'Click and drag to draw rectangle.'
|
65
|
+
}
|
66
|
+
},
|
67
|
+
simpleshape: {
|
68
|
+
tooltip: {
|
69
|
+
end: 'Release mouse to finish drawing.'
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
},
|
74
|
+
edit: {
|
75
|
+
toolbar: {
|
76
|
+
actions: {
|
77
|
+
save: {
|
78
|
+
title: 'Save changes.',
|
79
|
+
text: 'Save'
|
80
|
+
},
|
81
|
+
cancel: {
|
82
|
+
title: 'Cancel editing, discards all changes.',
|
83
|
+
text: 'Cancel'
|
84
|
+
}
|
85
|
+
},
|
86
|
+
buttons: {
|
87
|
+
edit: 'Edit layers.',
|
88
|
+
editDisabled: 'No layers to edit.',
|
89
|
+
remove: 'Delete layers.',
|
90
|
+
removeDisabled: 'No layers to delete.'
|
91
|
+
}
|
92
|
+
},
|
93
|
+
handlers: {
|
94
|
+
edit: {
|
95
|
+
tooltip: {
|
96
|
+
text: 'Drag handles, or marker to edit feature.',
|
97
|
+
subtext: 'Click cancel to undo changes.'
|
98
|
+
}
|
99
|
+
},
|
100
|
+
remove: {
|
101
|
+
tooltip: {
|
102
|
+
text: 'Click on a feature to remove'
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}
|
107
|
+
};
|
108
|
+
|
109
|
+
|
110
|
+
L.Draw = {};
|
111
|
+
|
112
|
+
L.Draw.Feature = L.Handler.extend({
|
113
|
+
includes: L.Mixin.Events,
|
114
|
+
|
115
|
+
initialize: function (map, options) {
|
116
|
+
this._map = map;
|
117
|
+
this._container = map._container;
|
118
|
+
this._overlayPane = map._panes.overlayPane;
|
119
|
+
this._popupPane = map._panes.popupPane;
|
120
|
+
|
121
|
+
// Merge default shapeOptions options with custom shapeOptions
|
122
|
+
if (options && options.shapeOptions) {
|
123
|
+
options.shapeOptions = L.Util.extend({}, this.options.shapeOptions, options.shapeOptions);
|
124
|
+
}
|
125
|
+
L.setOptions(this, options);
|
126
|
+
},
|
127
|
+
|
128
|
+
enable: function () {
|
129
|
+
if (this._enabled) { return; }
|
130
|
+
|
131
|
+
L.Handler.prototype.enable.call(this);
|
132
|
+
|
133
|
+
this.fire('enabled', { handler: this.type });
|
134
|
+
|
135
|
+
this._map.fire('draw:drawstart', { layerType: this.type });
|
136
|
+
},
|
137
|
+
|
138
|
+
disable: function () {
|
139
|
+
if (!this._enabled) { return; }
|
140
|
+
|
141
|
+
L.Handler.prototype.disable.call(this);
|
142
|
+
|
143
|
+
this._map.fire('draw:drawstop', { layerType: this.type });
|
144
|
+
|
145
|
+
this.fire('disabled', { handler: this.type });
|
146
|
+
},
|
147
|
+
|
148
|
+
addHooks: function () {
|
149
|
+
var map = this._map;
|
150
|
+
|
151
|
+
if (map) {
|
152
|
+
L.DomUtil.disableTextSelection();
|
153
|
+
|
154
|
+
map.getContainer().focus();
|
155
|
+
|
156
|
+
this._tooltip = new L.Tooltip(this._map);
|
157
|
+
|
158
|
+
L.DomEvent.on(this._container, 'keyup', this._cancelDrawing, this);
|
159
|
+
}
|
160
|
+
},
|
161
|
+
|
162
|
+
removeHooks: function () {
|
163
|
+
if (this._map) {
|
164
|
+
L.DomUtil.enableTextSelection();
|
165
|
+
|
166
|
+
this._tooltip.dispose();
|
167
|
+
this._tooltip = null;
|
168
|
+
|
169
|
+
L.DomEvent.off(this._container, 'keyup', this._cancelDrawing, this);
|
170
|
+
}
|
171
|
+
},
|
172
|
+
|
173
|
+
setOptions: function (options) {
|
174
|
+
L.setOptions(this, options);
|
175
|
+
},
|
176
|
+
|
177
|
+
_fireCreatedEvent: function (layer) {
|
178
|
+
this._map.fire('draw:created', { layer: layer, layerType: this.type });
|
179
|
+
},
|
180
|
+
|
181
|
+
// Cancel drawing when the escape key is pressed
|
182
|
+
_cancelDrawing: function (e) {
|
183
|
+
if (e.keyCode === 27) {
|
184
|
+
this.disable();
|
185
|
+
}
|
186
|
+
}
|
187
|
+
});
|
188
|
+
|
189
|
+
L.Draw.Polyline = L.Draw.Feature.extend({
|
190
|
+
statics: {
|
191
|
+
TYPE: 'polyline'
|
192
|
+
},
|
193
|
+
|
194
|
+
Poly: L.Polyline,
|
195
|
+
|
196
|
+
options: {
|
197
|
+
allowIntersection: true,
|
198
|
+
repeatMode: false,
|
199
|
+
drawError: {
|
200
|
+
color: '#b00b00',
|
201
|
+
timeout: 2500
|
202
|
+
},
|
203
|
+
icon: new L.DivIcon({
|
204
|
+
iconSize: new L.Point(8, 8),
|
205
|
+
className: 'leaflet-div-icon leaflet-editing-icon'
|
206
|
+
}),
|
207
|
+
guidelineDistance: 20,
|
208
|
+
maxGuideLineLength: 4000,
|
209
|
+
shapeOptions: {
|
210
|
+
stroke: true,
|
211
|
+
color: '#f06eaa',
|
212
|
+
weight: 4,
|
213
|
+
opacity: 0.5,
|
214
|
+
fill: false,
|
215
|
+
clickable: true
|
216
|
+
},
|
217
|
+
metric: true, // Whether to use the metric meaurement system or imperial
|
218
|
+
showLength: true, // Whether to display distance in the tooltip
|
219
|
+
zIndexOffset: 2000 // This should be > than the highest z-index any map layers
|
220
|
+
},
|
221
|
+
|
222
|
+
initialize: function (map, options) {
|
223
|
+
// Need to set this here to ensure the correct message is used.
|
224
|
+
this.options.drawError.message = L.drawLocal.draw.handlers.polyline.error;
|
225
|
+
|
226
|
+
// Merge default drawError options with custom options
|
227
|
+
if (options && options.drawError) {
|
228
|
+
options.drawError = L.Util.extend({}, this.options.drawError, options.drawError);
|
229
|
+
}
|
230
|
+
|
231
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
232
|
+
this.type = L.Draw.Polyline.TYPE;
|
233
|
+
|
234
|
+
L.Draw.Feature.prototype.initialize.call(this, map, options);
|
235
|
+
},
|
236
|
+
|
237
|
+
addHooks: function () {
|
238
|
+
L.Draw.Feature.prototype.addHooks.call(this);
|
239
|
+
if (this._map) {
|
240
|
+
this._markers = [];
|
241
|
+
|
242
|
+
this._markerGroup = new L.LayerGroup();
|
243
|
+
this._map.addLayer(this._markerGroup);
|
244
|
+
|
245
|
+
this._poly = new L.Polyline([], this.options.shapeOptions);
|
246
|
+
|
247
|
+
this._tooltip.updateContent(this._getTooltipText());
|
248
|
+
|
249
|
+
// Make a transparent marker that will used to catch click events. These click
|
250
|
+
// events will create the vertices. We need to do this so we can ensure that
|
251
|
+
// we can create vertices over other map layers (markers, vector layers). We
|
252
|
+
// also do not want to trigger any click handlers of objects we are clicking on
|
253
|
+
// while drawing.
|
254
|
+
if (!this._mouseMarker) {
|
255
|
+
this._mouseMarker = L.marker(this._map.getCenter(), {
|
256
|
+
icon: L.divIcon({
|
257
|
+
className: 'leaflet-mouse-marker',
|
258
|
+
iconAnchor: [20, 20],
|
259
|
+
iconSize: [40, 40]
|
260
|
+
}),
|
261
|
+
opacity: 0,
|
262
|
+
zIndexOffset: this.options.zIndexOffset
|
263
|
+
});
|
264
|
+
}
|
265
|
+
|
266
|
+
this._mouseMarker
|
267
|
+
.on('mousedown', this._onMouseDown, this)
|
268
|
+
.addTo(this._map);
|
269
|
+
|
270
|
+
this._map
|
271
|
+
.on('mousemove', this._onMouseMove, this)
|
272
|
+
.on('mouseup', this._onMouseUp, this)
|
273
|
+
.on('zoomend', this._onZoomEnd, this);
|
274
|
+
}
|
275
|
+
},
|
276
|
+
|
277
|
+
removeHooks: function () {
|
278
|
+
L.Draw.Feature.prototype.removeHooks.call(this);
|
279
|
+
|
280
|
+
this._clearHideErrorTimeout();
|
281
|
+
|
282
|
+
this._cleanUpShape();
|
283
|
+
|
284
|
+
// remove markers from map
|
285
|
+
this._map.removeLayer(this._markerGroup);
|
286
|
+
delete this._markerGroup;
|
287
|
+
delete this._markers;
|
288
|
+
|
289
|
+
this._map.removeLayer(this._poly);
|
290
|
+
delete this._poly;
|
291
|
+
|
292
|
+
this._mouseMarker
|
293
|
+
.off('mousedown', this._onMouseDown, this)
|
294
|
+
.off('mouseup', this._onMouseUp, this);
|
295
|
+
this._map.removeLayer(this._mouseMarker);
|
296
|
+
delete this._mouseMarker;
|
297
|
+
|
298
|
+
// clean up DOM
|
299
|
+
this._clearGuides();
|
300
|
+
|
301
|
+
this._map
|
302
|
+
.off('mousemove', this._onMouseMove, this)
|
303
|
+
.off('zoomend', this._onZoomEnd, this);
|
304
|
+
},
|
305
|
+
|
306
|
+
deleteLastVertex: function () {
|
307
|
+
if (this._markers.length <= 1) {
|
308
|
+
return;
|
309
|
+
}
|
310
|
+
|
311
|
+
var lastMarker = this._markers.pop(),
|
312
|
+
poly = this._poly,
|
313
|
+
latlng = this._poly.spliceLatLngs(poly.getLatLngs().length - 1, 1)[0];
|
314
|
+
|
315
|
+
this._markerGroup.removeLayer(lastMarker);
|
316
|
+
|
317
|
+
if (poly.getLatLngs().length < 2) {
|
318
|
+
this._map.removeLayer(poly);
|
319
|
+
}
|
320
|
+
|
321
|
+
this._vertexChanged(latlng, false);
|
322
|
+
},
|
323
|
+
|
324
|
+
addVertex: function (latlng) {
|
325
|
+
var markersLength = this._markers.length;
|
326
|
+
|
327
|
+
if (markersLength > 0 && !this.options.allowIntersection && this._poly.newLatLngIntersects(latlng)) {
|
328
|
+
this._showErrorTooltip();
|
329
|
+
return;
|
330
|
+
}
|
331
|
+
else if (this._errorShown) {
|
332
|
+
this._hideErrorTooltip();
|
333
|
+
}
|
334
|
+
|
335
|
+
this._markers.push(this._createMarker(latlng));
|
336
|
+
|
337
|
+
this._poly.addLatLng(latlng);
|
338
|
+
|
339
|
+
if (this._poly.getLatLngs().length === 2) {
|
340
|
+
this._map.addLayer(this._poly);
|
341
|
+
}
|
342
|
+
|
343
|
+
this._vertexChanged(latlng, true);
|
344
|
+
},
|
345
|
+
|
346
|
+
_finishShape: function () {
|
347
|
+
var intersects = this._poly.newLatLngIntersects(this._poly.getLatLngs()[0], true);
|
348
|
+
|
349
|
+
if ((!this.options.allowIntersection && intersects) || !this._shapeIsValid()) {
|
350
|
+
this._showErrorTooltip();
|
351
|
+
return;
|
352
|
+
}
|
353
|
+
|
354
|
+
this._fireCreatedEvent();
|
355
|
+
this.disable();
|
356
|
+
if (this.options.repeatMode) {
|
357
|
+
this.enable();
|
358
|
+
}
|
359
|
+
},
|
360
|
+
|
361
|
+
//Called to verify the shape is valid when the user tries to finish it
|
362
|
+
//Return false if the shape is not valid
|
363
|
+
_shapeIsValid: function () {
|
364
|
+
return true;
|
365
|
+
},
|
366
|
+
|
367
|
+
_onZoomEnd: function () {
|
368
|
+
this._updateGuide();
|
369
|
+
},
|
370
|
+
|
371
|
+
_onMouseMove: function (e) {
|
372
|
+
var newPos = e.layerPoint,
|
373
|
+
latlng = e.latlng;
|
374
|
+
|
375
|
+
// Save latlng
|
376
|
+
// should this be moved to _updateGuide() ?
|
377
|
+
this._currentLatLng = latlng;
|
378
|
+
|
379
|
+
this._updateTooltip(latlng);
|
380
|
+
|
381
|
+
// Update the guide line
|
382
|
+
this._updateGuide(newPos);
|
383
|
+
|
384
|
+
// Update the mouse marker position
|
385
|
+
this._mouseMarker.setLatLng(latlng);
|
386
|
+
|
387
|
+
L.DomEvent.preventDefault(e.originalEvent);
|
388
|
+
},
|
389
|
+
|
390
|
+
_vertexChanged: function (latlng, added) {
|
391
|
+
this._updateFinishHandler();
|
392
|
+
|
393
|
+
this._updateRunningMeasure(latlng, added);
|
394
|
+
|
395
|
+
this._clearGuides();
|
396
|
+
|
397
|
+
this._updateTooltip();
|
398
|
+
},
|
399
|
+
|
400
|
+
_onMouseDown: function (e) {
|
401
|
+
var originalEvent = e.originalEvent;
|
402
|
+
this._mouseDownOrigin = L.point(originalEvent.clientX, originalEvent.clientY);
|
403
|
+
},
|
404
|
+
|
405
|
+
_onMouseUp: function (e) {
|
406
|
+
if (this._mouseDownOrigin) {
|
407
|
+
// We detect clicks within a certain tolerance, otherwise let it
|
408
|
+
// be interpreted as a drag by the map
|
409
|
+
var distance = L.point(e.originalEvent.clientX, e.originalEvent.clientY)
|
410
|
+
.distanceTo(this._mouseDownOrigin);
|
411
|
+
if (Math.abs(distance) < 9 * (window.devicePixelRatio || 1)) {
|
412
|
+
this.addVertex(e.latlng);
|
413
|
+
}
|
414
|
+
}
|
415
|
+
this._mouseDownOrigin = null;
|
416
|
+
},
|
417
|
+
|
418
|
+
_updateFinishHandler: function () {
|
419
|
+
var markerCount = this._markers.length;
|
420
|
+
// The last marker should have a click handler to close the polyline
|
421
|
+
if (markerCount > 1) {
|
422
|
+
this._markers[markerCount - 1].on('click', this._finishShape, this);
|
423
|
+
}
|
424
|
+
|
425
|
+
// Remove the old marker click handler (as only the last point should close the polyline)
|
426
|
+
if (markerCount > 2) {
|
427
|
+
this._markers[markerCount - 2].off('click', this._finishShape, this);
|
428
|
+
}
|
429
|
+
},
|
430
|
+
|
431
|
+
_createMarker: function (latlng) {
|
432
|
+
var marker = new L.Marker(latlng, {
|
433
|
+
icon: this.options.icon,
|
434
|
+
zIndexOffset: this.options.zIndexOffset * 2
|
435
|
+
});
|
436
|
+
|
437
|
+
this._markerGroup.addLayer(marker);
|
438
|
+
|
439
|
+
return marker;
|
440
|
+
},
|
441
|
+
|
442
|
+
_updateGuide: function (newPos) {
|
443
|
+
var markerCount = this._markers.length;
|
444
|
+
|
445
|
+
if (markerCount > 0) {
|
446
|
+
newPos = newPos || this._map.latLngToLayerPoint(this._currentLatLng);
|
447
|
+
|
448
|
+
// draw the guide line
|
449
|
+
this._clearGuides();
|
450
|
+
this._drawGuide(
|
451
|
+
this._map.latLngToLayerPoint(this._markers[markerCount - 1].getLatLng()),
|
452
|
+
newPos
|
453
|
+
);
|
454
|
+
}
|
455
|
+
},
|
456
|
+
|
457
|
+
_updateTooltip: function (latLng) {
|
458
|
+
var text = this._getTooltipText();
|
459
|
+
|
460
|
+
if (latLng) {
|
461
|
+
this._tooltip.updatePosition(latLng);
|
462
|
+
}
|
463
|
+
|
464
|
+
if (!this._errorShown) {
|
465
|
+
this._tooltip.updateContent(text);
|
466
|
+
}
|
467
|
+
},
|
468
|
+
|
469
|
+
_drawGuide: function (pointA, pointB) {
|
470
|
+
var length = Math.floor(Math.sqrt(Math.pow((pointB.x - pointA.x), 2) + Math.pow((pointB.y - pointA.y), 2))),
|
471
|
+
guidelineDistance = this.options.guidelineDistance,
|
472
|
+
maxGuideLineLength = this.options.maxGuideLineLength,
|
473
|
+
// Only draw a guideline with a max length
|
474
|
+
i = length > maxGuideLineLength ? length - maxGuideLineLength : guidelineDistance,
|
475
|
+
fraction,
|
476
|
+
dashPoint,
|
477
|
+
dash;
|
478
|
+
|
479
|
+
//create the guides container if we haven't yet
|
480
|
+
if (!this._guidesContainer) {
|
481
|
+
this._guidesContainer = L.DomUtil.create('div', 'leaflet-draw-guides', this._overlayPane);
|
482
|
+
}
|
483
|
+
|
484
|
+
//draw a dash every GuildeLineDistance
|
485
|
+
for (; i < length; i += this.options.guidelineDistance) {
|
486
|
+
//work out fraction along line we are
|
487
|
+
fraction = i / length;
|
488
|
+
|
489
|
+
//calculate new x,y point
|
490
|
+
dashPoint = {
|
491
|
+
x: Math.floor((pointA.x * (1 - fraction)) + (fraction * pointB.x)),
|
492
|
+
y: Math.floor((pointA.y * (1 - fraction)) + (fraction * pointB.y))
|
493
|
+
};
|
494
|
+
|
495
|
+
//add guide dash to guide container
|
496
|
+
dash = L.DomUtil.create('div', 'leaflet-draw-guide-dash', this._guidesContainer);
|
497
|
+
dash.style.backgroundColor =
|
498
|
+
!this._errorShown ? this.options.shapeOptions.color : this.options.drawError.color;
|
499
|
+
|
500
|
+
L.DomUtil.setPosition(dash, dashPoint);
|
501
|
+
}
|
502
|
+
},
|
503
|
+
|
504
|
+
_updateGuideColor: function (color) {
|
505
|
+
if (this._guidesContainer) {
|
506
|
+
for (var i = 0, l = this._guidesContainer.childNodes.length; i < l; i++) {
|
507
|
+
this._guidesContainer.childNodes[i].style.backgroundColor = color;
|
508
|
+
}
|
509
|
+
}
|
510
|
+
},
|
511
|
+
|
512
|
+
// removes all child elements (guide dashes) from the guides container
|
513
|
+
_clearGuides: function () {
|
514
|
+
if (this._guidesContainer) {
|
515
|
+
while (this._guidesContainer.firstChild) {
|
516
|
+
this._guidesContainer.removeChild(this._guidesContainer.firstChild);
|
517
|
+
}
|
518
|
+
}
|
519
|
+
},
|
520
|
+
|
521
|
+
_getTooltipText: function () {
|
522
|
+
var showLength = this.options.showLength,
|
523
|
+
labelText, distanceStr;
|
524
|
+
|
525
|
+
if (this._markers.length === 0) {
|
526
|
+
labelText = {
|
527
|
+
text: L.drawLocal.draw.handlers.polyline.tooltip.start
|
528
|
+
};
|
529
|
+
} else {
|
530
|
+
distanceStr = showLength ? this._getMeasurementString() : '';
|
531
|
+
|
532
|
+
if (this._markers.length === 1) {
|
533
|
+
labelText = {
|
534
|
+
text: L.drawLocal.draw.handlers.polyline.tooltip.cont,
|
535
|
+
subtext: distanceStr
|
536
|
+
};
|
537
|
+
} else {
|
538
|
+
labelText = {
|
539
|
+
text: L.drawLocal.draw.handlers.polyline.tooltip.end,
|
540
|
+
subtext: distanceStr
|
541
|
+
};
|
542
|
+
}
|
543
|
+
}
|
544
|
+
return labelText;
|
545
|
+
},
|
546
|
+
|
547
|
+
_updateRunningMeasure: function (latlng, added) {
|
548
|
+
var markersLength = this._markers.length,
|
549
|
+
previousMarkerIndex, distance;
|
550
|
+
|
551
|
+
if (this._markers.length === 1) {
|
552
|
+
this._measurementRunningTotal = 0;
|
553
|
+
} else {
|
554
|
+
previousMarkerIndex = markersLength - (added ? 2 : 1);
|
555
|
+
distance = latlng.distanceTo(this._markers[previousMarkerIndex].getLatLng());
|
556
|
+
|
557
|
+
this._measurementRunningTotal += distance * (added ? 1 : -1);
|
558
|
+
}
|
559
|
+
},
|
560
|
+
|
561
|
+
_getMeasurementString: function () {
|
562
|
+
var currentLatLng = this._currentLatLng,
|
563
|
+
previousLatLng = this._markers[this._markers.length - 1].getLatLng(),
|
564
|
+
distance;
|
565
|
+
|
566
|
+
// calculate the distance from the last fixed point to the mouse position
|
567
|
+
distance = this._measurementRunningTotal + currentLatLng.distanceTo(previousLatLng);
|
568
|
+
|
569
|
+
return L.GeometryUtil.readableDistance(distance, this.options.metric);
|
570
|
+
},
|
571
|
+
|
572
|
+
_showErrorTooltip: function () {
|
573
|
+
this._errorShown = true;
|
574
|
+
|
575
|
+
// Update tooltip
|
576
|
+
this._tooltip
|
577
|
+
.showAsError()
|
578
|
+
.updateContent({ text: this.options.drawError.message });
|
579
|
+
|
580
|
+
// Update shape
|
581
|
+
this._updateGuideColor(this.options.drawError.color);
|
582
|
+
this._poly.setStyle({ color: this.options.drawError.color });
|
583
|
+
|
584
|
+
// Hide the error after 2 seconds
|
585
|
+
this._clearHideErrorTimeout();
|
586
|
+
this._hideErrorTimeout = setTimeout(L.Util.bind(this._hideErrorTooltip, this), this.options.drawError.timeout);
|
587
|
+
},
|
588
|
+
|
589
|
+
_hideErrorTooltip: function () {
|
590
|
+
this._errorShown = false;
|
591
|
+
|
592
|
+
this._clearHideErrorTimeout();
|
593
|
+
|
594
|
+
// Revert tooltip
|
595
|
+
this._tooltip
|
596
|
+
.removeError()
|
597
|
+
.updateContent(this._getTooltipText());
|
598
|
+
|
599
|
+
// Revert shape
|
600
|
+
this._updateGuideColor(this.options.shapeOptions.color);
|
601
|
+
this._poly.setStyle({ color: this.options.shapeOptions.color });
|
602
|
+
},
|
603
|
+
|
604
|
+
_clearHideErrorTimeout: function () {
|
605
|
+
if (this._hideErrorTimeout) {
|
606
|
+
clearTimeout(this._hideErrorTimeout);
|
607
|
+
this._hideErrorTimeout = null;
|
608
|
+
}
|
609
|
+
},
|
610
|
+
|
611
|
+
_cleanUpShape: function () {
|
612
|
+
if (this._markers.length > 1) {
|
613
|
+
this._markers[this._markers.length - 1].off('click', this._finishShape, this);
|
614
|
+
}
|
615
|
+
},
|
616
|
+
|
617
|
+
_fireCreatedEvent: function () {
|
618
|
+
var poly = new this.Poly(this._poly.getLatLngs(), this.options.shapeOptions);
|
619
|
+
L.Draw.Feature.prototype._fireCreatedEvent.call(this, poly);
|
620
|
+
}
|
621
|
+
});
|
622
|
+
|
623
|
+
|
624
|
+
L.Draw.Polygon = L.Draw.Polyline.extend({
|
625
|
+
statics: {
|
626
|
+
TYPE: 'polygon'
|
627
|
+
},
|
628
|
+
|
629
|
+
Poly: L.Polygon,
|
630
|
+
|
631
|
+
options: {
|
632
|
+
showArea: false,
|
633
|
+
shapeOptions: {
|
634
|
+
stroke: true,
|
635
|
+
color: '#f06eaa',
|
636
|
+
weight: 4,
|
637
|
+
opacity: 0.5,
|
638
|
+
fill: true,
|
639
|
+
fillColor: null, //same as color by default
|
640
|
+
fillOpacity: 0.2,
|
641
|
+
clickable: true
|
642
|
+
}
|
643
|
+
},
|
644
|
+
|
645
|
+
initialize: function (map, options) {
|
646
|
+
L.Draw.Polyline.prototype.initialize.call(this, map, options);
|
647
|
+
|
648
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
649
|
+
this.type = L.Draw.Polygon.TYPE;
|
650
|
+
},
|
651
|
+
|
652
|
+
_updateFinishHandler: function () {
|
653
|
+
var markerCount = this._markers.length;
|
654
|
+
|
655
|
+
// The first marker should have a click handler to close the polygon
|
656
|
+
if (markerCount === 1) {
|
657
|
+
this._markers[0].on('click', this._finishShape, this);
|
658
|
+
}
|
659
|
+
|
660
|
+
// Add and update the double click handler
|
661
|
+
if (markerCount > 2) {
|
662
|
+
this._markers[markerCount - 1].on('dblclick', this._finishShape, this);
|
663
|
+
// Only need to remove handler if has been added before
|
664
|
+
if (markerCount > 3) {
|
665
|
+
this._markers[markerCount - 2].off('dblclick', this._finishShape, this);
|
666
|
+
}
|
667
|
+
}
|
668
|
+
},
|
669
|
+
|
670
|
+
_getTooltipText: function () {
|
671
|
+
var text, subtext;
|
672
|
+
|
673
|
+
if (this._markers.length === 0) {
|
674
|
+
text = L.drawLocal.draw.handlers.polygon.tooltip.start;
|
675
|
+
} else if (this._markers.length < 3) {
|
676
|
+
text = L.drawLocal.draw.handlers.polygon.tooltip.cont;
|
677
|
+
} else {
|
678
|
+
text = L.drawLocal.draw.handlers.polygon.tooltip.end;
|
679
|
+
subtext = this._getMeasurementString();
|
680
|
+
}
|
681
|
+
|
682
|
+
return {
|
683
|
+
text: text,
|
684
|
+
subtext: subtext
|
685
|
+
};
|
686
|
+
},
|
687
|
+
|
688
|
+
_getMeasurementString: function () {
|
689
|
+
var area = this._area;
|
690
|
+
|
691
|
+
if (!area) {
|
692
|
+
return null;
|
693
|
+
}
|
694
|
+
|
695
|
+
return L.GeometryUtil.readableArea(area, this.options.metric);
|
696
|
+
},
|
697
|
+
|
698
|
+
_shapeIsValid: function () {
|
699
|
+
return this._markers.length >= 3;
|
700
|
+
},
|
701
|
+
|
702
|
+
_vertexChanged: function (latlng, added) {
|
703
|
+
var latLngs;
|
704
|
+
|
705
|
+
// Check to see if we should show the area
|
706
|
+
if (!this.options.allowIntersection && this.options.showArea) {
|
707
|
+
latLngs = this._poly.getLatLngs();
|
708
|
+
|
709
|
+
this._area = L.GeometryUtil.geodesicArea(latLngs);
|
710
|
+
}
|
711
|
+
|
712
|
+
L.Draw.Polyline.prototype._vertexChanged.call(this, latlng, added);
|
713
|
+
},
|
714
|
+
|
715
|
+
_cleanUpShape: function () {
|
716
|
+
var markerCount = this._markers.length;
|
717
|
+
|
718
|
+
if (markerCount > 0) {
|
719
|
+
this._markers[0].off('click', this._finishShape, this);
|
720
|
+
|
721
|
+
if (markerCount > 2) {
|
722
|
+
this._markers[markerCount - 1].off('dblclick', this._finishShape, this);
|
723
|
+
}
|
724
|
+
}
|
725
|
+
}
|
726
|
+
});
|
727
|
+
|
728
|
+
|
729
|
+
L.SimpleShape = {};
|
730
|
+
|
731
|
+
L.Draw.SimpleShape = L.Draw.Feature.extend({
|
732
|
+
options: {
|
733
|
+
repeatMode: false
|
734
|
+
},
|
735
|
+
|
736
|
+
initialize: function (map, options) {
|
737
|
+
this._endLabelText = L.drawLocal.draw.handlers.simpleshape.tooltip.end;
|
738
|
+
|
739
|
+
L.Draw.Feature.prototype.initialize.call(this, map, options);
|
740
|
+
},
|
741
|
+
|
742
|
+
addHooks: function () {
|
743
|
+
L.Draw.Feature.prototype.addHooks.call(this);
|
744
|
+
if (this._map) {
|
745
|
+
this._mapDraggable = this._map.dragging.enabled();
|
746
|
+
|
747
|
+
if (this._mapDraggable) {
|
748
|
+
this._map.dragging.disable();
|
749
|
+
}
|
750
|
+
|
751
|
+
//TODO refactor: move cursor to styles
|
752
|
+
this._container.style.cursor = 'crosshair';
|
753
|
+
|
754
|
+
this._tooltip.updateContent({ text: this._initialLabelText });
|
755
|
+
|
756
|
+
this._map
|
757
|
+
.on('mousedown', this._onMouseDown, this)
|
758
|
+
.on('mousemove', this._onMouseMove, this);
|
759
|
+
}
|
760
|
+
},
|
761
|
+
|
762
|
+
removeHooks: function () {
|
763
|
+
L.Draw.Feature.prototype.removeHooks.call(this);
|
764
|
+
if (this._map) {
|
765
|
+
if (this._mapDraggable) {
|
766
|
+
this._map.dragging.enable();
|
767
|
+
}
|
768
|
+
|
769
|
+
//TODO refactor: move cursor to styles
|
770
|
+
this._container.style.cursor = '';
|
771
|
+
|
772
|
+
this._map
|
773
|
+
.off('mousedown', this._onMouseDown, this)
|
774
|
+
.off('mousemove', this._onMouseMove, this);
|
775
|
+
|
776
|
+
L.DomEvent.off(document, 'mouseup', this._onMouseUp, this);
|
777
|
+
|
778
|
+
// If the box element doesn't exist they must not have moved the mouse, so don't need to destroy/return
|
779
|
+
if (this._shape) {
|
780
|
+
this._map.removeLayer(this._shape);
|
781
|
+
delete this._shape;
|
782
|
+
}
|
783
|
+
}
|
784
|
+
this._isDrawing = false;
|
785
|
+
},
|
786
|
+
|
787
|
+
_getTooltipText: function () {
|
788
|
+
return {
|
789
|
+
text: this._endLabelText
|
790
|
+
};
|
791
|
+
},
|
792
|
+
|
793
|
+
_onMouseDown: function (e) {
|
794
|
+
this._isDrawing = true;
|
795
|
+
this._startLatLng = e.latlng;
|
796
|
+
|
797
|
+
L.DomEvent
|
798
|
+
.on(document, 'mouseup', this._onMouseUp, this)
|
799
|
+
.preventDefault(e.originalEvent);
|
800
|
+
},
|
801
|
+
|
802
|
+
_onMouseMove: function (e) {
|
803
|
+
var latlng = e.latlng;
|
804
|
+
|
805
|
+
this._tooltip.updatePosition(latlng);
|
806
|
+
if (this._isDrawing) {
|
807
|
+
this._tooltip.updateContent(this._getTooltipText());
|
808
|
+
this._drawShape(latlng);
|
809
|
+
}
|
810
|
+
},
|
811
|
+
|
812
|
+
_onMouseUp: function () {
|
813
|
+
if (this._shape) {
|
814
|
+
this._fireCreatedEvent();
|
815
|
+
}
|
816
|
+
|
817
|
+
this.disable();
|
818
|
+
if (this.options.repeatMode) {
|
819
|
+
this.enable();
|
820
|
+
}
|
821
|
+
}
|
822
|
+
});
|
823
|
+
|
824
|
+
L.Draw.Rectangle = L.Draw.SimpleShape.extend({
|
825
|
+
statics: {
|
826
|
+
TYPE: 'rectangle'
|
827
|
+
},
|
828
|
+
|
829
|
+
options: {
|
830
|
+
shapeOptions: {
|
831
|
+
stroke: true,
|
832
|
+
color: '#f06eaa',
|
833
|
+
weight: 4,
|
834
|
+
opacity: 0.5,
|
835
|
+
fill: true,
|
836
|
+
fillColor: null, //same as color by default
|
837
|
+
fillOpacity: 0.2,
|
838
|
+
clickable: true
|
839
|
+
},
|
840
|
+
metric: true // Whether to use the metric meaurement system or imperial
|
841
|
+
},
|
842
|
+
|
843
|
+
initialize: function (map, options) {
|
844
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
845
|
+
this.type = L.Draw.Rectangle.TYPE;
|
846
|
+
|
847
|
+
this._initialLabelText = L.drawLocal.draw.handlers.rectangle.tooltip.start;
|
848
|
+
|
849
|
+
L.Draw.SimpleShape.prototype.initialize.call(this, map, options);
|
850
|
+
},
|
851
|
+
|
852
|
+
_drawShape: function (latlng) {
|
853
|
+
if (!this._shape) {
|
854
|
+
this._shape = new L.Rectangle(new L.LatLngBounds(this._startLatLng, latlng), this.options.shapeOptions);
|
855
|
+
this._map.addLayer(this._shape);
|
856
|
+
} else {
|
857
|
+
this._shape.setBounds(new L.LatLngBounds(this._startLatLng, latlng));
|
858
|
+
}
|
859
|
+
},
|
860
|
+
|
861
|
+
_fireCreatedEvent: function () {
|
862
|
+
var rectangle = new L.Rectangle(this._shape.getBounds(), this.options.shapeOptions);
|
863
|
+
L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this, rectangle);
|
864
|
+
},
|
865
|
+
|
866
|
+
_getTooltipText: function () {
|
867
|
+
var tooltipText = L.Draw.SimpleShape.prototype._getTooltipText.call(this),
|
868
|
+
shape = this._shape,
|
869
|
+
latLngs, area, subtext;
|
870
|
+
|
871
|
+
if (shape) {
|
872
|
+
latLngs = this._shape.getLatLngs();
|
873
|
+
area = L.GeometryUtil.geodesicArea(latLngs);
|
874
|
+
subtext = L.GeometryUtil.readableArea(area, this.options.metric);
|
875
|
+
}
|
876
|
+
|
877
|
+
return {
|
878
|
+
text: tooltipText.text,
|
879
|
+
subtext: subtext
|
880
|
+
};
|
881
|
+
}
|
882
|
+
});
|
883
|
+
|
884
|
+
|
885
|
+
L.Draw.Circle = L.Draw.SimpleShape.extend({
|
886
|
+
statics: {
|
887
|
+
TYPE: 'circle'
|
888
|
+
},
|
889
|
+
|
890
|
+
options: {
|
891
|
+
shapeOptions: {
|
892
|
+
stroke: true,
|
893
|
+
color: '#f06eaa',
|
894
|
+
weight: 4,
|
895
|
+
opacity: 0.5,
|
896
|
+
fill: true,
|
897
|
+
fillColor: null, //same as color by default
|
898
|
+
fillOpacity: 0.2,
|
899
|
+
clickable: true
|
900
|
+
},
|
901
|
+
showRadius: true,
|
902
|
+
metric: true // Whether to use the metric meaurement system or imperial
|
903
|
+
},
|
904
|
+
|
905
|
+
initialize: function (map, options) {
|
906
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
907
|
+
this.type = L.Draw.Circle.TYPE;
|
908
|
+
|
909
|
+
this._initialLabelText = L.drawLocal.draw.handlers.circle.tooltip.start;
|
910
|
+
|
911
|
+
L.Draw.SimpleShape.prototype.initialize.call(this, map, options);
|
912
|
+
},
|
913
|
+
|
914
|
+
_drawShape: function (latlng) {
|
915
|
+
if (!this._shape) {
|
916
|
+
this._shape = new L.Circle(this._startLatLng, this._startLatLng.distanceTo(latlng), this.options.shapeOptions);
|
917
|
+
this._map.addLayer(this._shape);
|
918
|
+
} else {
|
919
|
+
this._shape.setRadius(this._startLatLng.distanceTo(latlng));
|
920
|
+
}
|
921
|
+
},
|
922
|
+
|
923
|
+
_fireCreatedEvent: function () {
|
924
|
+
var circle = new L.Circle(this._startLatLng, this._shape.getRadius(), this.options.shapeOptions);
|
925
|
+
L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this, circle);
|
926
|
+
},
|
927
|
+
|
928
|
+
_onMouseMove: function (e) {
|
929
|
+
var latlng = e.latlng,
|
930
|
+
showRadius = this.options.showRadius,
|
931
|
+
useMetric = this.options.metric,
|
932
|
+
radius;
|
933
|
+
|
934
|
+
this._tooltip.updatePosition(latlng);
|
935
|
+
if (this._isDrawing) {
|
936
|
+
this._drawShape(latlng);
|
937
|
+
|
938
|
+
// Get the new radius (rounded to 1 dp)
|
939
|
+
radius = this._shape.getRadius().toFixed(1);
|
940
|
+
|
941
|
+
this._tooltip.updateContent({
|
942
|
+
text: this._endLabelText,
|
943
|
+
subtext: showRadius ? L.drawLocal.draw.handlers.circle.radius + ': ' + L.GeometryUtil.readableDistance(radius, useMetric) : ''
|
944
|
+
});
|
945
|
+
}
|
946
|
+
}
|
947
|
+
});
|
948
|
+
|
949
|
+
|
950
|
+
L.Draw.Marker = L.Draw.Feature.extend({
|
951
|
+
statics: {
|
952
|
+
TYPE: 'marker'
|
953
|
+
},
|
954
|
+
|
955
|
+
options: {
|
956
|
+
icon: new L.Icon.Default(),
|
957
|
+
repeatMode: false,
|
958
|
+
zIndexOffset: 2000 // This should be > than the highest z-index any markers
|
959
|
+
},
|
960
|
+
|
961
|
+
initialize: function (map, options) {
|
962
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
963
|
+
this.type = L.Draw.Marker.TYPE;
|
964
|
+
|
965
|
+
L.Draw.Feature.prototype.initialize.call(this, map, options);
|
966
|
+
},
|
967
|
+
|
968
|
+
addHooks: function () {
|
969
|
+
L.Draw.Feature.prototype.addHooks.call(this);
|
970
|
+
|
971
|
+
if (this._map) {
|
972
|
+
this._tooltip.updateContent({ text: L.drawLocal.draw.handlers.marker.tooltip.start });
|
973
|
+
|
974
|
+
// Same mouseMarker as in Draw.Polyline
|
975
|
+
if (!this._mouseMarker) {
|
976
|
+
this._mouseMarker = L.marker(this._map.getCenter(), {
|
977
|
+
icon: L.divIcon({
|
978
|
+
className: 'leaflet-mouse-marker',
|
979
|
+
iconAnchor: [20, 20],
|
980
|
+
iconSize: [40, 40]
|
981
|
+
}),
|
982
|
+
opacity: 0,
|
983
|
+
zIndexOffset: this.options.zIndexOffset
|
984
|
+
});
|
985
|
+
}
|
986
|
+
|
987
|
+
this._mouseMarker
|
988
|
+
.on('click', this._onClick, this)
|
989
|
+
.addTo(this._map);
|
990
|
+
|
991
|
+
this._map.on('mousemove', this._onMouseMove, this);
|
992
|
+
}
|
993
|
+
},
|
994
|
+
|
995
|
+
removeHooks: function () {
|
996
|
+
L.Draw.Feature.prototype.removeHooks.call(this);
|
997
|
+
|
998
|
+
if (this._map) {
|
999
|
+
if (this._marker) {
|
1000
|
+
this._marker.off('click', this._onClick, this);
|
1001
|
+
this._map
|
1002
|
+
.off('click', this._onClick, this)
|
1003
|
+
.removeLayer(this._marker);
|
1004
|
+
delete this._marker;
|
1005
|
+
}
|
1006
|
+
|
1007
|
+
this._mouseMarker.off('click', this._onClick, this);
|
1008
|
+
this._map.removeLayer(this._mouseMarker);
|
1009
|
+
delete this._mouseMarker;
|
1010
|
+
|
1011
|
+
this._map.off('mousemove', this._onMouseMove, this);
|
1012
|
+
}
|
1013
|
+
},
|
1014
|
+
|
1015
|
+
_onMouseMove: function (e) {
|
1016
|
+
var latlng = e.latlng;
|
1017
|
+
|
1018
|
+
this._tooltip.updatePosition(latlng);
|
1019
|
+
this._mouseMarker.setLatLng(latlng);
|
1020
|
+
|
1021
|
+
if (!this._marker) {
|
1022
|
+
this._marker = new L.Marker(latlng, {
|
1023
|
+
icon: this.options.icon,
|
1024
|
+
zIndexOffset: this.options.zIndexOffset
|
1025
|
+
});
|
1026
|
+
// Bind to both marker and map to make sure we get the click event.
|
1027
|
+
this._marker.on('click', this._onClick, this);
|
1028
|
+
this._map
|
1029
|
+
.on('click', this._onClick, this)
|
1030
|
+
.addLayer(this._marker);
|
1031
|
+
}
|
1032
|
+
else {
|
1033
|
+
latlng = this._mouseMarker.getLatLng();
|
1034
|
+
this._marker.setLatLng(latlng);
|
1035
|
+
}
|
1036
|
+
},
|
1037
|
+
|
1038
|
+
_onClick: function () {
|
1039
|
+
this._fireCreatedEvent();
|
1040
|
+
|
1041
|
+
this.disable();
|
1042
|
+
if (this.options.repeatMode) {
|
1043
|
+
this.enable();
|
1044
|
+
}
|
1045
|
+
},
|
1046
|
+
|
1047
|
+
_fireCreatedEvent: function () {
|
1048
|
+
var marker = new L.Marker(this._marker.getLatLng(), { icon: this.options.icon });
|
1049
|
+
L.Draw.Feature.prototype._fireCreatedEvent.call(this, marker);
|
1050
|
+
}
|
1051
|
+
});
|
1052
|
+
|
1053
|
+
|
1054
|
+
L.Edit = L.Edit || {};
|
1055
|
+
|
1056
|
+
L.Edit.Marker = L.Handler.extend({
|
1057
|
+
initialize: function (marker, options) {
|
1058
|
+
this._marker = marker;
|
1059
|
+
L.setOptions(this, options);
|
1060
|
+
},
|
1061
|
+
|
1062
|
+
addHooks: function () {
|
1063
|
+
var marker = this._marker;
|
1064
|
+
|
1065
|
+
marker.dragging.enable();
|
1066
|
+
marker.on('dragend', this._onDragEnd, marker);
|
1067
|
+
this._toggleMarkerHighlight();
|
1068
|
+
},
|
1069
|
+
|
1070
|
+
removeHooks: function () {
|
1071
|
+
var marker = this._marker;
|
1072
|
+
|
1073
|
+
marker.dragging.disable();
|
1074
|
+
marker.off('dragend', this._onDragEnd, marker);
|
1075
|
+
this._toggleMarkerHighlight();
|
1076
|
+
},
|
1077
|
+
|
1078
|
+
_onDragEnd: function (e) {
|
1079
|
+
var layer = e.target;
|
1080
|
+
layer.edited = true;
|
1081
|
+
},
|
1082
|
+
|
1083
|
+
_toggleMarkerHighlight: function () {
|
1084
|
+
|
1085
|
+
// Don't do anything if this layer is a marker but doesn't have an icon. Markers
|
1086
|
+
// should usually have icons. If using Leaflet.draw with Leafler.markercluster there
|
1087
|
+
// is a chance that a marker doesn't.
|
1088
|
+
if (!this._icon) {
|
1089
|
+
return;
|
1090
|
+
}
|
1091
|
+
|
1092
|
+
// This is quite naughty, but I don't see another way of doing it. (short of setting a new icon)
|
1093
|
+
var icon = this._icon;
|
1094
|
+
|
1095
|
+
icon.style.display = 'none';
|
1096
|
+
|
1097
|
+
if (L.DomUtil.hasClass(icon, 'leaflet-edit-marker-selected')) {
|
1098
|
+
L.DomUtil.removeClass(icon, 'leaflet-edit-marker-selected');
|
1099
|
+
// Offset as the border will make the icon move.
|
1100
|
+
this._offsetMarker(icon, -4);
|
1101
|
+
|
1102
|
+
} else {
|
1103
|
+
L.DomUtil.addClass(icon, 'leaflet-edit-marker-selected');
|
1104
|
+
// Offset as the border will make the icon move.
|
1105
|
+
this._offsetMarker(icon, 4);
|
1106
|
+
}
|
1107
|
+
|
1108
|
+
icon.style.display = '';
|
1109
|
+
},
|
1110
|
+
|
1111
|
+
_offsetMarker: function (icon, offset) {
|
1112
|
+
var iconMarginTop = parseInt(icon.style.marginTop, 10) - offset,
|
1113
|
+
iconMarginLeft = parseInt(icon.style.marginLeft, 10) - offset;
|
1114
|
+
|
1115
|
+
icon.style.marginTop = iconMarginTop + 'px';
|
1116
|
+
icon.style.marginLeft = iconMarginLeft + 'px';
|
1117
|
+
}
|
1118
|
+
});
|
1119
|
+
|
1120
|
+
L.Marker.addInitHook(function () {
|
1121
|
+
if (L.Edit.Marker) {
|
1122
|
+
this.editing = new L.Edit.Marker(this);
|
1123
|
+
|
1124
|
+
if (this.options.editable) {
|
1125
|
+
this.editing.enable();
|
1126
|
+
}
|
1127
|
+
}
|
1128
|
+
});
|
1129
|
+
|
1130
|
+
|
1131
|
+
L.Edit = L.Edit || {};
|
1132
|
+
|
1133
|
+
/*
|
1134
|
+
* L.Edit.Poly is an editing handler for polylines and polygons.
|
1135
|
+
*/
|
1136
|
+
|
1137
|
+
L.Edit.Poly = L.Handler.extend({
|
1138
|
+
options: {
|
1139
|
+
icon: new L.DivIcon({
|
1140
|
+
iconSize: new L.Point(8, 8),
|
1141
|
+
className: 'leaflet-div-icon leaflet-editing-icon'
|
1142
|
+
})
|
1143
|
+
},
|
1144
|
+
|
1145
|
+
initialize: function (poly, options) {
|
1146
|
+
this._poly = poly;
|
1147
|
+
L.setOptions(this, options);
|
1148
|
+
},
|
1149
|
+
|
1150
|
+
addHooks: function () {
|
1151
|
+
var poly = this._poly;
|
1152
|
+
|
1153
|
+
if (!(poly instanceof L.Polygon)) {
|
1154
|
+
poly.options.editing.fill = false;
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
poly.setStyle(poly.options.editing);
|
1158
|
+
|
1159
|
+
if (this._poly._map) {
|
1160
|
+
if (!this._markerGroup) {
|
1161
|
+
this._initMarkers();
|
1162
|
+
}
|
1163
|
+
this._poly._map.addLayer(this._markerGroup);
|
1164
|
+
}
|
1165
|
+
},
|
1166
|
+
|
1167
|
+
removeHooks: function () {
|
1168
|
+
var poly = this._poly;
|
1169
|
+
|
1170
|
+
poly.setStyle(poly.options.original);
|
1171
|
+
|
1172
|
+
if (poly._map) {
|
1173
|
+
poly._map.removeLayer(this._markerGroup);
|
1174
|
+
delete this._markerGroup;
|
1175
|
+
delete this._markers;
|
1176
|
+
}
|
1177
|
+
},
|
1178
|
+
|
1179
|
+
updateMarkers: function () {
|
1180
|
+
this._markerGroup.clearLayers();
|
1181
|
+
this._initMarkers();
|
1182
|
+
},
|
1183
|
+
|
1184
|
+
_initMarkers: function () {
|
1185
|
+
if (!this._markerGroup) {
|
1186
|
+
this._markerGroup = new L.LayerGroup();
|
1187
|
+
}
|
1188
|
+
this._markers = [];
|
1189
|
+
|
1190
|
+
var latlngs = this._poly._latlngs,
|
1191
|
+
i, j, len, marker;
|
1192
|
+
|
1193
|
+
// TODO refactor holes implementation in Polygon to support it here
|
1194
|
+
|
1195
|
+
for (i = 0, len = latlngs.length; i < len; i++) {
|
1196
|
+
|
1197
|
+
marker = this._createMarker(latlngs[i], i);
|
1198
|
+
marker.on('click', this._onMarkerClick, this);
|
1199
|
+
this._markers.push(marker);
|
1200
|
+
}
|
1201
|
+
|
1202
|
+
var markerLeft, markerRight;
|
1203
|
+
|
1204
|
+
for (i = 0, j = len - 1; i < len; j = i++) {
|
1205
|
+
if (i === 0 && !(L.Polygon && (this._poly instanceof L.Polygon))) {
|
1206
|
+
continue;
|
1207
|
+
}
|
1208
|
+
|
1209
|
+
markerLeft = this._markers[j];
|
1210
|
+
markerRight = this._markers[i];
|
1211
|
+
|
1212
|
+
this._createMiddleMarker(markerLeft, markerRight);
|
1213
|
+
this._updatePrevNext(markerLeft, markerRight);
|
1214
|
+
}
|
1215
|
+
},
|
1216
|
+
|
1217
|
+
_createMarker: function (latlng, index) {
|
1218
|
+
var marker = new L.Marker(latlng, {
|
1219
|
+
draggable: true,
|
1220
|
+
icon: this.options.icon
|
1221
|
+
});
|
1222
|
+
|
1223
|
+
marker._origLatLng = latlng;
|
1224
|
+
marker._index = index;
|
1225
|
+
|
1226
|
+
marker.on('drag', this._onMarkerDrag, this);
|
1227
|
+
marker.on('dragend', this._fireEdit, this);
|
1228
|
+
|
1229
|
+
this._markerGroup.addLayer(marker);
|
1230
|
+
|
1231
|
+
return marker;
|
1232
|
+
},
|
1233
|
+
|
1234
|
+
_removeMarker: function (marker) {
|
1235
|
+
var i = marker._index;
|
1236
|
+
|
1237
|
+
this._markerGroup.removeLayer(marker);
|
1238
|
+
this._markers.splice(i, 1);
|
1239
|
+
this._poly.spliceLatLngs(i, 1);
|
1240
|
+
this._updateIndexes(i, -1);
|
1241
|
+
|
1242
|
+
marker
|
1243
|
+
.off('drag', this._onMarkerDrag, this)
|
1244
|
+
.off('dragend', this._fireEdit, this)
|
1245
|
+
.off('click', this._onMarkerClick, this);
|
1246
|
+
},
|
1247
|
+
|
1248
|
+
_fireEdit: function () {
|
1249
|
+
this._poly.edited = true;
|
1250
|
+
this._poly.fire('edit');
|
1251
|
+
},
|
1252
|
+
|
1253
|
+
_onMarkerDrag: function (e) {
|
1254
|
+
var marker = e.target;
|
1255
|
+
|
1256
|
+
L.extend(marker._origLatLng, marker._latlng);
|
1257
|
+
|
1258
|
+
if (marker._middleLeft) {
|
1259
|
+
marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
|
1260
|
+
}
|
1261
|
+
if (marker._middleRight) {
|
1262
|
+
marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
|
1263
|
+
}
|
1264
|
+
|
1265
|
+
this._poly.redraw();
|
1266
|
+
},
|
1267
|
+
|
1268
|
+
_onMarkerClick: function (e) {
|
1269
|
+
var minPoints = L.Polygon && (this._poly instanceof L.Polygon) ? 4 : 3,
|
1270
|
+
marker = e.target;
|
1271
|
+
|
1272
|
+
// If removing this point would create an invalid polyline/polygon don't remove
|
1273
|
+
if (this._poly._latlngs.length < minPoints) {
|
1274
|
+
return;
|
1275
|
+
}
|
1276
|
+
|
1277
|
+
// remove the marker
|
1278
|
+
this._removeMarker(marker);
|
1279
|
+
|
1280
|
+
// update prev/next links of adjacent markers
|
1281
|
+
this._updatePrevNext(marker._prev, marker._next);
|
1282
|
+
|
1283
|
+
// remove ghost markers near the removed marker
|
1284
|
+
if (marker._middleLeft) {
|
1285
|
+
this._markerGroup.removeLayer(marker._middleLeft);
|
1286
|
+
}
|
1287
|
+
if (marker._middleRight) {
|
1288
|
+
this._markerGroup.removeLayer(marker._middleRight);
|
1289
|
+
}
|
1290
|
+
|
1291
|
+
// create a ghost marker in place of the removed one
|
1292
|
+
if (marker._prev && marker._next) {
|
1293
|
+
this._createMiddleMarker(marker._prev, marker._next);
|
1294
|
+
|
1295
|
+
} else if (!marker._prev) {
|
1296
|
+
marker._next._middleLeft = null;
|
1297
|
+
|
1298
|
+
} else if (!marker._next) {
|
1299
|
+
marker._prev._middleRight = null;
|
1300
|
+
}
|
1301
|
+
|
1302
|
+
this._fireEdit();
|
1303
|
+
},
|
1304
|
+
|
1305
|
+
_updateIndexes: function (index, delta) {
|
1306
|
+
this._markerGroup.eachLayer(function (marker) {
|
1307
|
+
if (marker._index > index) {
|
1308
|
+
marker._index += delta;
|
1309
|
+
}
|
1310
|
+
});
|
1311
|
+
},
|
1312
|
+
|
1313
|
+
_createMiddleMarker: function (marker1, marker2) {
|
1314
|
+
var latlng = this._getMiddleLatLng(marker1, marker2),
|
1315
|
+
marker = this._createMarker(latlng),
|
1316
|
+
onClick,
|
1317
|
+
onDragStart,
|
1318
|
+
onDragEnd;
|
1319
|
+
|
1320
|
+
marker.setOpacity(0.6);
|
1321
|
+
|
1322
|
+
marker1._middleRight = marker2._middleLeft = marker;
|
1323
|
+
|
1324
|
+
onDragStart = function () {
|
1325
|
+
var i = marker2._index;
|
1326
|
+
|
1327
|
+
marker._index = i;
|
1328
|
+
|
1329
|
+
marker
|
1330
|
+
.off('click', onClick, this)
|
1331
|
+
.on('click', this._onMarkerClick, this);
|
1332
|
+
|
1333
|
+
latlng.lat = marker.getLatLng().lat;
|
1334
|
+
latlng.lng = marker.getLatLng().lng;
|
1335
|
+
this._poly.spliceLatLngs(i, 0, latlng);
|
1336
|
+
this._markers.splice(i, 0, marker);
|
1337
|
+
|
1338
|
+
marker.setOpacity(1);
|
1339
|
+
|
1340
|
+
this._updateIndexes(i, 1);
|
1341
|
+
marker2._index++;
|
1342
|
+
this._updatePrevNext(marker1, marker);
|
1343
|
+
this._updatePrevNext(marker, marker2);
|
1344
|
+
|
1345
|
+
this._poly.fire('editstart');
|
1346
|
+
};
|
1347
|
+
|
1348
|
+
onDragEnd = function () {
|
1349
|
+
marker.off('dragstart', onDragStart, this);
|
1350
|
+
marker.off('dragend', onDragEnd, this);
|
1351
|
+
|
1352
|
+
this._createMiddleMarker(marker1, marker);
|
1353
|
+
this._createMiddleMarker(marker, marker2);
|
1354
|
+
};
|
1355
|
+
|
1356
|
+
onClick = function () {
|
1357
|
+
onDragStart.call(this);
|
1358
|
+
onDragEnd.call(this);
|
1359
|
+
this._fireEdit();
|
1360
|
+
};
|
1361
|
+
|
1362
|
+
marker
|
1363
|
+
.on('click', onClick, this)
|
1364
|
+
.on('dragstart', onDragStart, this)
|
1365
|
+
.on('dragend', onDragEnd, this);
|
1366
|
+
|
1367
|
+
this._markerGroup.addLayer(marker);
|
1368
|
+
},
|
1369
|
+
|
1370
|
+
_updatePrevNext: function (marker1, marker2) {
|
1371
|
+
if (marker1) {
|
1372
|
+
marker1._next = marker2;
|
1373
|
+
}
|
1374
|
+
if (marker2) {
|
1375
|
+
marker2._prev = marker1;
|
1376
|
+
}
|
1377
|
+
},
|
1378
|
+
|
1379
|
+
_getMiddleLatLng: function (marker1, marker2) {
|
1380
|
+
var map = this._poly._map,
|
1381
|
+
p1 = map.project(marker1.getLatLng()),
|
1382
|
+
p2 = map.project(marker2.getLatLng());
|
1383
|
+
|
1384
|
+
return map.unproject(p1._add(p2)._divideBy(2));
|
1385
|
+
}
|
1386
|
+
});
|
1387
|
+
|
1388
|
+
L.Polyline.addInitHook(function () {
|
1389
|
+
|
1390
|
+
// Check to see if handler has already been initialized. This is to support versions of Leaflet that still have L.Handler.PolyEdit
|
1391
|
+
if (this.editing) {
|
1392
|
+
return;
|
1393
|
+
}
|
1394
|
+
|
1395
|
+
if (L.Edit.Poly) {
|
1396
|
+
this.editing = new L.Edit.Poly(this);
|
1397
|
+
|
1398
|
+
if (this.options.editable) {
|
1399
|
+
this.editing.enable();
|
1400
|
+
}
|
1401
|
+
}
|
1402
|
+
|
1403
|
+
this.on('add', function () {
|
1404
|
+
if (this.editing && this.editing.enabled()) {
|
1405
|
+
this.editing.addHooks();
|
1406
|
+
}
|
1407
|
+
});
|
1408
|
+
|
1409
|
+
this.on('remove', function () {
|
1410
|
+
if (this.editing && this.editing.enabled()) {
|
1411
|
+
this.editing.removeHooks();
|
1412
|
+
}
|
1413
|
+
});
|
1414
|
+
});
|
1415
|
+
|
1416
|
+
|
1417
|
+
L.Edit = L.Edit || {};
|
1418
|
+
|
1419
|
+
L.Edit.SimpleShape = L.Handler.extend({
|
1420
|
+
options: {
|
1421
|
+
moveIcon: new L.DivIcon({
|
1422
|
+
iconSize: new L.Point(8, 8),
|
1423
|
+
className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-move'
|
1424
|
+
}),
|
1425
|
+
resizeIcon: new L.DivIcon({
|
1426
|
+
iconSize: new L.Point(8, 8),
|
1427
|
+
className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-resize'
|
1428
|
+
})
|
1429
|
+
},
|
1430
|
+
|
1431
|
+
initialize: function (shape, options) {
|
1432
|
+
this._shape = shape;
|
1433
|
+
L.Util.setOptions(this, options);
|
1434
|
+
},
|
1435
|
+
|
1436
|
+
addHooks: function () {
|
1437
|
+
var shape = this._shape;
|
1438
|
+
|
1439
|
+
shape.setStyle(shape.options.editing);
|
1440
|
+
|
1441
|
+
if (shape._map) {
|
1442
|
+
this._map = shape._map;
|
1443
|
+
|
1444
|
+
if (!this._markerGroup) {
|
1445
|
+
this._initMarkers();
|
1446
|
+
}
|
1447
|
+
this._map.addLayer(this._markerGroup);
|
1448
|
+
}
|
1449
|
+
},
|
1450
|
+
|
1451
|
+
removeHooks: function () {
|
1452
|
+
var shape = this._shape;
|
1453
|
+
|
1454
|
+
shape.setStyle(shape.options.original);
|
1455
|
+
|
1456
|
+
if (shape._map) {
|
1457
|
+
this._unbindMarker(this._moveMarker);
|
1458
|
+
|
1459
|
+
for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
|
1460
|
+
this._unbindMarker(this._resizeMarkers[i]);
|
1461
|
+
}
|
1462
|
+
this._resizeMarkers = null;
|
1463
|
+
|
1464
|
+
this._map.removeLayer(this._markerGroup);
|
1465
|
+
delete this._markerGroup;
|
1466
|
+
}
|
1467
|
+
|
1468
|
+
this._map = null;
|
1469
|
+
},
|
1470
|
+
|
1471
|
+
updateMarkers: function () {
|
1472
|
+
this._markerGroup.clearLayers();
|
1473
|
+
this._initMarkers();
|
1474
|
+
},
|
1475
|
+
|
1476
|
+
_initMarkers: function () {
|
1477
|
+
if (!this._markerGroup) {
|
1478
|
+
this._markerGroup = new L.LayerGroup();
|
1479
|
+
}
|
1480
|
+
|
1481
|
+
// Create center marker
|
1482
|
+
this._createMoveMarker();
|
1483
|
+
|
1484
|
+
// Create edge marker
|
1485
|
+
this._createResizeMarker();
|
1486
|
+
},
|
1487
|
+
|
1488
|
+
_createMoveMarker: function () {
|
1489
|
+
// Children override
|
1490
|
+
},
|
1491
|
+
|
1492
|
+
_createResizeMarker: function () {
|
1493
|
+
// Children override
|
1494
|
+
},
|
1495
|
+
|
1496
|
+
_createMarker: function (latlng, icon) {
|
1497
|
+
var marker = new L.Marker(latlng, {
|
1498
|
+
draggable: true,
|
1499
|
+
icon: icon,
|
1500
|
+
zIndexOffset: 10
|
1501
|
+
});
|
1502
|
+
|
1503
|
+
this._bindMarker(marker);
|
1504
|
+
|
1505
|
+
this._markerGroup.addLayer(marker);
|
1506
|
+
|
1507
|
+
return marker;
|
1508
|
+
},
|
1509
|
+
|
1510
|
+
_bindMarker: function (marker) {
|
1511
|
+
marker
|
1512
|
+
.on('dragstart', this._onMarkerDragStart, this)
|
1513
|
+
.on('drag', this._onMarkerDrag, this)
|
1514
|
+
.on('dragend', this._onMarkerDragEnd, this);
|
1515
|
+
},
|
1516
|
+
|
1517
|
+
_unbindMarker: function (marker) {
|
1518
|
+
marker
|
1519
|
+
.off('dragstart', this._onMarkerDragStart, this)
|
1520
|
+
.off('drag', this._onMarkerDrag, this)
|
1521
|
+
.off('dragend', this._onMarkerDragEnd, this);
|
1522
|
+
},
|
1523
|
+
|
1524
|
+
_onMarkerDragStart: function (e) {
|
1525
|
+
var marker = e.target;
|
1526
|
+
marker.setOpacity(0);
|
1527
|
+
|
1528
|
+
this._shape.fire('editstart');
|
1529
|
+
},
|
1530
|
+
|
1531
|
+
_fireEdit: function () {
|
1532
|
+
this._shape.edited = true;
|
1533
|
+
this._shape.fire('edit');
|
1534
|
+
},
|
1535
|
+
|
1536
|
+
_onMarkerDrag: function (e) {
|
1537
|
+
var marker = e.target,
|
1538
|
+
latlng = marker.getLatLng();
|
1539
|
+
|
1540
|
+
if (marker === this._moveMarker) {
|
1541
|
+
this._move(latlng);
|
1542
|
+
} else {
|
1543
|
+
this._resize(latlng);
|
1544
|
+
}
|
1545
|
+
|
1546
|
+
this._shape.redraw();
|
1547
|
+
},
|
1548
|
+
|
1549
|
+
_onMarkerDragEnd: function (e) {
|
1550
|
+
var marker = e.target;
|
1551
|
+
marker.setOpacity(1);
|
1552
|
+
|
1553
|
+
this._fireEdit();
|
1554
|
+
},
|
1555
|
+
|
1556
|
+
_move: function () {
|
1557
|
+
// Children override
|
1558
|
+
},
|
1559
|
+
|
1560
|
+
_resize: function () {
|
1561
|
+
// Children override
|
1562
|
+
}
|
1563
|
+
});
|
1564
|
+
|
1565
|
+
|
1566
|
+
L.Edit = L.Edit || {};
|
1567
|
+
|
1568
|
+
L.Edit.Rectangle = L.Edit.SimpleShape.extend({
|
1569
|
+
_createMoveMarker: function () {
|
1570
|
+
var bounds = this._shape.getBounds(),
|
1571
|
+
center = bounds.getCenter();
|
1572
|
+
|
1573
|
+
this._moveMarker = this._createMarker(center, this.options.moveIcon);
|
1574
|
+
},
|
1575
|
+
|
1576
|
+
_createResizeMarker: function () {
|
1577
|
+
var corners = this._getCorners();
|
1578
|
+
|
1579
|
+
this._resizeMarkers = [];
|
1580
|
+
|
1581
|
+
for (var i = 0, l = corners.length; i < l; i++) {
|
1582
|
+
this._resizeMarkers.push(this._createMarker(corners[i], this.options.resizeIcon));
|
1583
|
+
// Monkey in the corner index as we will need to know this for dragging
|
1584
|
+
this._resizeMarkers[i]._cornerIndex = i;
|
1585
|
+
}
|
1586
|
+
},
|
1587
|
+
|
1588
|
+
_onMarkerDragStart: function (e) {
|
1589
|
+
L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this, e);
|
1590
|
+
|
1591
|
+
// Save a reference to the opposite point
|
1592
|
+
var corners = this._getCorners(),
|
1593
|
+
marker = e.target,
|
1594
|
+
currentCornerIndex = marker._cornerIndex;
|
1595
|
+
|
1596
|
+
this._oppositeCorner = corners[(currentCornerIndex + 2) % 4];
|
1597
|
+
|
1598
|
+
this._toggleCornerMarkers(0, currentCornerIndex);
|
1599
|
+
},
|
1600
|
+
|
1601
|
+
_onMarkerDragEnd: function (e) {
|
1602
|
+
var marker = e.target,
|
1603
|
+
bounds, center;
|
1604
|
+
|
1605
|
+
// Reset move marker position to the center
|
1606
|
+
if (marker === this._moveMarker) {
|
1607
|
+
bounds = this._shape.getBounds();
|
1608
|
+
center = bounds.getCenter();
|
1609
|
+
|
1610
|
+
marker.setLatLng(center);
|
1611
|
+
}
|
1612
|
+
|
1613
|
+
this._toggleCornerMarkers(1);
|
1614
|
+
|
1615
|
+
this._repositionCornerMarkers();
|
1616
|
+
|
1617
|
+
L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this, e);
|
1618
|
+
},
|
1619
|
+
|
1620
|
+
_move: function (newCenter) {
|
1621
|
+
var latlngs = this._shape.getLatLngs(),
|
1622
|
+
bounds = this._shape.getBounds(),
|
1623
|
+
center = bounds.getCenter(),
|
1624
|
+
offset, newLatLngs = [];
|
1625
|
+
|
1626
|
+
// Offset the latlngs to the new center
|
1627
|
+
for (var i = 0, l = latlngs.length; i < l; i++) {
|
1628
|
+
offset = [latlngs[i].lat - center.lat, latlngs[i].lng - center.lng];
|
1629
|
+
newLatLngs.push([newCenter.lat + offset[0], newCenter.lng + offset[1]]);
|
1630
|
+
}
|
1631
|
+
|
1632
|
+
this._shape.setLatLngs(newLatLngs);
|
1633
|
+
|
1634
|
+
// Reposition the resize markers
|
1635
|
+
this._repositionCornerMarkers();
|
1636
|
+
},
|
1637
|
+
|
1638
|
+
_resize: function (latlng) {
|
1639
|
+
var bounds;
|
1640
|
+
|
1641
|
+
// Update the shape based on the current position of this corner and the opposite point
|
1642
|
+
this._shape.setBounds(L.latLngBounds(latlng, this._oppositeCorner));
|
1643
|
+
|
1644
|
+
// Reposition the move marker
|
1645
|
+
bounds = this._shape.getBounds();
|
1646
|
+
this._moveMarker.setLatLng(bounds.getCenter());
|
1647
|
+
},
|
1648
|
+
|
1649
|
+
_getCorners: function () {
|
1650
|
+
var bounds = this._shape.getBounds(),
|
1651
|
+
nw = bounds.getNorthWest(),
|
1652
|
+
ne = bounds.getNorthEast(),
|
1653
|
+
se = bounds.getSouthEast(),
|
1654
|
+
sw = bounds.getSouthWest();
|
1655
|
+
|
1656
|
+
return [nw, ne, se, sw];
|
1657
|
+
},
|
1658
|
+
|
1659
|
+
_toggleCornerMarkers: function (opacity) {
|
1660
|
+
for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
|
1661
|
+
this._resizeMarkers[i].setOpacity(opacity);
|
1662
|
+
}
|
1663
|
+
},
|
1664
|
+
|
1665
|
+
_repositionCornerMarkers: function () {
|
1666
|
+
var corners = this._getCorners();
|
1667
|
+
|
1668
|
+
for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
|
1669
|
+
this._resizeMarkers[i].setLatLng(corners[i]);
|
1670
|
+
}
|
1671
|
+
}
|
1672
|
+
});
|
1673
|
+
|
1674
|
+
L.Rectangle.addInitHook(function () {
|
1675
|
+
if (L.Edit.Rectangle) {
|
1676
|
+
this.editing = new L.Edit.Rectangle(this);
|
1677
|
+
|
1678
|
+
if (this.options.editable) {
|
1679
|
+
this.editing.enable();
|
1680
|
+
}
|
1681
|
+
}
|
1682
|
+
});
|
1683
|
+
|
1684
|
+
|
1685
|
+
L.Edit = L.Edit || {};
|
1686
|
+
|
1687
|
+
L.Edit.Circle = L.Edit.SimpleShape.extend({
|
1688
|
+
_createMoveMarker: function () {
|
1689
|
+
var center = this._shape.getLatLng();
|
1690
|
+
|
1691
|
+
this._moveMarker = this._createMarker(center, this.options.moveIcon);
|
1692
|
+
},
|
1693
|
+
|
1694
|
+
_createResizeMarker: function () {
|
1695
|
+
var center = this._shape.getLatLng(),
|
1696
|
+
resizemarkerPoint = this._getResizeMarkerPoint(center);
|
1697
|
+
|
1698
|
+
this._resizeMarkers = [];
|
1699
|
+
this._resizeMarkers.push(this._createMarker(resizemarkerPoint, this.options.resizeIcon));
|
1700
|
+
},
|
1701
|
+
|
1702
|
+
_getResizeMarkerPoint: function (latlng) {
|
1703
|
+
// From L.shape.getBounds()
|
1704
|
+
var delta = this._shape._radius * Math.cos(Math.PI / 4),
|
1705
|
+
point = this._map.project(latlng);
|
1706
|
+
return this._map.unproject([point.x + delta, point.y - delta]);
|
1707
|
+
},
|
1708
|
+
|
1709
|
+
_move: function (latlng) {
|
1710
|
+
var resizemarkerPoint = this._getResizeMarkerPoint(latlng);
|
1711
|
+
|
1712
|
+
// Move the resize marker
|
1713
|
+
this._resizeMarkers[0].setLatLng(resizemarkerPoint);
|
1714
|
+
|
1715
|
+
// Move the circle
|
1716
|
+
this._shape.setLatLng(latlng);
|
1717
|
+
},
|
1718
|
+
|
1719
|
+
_resize: function (latlng) {
|
1720
|
+
var moveLatLng = this._moveMarker.getLatLng(),
|
1721
|
+
radius = moveLatLng.distanceTo(latlng);
|
1722
|
+
|
1723
|
+
this._shape.setRadius(radius);
|
1724
|
+
}
|
1725
|
+
});
|
1726
|
+
|
1727
|
+
L.Circle.addInitHook(function () {
|
1728
|
+
if (L.Edit.Circle) {
|
1729
|
+
this.editing = new L.Edit.Circle(this);
|
1730
|
+
|
1731
|
+
if (this.options.editable) {
|
1732
|
+
this.editing.enable();
|
1733
|
+
}
|
1734
|
+
}
|
1735
|
+
|
1736
|
+
this.on('add', function () {
|
1737
|
+
if (this.editing && this.editing.enabled()) {
|
1738
|
+
this.editing.addHooks();
|
1739
|
+
}
|
1740
|
+
});
|
1741
|
+
|
1742
|
+
this.on('remove', function () {
|
1743
|
+
if (this.editing && this.editing.enabled()) {
|
1744
|
+
this.editing.removeHooks();
|
1745
|
+
}
|
1746
|
+
});
|
1747
|
+
});
|
1748
|
+
|
1749
|
+
/*
|
1750
|
+
* L.LatLngUtil contains different utility functions for LatLngs.
|
1751
|
+
*/
|
1752
|
+
|
1753
|
+
L.LatLngUtil = {
|
1754
|
+
// Clones a LatLngs[], returns [][]
|
1755
|
+
cloneLatLngs: function (latlngs) {
|
1756
|
+
var clone = [];
|
1757
|
+
for (var i = 0, l = latlngs.length; i < l; i++) {
|
1758
|
+
clone.push(this.cloneLatLng(latlngs[i]));
|
1759
|
+
}
|
1760
|
+
return clone;
|
1761
|
+
},
|
1762
|
+
|
1763
|
+
cloneLatLng: function (latlng) {
|
1764
|
+
return L.latLng(latlng.lat, latlng.lng);
|
1765
|
+
}
|
1766
|
+
};
|
1767
|
+
|
1768
|
+
L.GeometryUtil = L.extend(L.GeometryUtil || {}, {
|
1769
|
+
// Ported from the OpenLayers implementation. See https://github.com/openlayers/openlayers/blob/master/lib/OpenLayers/Geometry/LinearRing.js#L270
|
1770
|
+
geodesicArea: function (latLngs) {
|
1771
|
+
var pointsCount = latLngs.length,
|
1772
|
+
area = 0.0,
|
1773
|
+
d2r = L.LatLng.DEG_TO_RAD,
|
1774
|
+
p1, p2;
|
1775
|
+
|
1776
|
+
if (pointsCount > 2) {
|
1777
|
+
for (var i = 0; i < pointsCount; i++) {
|
1778
|
+
p1 = latLngs[i];
|
1779
|
+
p2 = latLngs[(i + 1) % pointsCount];
|
1780
|
+
area += ((p2.lng - p1.lng) * d2r) *
|
1781
|
+
(2 + Math.sin(p1.lat * d2r) + Math.sin(p2.lat * d2r));
|
1782
|
+
}
|
1783
|
+
area = area * 6378137.0 * 6378137.0 / 2.0;
|
1784
|
+
}
|
1785
|
+
|
1786
|
+
return Math.abs(area);
|
1787
|
+
},
|
1788
|
+
|
1789
|
+
readableArea: function (area, isMetric) {
|
1790
|
+
var areaStr;
|
1791
|
+
|
1792
|
+
if (isMetric) {
|
1793
|
+
if (area >= 10000) {
|
1794
|
+
areaStr = (area * 0.0001).toFixed(2) + ' ha';
|
1795
|
+
} else {
|
1796
|
+
areaStr = area.toFixed(2) + ' m²';
|
1797
|
+
}
|
1798
|
+
} else {
|
1799
|
+
area /= 0.836127; // Square yards in 1 meter
|
1800
|
+
|
1801
|
+
if (area >= 3097600) { //3097600 square yards in 1 square mile
|
1802
|
+
areaStr = (area / 3097600).toFixed(2) + ' mi²';
|
1803
|
+
} else if (area >= 4840) {//48040 square yards in 1 acre
|
1804
|
+
areaStr = (area / 4840).toFixed(2) + ' acres';
|
1805
|
+
} else {
|
1806
|
+
areaStr = Math.ceil(area) + ' yd²';
|
1807
|
+
}
|
1808
|
+
}
|
1809
|
+
|
1810
|
+
return areaStr;
|
1811
|
+
},
|
1812
|
+
|
1813
|
+
readableDistance: function (distance, isMetric) {
|
1814
|
+
var distanceStr;
|
1815
|
+
|
1816
|
+
if (isMetric) {
|
1817
|
+
// show metres when distance is < 1km, then show km
|
1818
|
+
if (distance > 1000) {
|
1819
|
+
distanceStr = (distance / 1000).toFixed(2) + ' km';
|
1820
|
+
} else {
|
1821
|
+
distanceStr = Math.ceil(distance) + ' m';
|
1822
|
+
}
|
1823
|
+
} else {
|
1824
|
+
distance *= 1.09361;
|
1825
|
+
|
1826
|
+
if (distance > 1760) {
|
1827
|
+
distanceStr = (distance / 1760).toFixed(2) + ' miles';
|
1828
|
+
} else {
|
1829
|
+
distanceStr = Math.ceil(distance) + ' yd';
|
1830
|
+
}
|
1831
|
+
}
|
1832
|
+
|
1833
|
+
return distanceStr;
|
1834
|
+
}
|
1835
|
+
});
|
1836
|
+
|
1837
|
+
L.Util.extend(L.LineUtil, {
|
1838
|
+
// Checks to see if two line segments intersect. Does not handle degenerate cases.
|
1839
|
+
// http://compgeom.cs.uiuc.edu/~jeffe/teaching/373/notes/x06-sweepline.pdf
|
1840
|
+
segmentsIntersect: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2, /*Point*/ p3) {
|
1841
|
+
return this._checkCounterclockwise(p, p2, p3) !==
|
1842
|
+
this._checkCounterclockwise(p1, p2, p3) &&
|
1843
|
+
this._checkCounterclockwise(p, p1, p2) !==
|
1844
|
+
this._checkCounterclockwise(p, p1, p3);
|
1845
|
+
},
|
1846
|
+
|
1847
|
+
// check to see if points are in counterclockwise order
|
1848
|
+
_checkCounterclockwise: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) {
|
1849
|
+
return (p2.y - p.y) * (p1.x - p.x) > (p1.y - p.y) * (p2.x - p.x);
|
1850
|
+
}
|
1851
|
+
});
|
1852
|
+
|
1853
|
+
L.Polyline.include({
|
1854
|
+
// Check to see if this polyline has any linesegments that intersect.
|
1855
|
+
// NOTE: does not support detecting intersection for degenerate cases.
|
1856
|
+
intersects: function () {
|
1857
|
+
var points = this._originalPoints,
|
1858
|
+
len = points ? points.length : 0,
|
1859
|
+
i, p, p1;
|
1860
|
+
|
1861
|
+
if (this._tooFewPointsForIntersection()) {
|
1862
|
+
return false;
|
1863
|
+
}
|
1864
|
+
|
1865
|
+
for (i = len - 1; i >= 3; i--) {
|
1866
|
+
p = points[i - 1];
|
1867
|
+
p1 = points[i];
|
1868
|
+
|
1869
|
+
|
1870
|
+
if (this._lineSegmentsIntersectsRange(p, p1, i - 2)) {
|
1871
|
+
return true;
|
1872
|
+
}
|
1873
|
+
}
|
1874
|
+
|
1875
|
+
return false;
|
1876
|
+
},
|
1877
|
+
|
1878
|
+
// Check for intersection if new latlng was added to this polyline.
|
1879
|
+
// NOTE: does not support detecting intersection for degenerate cases.
|
1880
|
+
newLatLngIntersects: function (latlng, skipFirst) {
|
1881
|
+
// Cannot check a polyline for intersecting lats/lngs when not added to the map
|
1882
|
+
if (!this._map) {
|
1883
|
+
return false;
|
1884
|
+
}
|
1885
|
+
|
1886
|
+
return this.newPointIntersects(this._map.latLngToLayerPoint(latlng), skipFirst);
|
1887
|
+
},
|
1888
|
+
|
1889
|
+
// Check for intersection if new point was added to this polyline.
|
1890
|
+
// newPoint must be a layer point.
|
1891
|
+
// NOTE: does not support detecting intersection for degenerate cases.
|
1892
|
+
newPointIntersects: function (newPoint, skipFirst) {
|
1893
|
+
var points = this._originalPoints,
|
1894
|
+
len = points ? points.length : 0,
|
1895
|
+
lastPoint = points ? points[len - 1] : null,
|
1896
|
+
// The previous previous line segment. Previous line segment doesn't need testing.
|
1897
|
+
maxIndex = len - 2;
|
1898
|
+
|
1899
|
+
if (this._tooFewPointsForIntersection(1)) {
|
1900
|
+
return false;
|
1901
|
+
}
|
1902
|
+
|
1903
|
+
return this._lineSegmentsIntersectsRange(lastPoint, newPoint, maxIndex, skipFirst ? 1 : 0);
|
1904
|
+
},
|
1905
|
+
|
1906
|
+
// Polylines with 2 sides can only intersect in cases where points are collinear (we don't support detecting these).
|
1907
|
+
// Cannot have intersection when < 3 line segments (< 4 points)
|
1908
|
+
_tooFewPointsForIntersection: function (extraPoints) {
|
1909
|
+
var points = this._originalPoints,
|
1910
|
+
len = points ? points.length : 0;
|
1911
|
+
// Increment length by extraPoints if present
|
1912
|
+
len += extraPoints || 0;
|
1913
|
+
|
1914
|
+
return !this._originalPoints || len <= 3;
|
1915
|
+
},
|
1916
|
+
|
1917
|
+
// Checks a line segment intersections with any line segments before its predecessor.
|
1918
|
+
// Don't need to check the predecessor as will never intersect.
|
1919
|
+
_lineSegmentsIntersectsRange: function (p, p1, maxIndex, minIndex) {
|
1920
|
+
var points = this._originalPoints,
|
1921
|
+
p2, p3;
|
1922
|
+
|
1923
|
+
minIndex = minIndex || 0;
|
1924
|
+
|
1925
|
+
// Check all previous line segments (beside the immediately previous) for intersections
|
1926
|
+
for (var j = maxIndex; j > minIndex; j--) {
|
1927
|
+
p2 = points[j - 1];
|
1928
|
+
p3 = points[j];
|
1929
|
+
|
1930
|
+
if (L.LineUtil.segmentsIntersect(p, p1, p2, p3)) {
|
1931
|
+
return true;
|
1932
|
+
}
|
1933
|
+
}
|
1934
|
+
|
1935
|
+
return false;
|
1936
|
+
}
|
1937
|
+
});
|
1938
|
+
|
1939
|
+
|
1940
|
+
L.Polygon.include({
|
1941
|
+
// Checks a polygon for any intersecting line segments. Ignores holes.
|
1942
|
+
intersects: function () {
|
1943
|
+
var polylineIntersects,
|
1944
|
+
points = this._originalPoints,
|
1945
|
+
len, firstPoint, lastPoint, maxIndex;
|
1946
|
+
|
1947
|
+
if (this._tooFewPointsForIntersection()) {
|
1948
|
+
return false;
|
1949
|
+
}
|
1950
|
+
|
1951
|
+
polylineIntersects = L.Polyline.prototype.intersects.call(this);
|
1952
|
+
|
1953
|
+
// If already found an intersection don't need to check for any more.
|
1954
|
+
if (polylineIntersects) {
|
1955
|
+
return true;
|
1956
|
+
}
|
1957
|
+
|
1958
|
+
len = points.length;
|
1959
|
+
firstPoint = points[0];
|
1960
|
+
lastPoint = points[len - 1];
|
1961
|
+
maxIndex = len - 2;
|
1962
|
+
|
1963
|
+
// Check the line segment between last and first point. Don't need to check the first line segment (minIndex = 1)
|
1964
|
+
return this._lineSegmentsIntersectsRange(lastPoint, firstPoint, maxIndex, 1);
|
1965
|
+
}
|
1966
|
+
});
|
1967
|
+
|
1968
|
+
L.Control.Draw = L.Control.extend({
|
1969
|
+
|
1970
|
+
options: {
|
1971
|
+
position: 'topleft',
|
1972
|
+
draw: {},
|
1973
|
+
edit: false
|
1974
|
+
},
|
1975
|
+
|
1976
|
+
initialize: function (options) {
|
1977
|
+
if (L.version < '0.7') {
|
1978
|
+
throw new Error('Leaflet.draw 0.2.3+ requires Leaflet 0.7.0+. Download latest from https://github.com/Leaflet/Leaflet/');
|
1979
|
+
}
|
1980
|
+
|
1981
|
+
L.Control.prototype.initialize.call(this, options);
|
1982
|
+
|
1983
|
+
var toolbar;
|
1984
|
+
|
1985
|
+
this._toolbars = {};
|
1986
|
+
|
1987
|
+
// Initialize toolbars
|
1988
|
+
if (L.DrawToolbar && this.options.draw) {
|
1989
|
+
toolbar = new L.DrawToolbar(this.options.draw);
|
1990
|
+
|
1991
|
+
this._toolbars[L.DrawToolbar.TYPE] = toolbar;
|
1992
|
+
|
1993
|
+
// Listen for when toolbar is enabled
|
1994
|
+
this._toolbars[L.DrawToolbar.TYPE].on('enable', this._toolbarEnabled, this);
|
1995
|
+
}
|
1996
|
+
|
1997
|
+
if (L.EditToolbar && this.options.edit) {
|
1998
|
+
toolbar = new L.EditToolbar(this.options.edit);
|
1999
|
+
|
2000
|
+
this._toolbars[L.EditToolbar.TYPE] = toolbar;
|
2001
|
+
|
2002
|
+
// Listen for when toolbar is enabled
|
2003
|
+
this._toolbars[L.EditToolbar.TYPE].on('enable', this._toolbarEnabled, this);
|
2004
|
+
}
|
2005
|
+
},
|
2006
|
+
|
2007
|
+
onAdd: function (map) {
|
2008
|
+
var container = L.DomUtil.create('div', 'leaflet-draw'),
|
2009
|
+
addedTopClass = false,
|
2010
|
+
topClassName = 'leaflet-draw-toolbar-top',
|
2011
|
+
toolbarContainer;
|
2012
|
+
|
2013
|
+
for (var toolbarId in this._toolbars) {
|
2014
|
+
if (this._toolbars.hasOwnProperty(toolbarId)) {
|
2015
|
+
toolbarContainer = this._toolbars[toolbarId].addToolbar(map);
|
2016
|
+
|
2017
|
+
if (toolbarContainer) {
|
2018
|
+
// Add class to the first toolbar to remove the margin
|
2019
|
+
if (!addedTopClass) {
|
2020
|
+
if (!L.DomUtil.hasClass(toolbarContainer, topClassName)) {
|
2021
|
+
L.DomUtil.addClass(toolbarContainer.childNodes[0], topClassName);
|
2022
|
+
}
|
2023
|
+
addedTopClass = true;
|
2024
|
+
}
|
2025
|
+
|
2026
|
+
container.appendChild(toolbarContainer);
|
2027
|
+
}
|
2028
|
+
}
|
2029
|
+
}
|
2030
|
+
|
2031
|
+
return container;
|
2032
|
+
},
|
2033
|
+
|
2034
|
+
onRemove: function () {
|
2035
|
+
for (var toolbarId in this._toolbars) {
|
2036
|
+
if (this._toolbars.hasOwnProperty(toolbarId)) {
|
2037
|
+
this._toolbars[toolbarId].removeToolbar();
|
2038
|
+
}
|
2039
|
+
}
|
2040
|
+
},
|
2041
|
+
|
2042
|
+
setDrawingOptions: function (options) {
|
2043
|
+
for (var toolbarId in this._toolbars) {
|
2044
|
+
if (this._toolbars[toolbarId] instanceof L.DrawToolbar) {
|
2045
|
+
this._toolbars[toolbarId].setOptions(options);
|
2046
|
+
}
|
2047
|
+
}
|
2048
|
+
},
|
2049
|
+
|
2050
|
+
_toolbarEnabled: function (e) {
|
2051
|
+
var enabledToolbar = e.target;
|
2052
|
+
|
2053
|
+
for (var toolbarId in this._toolbars) {
|
2054
|
+
if (this._toolbars[toolbarId] !== enabledToolbar) {
|
2055
|
+
this._toolbars[toolbarId].disable();
|
2056
|
+
}
|
2057
|
+
}
|
2058
|
+
}
|
2059
|
+
});
|
2060
|
+
|
2061
|
+
L.Map.mergeOptions({
|
2062
|
+
drawControlTooltips: true,
|
2063
|
+
drawControl: false
|
2064
|
+
});
|
2065
|
+
|
2066
|
+
L.Map.addInitHook(function () {
|
2067
|
+
if (this.options.drawControl) {
|
2068
|
+
this.drawControl = new L.Control.Draw();
|
2069
|
+
this.addControl(this.drawControl);
|
2070
|
+
}
|
2071
|
+
});
|
2072
|
+
|
2073
|
+
|
2074
|
+
L.Toolbar = L.Class.extend({
|
2075
|
+
includes: [L.Mixin.Events],
|
2076
|
+
|
2077
|
+
initialize: function (options) {
|
2078
|
+
L.setOptions(this, options);
|
2079
|
+
|
2080
|
+
this._modes = {};
|
2081
|
+
this._actionButtons = [];
|
2082
|
+
this._activeMode = null;
|
2083
|
+
},
|
2084
|
+
|
2085
|
+
enabled: function () {
|
2086
|
+
return this._activeMode !== null;
|
2087
|
+
},
|
2088
|
+
|
2089
|
+
disable: function () {
|
2090
|
+
if (!this.enabled()) { return; }
|
2091
|
+
|
2092
|
+
this._activeMode.handler.disable();
|
2093
|
+
},
|
2094
|
+
|
2095
|
+
addToolbar: function (map) {
|
2096
|
+
var container = L.DomUtil.create('div', 'leaflet-draw-section'),
|
2097
|
+
buttonIndex = 0,
|
2098
|
+
buttonClassPrefix = this._toolbarClass || '',
|
2099
|
+
modeHandlers = this.getModeHandlers(map),
|
2100
|
+
i;
|
2101
|
+
|
2102
|
+
this._toolbarContainer = L.DomUtil.create('div', 'leaflet-draw-toolbar leaflet-bar');
|
2103
|
+
this._map = map;
|
2104
|
+
|
2105
|
+
for (i = 0; i < modeHandlers.length; i++) {
|
2106
|
+
if (modeHandlers[i].enabled) {
|
2107
|
+
this._initModeHandler(
|
2108
|
+
modeHandlers[i].handler,
|
2109
|
+
this._toolbarContainer,
|
2110
|
+
buttonIndex++,
|
2111
|
+
buttonClassPrefix,
|
2112
|
+
modeHandlers[i].title
|
2113
|
+
);
|
2114
|
+
}
|
2115
|
+
}
|
2116
|
+
|
2117
|
+
// if no buttons were added, do not add the toolbar
|
2118
|
+
if (!buttonIndex) {
|
2119
|
+
return;
|
2120
|
+
}
|
2121
|
+
|
2122
|
+
// Save button index of the last button, -1 as we would have ++ after the last button
|
2123
|
+
this._lastButtonIndex = --buttonIndex;
|
2124
|
+
|
2125
|
+
// Create empty actions part of the toolbar
|
2126
|
+
this._actionsContainer = L.DomUtil.create('ul', 'leaflet-draw-actions');
|
2127
|
+
|
2128
|
+
// Add draw and cancel containers to the control container
|
2129
|
+
container.appendChild(this._toolbarContainer);
|
2130
|
+
container.appendChild(this._actionsContainer);
|
2131
|
+
|
2132
|
+
return container;
|
2133
|
+
},
|
2134
|
+
|
2135
|
+
removeToolbar: function () {
|
2136
|
+
// Dispose each handler
|
2137
|
+
for (var handlerId in this._modes) {
|
2138
|
+
if (this._modes.hasOwnProperty(handlerId)) {
|
2139
|
+
// Unbind handler button
|
2140
|
+
this._disposeButton(
|
2141
|
+
this._modes[handlerId].button,
|
2142
|
+
this._modes[handlerId].handler.enable,
|
2143
|
+
this._modes[handlerId].handler
|
2144
|
+
);
|
2145
|
+
|
2146
|
+
// Make sure is disabled
|
2147
|
+
this._modes[handlerId].handler.disable();
|
2148
|
+
|
2149
|
+
// Unbind handler
|
2150
|
+
this._modes[handlerId].handler
|
2151
|
+
.off('enabled', this._handlerActivated, this)
|
2152
|
+
.off('disabled', this._handlerDeactivated, this);
|
2153
|
+
}
|
2154
|
+
}
|
2155
|
+
this._modes = {};
|
2156
|
+
|
2157
|
+
// Dispose the actions toolbar
|
2158
|
+
for (var i = 0, l = this._actionButtons.length; i < l; i++) {
|
2159
|
+
this._disposeButton(
|
2160
|
+
this._actionButtons[i].button,
|
2161
|
+
this._actionButtons[i].callback,
|
2162
|
+
this
|
2163
|
+
);
|
2164
|
+
}
|
2165
|
+
this._actionButtons = [];
|
2166
|
+
this._actionsContainer = null;
|
2167
|
+
},
|
2168
|
+
|
2169
|
+
_initModeHandler: function (handler, container, buttonIndex, classNamePredix, buttonTitle) {
|
2170
|
+
var type = handler.type;
|
2171
|
+
|
2172
|
+
this._modes[type] = {};
|
2173
|
+
|
2174
|
+
this._modes[type].handler = handler;
|
2175
|
+
|
2176
|
+
this._modes[type].button = this._createButton({
|
2177
|
+
title: buttonTitle,
|
2178
|
+
className: classNamePredix + '-' + type,
|
2179
|
+
container: container,
|
2180
|
+
callback: this._modes[type].handler.enable,
|
2181
|
+
context: this._modes[type].handler
|
2182
|
+
});
|
2183
|
+
|
2184
|
+
this._modes[type].buttonIndex = buttonIndex;
|
2185
|
+
|
2186
|
+
this._modes[type].handler
|
2187
|
+
.on('enabled', this._handlerActivated, this)
|
2188
|
+
.on('disabled', this._handlerDeactivated, this);
|
2189
|
+
},
|
2190
|
+
|
2191
|
+
_createButton: function (options) {
|
2192
|
+
var link = L.DomUtil.create('a', options.className || '', options.container);
|
2193
|
+
link.href = '#';
|
2194
|
+
|
2195
|
+
if (options.text) {
|
2196
|
+
link.innerHTML = options.text;
|
2197
|
+
}
|
2198
|
+
|
2199
|
+
if (options.title) {
|
2200
|
+
link.title = options.title;
|
2201
|
+
}
|
2202
|
+
|
2203
|
+
L.DomEvent
|
2204
|
+
.on(link, 'click', L.DomEvent.stopPropagation)
|
2205
|
+
.on(link, 'mousedown', L.DomEvent.stopPropagation)
|
2206
|
+
.on(link, 'dblclick', L.DomEvent.stopPropagation)
|
2207
|
+
.on(link, 'click', L.DomEvent.preventDefault)
|
2208
|
+
.on(link, 'click', options.callback, options.context);
|
2209
|
+
|
2210
|
+
return link;
|
2211
|
+
},
|
2212
|
+
|
2213
|
+
_disposeButton: function (button, callback) {
|
2214
|
+
L.DomEvent
|
2215
|
+
.off(button, 'click', L.DomEvent.stopPropagation)
|
2216
|
+
.off(button, 'mousedown', L.DomEvent.stopPropagation)
|
2217
|
+
.off(button, 'dblclick', L.DomEvent.stopPropagation)
|
2218
|
+
.off(button, 'click', L.DomEvent.preventDefault)
|
2219
|
+
.off(button, 'click', callback);
|
2220
|
+
},
|
2221
|
+
|
2222
|
+
_handlerActivated: function (e) {
|
2223
|
+
// Disable active mode (if present)
|
2224
|
+
this.disable();
|
2225
|
+
|
2226
|
+
// Cache new active feature
|
2227
|
+
this._activeMode = this._modes[e.handler];
|
2228
|
+
|
2229
|
+
L.DomUtil.addClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled');
|
2230
|
+
|
2231
|
+
this._showActionsToolbar();
|
2232
|
+
|
2233
|
+
this.fire('enable');
|
2234
|
+
},
|
2235
|
+
|
2236
|
+
_handlerDeactivated: function () {
|
2237
|
+
this._hideActionsToolbar();
|
2238
|
+
|
2239
|
+
L.DomUtil.removeClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled');
|
2240
|
+
|
2241
|
+
this._activeMode = null;
|
2242
|
+
|
2243
|
+
this.fire('disable');
|
2244
|
+
},
|
2245
|
+
|
2246
|
+
_createActions: function (handler) {
|
2247
|
+
var container = this._actionsContainer,
|
2248
|
+
buttons = this.getActions(handler),
|
2249
|
+
l = buttons.length,
|
2250
|
+
li, di, dl, button;
|
2251
|
+
|
2252
|
+
// Dispose the actions toolbar (todo: dispose only not used buttons)
|
2253
|
+
for (di = 0, dl = this._actionButtons.length; di < dl; di++) {
|
2254
|
+
this._disposeButton(this._actionButtons[di].button, this._actionButtons[di].callback);
|
2255
|
+
}
|
2256
|
+
this._actionButtons = [];
|
2257
|
+
|
2258
|
+
// Remove all old buttons
|
2259
|
+
while (container.firstChild) {
|
2260
|
+
container.removeChild(container.firstChild);
|
2261
|
+
}
|
2262
|
+
|
2263
|
+
for (var i = 0; i < l; i++) {
|
2264
|
+
if ('enabled' in buttons[i] && !buttons[i].enabled) {
|
2265
|
+
continue;
|
2266
|
+
}
|
2267
|
+
|
2268
|
+
li = L.DomUtil.create('li', '', container);
|
2269
|
+
|
2270
|
+
button = this._createButton({
|
2271
|
+
title: buttons[i].title,
|
2272
|
+
text: buttons[i].text,
|
2273
|
+
container: li,
|
2274
|
+
callback: buttons[i].callback,
|
2275
|
+
context: buttons[i].context
|
2276
|
+
});
|
2277
|
+
|
2278
|
+
this._actionButtons.push({
|
2279
|
+
button: button,
|
2280
|
+
callback: buttons[i].callback
|
2281
|
+
});
|
2282
|
+
}
|
2283
|
+
},
|
2284
|
+
|
2285
|
+
_showActionsToolbar: function () {
|
2286
|
+
var buttonIndex = this._activeMode.buttonIndex,
|
2287
|
+
lastButtonIndex = this._lastButtonIndex,
|
2288
|
+
toolbarPosition = this._activeMode.button.offsetTop - 1;
|
2289
|
+
|
2290
|
+
// Recreate action buttons on every click
|
2291
|
+
this._createActions(this._activeMode.handler);
|
2292
|
+
|
2293
|
+
// Correctly position the cancel button
|
2294
|
+
this._actionsContainer.style.top = toolbarPosition + 'px';
|
2295
|
+
|
2296
|
+
if (buttonIndex === 0) {
|
2297
|
+
L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop');
|
2298
|
+
L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-top');
|
2299
|
+
}
|
2300
|
+
|
2301
|
+
if (buttonIndex === lastButtonIndex) {
|
2302
|
+
L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom');
|
2303
|
+
L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-bottom');
|
2304
|
+
}
|
2305
|
+
|
2306
|
+
this._actionsContainer.style.display = 'block';
|
2307
|
+
},
|
2308
|
+
|
2309
|
+
_hideActionsToolbar: function () {
|
2310
|
+
this._actionsContainer.style.display = 'none';
|
2311
|
+
|
2312
|
+
L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop');
|
2313
|
+
L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom');
|
2314
|
+
L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-top');
|
2315
|
+
L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-bottom');
|
2316
|
+
}
|
2317
|
+
});
|
2318
|
+
|
2319
|
+
|
2320
|
+
L.Tooltip = L.Class.extend({
|
2321
|
+
initialize: function (map) {
|
2322
|
+
this._map = map;
|
2323
|
+
this._popupPane = map._panes.popupPane;
|
2324
|
+
|
2325
|
+
this._container = map.options.drawControlTooltips ? L.DomUtil.create('div', 'leaflet-draw-tooltip', this._popupPane) : null;
|
2326
|
+
this._singleLineLabel = false;
|
2327
|
+
},
|
2328
|
+
|
2329
|
+
dispose: function () {
|
2330
|
+
if (this._container) {
|
2331
|
+
this._popupPane.removeChild(this._container);
|
2332
|
+
this._container = null;
|
2333
|
+
}
|
2334
|
+
},
|
2335
|
+
|
2336
|
+
updateContent: function (labelText) {
|
2337
|
+
if (!this._container) {
|
2338
|
+
return this;
|
2339
|
+
}
|
2340
|
+
labelText.subtext = labelText.subtext || '';
|
2341
|
+
|
2342
|
+
// update the vertical position (only if changed)
|
2343
|
+
if (labelText.subtext.length === 0 && !this._singleLineLabel) {
|
2344
|
+
L.DomUtil.addClass(this._container, 'leaflet-draw-tooltip-single');
|
2345
|
+
this._singleLineLabel = true;
|
2346
|
+
}
|
2347
|
+
else if (labelText.subtext.length > 0 && this._singleLineLabel) {
|
2348
|
+
L.DomUtil.removeClass(this._container, 'leaflet-draw-tooltip-single');
|
2349
|
+
this._singleLineLabel = false;
|
2350
|
+
}
|
2351
|
+
|
2352
|
+
this._container.innerHTML =
|
2353
|
+
(labelText.subtext.length > 0 ? '<span class="leaflet-draw-tooltip-subtext">' + labelText.subtext + '</span>' + '<br />' : '') +
|
2354
|
+
'<span>' + labelText.text + '</span>';
|
2355
|
+
|
2356
|
+
return this;
|
2357
|
+
},
|
2358
|
+
|
2359
|
+
updatePosition: function (latlng) {
|
2360
|
+
var pos = this._map.latLngToLayerPoint(latlng),
|
2361
|
+
tooltipContainer = this._container;
|
2362
|
+
|
2363
|
+
if (this._container) {
|
2364
|
+
tooltipContainer.style.visibility = 'inherit';
|
2365
|
+
L.DomUtil.setPosition(tooltipContainer, pos);
|
2366
|
+
}
|
2367
|
+
|
2368
|
+
return this;
|
2369
|
+
},
|
2370
|
+
|
2371
|
+
showAsError: function () {
|
2372
|
+
if (this._container) {
|
2373
|
+
L.DomUtil.addClass(this._container, 'leaflet-error-draw-tooltip');
|
2374
|
+
}
|
2375
|
+
return this;
|
2376
|
+
},
|
2377
|
+
|
2378
|
+
removeError: function () {
|
2379
|
+
if (this._container) {
|
2380
|
+
L.DomUtil.removeClass(this._container, 'leaflet-error-draw-tooltip');
|
2381
|
+
}
|
2382
|
+
return this;
|
2383
|
+
}
|
2384
|
+
});
|
2385
|
+
|
2386
|
+
L.DrawToolbar = L.Toolbar.extend({
|
2387
|
+
|
2388
|
+
statics: {
|
2389
|
+
TYPE: 'draw'
|
2390
|
+
},
|
2391
|
+
|
2392
|
+
options: {
|
2393
|
+
polyline: {},
|
2394
|
+
polygon: {},
|
2395
|
+
rectangle: {},
|
2396
|
+
circle: {},
|
2397
|
+
marker: {}
|
2398
|
+
},
|
2399
|
+
|
2400
|
+
initialize: function (options) {
|
2401
|
+
// Ensure that the options are merged correctly since L.extend is only shallow
|
2402
|
+
for (var type in this.options) {
|
2403
|
+
if (this.options.hasOwnProperty(type)) {
|
2404
|
+
if (options[type]) {
|
2405
|
+
options[type] = L.extend({}, this.options[type], options[type]);
|
2406
|
+
}
|
2407
|
+
}
|
2408
|
+
}
|
2409
|
+
|
2410
|
+
this._toolbarClass = 'leaflet-draw-draw';
|
2411
|
+
L.Toolbar.prototype.initialize.call(this, options);
|
2412
|
+
},
|
2413
|
+
|
2414
|
+
getModeHandlers: function (map) {
|
2415
|
+
return [
|
2416
|
+
{
|
2417
|
+
enabled: this.options.polyline,
|
2418
|
+
handler: new L.Draw.Polyline(map, this.options.polyline),
|
2419
|
+
title: L.drawLocal.draw.toolbar.buttons.polyline
|
2420
|
+
},
|
2421
|
+
{
|
2422
|
+
enabled: this.options.polygon,
|
2423
|
+
handler: new L.Draw.Polygon(map, this.options.polygon),
|
2424
|
+
title: L.drawLocal.draw.toolbar.buttons.polygon
|
2425
|
+
},
|
2426
|
+
{
|
2427
|
+
enabled: this.options.rectangle,
|
2428
|
+
handler: new L.Draw.Rectangle(map, this.options.rectangle),
|
2429
|
+
title: L.drawLocal.draw.toolbar.buttons.rectangle
|
2430
|
+
},
|
2431
|
+
{
|
2432
|
+
enabled: this.options.circle,
|
2433
|
+
handler: new L.Draw.Circle(map, this.options.circle),
|
2434
|
+
title: L.drawLocal.draw.toolbar.buttons.circle
|
2435
|
+
},
|
2436
|
+
{
|
2437
|
+
enabled: this.options.marker,
|
2438
|
+
handler: new L.Draw.Marker(map, this.options.marker),
|
2439
|
+
title: L.drawLocal.draw.toolbar.buttons.marker
|
2440
|
+
}
|
2441
|
+
];
|
2442
|
+
},
|
2443
|
+
|
2444
|
+
// Get the actions part of the toolbar
|
2445
|
+
getActions: function (handler) {
|
2446
|
+
return [
|
2447
|
+
{
|
2448
|
+
enabled: handler.deleteLastVertex,
|
2449
|
+
title: L.drawLocal.draw.toolbar.undo.title,
|
2450
|
+
text: L.drawLocal.draw.toolbar.undo.text,
|
2451
|
+
callback: handler.deleteLastVertex,
|
2452
|
+
context: handler
|
2453
|
+
},
|
2454
|
+
{
|
2455
|
+
title: L.drawLocal.draw.toolbar.actions.title,
|
2456
|
+
text: L.drawLocal.draw.toolbar.actions.text,
|
2457
|
+
callback: this.disable,
|
2458
|
+
context: this
|
2459
|
+
}
|
2460
|
+
];
|
2461
|
+
},
|
2462
|
+
|
2463
|
+
setOptions: function (options) {
|
2464
|
+
L.setOptions(this, options);
|
2465
|
+
|
2466
|
+
for (var type in this._modes) {
|
2467
|
+
if (this._modes.hasOwnProperty(type) && options.hasOwnProperty(type)) {
|
2468
|
+
this._modes[type].handler.setOptions(options[type]);
|
2469
|
+
}
|
2470
|
+
}
|
2471
|
+
}
|
2472
|
+
});
|
2473
|
+
|
2474
|
+
|
2475
|
+
/*L.Map.mergeOptions({
|
2476
|
+
editControl: true
|
2477
|
+
});*/
|
2478
|
+
|
2479
|
+
L.EditToolbar = L.Toolbar.extend({
|
2480
|
+
statics: {
|
2481
|
+
TYPE: 'edit'
|
2482
|
+
},
|
2483
|
+
|
2484
|
+
options: {
|
2485
|
+
edit: {
|
2486
|
+
selectedPathOptions: {
|
2487
|
+
color: '#fe57a1', /* Hot pink all the things! */
|
2488
|
+
opacity: 0.6,
|
2489
|
+
dashArray: '10, 10',
|
2490
|
+
|
2491
|
+
fill: true,
|
2492
|
+
fillColor: '#fe57a1',
|
2493
|
+
fillOpacity: 0.1,
|
2494
|
+
|
2495
|
+
// Whether to user the existing layers color
|
2496
|
+
maintainColor: false
|
2497
|
+
}
|
2498
|
+
},
|
2499
|
+
remove: {},
|
2500
|
+
featureGroup: null /* REQUIRED! TODO: perhaps if not set then all layers on the map are selectable? */
|
2501
|
+
},
|
2502
|
+
|
2503
|
+
initialize: function (options) {
|
2504
|
+
// Need to set this manually since null is an acceptable value here
|
2505
|
+
if (options.edit) {
|
2506
|
+
if (typeof options.edit.selectedPathOptions === 'undefined') {
|
2507
|
+
options.edit.selectedPathOptions = this.options.edit.selectedPathOptions;
|
2508
|
+
}
|
2509
|
+
options.edit.selectedPathOptions = L.extend({}, this.options.edit.selectedPathOptions, options.edit.selectedPathOptions);
|
2510
|
+
}
|
2511
|
+
|
2512
|
+
if (options.remove) {
|
2513
|
+
options.remove = L.extend({}, this.options.remove, options.remove);
|
2514
|
+
}
|
2515
|
+
|
2516
|
+
this._toolbarClass = 'leaflet-draw-edit';
|
2517
|
+
L.Toolbar.prototype.initialize.call(this, options);
|
2518
|
+
|
2519
|
+
this._selectedFeatureCount = 0;
|
2520
|
+
},
|
2521
|
+
|
2522
|
+
getModeHandlers: function (map) {
|
2523
|
+
var featureGroup = this.options.featureGroup;
|
2524
|
+
return [
|
2525
|
+
{
|
2526
|
+
enabled: this.options.edit,
|
2527
|
+
handler: new L.EditToolbar.Edit(map, {
|
2528
|
+
featureGroup: featureGroup,
|
2529
|
+
selectedPathOptions: this.options.edit.selectedPathOptions
|
2530
|
+
}),
|
2531
|
+
title: L.drawLocal.edit.toolbar.buttons.edit
|
2532
|
+
},
|
2533
|
+
{
|
2534
|
+
enabled: this.options.remove,
|
2535
|
+
handler: new L.EditToolbar.Delete(map, {
|
2536
|
+
featureGroup: featureGroup
|
2537
|
+
}),
|
2538
|
+
title: L.drawLocal.edit.toolbar.buttons.remove
|
2539
|
+
}
|
2540
|
+
];
|
2541
|
+
},
|
2542
|
+
|
2543
|
+
getActions: function () {
|
2544
|
+
return [
|
2545
|
+
{
|
2546
|
+
title: L.drawLocal.edit.toolbar.actions.save.title,
|
2547
|
+
text: L.drawLocal.edit.toolbar.actions.save.text,
|
2548
|
+
callback: this._save,
|
2549
|
+
context: this
|
2550
|
+
},
|
2551
|
+
{
|
2552
|
+
title: L.drawLocal.edit.toolbar.actions.cancel.title,
|
2553
|
+
text: L.drawLocal.edit.toolbar.actions.cancel.text,
|
2554
|
+
callback: this.disable,
|
2555
|
+
context: this
|
2556
|
+
}
|
2557
|
+
];
|
2558
|
+
},
|
2559
|
+
|
2560
|
+
addToolbar: function (map) {
|
2561
|
+
var container = L.Toolbar.prototype.addToolbar.call(this, map);
|
2562
|
+
|
2563
|
+
this._checkDisabled();
|
2564
|
+
|
2565
|
+
this.options.featureGroup.on('layeradd layerremove', this._checkDisabled, this);
|
2566
|
+
|
2567
|
+
return container;
|
2568
|
+
},
|
2569
|
+
|
2570
|
+
removeToolbar: function () {
|
2571
|
+
this.options.featureGroup.off('layeradd layerremove', this._checkDisabled, this);
|
2572
|
+
|
2573
|
+
L.Toolbar.prototype.removeToolbar.call(this);
|
2574
|
+
},
|
2575
|
+
|
2576
|
+
disable: function () {
|
2577
|
+
if (!this.enabled()) { return; }
|
2578
|
+
|
2579
|
+
this._activeMode.handler.revertLayers();
|
2580
|
+
|
2581
|
+
L.Toolbar.prototype.disable.call(this);
|
2582
|
+
},
|
2583
|
+
|
2584
|
+
_save: function () {
|
2585
|
+
this._activeMode.handler.save();
|
2586
|
+
this._activeMode.handler.disable();
|
2587
|
+
},
|
2588
|
+
|
2589
|
+
_checkDisabled: function () {
|
2590
|
+
var featureGroup = this.options.featureGroup,
|
2591
|
+
hasLayers = featureGroup.getLayers().length !== 0,
|
2592
|
+
button;
|
2593
|
+
|
2594
|
+
if (this.options.edit) {
|
2595
|
+
button = this._modes[L.EditToolbar.Edit.TYPE].button;
|
2596
|
+
|
2597
|
+
if (hasLayers) {
|
2598
|
+
L.DomUtil.removeClass(button, 'leaflet-disabled');
|
2599
|
+
} else {
|
2600
|
+
L.DomUtil.addClass(button, 'leaflet-disabled');
|
2601
|
+
}
|
2602
|
+
|
2603
|
+
button.setAttribute(
|
2604
|
+
'title',
|
2605
|
+
hasLayers ?
|
2606
|
+
L.drawLocal.edit.toolbar.buttons.edit
|
2607
|
+
: L.drawLocal.edit.toolbar.buttons.editDisabled
|
2608
|
+
);
|
2609
|
+
}
|
2610
|
+
|
2611
|
+
if (this.options.remove) {
|
2612
|
+
button = this._modes[L.EditToolbar.Delete.TYPE].button;
|
2613
|
+
|
2614
|
+
if (hasLayers) {
|
2615
|
+
L.DomUtil.removeClass(button, 'leaflet-disabled');
|
2616
|
+
} else {
|
2617
|
+
L.DomUtil.addClass(button, 'leaflet-disabled');
|
2618
|
+
}
|
2619
|
+
|
2620
|
+
button.setAttribute(
|
2621
|
+
'title',
|
2622
|
+
hasLayers ?
|
2623
|
+
L.drawLocal.edit.toolbar.buttons.remove
|
2624
|
+
: L.drawLocal.edit.toolbar.buttons.removeDisabled
|
2625
|
+
);
|
2626
|
+
}
|
2627
|
+
}
|
2628
|
+
});
|
2629
|
+
|
2630
|
+
|
2631
|
+
L.EditToolbar.Edit = L.Handler.extend({
|
2632
|
+
statics: {
|
2633
|
+
TYPE: 'edit'
|
2634
|
+
},
|
2635
|
+
|
2636
|
+
includes: L.Mixin.Events,
|
2637
|
+
|
2638
|
+
initialize: function (map, options) {
|
2639
|
+
L.Handler.prototype.initialize.call(this, map);
|
2640
|
+
|
2641
|
+
L.setOptions(this, options);
|
2642
|
+
|
2643
|
+
// Store the selectable layer group for ease of access
|
2644
|
+
this._featureGroup = options.featureGroup;
|
2645
|
+
|
2646
|
+
if (!(this._featureGroup instanceof L.FeatureGroup)) {
|
2647
|
+
throw new Error('options.featureGroup must be a L.FeatureGroup');
|
2648
|
+
}
|
2649
|
+
|
2650
|
+
this._uneditedLayerProps = {};
|
2651
|
+
|
2652
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
2653
|
+
this.type = L.EditToolbar.Edit.TYPE;
|
2654
|
+
},
|
2655
|
+
|
2656
|
+
enable: function () {
|
2657
|
+
if (this._enabled || !this._hasAvailableLayers()) {
|
2658
|
+
return;
|
2659
|
+
}
|
2660
|
+
this.fire('enabled', {handler: this.type});
|
2661
|
+
//this disable other handlers
|
2662
|
+
|
2663
|
+
this._map.fire('draw:editstart', { handler: this.type });
|
2664
|
+
//allow drawLayer to be updated before beginning edition.
|
2665
|
+
|
2666
|
+
L.Handler.prototype.enable.call(this);
|
2667
|
+
this._featureGroup
|
2668
|
+
.on('layeradd', this._enableLayerEdit, this)
|
2669
|
+
.on('layerremove', this._disableLayerEdit, this);
|
2670
|
+
},
|
2671
|
+
|
2672
|
+
disable: function () {
|
2673
|
+
if (!this._enabled) { return; }
|
2674
|
+
this._featureGroup
|
2675
|
+
.off('layeradd', this._enableLayerEdit, this)
|
2676
|
+
.off('layerremove', this._disableLayerEdit, this);
|
2677
|
+
L.Handler.prototype.disable.call(this);
|
2678
|
+
this._map.fire('draw:editstop', { handler: this.type });
|
2679
|
+
this.fire('disabled', {handler: this.type});
|
2680
|
+
},
|
2681
|
+
|
2682
|
+
addHooks: function () {
|
2683
|
+
var map = this._map;
|
2684
|
+
|
2685
|
+
if (map) {
|
2686
|
+
map.getContainer().focus();
|
2687
|
+
|
2688
|
+
this._featureGroup.eachLayer(this._enableLayerEdit, this);
|
2689
|
+
|
2690
|
+
this._tooltip = new L.Tooltip(this._map);
|
2691
|
+
this._tooltip.updateContent({
|
2692
|
+
text: L.drawLocal.edit.handlers.edit.tooltip.text,
|
2693
|
+
subtext: L.drawLocal.edit.handlers.edit.tooltip.subtext
|
2694
|
+
});
|
2695
|
+
|
2696
|
+
this._map.on('mousemove', this._onMouseMove, this);
|
2697
|
+
}
|
2698
|
+
},
|
2699
|
+
|
2700
|
+
removeHooks: function () {
|
2701
|
+
if (this._map) {
|
2702
|
+
// Clean up selected layers.
|
2703
|
+
this._featureGroup.eachLayer(this._disableLayerEdit, this);
|
2704
|
+
|
2705
|
+
// Clear the backups of the original layers
|
2706
|
+
this._uneditedLayerProps = {};
|
2707
|
+
|
2708
|
+
this._tooltip.dispose();
|
2709
|
+
this._tooltip = null;
|
2710
|
+
|
2711
|
+
this._map.off('mousemove', this._onMouseMove, this);
|
2712
|
+
}
|
2713
|
+
},
|
2714
|
+
|
2715
|
+
revertLayers: function () {
|
2716
|
+
this._featureGroup.eachLayer(function (layer) {
|
2717
|
+
this._revertLayer(layer);
|
2718
|
+
}, this);
|
2719
|
+
},
|
2720
|
+
|
2721
|
+
save: function () {
|
2722
|
+
var editedLayers = new L.LayerGroup();
|
2723
|
+
this._featureGroup.eachLayer(function (layer) {
|
2724
|
+
if (layer.edited) {
|
2725
|
+
editedLayers.addLayer(layer);
|
2726
|
+
layer.edited = false;
|
2727
|
+
}
|
2728
|
+
});
|
2729
|
+
this._map.fire('draw:edited', {layers: editedLayers});
|
2730
|
+
},
|
2731
|
+
|
2732
|
+
_backupLayer: function (layer) {
|
2733
|
+
var id = L.Util.stamp(layer);
|
2734
|
+
|
2735
|
+
if (!this._uneditedLayerProps[id]) {
|
2736
|
+
// Polyline, Polygon or Rectangle
|
2737
|
+
if (layer instanceof L.Polyline || layer instanceof L.Polygon || layer instanceof L.Rectangle) {
|
2738
|
+
this._uneditedLayerProps[id] = {
|
2739
|
+
latlngs: L.LatLngUtil.cloneLatLngs(layer.getLatLngs())
|
2740
|
+
};
|
2741
|
+
} else if (layer instanceof L.Circle) {
|
2742
|
+
this._uneditedLayerProps[id] = {
|
2743
|
+
latlng: L.LatLngUtil.cloneLatLng(layer.getLatLng()),
|
2744
|
+
radius: layer.getRadius()
|
2745
|
+
};
|
2746
|
+
} else if (layer instanceof L.Marker) { // Marker
|
2747
|
+
this._uneditedLayerProps[id] = {
|
2748
|
+
latlng: L.LatLngUtil.cloneLatLng(layer.getLatLng())
|
2749
|
+
};
|
2750
|
+
}
|
2751
|
+
}
|
2752
|
+
},
|
2753
|
+
|
2754
|
+
_revertLayer: function (layer) {
|
2755
|
+
var id = L.Util.stamp(layer);
|
2756
|
+
layer.edited = false;
|
2757
|
+
if (this._uneditedLayerProps.hasOwnProperty(id)) {
|
2758
|
+
// Polyline, Polygon or Rectangle
|
2759
|
+
if (layer instanceof L.Polyline || layer instanceof L.Polygon || layer instanceof L.Rectangle) {
|
2760
|
+
layer.setLatLngs(this._uneditedLayerProps[id].latlngs);
|
2761
|
+
} else if (layer instanceof L.Circle) {
|
2762
|
+
layer.setLatLng(this._uneditedLayerProps[id].latlng);
|
2763
|
+
layer.setRadius(this._uneditedLayerProps[id].radius);
|
2764
|
+
} else if (layer instanceof L.Marker) { // Marker
|
2765
|
+
layer.setLatLng(this._uneditedLayerProps[id].latlng);
|
2766
|
+
}
|
2767
|
+
|
2768
|
+
layer.fire('revert-edited', { layer: layer });
|
2769
|
+
}
|
2770
|
+
},
|
2771
|
+
|
2772
|
+
_enableLayerEdit: function (e) {
|
2773
|
+
var layer = e.layer || e.target || e,
|
2774
|
+
pathOptions;
|
2775
|
+
|
2776
|
+
// Back up this layer (if haven't before)
|
2777
|
+
this._backupLayer(layer);
|
2778
|
+
|
2779
|
+
// Set different style for editing mode
|
2780
|
+
if (this.options.selectedPathOptions) {
|
2781
|
+
pathOptions = L.Util.extend({}, this.options.selectedPathOptions);
|
2782
|
+
|
2783
|
+
// Use the existing color of the layer
|
2784
|
+
if (pathOptions.maintainColor) {
|
2785
|
+
pathOptions.color = layer.options.color;
|
2786
|
+
pathOptions.fillColor = layer.options.fillColor;
|
2787
|
+
}
|
2788
|
+
|
2789
|
+
layer.options.original = L.extend({}, layer.options);
|
2790
|
+
layer.options.editing = pathOptions;
|
2791
|
+
}
|
2792
|
+
|
2793
|
+
layer.editing.enable();
|
2794
|
+
},
|
2795
|
+
|
2796
|
+
_disableLayerEdit: function (e) {
|
2797
|
+
var layer = e.layer || e.target || e;
|
2798
|
+
|
2799
|
+
layer.edited = false;
|
2800
|
+
layer.editing.disable();
|
2801
|
+
|
2802
|
+
delete layer.options.editing;
|
2803
|
+
delete layer.options.original;
|
2804
|
+
},
|
2805
|
+
|
2806
|
+
_onMouseMove: function (e) {
|
2807
|
+
this._tooltip.updatePosition(e.latlng);
|
2808
|
+
},
|
2809
|
+
|
2810
|
+
_hasAvailableLayers: function () {
|
2811
|
+
return this._featureGroup.getLayers().length !== 0;
|
2812
|
+
}
|
2813
|
+
});
|
2814
|
+
|
2815
|
+
|
2816
|
+
L.EditToolbar.Delete = L.Handler.extend({
|
2817
|
+
statics: {
|
2818
|
+
TYPE: 'remove' // not delete as delete is reserved in js
|
2819
|
+
},
|
2820
|
+
|
2821
|
+
includes: L.Mixin.Events,
|
2822
|
+
|
2823
|
+
initialize: function (map, options) {
|
2824
|
+
L.Handler.prototype.initialize.call(this, map);
|
2825
|
+
|
2826
|
+
L.Util.setOptions(this, options);
|
2827
|
+
|
2828
|
+
// Store the selectable layer group for ease of access
|
2829
|
+
this._deletableLayers = this.options.featureGroup;
|
2830
|
+
|
2831
|
+
if (!(this._deletableLayers instanceof L.FeatureGroup)) {
|
2832
|
+
throw new Error('options.featureGroup must be a L.FeatureGroup');
|
2833
|
+
}
|
2834
|
+
|
2835
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
2836
|
+
this.type = L.EditToolbar.Delete.TYPE;
|
2837
|
+
},
|
2838
|
+
|
2839
|
+
enable: function () {
|
2840
|
+
if (this._enabled || !this._hasAvailableLayers()) {
|
2841
|
+
return;
|
2842
|
+
}
|
2843
|
+
this.fire('enabled', { handler: this.type});
|
2844
|
+
|
2845
|
+
this._map.fire('draw:deletestart', { handler: this.type });
|
2846
|
+
|
2847
|
+
L.Handler.prototype.enable.call(this);
|
2848
|
+
|
2849
|
+
this._deletableLayers
|
2850
|
+
.on('layeradd', this._enableLayerDelete, this)
|
2851
|
+
.on('layerremove', this._disableLayerDelete, this);
|
2852
|
+
},
|
2853
|
+
|
2854
|
+
disable: function () {
|
2855
|
+
if (!this._enabled) { return; }
|
2856
|
+
|
2857
|
+
this._deletableLayers
|
2858
|
+
.off('layeradd', this._enableLayerDelete, this)
|
2859
|
+
.off('layerremove', this._disableLayerDelete, this);
|
2860
|
+
|
2861
|
+
L.Handler.prototype.disable.call(this);
|
2862
|
+
|
2863
|
+
this._map.fire('draw:deletestop', { handler: this.type });
|
2864
|
+
|
2865
|
+
this.fire('disabled', { handler: this.type});
|
2866
|
+
},
|
2867
|
+
|
2868
|
+
addHooks: function () {
|
2869
|
+
var map = this._map;
|
2870
|
+
|
2871
|
+
if (map) {
|
2872
|
+
map.getContainer().focus();
|
2873
|
+
|
2874
|
+
this._deletableLayers.eachLayer(this._enableLayerDelete, this);
|
2875
|
+
this._deletedLayers = new L.LayerGroup();
|
2876
|
+
|
2877
|
+
this._tooltip = new L.Tooltip(this._map);
|
2878
|
+
this._tooltip.updateContent({ text: L.drawLocal.edit.handlers.remove.tooltip.text });
|
2879
|
+
|
2880
|
+
this._map.on('mousemove', this._onMouseMove, this);
|
2881
|
+
}
|
2882
|
+
},
|
2883
|
+
|
2884
|
+
removeHooks: function () {
|
2885
|
+
if (this._map) {
|
2886
|
+
this._deletableLayers.eachLayer(this._disableLayerDelete, this);
|
2887
|
+
this._deletedLayers = null;
|
2888
|
+
|
2889
|
+
this._tooltip.dispose();
|
2890
|
+
this._tooltip = null;
|
2891
|
+
|
2892
|
+
this._map.off('mousemove', this._onMouseMove, this);
|
2893
|
+
}
|
2894
|
+
},
|
2895
|
+
|
2896
|
+
revertLayers: function () {
|
2897
|
+
// Iterate of the deleted layers and add them back into the featureGroup
|
2898
|
+
this._deletedLayers.eachLayer(function (layer) {
|
2899
|
+
this._deletableLayers.addLayer(layer);
|
2900
|
+
layer.fire('revert-deleted', { layer: layer });
|
2901
|
+
}, this);
|
2902
|
+
},
|
2903
|
+
|
2904
|
+
save: function () {
|
2905
|
+
this._map.fire('draw:deleted', { layers: this._deletedLayers });
|
2906
|
+
},
|
2907
|
+
|
2908
|
+
_enableLayerDelete: function (e) {
|
2909
|
+
var layer = e.layer || e.target || e;
|
2910
|
+
|
2911
|
+
layer.on('click', this._removeLayer, this);
|
2912
|
+
},
|
2913
|
+
|
2914
|
+
_disableLayerDelete: function (e) {
|
2915
|
+
var layer = e.layer || e.target || e;
|
2916
|
+
|
2917
|
+
layer.off('click', this._removeLayer, this);
|
2918
|
+
|
2919
|
+
// Remove from the deleted layers so we can't accidently revert if the user presses cancel
|
2920
|
+
this._deletedLayers.removeLayer(layer);
|
2921
|
+
},
|
2922
|
+
|
2923
|
+
_removeLayer: function (e) {
|
2924
|
+
var layer = e.layer || e.target || e;
|
2925
|
+
|
2926
|
+
this._deletableLayers.removeLayer(layer);
|
2927
|
+
|
2928
|
+
this._deletedLayers.addLayer(layer);
|
2929
|
+
|
2930
|
+
layer.fire('deleted');
|
2931
|
+
},
|
2932
|
+
|
2933
|
+
_onMouseMove: function (e) {
|
2934
|
+
this._tooltip.updatePosition(e.latlng);
|
2935
|
+
},
|
2936
|
+
|
2937
|
+
_hasAvailableLayers: function () {
|
2938
|
+
return this._deletableLayers.getLayers().length !== 0;
|
2939
|
+
}
|
2940
|
+
});
|
2941
|
+
|
2942
|
+
|
2943
|
+
}(window, document));
|