From 1820aef3fb5c926664de1d4d484f64a5c9ba7099 Mon Sep 17 00:00:00 2001 From: YANGDL <114714267@qq.com> Date: 星期二, 05 一月 2021 17:06:08 +0800 Subject: [PATCH] 优化逻辑 --- src/components/plugin/Editable.js | 3845 +++++++++++++++++++++++++++++----------------------------- 1 files changed, 1,922 insertions(+), 1,923 deletions(-) diff --git a/src/components/plugin/Editable.js b/src/components/plugin/Editable.js index c2ae865..d86dbc0 100644 --- a/src/components/plugin/Editable.js +++ b/src/components/plugin/Editable.js @@ -1,1963 +1,1962 @@ 'use strict' const init = (L) => { - (function(factory, window) { - // define an AMD module that relies on 'leaflet' - if (typeof define === 'function' && window.define.amd) { - window.define(['leaflet'], factory) + (function (factory, window) { + // define an AMD module that relies on 'leaflet' + if (typeof define === 'function' && window.define.amd) { + window.define(['leaflet'], factory) - // define a Common JS module that relies on 'leaflet' - } else if (typeof exports === 'object') { - module.exports = factory(require('leaflet')) + // define a Common JS module that relies on 'leaflet' + } else if (typeof exports === 'object') { + module.exports = factory(require('leaflet')) + } + + // attach your plugin to the global 'L' variable + if (typeof window !== 'undefined' && L) { + factory(L) + } + }(function (L) { + // 馃崅miniclass CancelableEvent (Event objects) + // 馃崅method cancel() + // Cancel any subsequent action. + + // 馃崅miniclass VertexEvent (Event objects) + // 馃崅property vertex: VertexMarker + // The vertex that fires the event. + + // 馃崅miniclass ShapeEvent (Event objects) + // 馃崅property shape: Array + // The shape (LatLngs array) subject of the action. + + // 馃崅miniclass CancelableVertexEvent (Event objects) + // 馃崅inherits VertexEvent + // 馃崅inherits CancelableEvent + + // 馃崅miniclass CancelableShapeEvent (Event objects) + // 馃崅inherits ShapeEvent + // 馃崅inherits CancelableEvent + + // 馃崅miniclass LayerEvent (Event objects) + // 馃崅property layer: object + // The Layer (Marker, Polyline鈥�) subject of the action. + + // 馃崅namespace Editable; 馃崅class Editable; 馃崅aka L.Editable + // Main edition handler. By default, it is attached to the map + // as `map.editTools` property. + // Leaflet.Editable is made to be fully extendable. You have three ways to customize + // the behaviour: using options, listening to events, or extending. + L.Editable = L.Evented.extend({ + + statics: { + FORWARD: 1, + BACKWARD: -1 + }, + + options: { + + // You can pass them when creating a map using the `editOptions` key. + // 馃崅option zIndex: int = 1000 + // The default zIndex of the editing tools. + zIndex: 1000, + + // 馃崅option polygonClass: class = L.Polygon + // Class to be used when creating a new Polygon. + polygonClass: L.Polygon, + + // 馃崅option polylineClass: class = L.Polyline + // Class to be used when creating a new Polyline. + polylineClass: L.Polyline, + + // 馃崅option markerClass: class = L.Marker + // Class to be used when creating a new Marker. + markerClass: L.Marker, + + // 馃崅option rectangleClass: class = L.Rectangle + // Class to be used when creating a new Rectangle. + rectangleClass: L.Rectangle, + + // 馃崅option circleClass: class = L.Circle + // Class to be used when creating a new Circle. + circleClass: L.Circle, + + // 馃崅option drawingCSSClass: string = 'leaflet-editable-drawing' + // CSS class to be added to the map container while drawing. + drawingCSSClass: 'leaflet-editable-drawing', + + // 馃崅option drawingCursor: const = 'crosshair' + // Cursor mode set to the map while drawing. + drawingCursor: 'crosshair', + + // 馃崅option editLayer: Layer = new L.LayerGroup() + // Layer used to store edit tools (vertex, line guide鈥�). + editLayer: undefined, + + // 馃崅option featuresLayer: Layer = new L.LayerGroup() + // Default layer used to store drawn features (Marker, Polyline鈥�). + featuresLayer: undefined, + + // 馃崅option polylineEditorClass: class = PolylineEditor + // Class to be used as Polyline editor. + polylineEditorClass: undefined, + + // 馃崅option polygonEditorClass: class = PolygonEditor + // Class to be used as Polygon editor. + polygonEditorClass: undefined, + + // 馃崅option markerEditorClass: class = MarkerEditor + // Class to be used as Marker editor. + markerEditorClass: undefined, + + // 馃崅option rectangleEditorClass: class = RectangleEditor + // Class to be used as Rectangle editor. + rectangleEditorClass: undefined, + + // 馃崅option circleEditorClass: class = CircleEditor + // Class to be used as Circle editor. + circleEditorClass: undefined, + + // 馃崅option lineGuideOptions: hash = {} + // Options to be passed to the line guides. + lineGuideOptions: {}, + + // 馃崅option skipMiddleMarkers: boolean = false + // Set this to true if you don't want middle markers. + skipMiddleMarkers: false + + }, + + initialize: function (map, options) { + L.setOptions(this, options) + this._lastZIndex = this.options.zIndex + this.map = map + this.editLayer = this.createEditLayer() + this.featuresLayer = this.createFeaturesLayer() + this.forwardLineGuide = this.createLineGuide() + this.backwardLineGuide = this.createLineGuide() + }, + + fireAndForward: function (type, e) { + e = e || {} + e.editTools = this + this.fire(type, e) + this.map.fire(type, e) + }, + + createLineGuide: function () { + const options = L.extend({ + dashArray: '5,10', + weight: 1, + interactive: false + }, this.options.lineGuideOptions) + return L.polyline([], options) + }, + + createVertexIcon: function (options) { + return L.Browser.mobile && L.Browser.touch ? new L.Editable.TouchVertexIcon(options) : new L.Editable.VertexIcon(options) + }, + + createEditLayer: function () { + return this.options.editLayer || new L.LayerGroup().addTo(this.map) + }, + + createFeaturesLayer: function () { + return this.options.featuresLayer || new L.LayerGroup().addTo(this.map) + }, + + moveForwardLineGuide: function (latlng) { + if (this.forwardLineGuide._latlngs.length) { + this.forwardLineGuide._latlngs[1] = latlng + this.forwardLineGuide._bounds.extend(latlng) + this.forwardLineGuide.redraw() } + }, - // attach your plugin to the global 'L' variable - if (typeof window !== 'undefined' && L) { - factory(L) + moveBackwardLineGuide: function (latlng) { + if (this.backwardLineGuide._latlngs.length) { + this.backwardLineGuide._latlngs[1] = latlng + this.backwardLineGuide._bounds.extend(latlng) + this.backwardLineGuide.redraw() } - }(function(L) { - // 馃崅miniclass CancelableEvent (Event objects) - // 馃崅method cancel() - // Cancel any subsequent action. + }, - // 馃崅miniclass VertexEvent (Event objects) - // 馃崅property vertex: VertexMarker - // The vertex that fires the event. + anchorForwardLineGuide: function (latlng) { + this.forwardLineGuide._latlngs[0] = latlng + this.forwardLineGuide._bounds.extend(latlng) + this.forwardLineGuide.redraw() + }, - // 馃崅miniclass ShapeEvent (Event objects) - // 馃崅property shape: Array - // The shape (LatLngs array) subject of the action. + anchorBackwardLineGuide: function (latlng) { + this.backwardLineGuide._latlngs[0] = latlng + this.backwardLineGuide._bounds.extend(latlng) + this.backwardLineGuide.redraw() + }, - // 馃崅miniclass CancelableVertexEvent (Event objects) - // 馃崅inherits VertexEvent - // 馃崅inherits CancelableEvent + attachForwardLineGuide: function () { + this.editLayer.addLayer(this.forwardLineGuide) + }, - // 馃崅miniclass CancelableShapeEvent (Event objects) - // 馃崅inherits ShapeEvent - // 馃崅inherits CancelableEvent + attachBackwardLineGuide: function () { + this.editLayer.addLayer(this.backwardLineGuide) + }, - // 馃崅miniclass LayerEvent (Event objects) - // 馃崅property layer: object - // The Layer (Marker, Polyline鈥�) subject of the action. + detachForwardLineGuide: function () { + this.forwardLineGuide.setLatLngs([]) + this.editLayer.removeLayer(this.forwardLineGuide) + }, - // 馃崅namespace Editable; 馃崅class Editable; 馃崅aka L.Editable - // Main edition handler. By default, it is attached to the map - // as `map.editTools` property. - // Leaflet.Editable is made to be fully extendable. You have three ways to customize - // the behaviour: using options, listening to events, or extending. - L.Editable = L.Evented.extend({ + detachBackwardLineGuide: function () { + this.backwardLineGuide.setLatLngs([]) + this.editLayer.removeLayer(this.backwardLineGuide) + }, - statics: { - FORWARD: 1, - BACKWARD: -1 - }, - - options: { - - // You can pass them when creating a map using the `editOptions` key. - // 馃崅option zIndex: int = 1000 - // The default zIndex of the editing tools. - zIndex: 1000, - - // 馃崅option polygonClass: class = L.Polygon - // Class to be used when creating a new Polygon. - polygonClass: L.Polygon, - - // 馃崅option polylineClass: class = L.Polyline - // Class to be used when creating a new Polyline. - polylineClass: L.Polyline, - - // 馃崅option markerClass: class = L.Marker - // Class to be used when creating a new Marker. - markerClass: L.Marker, - - // 馃崅option rectangleClass: class = L.Rectangle - // Class to be used when creating a new Rectangle. - rectangleClass: L.Rectangle, - - // 馃崅option circleClass: class = L.Circle - // Class to be used when creating a new Circle. - circleClass: L.Circle, - - // 馃崅option drawingCSSClass: string = 'leaflet-editable-drawing' - // CSS class to be added to the map container while drawing. - drawingCSSClass: 'leaflet-editable-drawing', - - // 馃崅option drawingCursor: const = 'crosshair' - // Cursor mode set to the map while drawing. - drawingCursor: 'crosshair', - - // 馃崅option editLayer: Layer = new L.LayerGroup() - // Layer used to store edit tools (vertex, line guide鈥�). - editLayer: undefined, - - // 馃崅option featuresLayer: Layer = new L.LayerGroup() - // Default layer used to store drawn features (Marker, Polyline鈥�). - featuresLayer: undefined, - - // 馃崅option polylineEditorClass: class = PolylineEditor - // Class to be used as Polyline editor. - polylineEditorClass: undefined, - - // 馃崅option polygonEditorClass: class = PolygonEditor - // Class to be used as Polygon editor. - polygonEditorClass: undefined, - - // 馃崅option markerEditorClass: class = MarkerEditor - // Class to be used as Marker editor. - markerEditorClass: undefined, - - // 馃崅option rectangleEditorClass: class = RectangleEditor - // Class to be used as Rectangle editor. - rectangleEditorClass: undefined, - - // 馃崅option circleEditorClass: class = CircleEditor - // Class to be used as Circle editor. - circleEditorClass: undefined, - - // 馃崅option lineGuideOptions: hash = {} - // Options to be passed to the line guides. - lineGuideOptions: {}, - - // 馃崅option skipMiddleMarkers: boolean = false - // Set this to true if you don't want middle markers. - skipMiddleMarkers: false - - }, - - initialize: function(map, options) { - L.setOptions(this, options) - this._lastZIndex = this.options.zIndex - this.map = map - this.editLayer = this.createEditLayer() - this.featuresLayer = this.createFeaturesLayer() - this.forwardLineGuide = this.createLineGuide() - this.backwardLineGuide = this.createLineGuide() - }, - - fireAndForward: function(type, e) { - e = e || {} - e.editTools = this - this.fire(type, e) - this.map.fire(type, e) - }, - - createLineGuide: function() { - let options = L.extend({ - dashArray: '5,10', - weight: 1, - interactive: false - }, this.options.lineGuideOptions) - return L.polyline([], options) - }, - - createVertexIcon: function(options) { - return L.Browser.mobile && L.Browser.touch ? new L.Editable.TouchVertexIcon(options) : new L.Editable.VertexIcon(options) - }, - - createEditLayer: function() { - return this.options.editLayer || new L.LayerGroup().addTo(this.map) - }, - - createFeaturesLayer: function() { - return this.options.featuresLayer || new L.LayerGroup().addTo(this.map) - }, - - moveForwardLineGuide: function(latlng) { - if (this.forwardLineGuide._latlngs.length) { - this.forwardLineGuide._latlngs[1] = latlng - this.forwardLineGuide._bounds.extend(latlng) - this.forwardLineGuide.redraw() - } - }, - - moveBackwardLineGuide: function(latlng) { - if (this.backwardLineGuide._latlngs.length) { - this.backwardLineGuide._latlngs[1] = latlng - this.backwardLineGuide._bounds.extend(latlng) - this.backwardLineGuide.redraw() - } - }, - - anchorForwardLineGuide: function(latlng) { - this.forwardLineGuide._latlngs[0] = latlng - this.forwardLineGuide._bounds.extend(latlng) - this.forwardLineGuide.redraw() - }, - - anchorBackwardLineGuide: function(latlng) { - this.backwardLineGuide._latlngs[0] = latlng - this.backwardLineGuide._bounds.extend(latlng) - this.backwardLineGuide.redraw() - }, - - attachForwardLineGuide: function() { - this.editLayer.addLayer(this.forwardLineGuide) - }, - - attachBackwardLineGuide: function() { - this.editLayer.addLayer(this.backwardLineGuide) - }, - - detachForwardLineGuide: function() { - this.forwardLineGuide.setLatLngs([]) - this.editLayer.removeLayer(this.forwardLineGuide) - }, - - detachBackwardLineGuide: function() { - this.backwardLineGuide.setLatLngs([]) - this.editLayer.removeLayer(this.backwardLineGuide) - }, - - blockEvents: function() { - // Hack: force map not to listen to other layers events while drawing. - if (!this._oldTargets) { - this._oldTargets = this.map._targets - this.map._targets = {} - } - }, - - unblockEvents: function() { - if (this._oldTargets) { - // Reset, but keep targets created while drawing. - this.map._targets = L.extend(this.map._targets, this._oldTargets) - delete this._oldTargets - } - }, - - registerForDrawing: function(editor) { - if (this._drawingEditor) this.unregisterForDrawing(this._drawingEditor) - this.blockEvents() - editor.reset() // Make sure editor tools still receive events. - this._drawingEditor = editor - this.map.on('mousemove touchmove', editor.onDrawingMouseMove, editor) - this.map.on('mousedown', this.onMousedown, this) - this.map.on('mouseup', this.onMouseup, this) - L.DomUtil.addClass(this.map._container, this.options.drawingCSSClass) - this.defaultMapCursor = this.map._container.style.cursor - this.map._container.style.cursor = this.options.drawingCursor - }, - - unregisterForDrawing: function(editor) { - this.unblockEvents() - L.DomUtil.removeClass(this.map._container, this.options.drawingCSSClass) - this.map._container.style.cursor = this.defaultMapCursor - editor = editor || this._drawingEditor - if (!editor) return - this.map.off('mousemove touchmove', editor.onDrawingMouseMove, editor) - this.map.off('mousedown', this.onMousedown, this) - this.map.off('mouseup', this.onMouseup, this) - if (editor !== this._drawingEditor) return - delete this._drawingEditor - if (editor._drawing) editor.cancelDrawing() - }, - - onMousedown: function(e) { - if (e.originalEvent.which !== 1) return - this._mouseDown = e - this._drawingEditor.onDrawingMouseDown(e) - }, - - onMouseup: function(e) { - if (this._mouseDown) { - let editor = this._drawingEditor - let mouseDown = this._mouseDown - this._mouseDown = null - editor.onDrawingMouseUp(e) - if (this._drawingEditor !== editor) return // onDrawingMouseUp may call unregisterFromDrawing. - let origin = L.point(mouseDown.originalEvent.clientX, mouseDown.originalEvent.clientY) - let distance = L.point(e.originalEvent.clientX, e.originalEvent.clientY).distanceTo(origin) - if (Math.abs(distance) < 9 * (window.devicePixelRatio || 1)) this._drawingEditor.onDrawingClick(e) - } - }, - - // 馃崅section Public methods - // You will generally access them by the `map.editTools` - // instance: - // - // `map.editTools.startPolyline();` - - // 馃崅method drawing(): boolean - // Return true if any drawing action is ongoing. - drawing: function() { - return this._drawingEditor && this._drawingEditor.drawing() - }, - - // 馃崅method stopDrawing() - // When you need to stop any ongoing drawing, without needing to know which editor is active. - stopDrawing: function() { - this.unregisterForDrawing() - }, - - // 馃崅method commitDrawing() - // When you need to commit any ongoing drawing, without needing to know which editor is active. - commitDrawing: function(e) { - if (!this._drawingEditor) return - this._drawingEditor.commitDrawing(e) - }, - - connectCreatedToMap: function(layer) { - return this.featuresLayer.addLayer(layer) - }, - - // 馃崅method startPolyline(latlng: L.LatLng, options: hash): L.Polyline - // Start drawing a Polyline. If `latlng` is given, a first point will be added. In any case, continuing on user click. - // If `options` is given, it will be passed to the Polyline class constructor. - startPolyline: function(latlng, options) { - let line = this.createPolyline([], options) - line.enableEdit(this.map).newShape(latlng) - return line - }, - - // 馃崅method startPolygon(latlng: L.LatLng, options: hash): L.Polygon - // Start drawing a Polygon. If `latlng` is given, a first point will be added. In any case, continuing on user click. - // If `options` is given, it will be passed to the Polygon class constructor. - startPolygon: function(latlng, options) { - let polygon = this.createPolygon([], options) - polygon.enableEdit(this.map).newShape(latlng) - return polygon - }, - - // 馃崅method startMarker(latlng: L.LatLng, options: hash): L.Marker - // Start adding a Marker. If `latlng` is given, the Marker will be shown first at this point. - // In any case, it will follow the user mouse, and will have a final `latlng` on next click (or touch). - // If `options` is given, it will be passed to the Marker class constructor. - startMarker: function(latlng, options) { - latlng = latlng || this.map.getCenter().clone() - let marker = this.createMarker(latlng, options) - marker.enableEdit(this.map).startDrawing() - return marker - }, - - // 馃崅method startRectangle(latlng: L.LatLng, options: hash): L.Rectangle - // Start drawing a Rectangle. If `latlng` is given, the Rectangle anchor will be added. In any case, continuing on user drag. - // If `options` is given, it will be passed to the Rectangle class constructor. - startRectangle: function(latlng, options) { - let corner = latlng || L.latLng([0, 0]) - let bounds = new L.LatLngBounds(corner, corner) - let rectangle = this.createRectangle(bounds, options) - rectangle.enableEdit(this.map).startDrawing() - return rectangle - }, - - // 馃崅method startCircle(latlng: L.LatLng, options: hash): L.Circle - // Start drawing a Circle. If `latlng` is given, the Circle anchor will be added. In any case, continuing on user drag. - // If `options` is given, it will be passed to the Circle class constructor. - startCircle: function(latlng, options) { - latlng = latlng || this.map.getCenter().clone() - let circle = this.createCircle(latlng, options) - circle.enableEdit(this.map).startDrawing() - return circle - }, - - startHole: function(editor, latlng) { - editor.newHole(latlng) - }, - - createLayer: function(Klass, latlngs, options) { - options = L.Util.extend({ editOptions: { editTools: this } }, options) - let layer = new Klass(latlngs, options) - // 馃崅namespace Editable - // 馃崅event editable:created: LayerEvent - // Fired when a new feature (Marker, Polyline鈥�) is created. - this.fireAndForward('editable:created', { layer: layer }) - return layer - }, - - createPolyline: function(latlngs, options) { - return this.createLayer((options && options.polylineClass) || this.options.polylineClass, latlngs, options) - }, - - createPolygon: function(latlngs, options) { - return this.createLayer((options && options.polygonClass) || this.options.polygonClass, latlngs, options) - }, - - createMarker: function(latlng, options) { - return this.createLayer((options && options.markerClass) || this.options.markerClass, latlng, options) - }, - - createRectangle: function(bounds, options) { - return this.createLayer((options && options.rectangleClass) || this.options.rectangleClass, bounds, options) - }, - - createCircle: function(latlng, options) { - return this.createLayer((options && options.circleClass) || this.options.circleClass, latlng, options) - } - - }) - - L.extend(L.Editable, { - - makeCancellable: function(e) { - e.cancel = function() { - e._cancelled = true - } - } - - }) - - // 馃崅namespace Map; 馃崅class Map - // Leaflet.Editable add options and events to the `L.Map` object. - // See `Editable` events for the list of events fired on the Map. - // 馃崅example - // - // ```js - // let map = L.map('map', { - // editable: true, - // editOptions: { - // 鈥� - // } - // }); - // ``` - // 馃崅section Editable Map Options - L.Map.mergeOptions({ - - // 馃崅namespace Map - // 馃崅section Map Options - // 馃崅option EditToolsClass: class = L.Editable - // Class to be used as vertex, for path editing. - EditToolsClass: L.Editable, - - // 馃崅option editable: boolean = false - // Whether to create a L.Editable instance at map init. - editable: false, - - // 馃崅option editOptions: hash = {} - // Options to pass to L.Editable when instantiating. - editOptions: {} - - }) - - L.Map.addInitHook(function() { - this.whenReady(function() { - if (this.options.editable) { - this.editTools = new this.options.EditToolsClass(this, this.options.editOptions) - } - }) - }) - - L.Editable.VertexIcon = L.DivIcon.extend({ - - options: { - iconSize: new L.Point(8, 8) - } - - }) - - L.Editable.TouchVertexIcon = L.Editable.VertexIcon.extend({ - - options: { - iconSize: new L.Point(20, 20) - } - - }) - - // 馃崅namespace Editable; 馃崅class VertexMarker; Handler for dragging path vertices. - L.Editable.VertexMarker = L.Marker.extend({ - - options: { - draggable: true, - className: 'leaflet-vertex-icon leaflet-custom-icon' - }, - - // 馃崅section Public methods - // The marker used to handle path vertex. You will usually interact with a `VertexMarker` - // instance when listening for events like `editable:vertex:ctrlclick`. - - initialize: function(latlng, latlngs, editor, options) { - // We don't use this._latlng, because on drag Leaflet replace it while - // we want to keep reference. - this.latlng = latlng - this.latlngs = latlngs - this.editor = editor - L.Marker.prototype.initialize.call(this, latlng, options) - this.options.icon = this.editor.tools.createVertexIcon({ className: this.options.className }) - this.latlng.__vertex = this - this.editor.editLayer.addLayer(this) - this.setZIndexOffset(editor.tools._lastZIndex + 1) - }, - - onAdd: function(map) { - L.Marker.prototype.onAdd.call(this, map) - this.on('drag', this.onDrag) - this.on('dragstart', this.onDragStart) - this.on('dragend', this.onDragEnd) - this.on('mouseup', this.onMouseup) - this.on('click', this.onClick) - this.on('contextmenu', this.onContextMenu) - this.on('mousedown touchstart', this.onMouseDown) - this.on('mouseover', this.onMouseOver) - this.on('mouseout', this.onMouseOut) - this.addMiddleMarkers() - }, - - onRemove: function(map) { - if (this.middleMarker) this.middleMarker.delete() - delete this.latlng.__vertex - this.off('drag', this.onDrag) - this.off('dragstart', this.onDragStart) - this.off('dragend', this.onDragEnd) - this.off('mouseup', this.onMouseup) - this.off('click', this.onClick) - this.off('contextmenu', this.onContextMenu) - this.off('mousedown touchstart', this.onMouseDown) - this.off('mouseover', this.onMouseOver) - this.off('mouseout', this.onMouseOut) - L.Marker.prototype.onRemove.call(this, map) - }, - - onDrag: function(e) { - e.vertex = this - this.editor.onVertexMarkerDrag(e) - let iconPos = L.DomUtil.getPosition(this._icon) - let latlng = this._map.layerPointToLatLng(iconPos) - this.latlng.update(latlng) - this._latlng = this.latlng // Push back to Leaflet our reference. - this.editor.refresh() - if (this.middleMarker) this.middleMarker.updateLatLng() - let next = this.getNext() - if (next && next.middleMarker) next.middleMarker.updateLatLng() - }, - - onDragStart: function(e) { - e.vertex = this - this.editor.onVertexMarkerDragStart(e) - }, - - onDragEnd: function(e) { - e.vertex = this - this.editor.onVertexMarkerDragEnd(e) - }, - - onClick: function(e) { - e.vertex = this - this.editor.onVertexMarkerClick(e) - }, - - onMouseup: function(e) { - L.DomEvent.stop(e) - e.vertex = this - this.editor.map.fire('mouseup', e) - }, - - onContextMenu: function(e) { - e.vertex = this - this.editor.onVertexMarkerContextMenu(e) - }, - - onMouseDown: function(e) { - e.vertex = this - this.editor.onVertexMarkerMouseDown(e) - }, - - onMouseOver: function(e) { - e.vertex = this - this.editor.onVertexMarkerMouseOver(e) - }, - - onMouseOut: function(e) { - e.vertex = this - this.editor.onVertexMarkerMouseOut(e) - }, - - // 馃崅method delete() - // Delete a vertex and the related LatLng. - delete: function() { - let next = this.getNext() // Compute before changing latlng - this.latlngs.splice(this.getIndex(), 1) - this.editor.editLayer.removeLayer(this) - this.editor.onVertexDeleted({ latlng: this.latlng, vertex: this }) - if (!this.latlngs.length) this.editor.deleteShape(this.latlngs) - if (next) next.resetMiddleMarker() - this.editor.refresh() - }, - - // 馃崅method getIndex(): int - // Get the index of the current vertex among others of the same LatLngs group. - getIndex: function() { - return this.latlngs.indexOf(this.latlng) - }, - - // 馃崅method getLastIndex(): int - // Get last vertex index of the LatLngs group of the current vertex. - getLastIndex: function() { - return this.latlngs.length - 1 - }, - - // 馃崅method getPrevious(): VertexMarker - // Get the previous VertexMarker in the same LatLngs group. - getPrevious: function() { - if (this.latlngs.length < 2) return - let index = this.getIndex() - let previousIndex = index - 1 - if (index === 0 && this.editor.CLOSED) previousIndex = this.getLastIndex() - let previous = this.latlngs[previousIndex] - if (previous) return previous.__vertex - }, - - // 馃崅method getNext(): VertexMarker - // Get the next VertexMarker in the same LatLngs group. - getNext: function() { - if (this.latlngs.length < 2) return - let index = this.getIndex() - let nextIndex = index + 1 - if (index === this.getLastIndex() && this.editor.CLOSED) nextIndex = 0 - let next = this.latlngs[nextIndex] - if (next) return next.__vertex - }, - - addMiddleMarker: function(previous) { - if (!this.editor.hasMiddleMarkers()) return - previous = previous || this.getPrevious() - if (previous && !this.middleMarker) this.middleMarker = this.editor.addMiddleMarker(previous, this, this.latlngs, this.editor) - }, - - addMiddleMarkers: function() { - if (!this.editor.hasMiddleMarkers()) return - let previous = this.getPrevious() - if (previous) this.addMiddleMarker(previous) - let next = this.getNext() - if (next) next.resetMiddleMarker() - }, - - resetMiddleMarker: function() { - if (this.middleMarker) this.middleMarker.delete() - this.addMiddleMarker() - }, - - // 馃崅method split() - // Split the vertex LatLngs group at its index, if possible. - split: function() { - if (!this.editor.splitShape) return // Only for PolylineEditor - this.editor.splitShape(this.latlngs, this.getIndex()) - }, - - // 馃崅method continue() - // Continue the vertex LatLngs from this vertex. Only active for first and last vertices of a Polyline. - continue: function() { - if (!this.editor.continueBackward) return // Only for PolylineEditor - let index = this.getIndex() - if (index === 0) this.editor.continueBackward(this.latlngs) - else if (index === this.getLastIndex()) this.editor.continueForward(this.latlngs) - } - - }) - - L.Editable.mergeOptions({ - - // 馃崅namespace Editable - // 馃崅option VertexMarkerClass: class = VertexMarker - // Class to be used as vertex, for path editing. - VertexMarkerClass: L.Editable.VertexMarker - - }) - - L.Editable.MiddleMarker = L.Marker.extend({ - - options: { - opacity: 0.5, - className: 'leaflet-div-icon leaflet-middle-icon', - draggable: true - }, - - initialize: function(left, right, latlngs, editor, options) { - this.left = left - this.right = right - this.editor = editor - this.latlngs = latlngs - L.Marker.prototype.initialize.call(this, this.computeLatLng(), options) - this._opacity = this.options.opacity - this.options.icon = this.editor.tools.createVertexIcon({ className: this.options.className }) - this.editor.editLayer.addLayer(this) - this.setVisibility() - }, - - setVisibility: function() { - let leftPoint = this._map.latLngToContainerPoint(this.left.latlng) - let rightPoint = this._map.latLngToContainerPoint(this.right.latlng) - let size = L.point(this.options.icon.options.iconSize) - if (leftPoint.distanceTo(rightPoint) < size.x * 3) this.hide() - else this.show() - }, - - show: function() { - this.setOpacity(this._opacity) - }, - - hide: function() { - this.setOpacity(0) - }, - - updateLatLng: function() { - this.setLatLng(this.computeLatLng()) - this.setVisibility() - }, - - computeLatLng: function() { - let leftPoint = this.editor.map.latLngToContainerPoint(this.left.latlng) - let rightPoint = this.editor.map.latLngToContainerPoint(this.right.latlng) - let y = (leftPoint.y + rightPoint.y) / 2 - let x = (leftPoint.x + rightPoint.x) / 2 - return this.editor.map.containerPointToLatLng([x, y]) - }, - - onAdd: function(map) { - L.Marker.prototype.onAdd.call(this, map) - L.DomEvent.on(this._icon, 'mousedown touchstart', this.onMouseDown, this) - map.on('zoomend', this.setVisibility, this) - }, - - onRemove: function(map) { - delete this.right.middleMarker - L.DomEvent.off(this._icon, 'mousedown touchstart', this.onMouseDown, this) - map.off('zoomend', this.setVisibility, this) - L.Marker.prototype.onRemove.call(this, map) - }, - - onMouseDown: function(e) { - let iconPos = L.DomUtil.getPosition(this._icon) - let latlng = this.editor.map.layerPointToLatLng(iconPos) - e = { - originalEvent: e, - latlng: latlng - } - if (this.options.opacity === 0) return - L.Editable.makeCancellable(e) - this.editor.onMiddleMarkerMouseDown(e) - if (e._cancelled) return - this.latlngs.splice(this.index(), 0, e.latlng) - this.editor.refresh() - let icon = this._icon - let marker = this.editor.addVertexMarker(e.latlng, this.latlngs) - this.editor.onNewVertex(marker) - /* Hack to workaround browser not firing touchend when element is no more on DOM */ - let parent = marker._icon.parentNode - parent.removeChild(marker._icon) - marker._icon = icon - parent.appendChild(marker._icon) - marker._initIcon() - marker._initInteraction() - marker.setOpacity(1) - /* End hack */ - // Transfer ongoing dragging to real marker - L.Draggable._dragging = false - marker.dragging._draggable._onDown(e.originalEvent) - this.delete() - }, - - delete: function() { - this.editor.editLayer.removeLayer(this) - }, - - index: function() { - return this.latlngs.indexOf(this.right.latlng) - } - - }) - - L.Editable.mergeOptions({ - - // 馃崅namespace Editable - // 馃崅option MiddleMarkerClass: class = VertexMarker - // Class to be used as middle vertex, pulled by the user to create a new point in the middle of a path. - MiddleMarkerClass: L.Editable.MiddleMarker - - }) - - // 馃崅namespace Editable; 馃崅class BaseEditor; 馃崅aka L.Editable.BaseEditor - // When editing a feature (Marker, Polyline鈥�), an editor is attached to it. This - // editor basically knows how to handle the edition. - L.Editable.BaseEditor = L.Handler.extend({ - - initialize: function(map, feature, options) { - L.setOptions(this, options) - this.map = map - this.feature = feature - this.feature.editor = this - this.editLayer = new L.LayerGroup() - this.tools = this.options.editTools || map.editTools - }, - - // 馃崅method enable(): this - // Set up the drawing tools for the feature to be editable. - addHooks: function() { - if (this.isConnected()) this.onFeatureAdd() - else this.feature.once('add', this.onFeatureAdd, this) - this.onEnable() - this.feature.on(this._getEvents(), this) - }, - - // 馃崅method disable(): this - // Remove the drawing tools for the feature. - removeHooks: function() { - this.feature.off(this._getEvents(), this) - if (this.feature.dragging) this.feature.dragging.disable() - this.editLayer.clearLayers() - this.tools.editLayer.removeLayer(this.editLayer) - this.onDisable() - if (this._drawing) this.cancelDrawing() - }, - - // 馃崅method drawing(): boolean - // Return true if any drawing action is ongoing with this editor. - drawing: function() { - return !!this._drawing - }, - - reset: function() { - }, - - onFeatureAdd: function() { - this.tools.editLayer.addLayer(this.editLayer) - if (this.feature.dragging) this.feature.dragging.enable() - }, - - hasMiddleMarkers: function() { - return !this.options.skipMiddleMarkers && !this.tools.options.skipMiddleMarkers - }, - - fireAndForward: function(type, e) { - e = e || {} - e.layer = this.feature - this.feature.fire(type, e) - this.tools.fireAndForward(type, e) - }, - - onEnable: function() { - // 馃崅namespace Editable - // 馃崅event editable:enable: Event - // Fired when an existing feature is ready to be edited. - this.fireAndForward('editable:enable') - }, - - onDisable: function() { - // 馃崅namespace Editable - // 馃崅event editable:disable: Event - // Fired when an existing feature is not ready anymore to be edited. - this.fireAndForward('editable:disable') - }, - - onEditing: function() { - // 馃崅namespace Editable - // 馃崅event editable:editing: Event - // Fired as soon as any change is made to the feature geometry. - this.fireAndForward('editable:editing') - }, - - onStartDrawing: function() { - // 馃崅namespace Editable - // 馃崅section Drawing events - // 馃崅event editable:drawing:start: Event - // Fired when a feature is to be drawn. - this.fireAndForward('editable:drawing:start') - }, - - onEndDrawing: function() { - // 馃崅namespace Editable - // 馃崅section Drawing events - // 馃崅event editable:drawing:end: Event - // Fired when a feature is not drawn anymore. - this.fireAndForward('editable:drawing:end') - }, - - onCancelDrawing: function() { - // 馃崅namespace Editable - // 馃崅section Drawing events - // 馃崅event editable:drawing:cancel: Event - // Fired when user cancel drawing while a feature is being drawn. - this.fireAndForward('editable:drawing:cancel') - }, - - onCommitDrawing: function(e) { - // 馃崅namespace Editable - // 馃崅section Drawing events - // 馃崅event editable:drawing:commit: Event - // Fired when user finish drawing a feature. - this.fireAndForward('editable:drawing:commit', e) - }, - - onDrawingMouseDown: function(e) { - // 馃崅namespace Editable - // 馃崅section Drawing events - // 馃崅event editable:drawing:mousedown: Event - // Fired when user `mousedown` while drawing. - this.fireAndForward('editable:drawing:mousedown', e) - }, - - onDrawingMouseUp: function(e) { - // 馃崅namespace Editable - // 馃崅section Drawing events - // 馃崅event editable:drawing:mouseup: Event - // Fired when user `mouseup` while drawing. - this.fireAndForward('editable:drawing:mouseup', e) - }, - - startDrawing: function() { - if (!this._drawing) this._drawing = L.Editable.FORWARD - this.tools.registerForDrawing(this) - this.onStartDrawing() - }, - - commitDrawing: function(e) { - this.onCommitDrawing(e) - this.endDrawing() - }, - - cancelDrawing: function() { - // If called during a vertex drag, the vertex will be removed before - // the mouseup fires on it. This is a workaround. Maybe better fix is - // To have L.Draggable reset it's status on disable (Leaflet side). - L.Draggable._dragging = false - this.onCancelDrawing() - this.endDrawing() - }, - - endDrawing: function() { - this._drawing = false - this.tools.unregisterForDrawing(this) - this.onEndDrawing() - }, - - onDrawingClick: function(e) { - if (!this.drawing()) return - L.Editable.makeCancellable(e) - // 馃崅namespace Editable - // 馃崅section Drawing events - // 馃崅event editable:drawing:click: CancelableEvent - // Fired when user `click` while drawing, before any internal action is being processed. - this.fireAndForward('editable:drawing:click', e) - if (e._cancelled) return - if (!this.isConnected()) this.connect(e) - this.processDrawingClick(e) - }, - - isConnected: function() { - return this.map.hasLayer(this.feature) - }, - - connect: function() { - this.tools.connectCreatedToMap(this.feature) - this.tools.editLayer.addLayer(this.editLayer) - }, - - onMove: function(e) { - // 馃崅namespace Editable - // 馃崅section Drawing events - // 馃崅event editable:drawing:move: Event - // Fired when `move` mouse while drawing, while dragging a marker, and while dragging a vertex. - this.fireAndForward('editable:drawing:move', e) - }, - - onDrawingMouseMove: function(e) { - this.onMove(e) - }, - - _getEvents: function() { - return { - dragstart: this.onDragStart, - drag: this.onDrag, - dragend: this.onDragEnd, - remove: this.disable - } - }, - - onDragStart: function(e) { - this.onEditing() - // 馃崅namespace Editable - // 馃崅event editable:dragstart: Event - // Fired before a path feature is dragged. - this.fireAndForward('editable:dragstart', e) - }, - - onDrag: function(e) { - this.onMove(e) - // 馃崅namespace Editable - // 馃崅event editable:drag: Event - // Fired when a path feature is being dragged. - this.fireAndForward('editable:drag', e) - }, - - onDragEnd: function(e) { - // 馃崅namespace Editable - // 馃崅event editable:dragend: Event - // Fired after a path feature has been dragged. - this.fireAndForward('editable:dragend', e) - } - - }) - - // 馃崅namespace Editable; 馃崅class MarkerEditor; 馃崅aka L.Editable.MarkerEditor - // 馃崅inherits BaseEditor - // Editor for Marker. - L.Editable.MarkerEditor = L.Editable.BaseEditor.extend({ - - onDrawingMouseMove: function(e) { - L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e) - if (this._drawing) this.feature.setLatLng(e.latlng) - }, - - processDrawingClick: function(e) { - // 馃崅namespace Editable - // 馃崅section Drawing events - // 馃崅event editable:drawing:clicked: Event - // Fired when user `click` while drawing, after all internal actions. - this.fireAndForward('editable:drawing:clicked', e) - this.commitDrawing(e) - }, - - connect: function(e) { - // On touch, the latlng has not been updated because there is - // no mousemove. - if (e) this.feature._latlng = e.latlng - L.Editable.BaseEditor.prototype.connect.call(this, e) - } - - }) - - // 馃崅namespace Editable; 馃崅class PathEditor; 馃崅aka L.Editable.PathEditor - // 馃崅inherits BaseEditor - // Base class for all path editors. - L.Editable.PathEditor = L.Editable.BaseEditor.extend({ - - CLOSED: false, - MIN_VERTEX: 2, - - addHooks: function() { - L.Editable.BaseEditor.prototype.addHooks.call(this) - if (this.feature) this.initVertexMarkers() - return this - }, - - initVertexMarkers: function(latlngs) { - if (!this.enabled()) return - latlngs = latlngs || this.getLatLngs() - if (isFlat(latlngs)) this.addVertexMarkers(latlngs) - else for (let i = 0; i < latlngs.length; i++) this.initVertexMarkers(latlngs[i]) - }, - - getLatLngs: function() { - return this.feature.getLatLngs() - }, - - // 馃崅method reset() - // Rebuild edit elements (Vertex, MiddleMarker, etc.). - reset: function() { - this.editLayer.clearLayers() - this.initVertexMarkers() - }, - - addVertexMarker: function(latlng, latlngs) { - return new this.tools.options.VertexMarkerClass(latlng, latlngs, this) - }, - - onNewVertex: function(vertex) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:new: VertexEvent - // Fired when a new vertex is created. - this.fireAndForward('editable:vertex:new', { latlng: vertex.latlng, vertex: vertex }) - }, - - addVertexMarkers: function(latlngs) { - for (let i = 0; i < latlngs.length; i++) { - this.addVertexMarker(latlngs[i], latlngs) - } - }, - - refreshVertexMarkers: function(latlngs) { - latlngs = latlngs || this.getDefaultLatLngs() - for (let i = 0; i < latlngs.length; i++) { - latlngs[i].__vertex.update() - } - }, - - addMiddleMarker: function(left, right, latlngs) { - return new this.tools.options.MiddleMarkerClass(left, right, latlngs, this) - }, - - onVertexMarkerClick: function(e) { - L.Editable.makeCancellable(e) - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:click: CancelableVertexEvent - // Fired when a `click` is issued on a vertex, before any internal action is being processed. - this.fireAndForward('editable:vertex:click', e) - if (e._cancelled) return - if (this.tools.drawing() && this.tools._drawingEditor !== this) return - let index = e.vertex.getIndex() - let commit - if (e.originalEvent.ctrlKey) { - this.onVertexMarkerCtrlClick(e) - } else if (e.originalEvent.altKey) { - this.onVertexMarkerAltClick(e) - } else if (e.originalEvent.shiftKey) { - this.onVertexMarkerShiftClick(e) - } else if (e.originalEvent.metaKey) { - this.onVertexMarkerMetaKeyClick(e) - } else if (index === e.vertex.getLastIndex() && this._drawing === L.Editable.FORWARD) { - if (index >= this.MIN_VERTEX - 1) commit = true - } else if (index === 0 && this._drawing === L.Editable.BACKWARD && this._drawnLatLngs.length >= this.MIN_VERTEX) { - commit = true - } else if (index === 0 && this._drawing === L.Editable.FORWARD && this._drawnLatLngs.length >= this.MIN_VERTEX && this.CLOSED) { - commit = true // Allow to close on first point also for polygons - } else { - this.onVertexRawMarkerClick(e) - } - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:clicked: VertexEvent - // Fired when a `click` is issued on a vertex, after all internal actions. - this.fireAndForward('editable:vertex:clicked', e) - if (commit) this.commitDrawing(e) - }, - - onVertexRawMarkerClick: function(e) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:rawclick: CancelableVertexEvent - // Fired when a `click` is issued on a vertex without any special key and without being in drawing mode. - this.fireAndForward('editable:vertex:rawclick', e) - if (e._cancelled) return - if (!this.vertexCanBeDeleted(e.vertex)) return - e.vertex.delete() - }, - - vertexCanBeDeleted: function(vertex) { - return vertex.latlngs.length > this.MIN_VERTEX - }, - - onVertexDeleted: function(e) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:deleted: VertexEvent - // Fired after a vertex has been deleted by user. - this.fireAndForward('editable:vertex:deleted', e) - }, - - onVertexMarkerCtrlClick: function(e) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:ctrlclick: VertexEvent - // Fired when a `click` with `ctrlKey` is issued on a vertex. - this.fireAndForward('editable:vertex:ctrlclick', e) - }, - - onVertexMarkerShiftClick: function(e) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:shiftclick: VertexEvent - // Fired when a `click` with `shiftKey` is issued on a vertex. - this.fireAndForward('editable:vertex:shiftclick', e) - }, - - onVertexMarkerMetaKeyClick: function(e) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:metakeyclick: VertexEvent - // Fired when a `click` with `metaKey` is issued on a vertex. - this.fireAndForward('editable:vertex:metakeyclick', e) - }, - - onVertexMarkerAltClick: function(e) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:altclick: VertexEvent - // Fired when a `click` with `altKey` is issued on a vertex. - this.fireAndForward('editable:vertex:altclick', e) - }, - - onVertexMarkerContextMenu: function(e) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:contextmenu: VertexEvent - // Fired when a `contextmenu` is issued on a vertex. - this.fireAndForward('editable:vertex:contextmenu', e) - }, - - onVertexMarkerMouseDown: function(e) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:mousedown: VertexEvent - // Fired when user `mousedown` a vertex. - this.fireAndForward('editable:vertex:mousedown', e) - }, - - onVertexMarkerMouseOver: function(e) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:mouseover: VertexEvent - // Fired when a user's mouse enters the vertex - this.fireAndForward('editable:vertex:mouseover', e) - }, - - onVertexMarkerMouseOut: function(e) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:mouseout: VertexEvent - // Fired when a user's mouse leaves the vertex - this.fireAndForward('editable:vertex:mouseout', e) - }, - - onMiddleMarkerMouseDown: function(e) { - // 馃崅namespace Editable - // 馃崅section MiddleMarker events - // 馃崅event editable:middlemarker:mousedown: VertexEvent - // Fired when user `mousedown` a middle marker. - this.fireAndForward('editable:middlemarker:mousedown', e) - }, - - onVertexMarkerDrag: function(e) { - this.onMove(e) - if (this.feature._bounds) this.extendBounds(e) - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:drag: VertexEvent - // Fired when a vertex is dragged by user. - this.fireAndForward('editable:vertex:drag', e) - }, - - onVertexMarkerDragStart: function(e) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:dragstart: VertexEvent - // Fired before a vertex is dragged by user. - this.fireAndForward('editable:vertex:dragstart', e) - }, - - onVertexMarkerDragEnd: function(e) { - // 馃崅namespace Editable - // 馃崅section Vertex events - // 馃崅event editable:vertex:dragend: VertexEvent - // Fired after a vertex is dragged by user. - this.fireAndForward('editable:vertex:dragend', e) - }, - - setDrawnLatLngs: function(latlngs) { - this._drawnLatLngs = latlngs || this.getDefaultLatLngs() - }, - - startDrawing: function() { - if (!this._drawnLatLngs) this.setDrawnLatLngs() - L.Editable.BaseEditor.prototype.startDrawing.call(this) - }, - - startDrawingForward: function() { - this.startDrawing() - }, - - endDrawing: function() { - this.tools.detachForwardLineGuide() - this.tools.detachBackwardLineGuide() - if (this._drawnLatLngs && this._drawnLatLngs.length < this.MIN_VERTEX) this.deleteShape(this._drawnLatLngs) - L.Editable.BaseEditor.prototype.endDrawing.call(this) - delete this._drawnLatLngs - }, - - addLatLng: function(latlng) { - if (this._drawing === L.Editable.FORWARD) this._drawnLatLngs.push(latlng) - else this._drawnLatLngs.unshift(latlng) - this.feature._bounds.extend(latlng) - let vertex = this.addVertexMarker(latlng, this._drawnLatLngs) - this.onNewVertex(vertex) - this.refresh() - }, - - newPointForward: function(latlng) { - this.addLatLng(latlng) - this.tools.attachForwardLineGuide() - this.tools.anchorForwardLineGuide(latlng) - }, - - newPointBackward: function(latlng) { - this.addLatLng(latlng) - this.tools.anchorBackwardLineGuide(latlng) - }, - - // 馃崅namespace PathEditor - // 馃崅method push() - // Programmatically add a point while drawing. - push: function(latlng) { - if (!latlng) return console.error('L.Editable.PathEditor.push expect a valid latlng as parameter') - if (this._drawing === L.Editable.FORWARD) this.newPointForward(latlng) - else this.newPointBackward(latlng) - }, - - removeLatLng: function(latlng) { - latlng.__vertex.delete() - this.refresh() - }, - - // 馃崅method pop(): L.LatLng or null - // Programmatically remove last point (if any) while drawing. - pop: function() { - if (this._drawnLatLngs.length <= 1) return - let latlng - if (this._drawing === L.Editable.FORWARD) latlng = this._drawnLatLngs[this._drawnLatLngs.length - 1] - else latlng = this._drawnLatLngs[0] - this.removeLatLng(latlng) - if (this._drawing === L.Editable.FORWARD) this.tools.anchorForwardLineGuide(this._drawnLatLngs[this._drawnLatLngs.length - 1]) - else this.tools.anchorForwardLineGuide(this._drawnLatLngs[0]) - return latlng - }, - - processDrawingClick: function(e) { - if (e.vertex && e.vertex.editor === this) return - if (this._drawing === L.Editable.FORWARD) this.newPointForward(e.latlng) - else this.newPointBackward(e.latlng) - this.fireAndForward('editable:drawing:clicked', e) - }, - - onDrawingMouseMove: function(e) { - L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e) - if (this._drawing) { - this.tools.moveForwardLineGuide(e.latlng) - this.tools.moveBackwardLineGuide(e.latlng) - } - }, - - refresh: function() { - this.feature.redraw() - this.onEditing() - }, - - // 馃崅namespace PathEditor - // 馃崅method newShape(latlng?: L.LatLng) - // Add a new shape (Polyline, Polygon) in a multi, and setup up drawing tools to draw it; - // if optional `latlng` is given, start a path at this point. - newShape: function(latlng) { - let shape = this.addNewEmptyShape() - if (!shape) return - this.setDrawnLatLngs(shape[0] || shape) // Polygon or polyline - this.startDrawingForward() - // 馃崅namespace Editable - // 馃崅section Shape events - // 馃崅event editable:shape:new: ShapeEvent - // Fired when a new shape is created in a multi (Polygon or Polyline). - this.fireAndForward('editable:shape:new', { shape: shape }) - if (latlng) this.newPointForward(latlng) - }, - - deleteShape: function(shape, latlngs) { - let e = { shape: shape } - L.Editable.makeCancellable(e) - // 馃崅namespace Editable - // 馃崅section Shape events - // 馃崅event editable:shape:delete: CancelableShapeEvent - // Fired before a new shape is deleted in a multi (Polygon or Polyline). - this.fireAndForward('editable:shape:delete', e) - if (e._cancelled) return - shape = this._deleteShape(shape, latlngs) - if (this.ensureNotFlat) this.ensureNotFlat() // Polygon. - this.feature.setLatLngs(this.getLatLngs()) // Force bounds reset. - this.refresh() - this.reset() - // 馃崅namespace Editable - // 馃崅section Shape events - // 馃崅event editable:shape:deleted: ShapeEvent - // Fired after a new shape is deleted in a multi (Polygon or Polyline). - this.fireAndForward('editable:shape:deleted', { shape: shape }) - return shape - }, - - _deleteShape: function(shape, latlngs) { - latlngs = latlngs || this.getLatLngs() - if (!latlngs.length) return - let self = this - let inplaceDelete = function(latlngs, shape) { - // Called when deleting a flat latlngs - shape = latlngs.splice(0, Number.MAX_VALUE) - return shape - } - let spliceDelete = function(latlngs, shape) { - // Called when removing a latlngs inside an array - latlngs.splice(latlngs.indexOf(shape), 1) - if (!latlngs.length) self._deleteShape(latlngs) - return shape - } - if (latlngs === shape) return inplaceDelete(latlngs, shape) - for (let i = 0; i < latlngs.length; i++) { - if (latlngs[i] === shape) return spliceDelete(latlngs, shape) - else if (latlngs[i].indexOf(shape) !== -1) return spliceDelete(latlngs[i], shape) - } - }, - - // 馃崅namespace PathEditor - // 馃崅method deleteShapeAt(latlng: L.LatLng): Array - // Remove a path shape at the given `latlng`. - deleteShapeAt: function(latlng) { - let shape = this.feature.shapeAt(latlng) - if (shape) return this.deleteShape(shape) - }, - - // 馃崅method appendShape(shape: Array) - // Append a new shape to the Polygon or Polyline. - appendShape: function(shape) { - this.insertShape(shape) - }, - - // 馃崅method prependShape(shape: Array) - // Prepend a new shape to the Polygon or Polyline. - prependShape: function(shape) { - this.insertShape(shape, 0) - }, - - // 馃崅method insertShape(shape: Array, index: int) - // Insert a new shape to the Polygon or Polyline at given index (default is to append). - insertShape: function(shape, index) { - this.ensureMulti() - shape = this.formatShape(shape) - if (typeof index === 'undefined') index = this.feature._latlngs.length - this.feature._latlngs.splice(index, 0, shape) - this.feature.redraw() - if (this._enabled) this.reset() - }, - - extendBounds: function(e) { - this.feature._bounds.extend(e.vertex.latlng) - }, - - onDragStart: function(e) { - this.editLayer.clearLayers() - L.Editable.BaseEditor.prototype.onDragStart.call(this, e) - }, - - onDragEnd: function(e) { - this.initVertexMarkers() - L.Editable.BaseEditor.prototype.onDragEnd.call(this, e) - } - - }) - - // 馃崅namespace Editable; 馃崅class PolylineEditor; 馃崅aka L.Editable.PolylineEditor - // 馃崅inherits PathEditor - L.Editable.PolylineEditor = L.Editable.PathEditor.extend({ - - startDrawingBackward: function() { - this._drawing = L.Editable.BACKWARD - this.startDrawing() - }, - - // 馃崅method continueBackward(latlngs?: Array) - // Set up drawing tools to continue the line backward. - continueBackward: function(latlngs) { - if (this.drawing()) return - latlngs = latlngs || this.getDefaultLatLngs() - this.setDrawnLatLngs(latlngs) - if (latlngs.length > 0) { - this.tools.attachBackwardLineGuide() - this.tools.anchorBackwardLineGuide(latlngs[0]) - } - this.startDrawingBackward() - }, - - // 馃崅method continueForward(latlngs?: Array) - // Set up drawing tools to continue the line forward. - continueForward: function(latlngs) { - if (this.drawing()) return - latlngs = latlngs || this.getDefaultLatLngs() - this.setDrawnLatLngs(latlngs) - if (latlngs.length > 0) { - this.tools.attachForwardLineGuide() - this.tools.anchorForwardLineGuide(latlngs[latlngs.length - 1]) - } - this.startDrawingForward() - }, - - getDefaultLatLngs: function(latlngs) { - latlngs = latlngs || this.feature._latlngs - if (!latlngs.length || latlngs[0] instanceof L.LatLng) return latlngs - else return this.getDefaultLatLngs(latlngs[0]) - }, - - ensureMulti: function() { - if (this.feature._latlngs.length && isFlat(this.feature._latlngs)) { - this.feature._latlngs = [this.feature._latlngs] - } - }, - - addNewEmptyShape: function() { - if (this.feature._latlngs.length) { - let shape = [] - this.appendShape(shape) - return shape - } else { - return this.feature._latlngs - } - }, - - formatShape: function(shape) { - if (isFlat(shape)) return shape - else if (shape[0]) return this.formatShape(shape[0]) - }, - - // 馃崅method splitShape(latlngs?: Array, index: int) - // Split the given `latlngs` shape at index `index` and integrate new shape in instance `latlngs`. - splitShape: function(shape, index) { - if (!index || index >= shape.length - 1) return - this.ensureMulti() - let shapeIndex = this.feature._latlngs.indexOf(shape) - if (shapeIndex === -1) return - let first = shape.slice(0, index + 1) - let second = shape.slice(index) - // We deal with reference, we don't want twice the same latlng around. - second[0] = L.latLng(second[0].lat, second[0].lng, second[0].alt) - this.feature._latlngs.splice(shapeIndex, 1, first, second) - this.refresh() - this.reset() - } - - }) - - // 馃崅namespace Editable; 馃崅class PolygonEditor; 馃崅aka L.Editable.PolygonEditor - // 馃崅inherits PathEditor - L.Editable.PolygonEditor = L.Editable.PathEditor.extend({ - - CLOSED: true, - MIN_VERTEX: 3, - - newPointForward: function(latlng) { - L.Editable.PathEditor.prototype.newPointForward.call(this, latlng) - if (!this.tools.backwardLineGuide._latlngs.length) this.tools.anchorBackwardLineGuide(latlng) - if (this._drawnLatLngs.length === 2) this.tools.attachBackwardLineGuide() - }, - - addNewEmptyHole: function(latlng) { - this.ensureNotFlat() - let latlngs = this.feature.shapeAt(latlng) - if (!latlngs) return - let holes = [] - latlngs.push(holes) - return holes - }, - - // 馃崅method newHole(latlng?: L.LatLng, index: int) - // Set up drawing tools for creating a new hole on the Polygon. If the `latlng` param is given, a first point is created. - newHole: function(latlng) { - let holes = this.addNewEmptyHole(latlng) - if (!holes) return - this.setDrawnLatLngs(holes) - this.startDrawingForward() - if (latlng) this.newPointForward(latlng) - }, - - addNewEmptyShape: function() { - if (this.feature._latlngs.length && this.feature._latlngs[0].length) { - let shape = [] - this.appendShape(shape) - return shape - } else { - return this.feature._latlngs - } - }, - - ensureMulti: function() { - if (this.feature._latlngs.length && isFlat(this.feature._latlngs[0])) { - this.feature._latlngs = [this.feature._latlngs] - } - }, - - ensureNotFlat: function() { - if (!this.feature._latlngs.length || isFlat(this.feature._latlngs)) this.feature._latlngs = [this.feature._latlngs] - }, - - vertexCanBeDeleted: function(vertex) { - let parent = this.feature.parentShape(vertex.latlngs) - let idx = L.Util.indexOf(parent, vertex.latlngs) - if (idx > 0) return true // Holes can be totally deleted without removing the layer itself. - return L.Editable.PathEditor.prototype.vertexCanBeDeleted.call(this, vertex) - }, - - getDefaultLatLngs: function() { - if (!this.feature._latlngs.length) this.feature._latlngs.push([]) - return this.feature._latlngs[0] - }, - - formatShape: function(shape) { - // [[1, 2], [3, 4]] => must be nested - // [] => must be nested - // [[]] => is already nested - if (isFlat(shape) && (!shape[0] || shape[0].length !== 0)) return [shape] - else return shape - } - - }) - - // 馃崅namespace Editable; 馃崅class RectangleEditor; 馃崅aka L.Editable.RectangleEditor - // 馃崅inherits PathEditor - L.Editable.RectangleEditor = L.Editable.PathEditor.extend({ - - CLOSED: true, - MIN_VERTEX: 4, - - options: { - skipMiddleMarkers: true - }, - - extendBounds: function(e) { - let index = e.vertex.getIndex() - let next = e.vertex.getNext() - let previous = e.vertex.getPrevious() - let oppositeIndex = (index + 2) % 4 - let opposite = e.vertex.latlngs[oppositeIndex] - let bounds = new L.LatLngBounds(e.latlng, opposite) - // Update latlngs by hand to preserve order. - previous.latlng.update([e.latlng.lat, opposite.lng]) - next.latlng.update([opposite.lat, e.latlng.lng]) - this.updateBounds(bounds) - this.refreshVertexMarkers() - }, - - onDrawingMouseDown: function(e) { - L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e) - this.connect() - let latlngs = this.getDefaultLatLngs() - // L.Polygon._convertLatLngs removes last latlng if it equals first point, - // which is the case here as all latlngs are [0, 0] - if (latlngs.length === 3) latlngs.push(e.latlng) - let bounds = new L.LatLngBounds(e.latlng, e.latlng) - this.updateBounds(bounds) - this.updateLatLngs(bounds) - this.refresh() - this.reset() - // Stop dragging map. - // L.Draggable has two workflows: - // - mousedown => mousemove => mouseup - // - touchstart => touchmove => touchend - // Problem: L.Map.Tap does not allow us to listen to touchstart, so we only - // can deal with mousedown, but then when in a touch device, we are dealing with - // simulated events (actually simulated by L.Map.Tap), which are no more taken - // into account by L.Draggable. - // Ref.: https://github.com/Leaflet/Leaflet.Editable/issues/103 - e.originalEvent._simulated = false - this.map.dragging._draggable._onUp(e.originalEvent) - // Now transfer ongoing drag action to the bottom right corner. - // Should we refine which corner will handle the drag according to - // drag direction? - latlngs[3].__vertex.dragging._draggable._onDown(e.originalEvent) - }, - - onDrawingMouseUp: function(e) { - this.commitDrawing(e) - e.originalEvent._simulated = false - L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e) - }, - - onDrawingMouseMove: function(e) { - e.originalEvent._simulated = false - L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e) - }, - - getDefaultLatLngs: function(latlngs) { - return latlngs || this.feature._latlngs[0] - }, - - updateBounds: function(bounds) { - this.feature._bounds = bounds - }, - - updateLatLngs: function(bounds) { - let latlngs = this.getDefaultLatLngs() - let newLatlngs = this.feature._boundsToLatLngs(bounds) - // Keep references. - for (let i = 0; i < latlngs.length; i++) { - latlngs[i].update(newLatlngs[i]) - } - } - - }) - - // 馃崅namespace Editable; 馃崅class CircleEditor; 馃崅aka L.Editable.CircleEditor - // 馃崅inherits PathEditor - L.Editable.CircleEditor = L.Editable.PathEditor.extend({ - - MIN_VERTEX: 2, - - options: { - skipMiddleMarkers: true - }, - - initialize: function(map, feature, options) { - L.Editable.PathEditor.prototype.initialize.call(this, map, feature, options) - // C.Y.B Modify - - let latlng = this.computeResizeLatLng() - - // latlng.lat = latlng.lat-0.007855; - // latlng.lng= latlng.lng-0.1; - this._resizeLatLng = latlng - // 鍘熷鏂规硶 - // this._resizeLatLng = this.computeResizeLatLng(); - }, - - computeResizeLatLng: function() { - // While circle is not added to the map, _radius is not set. - // let delta = (this.feature._radius || this.feature._mRadius) * Math.cos(Math.PI / 4) - let delta = (this.feature._radius || this.feature._mRadius) - let point = this.map.project(this.feature._latlng) - // return this.map.unproject([point.x + delta, point.y - delta]) - return this.map.unproject([point.x + delta, point.y]) - }, - - updateResizeLatLng: function() { - this._resizeLatLng.update(this.computeResizeLatLng()) - this._resizeLatLng.__vertex.update() - }, - - getLatLngs: function() { - return [this.feature._latlng, this._resizeLatLng] - }, - - getDefaultLatLngs: function() { - return this.getLatLngs() - }, - - onVertexMarkerDrag: function(e) { - if (e.vertex.getIndex() === 1) this.resize(e) - else this.updateResizeLatLng(e) - L.Editable.PathEditor.prototype.onVertexMarkerDrag.call(this, e) - }, - - resize: function(e) { - let radius = this.feature._latlng.distanceTo(e.latlng) - this.feature.setRadius(radius) - }, - - onDrawingMouseDown: function(e) { - L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e) - this._resizeLatLng.update(e.latlng) - this.feature._latlng.update(e.latlng) - this.connect() - // Stop dragging map. - e.originalEvent._simulated = false - this.map.dragging._draggable._onUp(e.originalEvent) - // Now transfer ongoing drag action to the radius handler. - this._resizeLatLng.__vertex.dragging._draggable._onDown(e.originalEvent) - }, - - onDrawingMouseUp: function(e) { - this.commitDrawing(e) - e.originalEvent._simulated = false - L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e) - }, - - onDrawingMouseMove: function(e) { - e.originalEvent._simulated = false - L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e) - }, - - onDrag: function(e) { - L.Editable.PathEditor.prototype.onDrag.call(this, e) - this.feature.dragging.updateLatLng(this._resizeLatLng) - } - - }) - - // 馃崅namespace Editable; 馃崅class EditableMixin - // `EditableMixin` is included to `L.Polyline`, `L.Polygon`, `L.Rectangle`, `L.Circle` - // and `L.Marker`. It adds some methods to them. - // *When editing is enabled, the editor is accessible on the instance with the - // `editor` property.* - let EditableMixin = { - - createEditor: function(map) { - map = map || this._map - let tools = (this.options.editOptions || {}).editTools || map.editTools - if (!tools) throw Error('Unable to detect Editable instance.') - let Klass = this.options.editorClass || this.getEditorClass(tools) - return new Klass(map, this, this.options.editOptions) - }, - - // 馃崅method enableEdit(map?: L.Map): this.editor - // Enable editing, by creating an editor if not existing, and then calling `enable` on it. - enableEdit: function(map) { - if (!this.editor) this.createEditor(map) - this.editor.enable() - return this.editor - }, - - // 馃崅method editEnabled(): boolean - // Return true if current instance has an editor attached, and this editor is enabled. - editEnabled: function() { - return this.editor && this.editor.enabled() - }, - - // 馃崅method disableEdit() - // Disable editing, also remove the editor property reference. - disableEdit: function() { - if (this.editor) { - this.editor.disable() - delete this.editor - } - }, - - // 馃崅method toggleEdit() - // Enable or disable editing, according to current status. - toggleEdit: function() { - if (this.editEnabled()) this.disableEdit() - else this.enableEdit() - }, - - _onEditableAdd: function() { - if (this.editor) this.enableEdit() - } - + blockEvents: function () { + // Hack: force map not to listen to other layers events while drawing. + if (!this._oldTargets) { + this._oldTargets = this.map._targets + this.map._targets = {} } + }, - let PolylineMixin = { - - getEditorClass: function(tools) { - return (tools && tools.options.polylineEditorClass) ? tools.options.polylineEditorClass : L.Editable.PolylineEditor - }, - - shapeAt: function(latlng, latlngs) { - // We can have those cases: - // - latlngs are just a flat array of latlngs, use this - // - latlngs is an array of arrays of latlngs, loop over - let shape = null - latlngs = latlngs || this._latlngs - if (!latlngs.length) return shape - else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs - else for (let i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i])) return latlngs[i] - return shape - }, - - isInLatLngs: function(l, latlngs) { - if (!latlngs) return false - let i, k, len - let part = [] - let p - let w = this._clickTolerance() - this._projectLatlngs(latlngs, part, this._pxBounds) - part = part[0] - p = this._map.latLngToLayerPoint(l) - - if (!this._pxBounds.contains(p)) { - return false - } - for (i = 1, len = part.length, k = 0; i < len; k = i++) { - if (L.LineUtil.pointToSegmentDistance(p, part[k], part[i]) <= w) { - return true - } - } - return false - } - + unblockEvents: function () { + if (this._oldTargets) { + // Reset, but keep targets created while drawing. + this.map._targets = L.extend(this.map._targets, this._oldTargets) + delete this._oldTargets } + }, - let PolygonMixin = { + registerForDrawing: function (editor) { + if (this._drawingEditor) this.unregisterForDrawing(this._drawingEditor) + this.blockEvents() + editor.reset() // Make sure editor tools still receive events. + this._drawingEditor = editor + this.map.on('mousemove touchmove', editor.onDrawingMouseMove, editor) + this.map.on('mousedown', this.onMousedown, this) + this.map.on('mouseup', this.onMouseup, this) + L.DomUtil.addClass(this.map._container, this.options.drawingCSSClass) + this.defaultMapCursor = this.map._container.style.cursor + this.map._container.style.cursor = this.options.drawingCursor + }, - getEditorClass: function(tools) { - return (tools && tools.options.polygonEditorClass) ? tools.options.polygonEditorClass : L.Editable.PolygonEditor - }, + unregisterForDrawing: function (editor) { + this.unblockEvents() + L.DomUtil.removeClass(this.map._container, this.options.drawingCSSClass) + this.map._container.style.cursor = this.defaultMapCursor + editor = editor || this._drawingEditor + if (!editor) return + this.map.off('mousemove touchmove', editor.onDrawingMouseMove, editor) + this.map.off('mousedown', this.onMousedown, this) + this.map.off('mouseup', this.onMouseup, this) + if (editor !== this._drawingEditor) return + delete this._drawingEditor + if (editor._drawing) editor.cancelDrawing() + }, - shapeAt: function(latlng, latlngs) { - // We can have those cases: - // - latlngs are just a flat array of latlngs, use this - // - latlngs is an array of arrays of latlngs, this is a simple polygon (maybe with holes), use the first - // - latlngs is an array of arrays of arrays, this is a multi, loop over - let shape = null - latlngs = latlngs || this._latlngs - if (!latlngs.length) return shape - else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs - else if (isFlat(latlngs[0]) && this.isInLatLngs(latlng, latlngs[0])) shape = latlngs - else for (let i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i][0])) return latlngs[i] - return shape - }, + onMousedown: function (e) { + if (e.originalEvent.which !== 1) return + this._mouseDown = e + this._drawingEditor.onDrawingMouseDown(e) + }, - isInLatLngs: function(l, latlngs) { - let inside = false - let l1 - let l2 - let j - let k - let len2 - for (j = 0, len2 = latlngs.length, k = len2 - 1; j < len2; k = j++) { - l1 = latlngs[j] - l2 = latlngs[k] + onMouseup: function (e) { + if (this._mouseDown) { + const editor = this._drawingEditor + const mouseDown = this._mouseDown + this._mouseDown = null + editor.onDrawingMouseUp(e) + if (this._drawingEditor !== editor) return // onDrawingMouseUp may call unregisterFromDrawing. + const origin = L.point(mouseDown.originalEvent.clientX, mouseDown.originalEvent.clientY) + const distance = L.point(e.originalEvent.clientX, e.originalEvent.clientY).distanceTo(origin) + if (Math.abs(distance) < 9 * (window.devicePixelRatio || 1)) this._drawingEditor.onDrawingClick(e) + } + }, - if (((l1.lat > l.lat) !== (l2.lat > l.lat)) && + // 馃崅section Public methods + // You will generally access them by the `map.editTools` + // instance: + // + // `map.editTools.startPolyline();` + + // 馃崅method drawing(): boolean + // Return true if any drawing action is ongoing. + drawing: function () { + return this._drawingEditor && this._drawingEditor.drawing() + }, + + // 馃崅method stopDrawing() + // When you need to stop any ongoing drawing, without needing to know which editor is active. + stopDrawing: function () { + this.unregisterForDrawing() + }, + + // 馃崅method commitDrawing() + // When you need to commit any ongoing drawing, without needing to know which editor is active. + commitDrawing: function (e) { + if (!this._drawingEditor) return + this._drawingEditor.commitDrawing(e) + }, + + connectCreatedToMap: function (layer) { + return this.featuresLayer.addLayer(layer) + }, + + // 馃崅method startPolyline(latlng: L.LatLng, options: hash): L.Polyline + // Start drawing a Polyline. If `latlng` is given, a first point will be added. In any case, continuing on user click. + // If `options` is given, it will be passed to the Polyline class constructor. + startPolyline: function (latlng, options) { + const line = this.createPolyline([], options) + line.enableEdit(this.map).newShape(latlng) + return line + }, + + // 馃崅method startPolygon(latlng: L.LatLng, options: hash): L.Polygon + // Start drawing a Polygon. If `latlng` is given, a first point will be added. In any case, continuing on user click. + // If `options` is given, it will be passed to the Polygon class constructor. + startPolygon: function (latlng, options) { + const polygon = this.createPolygon([], options) + polygon.enableEdit(this.map).newShape(latlng) + return polygon + }, + + // 馃崅method startMarker(latlng: L.LatLng, options: hash): L.Marker + // Start adding a Marker. If `latlng` is given, the Marker will be shown first at this point. + // In any case, it will follow the user mouse, and will have a final `latlng` on next click (or touch). + // If `options` is given, it will be passed to the Marker class constructor. + startMarker: function (latlng, options) { + latlng = latlng || this.map.getCenter().clone() + const marker = this.createMarker(latlng, options) + marker.enableEdit(this.map).startDrawing() + return marker + }, + + // 馃崅method startRectangle(latlng: L.LatLng, options: hash): L.Rectangle + // Start drawing a Rectangle. If `latlng` is given, the Rectangle anchor will be added. In any case, continuing on user drag. + // If `options` is given, it will be passed to the Rectangle class constructor. + startRectangle: function (latlng, options) { + const corner = latlng || L.latLng([0, 0]) + const bounds = new L.LatLngBounds(corner, corner) + const rectangle = this.createRectangle(bounds, options) + rectangle.enableEdit(this.map).startDrawing() + return rectangle + }, + + // 馃崅method startCircle(latlng: L.LatLng, options: hash): L.Circle + // Start drawing a Circle. If `latlng` is given, the Circle anchor will be added. In any case, continuing on user drag. + // If `options` is given, it will be passed to the Circle class constructor. + startCircle: function (latlng, options) { + latlng = latlng || this.map.getCenter().clone() + const circle = this.createCircle(latlng, options) + circle.enableEdit(this.map).startDrawing() + return circle + }, + + startHole: function (editor, latlng) { + editor.newHole(latlng) + }, + + createLayer: function (Klass, latlngs, options) { + options = L.Util.extend({ editOptions: { editTools: this } }, options) + const layer = new Klass(latlngs, options) + // 馃崅namespace Editable + // 馃崅event editable:created: LayerEvent + // Fired when a new feature (Marker, Polyline鈥�) is created. + this.fireAndForward('editable:created', { layer: layer }) + return layer + }, + + createPolyline: function (latlngs, options) { + return this.createLayer((options && options.polylineClass) || this.options.polylineClass, latlngs, options) + }, + + createPolygon: function (latlngs, options) { + return this.createLayer((options && options.polygonClass) || this.options.polygonClass, latlngs, options) + }, + + createMarker: function (latlng, options) { + return this.createLayer((options && options.markerClass) || this.options.markerClass, latlng, options) + }, + + createRectangle: function (bounds, options) { + return this.createLayer((options && options.rectangleClass) || this.options.rectangleClass, bounds, options) + }, + + createCircle: function (latlng, options) { + return this.createLayer((options && options.circleClass) || this.options.circleClass, latlng, options) + } + + }) + + L.extend(L.Editable, { + + makeCancellable: function (e) { + e.cancel = function () { + e._cancelled = true + } + } + + }) + + // 馃崅namespace Map; 馃崅class Map + // Leaflet.Editable add options and events to the `L.Map` object. + // See `Editable` events for the list of events fired on the Map. + // 馃崅example + // + // ```js + // let map = L.map('map', { + // editable: true, + // editOptions: { + // 鈥� + // } + // }); + // ``` + // 馃崅section Editable Map Options + L.Map.mergeOptions({ + + // 馃崅namespace Map + // 馃崅section Map Options + // 馃崅option EditToolsClass: class = L.Editable + // Class to be used as vertex, for path editing. + EditToolsClass: L.Editable, + + // 馃崅option editable: boolean = false + // Whether to create a L.Editable instance at map init. + editable: false, + + // 馃崅option editOptions: hash = {} + // Options to pass to L.Editable when instantiating. + editOptions: {} + + }) + + L.Map.addInitHook(function () { + this.whenReady(function () { + if (this.options.editable) { + this.editTools = new this.options.EditToolsClass(this, this.options.editOptions) + } + }) + }) + + L.Editable.VertexIcon = L.DivIcon.extend({ + + options: { + iconSize: new L.Point(8, 8) + } + + }) + + L.Editable.TouchVertexIcon = L.Editable.VertexIcon.extend({ + + options: { + iconSize: new L.Point(20, 20) + } + + }) + + // 馃崅namespace Editable; 馃崅class VertexMarker; Handler for dragging path vertices. + L.Editable.VertexMarker = L.Marker.extend({ + + options: { + draggable: true, + className: 'leaflet-vertex-icon leaflet-custom-icon' + }, + + // 馃崅section Public methods + // The marker used to handle path vertex. You will usually interact with a `VertexMarker` + // instance when listening for events like `editable:vertex:ctrlclick`. + + initialize: function (latlng, latlngs, editor, options) { + // We don't use this._latlng, because on drag Leaflet replace it while + // we want to keep reference. + this.latlng = latlng + this.latlngs = latlngs + this.editor = editor + L.Marker.prototype.initialize.call(this, latlng, options) + this.options.icon = this.editor.tools.createVertexIcon({ className: this.options.className }) + this.latlng.__vertex = this + this.editor.editLayer.addLayer(this) + this.setZIndexOffset(editor.tools._lastZIndex + 1) + }, + + onAdd: function (map) { + L.Marker.prototype.onAdd.call(this, map) + this.on('drag', this.onDrag) + this.on('dragstart', this.onDragStart) + this.on('dragend', this.onDragEnd) + this.on('mouseup', this.onMouseup) + this.on('click', this.onClick) + this.on('contextmenu', this.onContextMenu) + this.on('mousedown touchstart', this.onMouseDown) + this.on('mouseover', this.onMouseOver) + this.on('mouseout', this.onMouseOut) + this.addMiddleMarkers() + }, + + onRemove: function (map) { + if (this.middleMarker) this.middleMarker.delete() + delete this.latlng.__vertex + this.off('drag', this.onDrag) + this.off('dragstart', this.onDragStart) + this.off('dragend', this.onDragEnd) + this.off('mouseup', this.onMouseup) + this.off('click', this.onClick) + this.off('contextmenu', this.onContextMenu) + this.off('mousedown touchstart', this.onMouseDown) + this.off('mouseover', this.onMouseOver) + this.off('mouseout', this.onMouseOut) + L.Marker.prototype.onRemove.call(this, map) + }, + + onDrag: function (e) { + e.vertex = this + this.editor.onVertexMarkerDrag(e) + const iconPos = L.DomUtil.getPosition(this._icon) + const latlng = this._map.layerPointToLatLng(iconPos) + this.latlng.update(latlng) + this._latlng = this.latlng // Push back to Leaflet our reference. + this.editor.refresh() + if (this.middleMarker) this.middleMarker.updateLatLng() + const next = this.getNext() + if (next && next.middleMarker) next.middleMarker.updateLatLng() + }, + + onDragStart: function (e) { + e.vertex = this + this.editor.onVertexMarkerDragStart(e) + }, + + onDragEnd: function (e) { + e.vertex = this + this.editor.onVertexMarkerDragEnd(e) + }, + + onClick: function (e) { + e.vertex = this + this.editor.onVertexMarkerClick(e) + }, + + onMouseup: function (e) { + L.DomEvent.stop(e) + e.vertex = this + this.editor.map.fire('mouseup', e) + }, + + onContextMenu: function (e) { + e.vertex = this + this.editor.onVertexMarkerContextMenu(e) + }, + + onMouseDown: function (e) { + e.vertex = this + this.editor.onVertexMarkerMouseDown(e) + }, + + onMouseOver: function (e) { + e.vertex = this + this.editor.onVertexMarkerMouseOver(e) + }, + + onMouseOut: function (e) { + e.vertex = this + this.editor.onVertexMarkerMouseOut(e) + }, + + // 馃崅method delete() + // Delete a vertex and the related LatLng. + delete: function () { + const next = this.getNext() // Compute before changing latlng + this.latlngs.splice(this.getIndex(), 1) + this.editor.editLayer.removeLayer(this) + this.editor.onVertexDeleted({ latlng: this.latlng, vertex: this }) + if (!this.latlngs.length) this.editor.deleteShape(this.latlngs) + if (next) next.resetMiddleMarker() + this.editor.refresh() + }, + + // 馃崅method getIndex(): int + // Get the index of the current vertex among others of the same LatLngs group. + getIndex: function () { + return this.latlngs.indexOf(this.latlng) + }, + + // 馃崅method getLastIndex(): int + // Get last vertex index of the LatLngs group of the current vertex. + getLastIndex: function () { + return this.latlngs.length - 1 + }, + + // 馃崅method getPrevious(): VertexMarker + // Get the previous VertexMarker in the same LatLngs group. + getPrevious: function () { + if (this.latlngs.length < 2) return + const index = this.getIndex() + let previousIndex = index - 1 + if (index === 0 && this.editor.CLOSED) previousIndex = this.getLastIndex() + const previous = this.latlngs[previousIndex] + if (previous) return previous.__vertex + }, + + // 馃崅method getNext(): VertexMarker + // Get the next VertexMarker in the same LatLngs group. + getNext: function () { + if (this.latlngs.length < 2) return + const index = this.getIndex() + let nextIndex = index + 1 + if (index === this.getLastIndex() && this.editor.CLOSED) nextIndex = 0 + const next = this.latlngs[nextIndex] + if (next) return next.__vertex + }, + + addMiddleMarker: function (previous) { + if (!this.editor.hasMiddleMarkers()) return + previous = previous || this.getPrevious() + if (previous && !this.middleMarker) this.middleMarker = this.editor.addMiddleMarker(previous, this, this.latlngs, this.editor) + }, + + addMiddleMarkers: function () { + if (!this.editor.hasMiddleMarkers()) return + const previous = this.getPrevious() + if (previous) this.addMiddleMarker(previous) + const next = this.getNext() + if (next) next.resetMiddleMarker() + }, + + resetMiddleMarker: function () { + if (this.middleMarker) this.middleMarker.delete() + this.addMiddleMarker() + }, + + // 馃崅method split() + // Split the vertex LatLngs group at its index, if possible. + split: function () { + if (!this.editor.splitShape) return // Only for PolylineEditor + this.editor.splitShape(this.latlngs, this.getIndex()) + }, + + // 馃崅method continue() + // Continue the vertex LatLngs from this vertex. Only active for first and last vertices of a Polyline. + continue: function () { + if (!this.editor.continueBackward) return // Only for PolylineEditor + const index = this.getIndex() + if (index === 0) this.editor.continueBackward(this.latlngs) + else if (index === this.getLastIndex()) this.editor.continueForward(this.latlngs) + } + + }) + + L.Editable.mergeOptions({ + + // 馃崅namespace Editable + // 馃崅option VertexMarkerClass: class = VertexMarker + // Class to be used as vertex, for path editing. + VertexMarkerClass: L.Editable.VertexMarker + + }) + + L.Editable.MiddleMarker = L.Marker.extend({ + + options: { + opacity: 0.5, + className: 'leaflet-div-icon leaflet-middle-icon', + draggable: true + }, + + initialize: function (left, right, latlngs, editor, options) { + this.left = left + this.right = right + this.editor = editor + this.latlngs = latlngs + L.Marker.prototype.initialize.call(this, this.computeLatLng(), options) + this._opacity = this.options.opacity + this.options.icon = this.editor.tools.createVertexIcon({ className: this.options.className }) + this.editor.editLayer.addLayer(this) + this.setVisibility() + }, + + setVisibility: function () { + const leftPoint = this._map.latLngToContainerPoint(this.left.latlng) + const rightPoint = this._map.latLngToContainerPoint(this.right.latlng) + const size = L.point(this.options.icon.options.iconSize) + if (leftPoint.distanceTo(rightPoint) < size.x * 3) this.hide() + else this.show() + }, + + show: function () { + this.setOpacity(this._opacity) + }, + + hide: function () { + this.setOpacity(0) + }, + + updateLatLng: function () { + this.setLatLng(this.computeLatLng()) + this.setVisibility() + }, + + computeLatLng: function () { + const leftPoint = this.editor.map.latLngToContainerPoint(this.left.latlng) + const rightPoint = this.editor.map.latLngToContainerPoint(this.right.latlng) + const y = (leftPoint.y + rightPoint.y) / 2 + const x = (leftPoint.x + rightPoint.x) / 2 + return this.editor.map.containerPointToLatLng([x, y]) + }, + + onAdd: function (map) { + L.Marker.prototype.onAdd.call(this, map) + L.DomEvent.on(this._icon, 'mousedown touchstart', this.onMouseDown, this) + map.on('zoomend', this.setVisibility, this) + }, + + onRemove: function (map) { + delete this.right.middleMarker + L.DomEvent.off(this._icon, 'mousedown touchstart', this.onMouseDown, this) + map.off('zoomend', this.setVisibility, this) + L.Marker.prototype.onRemove.call(this, map) + }, + + onMouseDown: function (e) { + const iconPos = L.DomUtil.getPosition(this._icon) + const latlng = this.editor.map.layerPointToLatLng(iconPos) + e = { + originalEvent: e, + latlng: latlng + } + if (this.options.opacity === 0) return + L.Editable.makeCancellable(e) + this.editor.onMiddleMarkerMouseDown(e) + if (e._cancelled) return + this.latlngs.splice(this.index(), 0, e.latlng) + this.editor.refresh() + const icon = this._icon + const marker = this.editor.addVertexMarker(e.latlng, this.latlngs) + this.editor.onNewVertex(marker) + /* Hack to workaround browser not firing touchend when element is no more on DOM */ + const parent = marker._icon.parentNode + parent.removeChild(marker._icon) + marker._icon = icon + parent.appendChild(marker._icon) + marker._initIcon() + marker._initInteraction() + marker.setOpacity(1) + /* End hack */ + // Transfer ongoing dragging to real marker + L.Draggable._dragging = false + marker.dragging._draggable._onDown(e.originalEvent) + this.delete() + }, + + delete: function () { + this.editor.editLayer.removeLayer(this) + }, + + index: function () { + return this.latlngs.indexOf(this.right.latlng) + } + + }) + + L.Editable.mergeOptions({ + + // 馃崅namespace Editable + // 馃崅option MiddleMarkerClass: class = VertexMarker + // Class to be used as middle vertex, pulled by the user to create a new point in the middle of a path. + MiddleMarkerClass: L.Editable.MiddleMarker + + }) + + // 馃崅namespace Editable; 馃崅class BaseEditor; 馃崅aka L.Editable.BaseEditor + // When editing a feature (Marker, Polyline鈥�), an editor is attached to it. This + // editor basically knows how to handle the edition. + L.Editable.BaseEditor = L.Handler.extend({ + + initialize: function (map, feature, options) { + L.setOptions(this, options) + this.map = map + this.feature = feature + this.feature.editor = this + this.editLayer = new L.LayerGroup() + this.tools = this.options.editTools || map.editTools + }, + + // 馃崅method enable(): this + // Set up the drawing tools for the feature to be editable. + addHooks: function () { + if (this.isConnected()) this.onFeatureAdd() + else this.feature.once('add', this.onFeatureAdd, this) + this.onEnable() + this.feature.on(this._getEvents(), this) + }, + + // 馃崅method disable(): this + // Remove the drawing tools for the feature. + removeHooks: function () { + this.feature.off(this._getEvents(), this) + if (this.feature.dragging) this.feature.dragging.disable() + this.editLayer.clearLayers() + this.tools.editLayer.removeLayer(this.editLayer) + this.onDisable() + if (this._drawing) this.cancelDrawing() + }, + + // 馃崅method drawing(): boolean + // Return true if any drawing action is ongoing with this editor. + drawing: function () { + return !!this._drawing + }, + + reset: function () { + }, + + onFeatureAdd: function () { + this.tools.editLayer.addLayer(this.editLayer) + if (this.feature.dragging) this.feature.dragging.enable() + }, + + hasMiddleMarkers: function () { + return !this.options.skipMiddleMarkers && !this.tools.options.skipMiddleMarkers + }, + + fireAndForward: function (type, e) { + e = e || {} + e.layer = this.feature + this.feature.fire(type, e) + this.tools.fireAndForward(type, e) + }, + + onEnable: function () { + // 馃崅namespace Editable + // 馃崅event editable:enable: Event + // Fired when an existing feature is ready to be edited. + this.fireAndForward('editable:enable') + }, + + onDisable: function () { + // 馃崅namespace Editable + // 馃崅event editable:disable: Event + // Fired when an existing feature is not ready anymore to be edited. + this.fireAndForward('editable:disable') + }, + + onEditing: function () { + // 馃崅namespace Editable + // 馃崅event editable:editing: Event + // Fired as soon as any change is made to the feature geometry. + this.fireAndForward('editable:editing') + }, + + onStartDrawing: function () { + // 馃崅namespace Editable + // 馃崅section Drawing events + // 馃崅event editable:drawing:start: Event + // Fired when a feature is to be drawn. + this.fireAndForward('editable:drawing:start') + }, + + onEndDrawing: function () { + // 馃崅namespace Editable + // 馃崅section Drawing events + // 馃崅event editable:drawing:end: Event + // Fired when a feature is not drawn anymore. + this.fireAndForward('editable:drawing:end') + }, + + onCancelDrawing: function () { + // 馃崅namespace Editable + // 馃崅section Drawing events + // 馃崅event editable:drawing:cancel: Event + // Fired when user cancel drawing while a feature is being drawn. + this.fireAndForward('editable:drawing:cancel') + }, + + onCommitDrawing: function (e) { + // 馃崅namespace Editable + // 馃崅section Drawing events + // 馃崅event editable:drawing:commit: Event + // Fired when user finish drawing a feature. + this.fireAndForward('editable:drawing:commit', e) + }, + + onDrawingMouseDown: function (e) { + // 馃崅namespace Editable + // 馃崅section Drawing events + // 馃崅event editable:drawing:mousedown: Event + // Fired when user `mousedown` while drawing. + this.fireAndForward('editable:drawing:mousedown', e) + }, + + onDrawingMouseUp: function (e) { + // 馃崅namespace Editable + // 馃崅section Drawing events + // 馃崅event editable:drawing:mouseup: Event + // Fired when user `mouseup` while drawing. + this.fireAndForward('editable:drawing:mouseup', e) + }, + + startDrawing: function () { + if (!this._drawing) this._drawing = L.Editable.FORWARD + this.tools.registerForDrawing(this) + this.onStartDrawing() + }, + + commitDrawing: function (e) { + this.onCommitDrawing(e) + this.endDrawing() + }, + + cancelDrawing: function () { + // If called during a vertex drag, the vertex will be removed before + // the mouseup fires on it. This is a workaround. Maybe better fix is + // To have L.Draggable reset it's status on disable (Leaflet side). + L.Draggable._dragging = false + this.onCancelDrawing() + this.endDrawing() + }, + + endDrawing: function () { + this._drawing = false + this.tools.unregisterForDrawing(this) + this.onEndDrawing() + }, + + onDrawingClick: function (e) { + if (!this.drawing()) return + L.Editable.makeCancellable(e) + // 馃崅namespace Editable + // 馃崅section Drawing events + // 馃崅event editable:drawing:click: CancelableEvent + // Fired when user `click` while drawing, before any internal action is being processed. + this.fireAndForward('editable:drawing:click', e) + if (e._cancelled) return + if (!this.isConnected()) this.connect(e) + this.processDrawingClick(e) + }, + + isConnected: function () { + return this.map.hasLayer(this.feature) + }, + + connect: function () { + this.tools.connectCreatedToMap(this.feature) + this.tools.editLayer.addLayer(this.editLayer) + }, + + onMove: function (e) { + // 馃崅namespace Editable + // 馃崅section Drawing events + // 馃崅event editable:drawing:move: Event + // Fired when `move` mouse while drawing, while dragging a marker, and while dragging a vertex. + this.fireAndForward('editable:drawing:move', e) + }, + + onDrawingMouseMove: function (e) { + this.onMove(e) + }, + + _getEvents: function () { + return { + dragstart: this.onDragStart, + drag: this.onDrag, + dragend: this.onDragEnd, + remove: this.disable + } + }, + + onDragStart: function (e) { + this.onEditing() + // 馃崅namespace Editable + // 馃崅event editable:dragstart: Event + // Fired before a path feature is dragged. + this.fireAndForward('editable:dragstart', e) + }, + + onDrag: function (e) { + this.onMove(e) + // 馃崅namespace Editable + // 馃崅event editable:drag: Event + // Fired when a path feature is being dragged. + this.fireAndForward('editable:drag', e) + }, + + onDragEnd: function (e) { + // 馃崅namespace Editable + // 馃崅event editable:dragend: Event + // Fired after a path feature has been dragged. + this.fireAndForward('editable:dragend', e) + } + + }) + + // 馃崅namespace Editable; 馃崅class MarkerEditor; 馃崅aka L.Editable.MarkerEditor + // 馃崅inherits BaseEditor + // Editor for Marker. + L.Editable.MarkerEditor = L.Editable.BaseEditor.extend({ + + onDrawingMouseMove: function (e) { + L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e) + if (this._drawing) this.feature.setLatLng(e.latlng) + }, + + processDrawingClick: function (e) { + // 馃崅namespace Editable + // 馃崅section Drawing events + // 馃崅event editable:drawing:clicked: Event + // Fired when user `click` while drawing, after all internal actions. + this.fireAndForward('editable:drawing:clicked', e) + this.commitDrawing(e) + }, + + connect: function (e) { + // On touch, the latlng has not been updated because there is + // no mousemove. + if (e) this.feature._latlng = e.latlng + L.Editable.BaseEditor.prototype.connect.call(this, e) + } + + }) + + // 馃崅namespace Editable; 馃崅class PathEditor; 馃崅aka L.Editable.PathEditor + // 馃崅inherits BaseEditor + // Base class for all path editors. + L.Editable.PathEditor = L.Editable.BaseEditor.extend({ + + CLOSED: false, + MIN_VERTEX: 2, + + addHooks: function () { + L.Editable.BaseEditor.prototype.addHooks.call(this) + if (this.feature) this.initVertexMarkers() + return this + }, + + initVertexMarkers: function (latlngs) { + if (!this.enabled()) return + latlngs = latlngs || this.getLatLngs() + if (isFlat(latlngs)) this.addVertexMarkers(latlngs) + else for (let i = 0; i < latlngs.length; i++) this.initVertexMarkers(latlngs[i]) + }, + + getLatLngs: function () { + return this.feature.getLatLngs() + }, + + // 馃崅method reset() + // Rebuild edit elements (Vertex, MiddleMarker, etc.). + reset: function () { + this.editLayer.clearLayers() + this.initVertexMarkers() + }, + + addVertexMarker: function (latlng, latlngs) { + return new this.tools.options.VertexMarkerClass(latlng, latlngs, this) + }, + + onNewVertex: function (vertex) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:new: VertexEvent + // Fired when a new vertex is created. + this.fireAndForward('editable:vertex:new', { latlng: vertex.latlng, vertex: vertex }) + }, + + addVertexMarkers: function (latlngs) { + for (let i = 0; i < latlngs.length; i++) { + this.addVertexMarker(latlngs[i], latlngs) + } + }, + + refreshVertexMarkers: function (latlngs) { + latlngs = latlngs || this.getDefaultLatLngs() + for (let i = 0; i < latlngs.length; i++) { + latlngs[i].__vertex.update() + } + }, + + addMiddleMarker: function (left, right, latlngs) { + return new this.tools.options.MiddleMarkerClass(left, right, latlngs, this) + }, + + onVertexMarkerClick: function (e) { + L.Editable.makeCancellable(e) + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:click: CancelableVertexEvent + // Fired when a `click` is issued on a vertex, before any internal action is being processed. + this.fireAndForward('editable:vertex:click', e) + if (e._cancelled) return + if (this.tools.drawing() && this.tools._drawingEditor !== this) return + const index = e.vertex.getIndex() + let commit + if (e.originalEvent.ctrlKey) { + this.onVertexMarkerCtrlClick(e) + } else if (e.originalEvent.altKey) { + this.onVertexMarkerAltClick(e) + } else if (e.originalEvent.shiftKey) { + this.onVertexMarkerShiftClick(e) + } else if (e.originalEvent.metaKey) { + this.onVertexMarkerMetaKeyClick(e) + } else if (index === e.vertex.getLastIndex() && this._drawing === L.Editable.FORWARD) { + if (index >= this.MIN_VERTEX - 1) commit = true + } else if (index === 0 && this._drawing === L.Editable.BACKWARD && this._drawnLatLngs.length >= this.MIN_VERTEX) { + commit = true + } else if (index === 0 && this._drawing === L.Editable.FORWARD && this._drawnLatLngs.length >= this.MIN_VERTEX && this.CLOSED) { + commit = true // Allow to close on first point also for polygons + } else { + this.onVertexRawMarkerClick(e) + } + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:clicked: VertexEvent + // Fired when a `click` is issued on a vertex, after all internal actions. + this.fireAndForward('editable:vertex:clicked', e) + if (commit) this.commitDrawing(e) + }, + + onVertexRawMarkerClick: function (e) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:rawclick: CancelableVertexEvent + // Fired when a `click` is issued on a vertex without any special key and without being in drawing mode. + this.fireAndForward('editable:vertex:rawclick', e) + if (e._cancelled) return + if (!this.vertexCanBeDeleted(e.vertex)) return + e.vertex.delete() + }, + + vertexCanBeDeleted: function (vertex) { + return vertex.latlngs.length > this.MIN_VERTEX + }, + + onVertexDeleted: function (e) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:deleted: VertexEvent + // Fired after a vertex has been deleted by user. + this.fireAndForward('editable:vertex:deleted', e) + }, + + onVertexMarkerCtrlClick: function (e) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:ctrlclick: VertexEvent + // Fired when a `click` with `ctrlKey` is issued on a vertex. + this.fireAndForward('editable:vertex:ctrlclick', e) + }, + + onVertexMarkerShiftClick: function (e) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:shiftclick: VertexEvent + // Fired when a `click` with `shiftKey` is issued on a vertex. + this.fireAndForward('editable:vertex:shiftclick', e) + }, + + onVertexMarkerMetaKeyClick: function (e) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:metakeyclick: VertexEvent + // Fired when a `click` with `metaKey` is issued on a vertex. + this.fireAndForward('editable:vertex:metakeyclick', e) + }, + + onVertexMarkerAltClick: function (e) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:altclick: VertexEvent + // Fired when a `click` with `altKey` is issued on a vertex. + this.fireAndForward('editable:vertex:altclick', e) + }, + + onVertexMarkerContextMenu: function (e) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:contextmenu: VertexEvent + // Fired when a `contextmenu` is issued on a vertex. + this.fireAndForward('editable:vertex:contextmenu', e) + }, + + onVertexMarkerMouseDown: function (e) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:mousedown: VertexEvent + // Fired when user `mousedown` a vertex. + this.fireAndForward('editable:vertex:mousedown', e) + }, + + onVertexMarkerMouseOver: function (e) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:mouseover: VertexEvent + // Fired when a user's mouse enters the vertex + this.fireAndForward('editable:vertex:mouseover', e) + }, + + onVertexMarkerMouseOut: function (e) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:mouseout: VertexEvent + // Fired when a user's mouse leaves the vertex + this.fireAndForward('editable:vertex:mouseout', e) + }, + + onMiddleMarkerMouseDown: function (e) { + // 馃崅namespace Editable + // 馃崅section MiddleMarker events + // 馃崅event editable:middlemarker:mousedown: VertexEvent + // Fired when user `mousedown` a middle marker. + this.fireAndForward('editable:middlemarker:mousedown', e) + }, + + onVertexMarkerDrag: function (e) { + this.onMove(e) + if (this.feature._bounds) this.extendBounds(e) + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:drag: VertexEvent + // Fired when a vertex is dragged by user. + this.fireAndForward('editable:vertex:drag', e) + }, + + onVertexMarkerDragStart: function (e) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:dragstart: VertexEvent + // Fired before a vertex is dragged by user. + this.fireAndForward('editable:vertex:dragstart', e) + }, + + onVertexMarkerDragEnd: function (e) { + // 馃崅namespace Editable + // 馃崅section Vertex events + // 馃崅event editable:vertex:dragend: VertexEvent + // Fired after a vertex is dragged by user. + this.fireAndForward('editable:vertex:dragend', e) + }, + + setDrawnLatLngs: function (latlngs) { + this._drawnLatLngs = latlngs || this.getDefaultLatLngs() + }, + + startDrawing: function () { + if (!this._drawnLatLngs) this.setDrawnLatLngs() + L.Editable.BaseEditor.prototype.startDrawing.call(this) + }, + + startDrawingForward: function () { + this.startDrawing() + }, + + endDrawing: function () { + this.tools.detachForwardLineGuide() + this.tools.detachBackwardLineGuide() + if (this._drawnLatLngs && this._drawnLatLngs.length < this.MIN_VERTEX) this.deleteShape(this._drawnLatLngs) + L.Editable.BaseEditor.prototype.endDrawing.call(this) + delete this._drawnLatLngs + }, + + addLatLng: function (latlng) { + if (this._drawing === L.Editable.FORWARD) this._drawnLatLngs.push(latlng) + else this._drawnLatLngs.unshift(latlng) + this.feature._bounds.extend(latlng) + const vertex = this.addVertexMarker(latlng, this._drawnLatLngs) + this.onNewVertex(vertex) + this.refresh() + }, + + newPointForward: function (latlng) { + this.addLatLng(latlng) + this.tools.attachForwardLineGuide() + this.tools.anchorForwardLineGuide(latlng) + }, + + newPointBackward: function (latlng) { + this.addLatLng(latlng) + this.tools.anchorBackwardLineGuide(latlng) + }, + + // 馃崅namespace PathEditor + // 馃崅method push() + // Programmatically add a point while drawing. + push: function (latlng) { + if (!latlng) return console.error('L.Editable.PathEditor.push expect a valid latlng as parameter') + if (this._drawing === L.Editable.FORWARD) this.newPointForward(latlng) + else this.newPointBackward(latlng) + }, + + removeLatLng: function (latlng) { + latlng.__vertex.delete() + this.refresh() + }, + + // 馃崅method pop(): L.LatLng or null + // Programmatically remove last point (if any) while drawing. + pop: function () { + if (this._drawnLatLngs.length <= 1) return + let latlng + if (this._drawing === L.Editable.FORWARD) latlng = this._drawnLatLngs[this._drawnLatLngs.length - 1] + else latlng = this._drawnLatLngs[0] + this.removeLatLng(latlng) + if (this._drawing === L.Editable.FORWARD) this.tools.anchorForwardLineGuide(this._drawnLatLngs[this._drawnLatLngs.length - 1]) + else this.tools.anchorForwardLineGuide(this._drawnLatLngs[0]) + return latlng + }, + + processDrawingClick: function (e) { + if (e.vertex && e.vertex.editor === this) return + if (this._drawing === L.Editable.FORWARD) this.newPointForward(e.latlng) + else this.newPointBackward(e.latlng) + this.fireAndForward('editable:drawing:clicked', e) + }, + + onDrawingMouseMove: function (e) { + L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e) + if (this._drawing) { + this.tools.moveForwardLineGuide(e.latlng) + this.tools.moveBackwardLineGuide(e.latlng) + } + }, + + refresh: function () { + this.feature.redraw() + this.onEditing() + }, + + // 馃崅namespace PathEditor + // 馃崅method newShape(latlng?: L.LatLng) + // Add a new shape (Polyline, Polygon) in a multi, and setup up drawing tools to draw it; + // if optional `latlng` is given, start a path at this point. + newShape: function (latlng) { + const shape = this.addNewEmptyShape() + if (!shape) return + this.setDrawnLatLngs(shape[0] || shape) // Polygon or polyline + this.startDrawingForward() + // 馃崅namespace Editable + // 馃崅section Shape events + // 馃崅event editable:shape:new: ShapeEvent + // Fired when a new shape is created in a multi (Polygon or Polyline). + this.fireAndForward('editable:shape:new', { shape: shape }) + if (latlng) this.newPointForward(latlng) + }, + + deleteShape: function (shape, latlngs) { + const e = { shape: shape } + L.Editable.makeCancellable(e) + // 馃崅namespace Editable + // 馃崅section Shape events + // 馃崅event editable:shape:delete: CancelableShapeEvent + // Fired before a new shape is deleted in a multi (Polygon or Polyline). + this.fireAndForward('editable:shape:delete', e) + if (e._cancelled) return + shape = this._deleteShape(shape, latlngs) + if (this.ensureNotFlat) this.ensureNotFlat() // Polygon. + this.feature.setLatLngs(this.getLatLngs()) // Force bounds reset. + this.refresh() + this.reset() + // 馃崅namespace Editable + // 馃崅section Shape events + // 馃崅event editable:shape:deleted: ShapeEvent + // Fired after a new shape is deleted in a multi (Polygon or Polyline). + this.fireAndForward('editable:shape:deleted', { shape: shape }) + return shape + }, + + _deleteShape: function (shape, latlngs) { + latlngs = latlngs || this.getLatLngs() + if (!latlngs.length) return + const self = this + const inplaceDelete = function (latlngs, shape) { + // Called when deleting a flat latlngs + shape = latlngs.splice(0, Number.MAX_VALUE) + return shape + } + const spliceDelete = function (latlngs, shape) { + // Called when removing a latlngs inside an array + latlngs.splice(latlngs.indexOf(shape), 1) + if (!latlngs.length) self._deleteShape(latlngs) + return shape + } + if (latlngs === shape) return inplaceDelete(latlngs, shape) + for (let i = 0; i < latlngs.length; i++) { + if (latlngs[i] === shape) return spliceDelete(latlngs, shape) + else if (latlngs[i].indexOf(shape) !== -1) return spliceDelete(latlngs[i], shape) + } + }, + + // 馃崅namespace PathEditor + // 馃崅method deleteShapeAt(latlng: L.LatLng): Array + // Remove a path shape at the given `latlng`. + deleteShapeAt: function (latlng) { + const shape = this.feature.shapeAt(latlng) + if (shape) return this.deleteShape(shape) + }, + + // 馃崅method appendShape(shape: Array) + // Append a new shape to the Polygon or Polyline. + appendShape: function (shape) { + this.insertShape(shape) + }, + + // 馃崅method prependShape(shape: Array) + // Prepend a new shape to the Polygon or Polyline. + prependShape: function (shape) { + this.insertShape(shape, 0) + }, + + // 馃崅method insertShape(shape: Array, index: int) + // Insert a new shape to the Polygon or Polyline at given index (default is to append). + insertShape: function (shape, index) { + this.ensureMulti() + shape = this.formatShape(shape) + if (typeof index === 'undefined') index = this.feature._latlngs.length + this.feature._latlngs.splice(index, 0, shape) + this.feature.redraw() + if (this._enabled) this.reset() + }, + + extendBounds: function (e) { + this.feature._bounds.extend(e.vertex.latlng) + }, + + onDragStart: function (e) { + this.editLayer.clearLayers() + L.Editable.BaseEditor.prototype.onDragStart.call(this, e) + }, + + onDragEnd: function (e) { + this.initVertexMarkers() + L.Editable.BaseEditor.prototype.onDragEnd.call(this, e) + } + + }) + + // 馃崅namespace Editable; 馃崅class PolylineEditor; 馃崅aka L.Editable.PolylineEditor + // 馃崅inherits PathEditor + L.Editable.PolylineEditor = L.Editable.PathEditor.extend({ + + startDrawingBackward: function () { + this._drawing = L.Editable.BACKWARD + this.startDrawing() + }, + + // 馃崅method continueBackward(latlngs?: Array) + // Set up drawing tools to continue the line backward. + continueBackward: function (latlngs) { + if (this.drawing()) return + latlngs = latlngs || this.getDefaultLatLngs() + this.setDrawnLatLngs(latlngs) + if (latlngs.length > 0) { + this.tools.attachBackwardLineGuide() + this.tools.anchorBackwardLineGuide(latlngs[0]) + } + this.startDrawingBackward() + }, + + // 馃崅method continueForward(latlngs?: Array) + // Set up drawing tools to continue the line forward. + continueForward: function (latlngs) { + if (this.drawing()) return + latlngs = latlngs || this.getDefaultLatLngs() + this.setDrawnLatLngs(latlngs) + if (latlngs.length > 0) { + this.tools.attachForwardLineGuide() + this.tools.anchorForwardLineGuide(latlngs[latlngs.length - 1]) + } + this.startDrawingForward() + }, + + getDefaultLatLngs: function (latlngs) { + latlngs = latlngs || this.feature._latlngs + if (!latlngs.length || latlngs[0] instanceof L.LatLng) return latlngs + else return this.getDefaultLatLngs(latlngs[0]) + }, + + ensureMulti: function () { + if (this.feature._latlngs.length && isFlat(this.feature._latlngs)) { + this.feature._latlngs = [this.feature._latlngs] + } + }, + + addNewEmptyShape: function () { + if (this.feature._latlngs.length) { + const shape = [] + this.appendShape(shape) + return shape + } else { + return this.feature._latlngs + } + }, + + formatShape: function (shape) { + if (isFlat(shape)) return shape + else if (shape[0]) return this.formatShape(shape[0]) + }, + + // 馃崅method splitShape(latlngs?: Array, index: int) + // Split the given `latlngs` shape at index `index` and integrate new shape in instance `latlngs`. + splitShape: function (shape, index) { + if (!index || index >= shape.length - 1) return + this.ensureMulti() + const shapeIndex = this.feature._latlngs.indexOf(shape) + if (shapeIndex === -1) return + const first = shape.slice(0, index + 1) + const second = shape.slice(index) + // We deal with reference, we don't want twice the same latlng around. + second[0] = L.latLng(second[0].lat, second[0].lng, second[0].alt) + this.feature._latlngs.splice(shapeIndex, 1, first, second) + this.refresh() + this.reset() + } + + }) + + // 馃崅namespace Editable; 馃崅class PolygonEditor; 馃崅aka L.Editable.PolygonEditor + // 馃崅inherits PathEditor + L.Editable.PolygonEditor = L.Editable.PathEditor.extend({ + + CLOSED: true, + MIN_VERTEX: 3, + + newPointForward: function (latlng) { + L.Editable.PathEditor.prototype.newPointForward.call(this, latlng) + if (!this.tools.backwardLineGuide._latlngs.length) this.tools.anchorBackwardLineGuide(latlng) + if (this._drawnLatLngs.length === 2) this.tools.attachBackwardLineGuide() + }, + + addNewEmptyHole: function (latlng) { + this.ensureNotFlat() + const latlngs = this.feature.shapeAt(latlng) + if (!latlngs) return + const holes = [] + latlngs.push(holes) + return holes + }, + + // 馃崅method newHole(latlng?: L.LatLng, index: int) + // Set up drawing tools for creating a new hole on the Polygon. If the `latlng` param is given, a first point is created. + newHole: function (latlng) { + const holes = this.addNewEmptyHole(latlng) + if (!holes) return + this.setDrawnLatLngs(holes) + this.startDrawingForward() + if (latlng) this.newPointForward(latlng) + }, + + addNewEmptyShape: function () { + if (this.feature._latlngs.length && this.feature._latlngs[0].length) { + const shape = [] + this.appendShape(shape) + return shape + } else { + return this.feature._latlngs + } + }, + + ensureMulti: function () { + if (this.feature._latlngs.length && isFlat(this.feature._latlngs[0])) { + this.feature._latlngs = [this.feature._latlngs] + } + }, + + ensureNotFlat: function () { + if (!this.feature._latlngs.length || isFlat(this.feature._latlngs)) this.feature._latlngs = [this.feature._latlngs] + }, + + vertexCanBeDeleted: function (vertex) { + const parent = this.feature.parentShape(vertex.latlngs) + const idx = L.Util.indexOf(parent, vertex.latlngs) + if (idx > 0) return true // Holes can be totally deleted without removing the layer itself. + return L.Editable.PathEditor.prototype.vertexCanBeDeleted.call(this, vertex) + }, + + getDefaultLatLngs: function () { + if (!this.feature._latlngs.length) this.feature._latlngs.push([]) + return this.feature._latlngs[0] + }, + + formatShape: function (shape) { + // [[1, 2], [3, 4]] => must be nested + // [] => must be nested + // [[]] => is already nested + if (isFlat(shape) && (!shape[0] || shape[0].length !== 0)) return [shape] + else return shape + } + + }) + + // 馃崅namespace Editable; 馃崅class RectangleEditor; 馃崅aka L.Editable.RectangleEditor + // 馃崅inherits PathEditor + L.Editable.RectangleEditor = L.Editable.PathEditor.extend({ + + CLOSED: true, + MIN_VERTEX: 4, + + options: { + skipMiddleMarkers: true + }, + + extendBounds: function (e) { + const index = e.vertex.getIndex() + const next = e.vertex.getNext() + const previous = e.vertex.getPrevious() + const oppositeIndex = (index + 2) % 4 + const opposite = e.vertex.latlngs[oppositeIndex] + const bounds = new L.LatLngBounds(e.latlng, opposite) + // Update latlngs by hand to preserve order. + previous.latlng.update([e.latlng.lat, opposite.lng]) + next.latlng.update([opposite.lat, e.latlng.lng]) + this.updateBounds(bounds) + this.refreshVertexMarkers() + }, + + onDrawingMouseDown: function (e) { + L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e) + this.connect() + const latlngs = this.getDefaultLatLngs() + // L.Polygon._convertLatLngs removes last latlng if it equals first point, + // which is the case here as all latlngs are [0, 0] + if (latlngs.length === 3) latlngs.push(e.latlng) + const bounds = new L.LatLngBounds(e.latlng, e.latlng) + this.updateBounds(bounds) + this.updateLatLngs(bounds) + this.refresh() + this.reset() + // Stop dragging map. + // L.Draggable has two workflows: + // - mousedown => mousemove => mouseup + // - touchstart => touchmove => touchend + // Problem: L.Map.Tap does not allow us to listen to touchstart, so we only + // can deal with mousedown, but then when in a touch device, we are dealing with + // simulated events (actually simulated by L.Map.Tap), which are no more taken + // into account by L.Draggable. + // Ref.: https://github.com/Leaflet/Leaflet.Editable/issues/103 + e.originalEvent._simulated = false + this.map.dragging._draggable._onUp(e.originalEvent) + // Now transfer ongoing drag action to the bottom right corner. + // Should we refine which corner will handle the drag according to + // drag direction? + latlngs[3].__vertex.dragging._draggable._onDown(e.originalEvent) + }, + + onDrawingMouseUp: function (e) { + this.commitDrawing(e) + e.originalEvent._simulated = false + L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e) + }, + + onDrawingMouseMove: function (e) { + e.originalEvent._simulated = false + L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e) + }, + + getDefaultLatLngs: function (latlngs) { + return latlngs || this.feature._latlngs[0] + }, + + updateBounds: function (bounds) { + this.feature._bounds = bounds + }, + + updateLatLngs: function (bounds) { + const latlngs = this.getDefaultLatLngs() + const newLatlngs = this.feature._boundsToLatLngs(bounds) + // Keep references. + for (let i = 0; i < latlngs.length; i++) { + latlngs[i].update(newLatlngs[i]) + } + } + + }) + + // 馃崅namespace Editable; 馃崅class CircleEditor; 馃崅aka L.Editable.CircleEditor + // 馃崅inherits PathEditor + L.Editable.CircleEditor = L.Editable.PathEditor.extend({ + + MIN_VERTEX: 2, + + options: { + skipMiddleMarkers: true + }, + + initialize: function (map, feature, options) { + L.Editable.PathEditor.prototype.initialize.call(this, map, feature, options) + // C.Y.B Modify + + const latlng = this.computeResizeLatLng() + + // latlng.lat = latlng.lat-0.007855; + // latlng.lng= latlng.lng-0.1; + this._resizeLatLng = latlng + // 鍘熷鏂规硶 + // this._resizeLatLng = this.computeResizeLatLng(); + }, + + computeResizeLatLng: function () { + // While circle is not added to the map, _radius is not set. + // let delta = (this.feature._radius || this.feature._mRadius) * Math.cos(Math.PI / 4) + const delta = (this.feature._radius || this.feature._mRadius) + const point = this.map.project(this.feature._latlng) + // return this.map.unproject([point.x + delta, point.y - delta]) + return this.map.unproject([point.x + delta, point.y]) + }, + + updateResizeLatLng: function () { + this._resizeLatLng.update(this.computeResizeLatLng()) + this._resizeLatLng.__vertex.update() + }, + + getLatLngs: function () { + return [this.feature._latlng, this._resizeLatLng] + }, + + getDefaultLatLngs: function () { + return this.getLatLngs() + }, + + onVertexMarkerDrag: function (e) { + if (e.vertex.getIndex() === 1) this.resize(e) + else this.updateResizeLatLng(e) + L.Editable.PathEditor.prototype.onVertexMarkerDrag.call(this, e) + }, + + resize: function (e) { + const radius = this.feature._latlng.distanceTo(e.latlng) + this.feature.setRadius(radius) + }, + + onDrawingMouseDown: function (e) { + L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e) + this._resizeLatLng.update(e.latlng) + this.feature._latlng.update(e.latlng) + this.connect() + // Stop dragging map. + e.originalEvent._simulated = false + this.map.dragging._draggable._onUp(e.originalEvent) + // Now transfer ongoing drag action to the radius handler. + this._resizeLatLng.__vertex.dragging._draggable._onDown(e.originalEvent) + }, + + onDrawingMouseUp: function (e) { + this.commitDrawing(e) + e.originalEvent._simulated = false + L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e) + }, + + onDrawingMouseMove: function (e) { + e.originalEvent._simulated = false + L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e) + }, + + onDrag: function (e) { + L.Editable.PathEditor.prototype.onDrag.call(this, e) + this.feature.dragging.updateLatLng(this._resizeLatLng) + } + + }) + + // 馃崅namespace Editable; 馃崅class EditableMixin + // `EditableMixin` is included to `L.Polyline`, `L.Polygon`, `L.Rectangle`, `L.Circle` + // and `L.Marker`. It adds some methods to them. + // *When editing is enabled, the editor is accessible on the instance with the + // `editor` property.* + const EditableMixin = { + + createEditor: function (map) { + map = map || this._map + const tools = (this.options.editOptions || {}).editTools || map.editTools + if (!tools) throw Error('Unable to detect Editable instance.') + const Klass = this.options.editorClass || this.getEditorClass(tools) + return new Klass(map, this, this.options.editOptions) + }, + + // 馃崅method enableEdit(map?: L.Map): this.editor + // Enable editing, by creating an editor if not existing, and then calling `enable` on it. + enableEdit: function (map) { + if (!this.editor) this.createEditor(map) + this.editor.enable() + return this.editor + }, + + // 馃崅method editEnabled(): boolean + // Return true if current instance has an editor attached, and this editor is enabled. + editEnabled: function () { + return this.editor && this.editor.enabled() + }, + + // 馃崅method disableEdit() + // Disable editing, also remove the editor property reference. + disableEdit: function () { + if (this.editor) { + this.editor.disable() + delete this.editor + } + }, + + // 馃崅method toggleEdit() + // Enable or disable editing, according to current status. + toggleEdit: function () { + if (this.editEnabled()) this.disableEdit() + else this.enableEdit() + }, + + _onEditableAdd: function () { + if (this.editor) this.enableEdit() + } + + } + + const PolylineMixin = { + + getEditorClass: function (tools) { + return (tools && tools.options.polylineEditorClass) ? tools.options.polylineEditorClass : L.Editable.PolylineEditor + }, + + shapeAt: function (latlng, latlngs) { + // We can have those cases: + // - latlngs are just a flat array of latlngs, use this + // - latlngs is an array of arrays of latlngs, loop over + let shape = null + latlngs = latlngs || this._latlngs + if (!latlngs.length) return shape + else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs + else for (let i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i])) return latlngs[i] + return shape + }, + + isInLatLngs: function (l, latlngs) { + if (!latlngs) return false + let i, k, len + let part = [] + const w = this._clickTolerance() + this._projectLatlngs(latlngs, part, this._pxBounds) + part = part[0] + const p = this._map.latLngToLayerPoint(l) + + if (!this._pxBounds.contains(p)) { + return false + } + for (i = 1, len = part.length, k = 0; i < len; k = i++) { + if (L.LineUtil.pointToSegmentDistance(p, part[k], part[i]) <= w) { + return true + } + } + return false + } + + } + + const PolygonMixin = { + + getEditorClass: function (tools) { + return (tools && tools.options.polygonEditorClass) ? tools.options.polygonEditorClass : L.Editable.PolygonEditor + }, + + shapeAt: function (latlng, latlngs) { + // We can have those cases: + // - latlngs are just a flat array of latlngs, use this + // - latlngs is an array of arrays of latlngs, this is a simple polygon (maybe with holes), use the first + // - latlngs is an array of arrays of arrays, this is a multi, loop over + let shape = null + latlngs = latlngs || this._latlngs + if (!latlngs.length) return shape + else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs + else if (isFlat(latlngs[0]) && this.isInLatLngs(latlng, latlngs[0])) shape = latlngs + else for (let i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i][0])) return latlngs[i] + return shape + }, + + isInLatLngs: function (l, latlngs) { + let inside = false + let l1 + let l2 + let j + let k + let len2 + for (j = 0, len2 = latlngs.length, k = len2 - 1; j < len2; k = j++) { + l1 = latlngs[j] + l2 = latlngs[k] + + if (((l1.lat > l.lat) !== (l2.lat > l.lat)) && (l.lng < (l2.lng - l1.lng) * (l.lat - l1.lat) / (l2.lat - l1.lat) + l1.lng)) { - inside = !inside - } - } - - return inside - }, - - parentShape: function(shape, latlngs) { - latlngs = latlngs || this._latlngs - if (!latlngs) return - let idx = L.Util.indexOf(latlngs, shape) - if (idx !== -1) return latlngs - for (let i = 0; i < latlngs.length; i++) { - idx = L.Util.indexOf(latlngs[i], shape) - if (idx !== -1) return latlngs[i] - } - } - + inside = !inside + } } - let MarkerMixin = { + return inside + }, - getEditorClass: function(tools) { - return (tools && tools.options.markerEditorClass) ? tools.options.markerEditorClass : L.Editable.MarkerEditor - } - + parentShape: function (shape, latlngs) { + latlngs = latlngs || this._latlngs + if (!latlngs) return + let idx = L.Util.indexOf(latlngs, shape) + if (idx !== -1) return latlngs + for (let i = 0; i < latlngs.length; i++) { + idx = L.Util.indexOf(latlngs[i], shape) + if (idx !== -1) return latlngs[i] } + } - let RectangleMixin = { + } - getEditorClass: function(tools) { - return (tools && tools.options.rectangleEditorClass) ? tools.options.rectangleEditorClass : L.Editable.RectangleEditor - } + const MarkerMixin = { - } + getEditorClass: function (tools) { + return (tools && tools.options.markerEditorClass) ? tools.options.markerEditorClass : L.Editable.MarkerEditor + } - let CircleMixin = { + } - getEditorClass: function(tools) { - return (tools && tools.options.circleEditorClass) ? tools.options.circleEditorClass : L.Editable.CircleEditor - } + const RectangleMixin = { - } + getEditorClass: function (tools) { + return (tools && tools.options.rectangleEditorClass) ? tools.options.rectangleEditorClass : L.Editable.RectangleEditor + } - let keepEditable = function() { - // Make sure you can remove/readd an editable layer. - this.on('add', this._onEditableAdd) - } + } - let isFlat = L.LineUtil.isFlat || L.LineUtil._flat || L.Polyline._flat // <=> 1.1 compat. + const CircleMixin = { - if (L.Polyline) { - L.Polyline.include(EditableMixin) - L.Polyline.include(PolylineMixin) - L.Polyline.addInitHook(keepEditable) - } - if (L.Polygon) { - L.Polygon.include(EditableMixin) - L.Polygon.include(PolygonMixin) - } - if (L.Marker) { - L.Marker.include(EditableMixin) - L.Marker.include(MarkerMixin) - L.Marker.addInitHook(keepEditable) - } - if (L.Rectangle) { - L.Rectangle.include(EditableMixin) - L.Rectangle.include(RectangleMixin) - } - if (L.Circle) { - L.Circle.include(EditableMixin) - L.Circle.include(CircleMixin) - } + getEditorClass: function (tools) { + return (tools && tools.options.circleEditorClass) ? tools.options.circleEditorClass : L.Editable.CircleEditor + } - L.LatLng.prototype.update = function(latlng) { - latlng = L.latLng(latlng) - this.lat = latlng.lat - this.lng = latlng.lng - } - }, window)) + } + + const keepEditable = function () { + // Make sure you can remove/readd an editable layer. + this.on('add', this._onEditableAdd) + } + + const isFlat = L.LineUtil.isFlat || L.LineUtil._flat || L.Polyline._flat // <=> 1.1 compat. + + if (L.Polyline) { + L.Polyline.include(EditableMixin) + L.Polyline.include(PolylineMixin) + L.Polyline.addInitHook(keepEditable) + } + if (L.Polygon) { + L.Polygon.include(EditableMixin) + L.Polygon.include(PolygonMixin) + } + if (L.Marker) { + L.Marker.include(EditableMixin) + L.Marker.include(MarkerMixin) + L.Marker.addInitHook(keepEditable) + } + if (L.Rectangle) { + L.Rectangle.include(EditableMixin) + L.Rectangle.include(RectangleMixin) + } + if (L.Circle) { + L.Circle.include(EditableMixin) + L.Circle.include(CircleMixin) + } + + L.LatLng.prototype.update = function (latlng) { + latlng = L.latLng(latlng) + this.lat = latlng.lat + this.lng = latlng.lng + } + }, window)) } export default { - init + init } -- Gitblit v1.8.0