From c88e6fc89736da8faa46d525c8781c0f1dac5384 Mon Sep 17 00:00:00 2001
From: YANGDL <114714267@qq.com>
Date: 星期五, 19 三月 2021 01:50:18 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 src/components/plugin/Editable.js | 3826 +++++++++++++++++++++++++++++-----------------------------
 1 files changed, 1,910 insertions(+), 1,916 deletions(-)

diff --git a/src/components/plugin/Editable.js b/src/components/plugin/Editable.js
index 79fc3ad..3f24a8d 100644
--- a/src/components/plugin/Editable.js
+++ b/src/components/plugin/Editable.js
@@ -1,2016 +1,2010 @@
-'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)
+'use strict';
+(function (factory, window) {
+  // define an AMD module that relies on 'leaflet'
+  if (typeof define === 'function' && define.amd) {
+    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.
+  // attach your plugin to the global 'L' variable
+  if (typeof window !== 'undefined' && window.L) {
+    factory(window.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 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 ShapeEvent (Event objects)
+  // 馃崅property shape: Array
+  // The shape (LatLngs array) subject of the action.
 
-    // 馃崅miniclass CancelableVertexEvent (Event objects)
-    // 馃崅inherits VertexEvent
-    // 馃崅inherits CancelableEvent
+  // 馃崅miniclass CancelableVertexEvent (Event objects)
+  // 馃崅inherits VertexEvent
+  // 馃崅inherits CancelableEvent
 
-    // 馃崅miniclass CancelableShapeEvent (Event objects)
-    // 馃崅inherits ShapeEvent
-    // 馃崅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.
+  // 馃崅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({
+  // 馃崅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
-      },
+    statics: {
+      FORWARD: 1,
+      BACKWARD: -1
+    },
 
-      options: {
+    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,
+      // 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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
+      // 馃崅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()
-      },
+    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)
-      },
+    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)
-      },
+    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)
-      },
+    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)
-      },
+    createEditLayer: function () {
+      return this.options.editLayer || new L.LayerGroup().addTo(this.map)
+    },
 
-      createFeaturesLayer: function () {
-        return this.options.featuresLayer || 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
+    moveForwardLineGuide: function (latlng) {
+      if (this.forwardLineGuide._latlngs.length) {
+        this.forwardLineGuide._latlngs[1] = latlng
         this.forwardLineGuide._bounds.extend(latlng)
         this.forwardLineGuide.redraw()
-      },
+      }
+    },
 
-      anchorBackwardLineGuide: function (latlng) {
-        this.backwardLineGuide._latlngs[0] = latlng
+    moveBackwardLineGuide: function (latlng) {
+      if (this.backwardLineGuide._latlngs.length) {
+        this.backwardLineGuide._latlngs[1] = 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) {
-          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)
-        }
-      },
-
-      // 馃崅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)
       }
+    },
 
-    })
+    anchorForwardLineGuide: function (latlng) {
+      this.forwardLineGuide._latlngs[0] = latlng
+      this.forwardLineGuide._bounds.extend(latlng)
+      this.forwardLineGuide.redraw()
+    },
 
-    L.extend(L.Editable, {
+    anchorBackwardLineGuide: function (latlng) {
+      this.backwardLineGuide._latlngs[0] = latlng
+      this.backwardLineGuide._bounds.extend(latlng)
+      this.backwardLineGuide.redraw()
+    },
 
-      makeCancellable: function (e) {
-        e.cancel = function () {
-          e._cancelled = true
-        }
+    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
+      }
+    },
 
-    // 馃崅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
+    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) {
+        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)
+      }
+    },
+
+    // 馃崅section Public methods
+    // You will generally access them by the `map.editTools`
+    // instance:
     //
-    // ```js
-    // let map = L.map('map', {
-    //  editable: true,
-    //  editOptions: {
-    //    鈥�
-    // }
-    // });
-    // ```
-    // 馃崅section Editable Map Options
-    L.Map.mergeOptions({
+    // `map.editTools.startPolyline();`
 
-      // 馃崅namespace Map
-      // 馃崅section Map Options
-      // 馃崅option EditToolsClass: class = L.Editable
-      // Class to be used as vertex, for path editing.
-      EditToolsClass: L.Editable,
+    // 馃崅method drawing(): boolean
+    // Return true if any drawing action is ongoing.
+    drawing: function () {
+      return this._drawingEditor && this._drawingEditor.drawing()
+    },
 
-      // 馃崅option editable: boolean = false
-      // Whether to create a L.Editable instance at map init.
-      editable: false,
+    // 馃崅method stopDrawing()
+    // When you need to stop any ongoing drawing, without needing to know which editor is active.
+    stopDrawing: function () {
+      this.unregisterForDrawing()
+    },
 
-      // 馃崅option editOptions: hash = {}
-      // Options to pass to L.Editable when instantiating.
-      editOptions: {}
+    // 馃崅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
+    },
 
-    L.Map.addInitHook(function () {
-      this.whenReady(function () {
-        if (this.options.editable) {
-          this.editTools = new this.options.EditToolsClass(this, this.options.editOptions)
-        }
-      })
-    })
+    // 馃崅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
+    },
 
-    L.Editable.VertexIcon = L.DivIcon.extend({
+    // 馃崅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
+    },
 
-      options: {
-        iconSize: new L.Point(8, 8)
-      }
+    // 馃崅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
+    },
 
-    L.Editable.TouchVertexIcon = L.Editable.VertexIcon.extend({
+    startHole: function (editor, latlng) {
+      editor.newHole(latlng)
+    },
 
-      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({
-
+    createLayer: function (Klass, latlngs, options) {
+      options = L.Util.extend({ editOptions: { editTools: this } }, options)
+      const layer = new Klass(latlngs, options)
       // 馃崅namespace Editable
-      // 馃崅option VertexMarkerClass: class = VertexMarker
-      // Class to be used as vertex, for path editing.
-      VertexMarkerClass: L.Editable.VertexMarker
+      // 馃崅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)
+    },
 
-    L.Editable.MiddleMarker = L.Marker.extend({
+    createPolygon: function (latlngs, options) {
+      return this.createLayer((options && options.polygonClass) || this.options.polygonClass, latlngs, options)
+    },
 
-      options: {
-        opacity: 0.5,
-        className: 'leaflet-div-icon leaflet-middle-icon',
-        draggable: true
-      },
+    createMarker: function (latlng, options) {
+      return this.createLayer((options && options.markerClass) || this.options.markerClass, latlng, options)
+    },
 
-      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()
-      },
+    createRectangle: function (bounds, options) {
+      return this.createLayer((options && options.rectangleClass) || this.options.rectangleClass, bounds, options)
+    },
 
-      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()
-      }
-
+    createCircle: function (latlng, options) {
+      return this.createLayer((options && options.circleClass) || this.options.circleClass, latlng, options)
     }
 
-    const PolylineMixin = {
+  })
 
-      getEditorClass: function (tools) {
-        return (tools && tools.options.polylineEditorClass) ? tools.options.polylineEditorClass : L.Editable.PolylineEditor
-      },
+  L.extend(L.Editable, {
 
-      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]
-        }
+    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)
+      }
+    },
 
-      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)
+    // 馃崅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)
+    },
 
-        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
-          }
-        }
+    // 馃崅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
-      },
+  const PolygonMixin = {
 
-      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]
-        }
+    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]
+    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]
+        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
+    },
 
-    const MarkerMixin = {
-
-      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]
       }
-
     }
 
-    const 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
     }
 
-    const 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
     }
 
-    const keepEditable = function () {
-      // Make sure you can remove/readd an editable layer.
-      this.on('add', this._onEditableAdd)
+  }
+
+  const CircleMixin = {
+
+    getEditorClass: function (tools) {
+      return (tools && tools.options.circleEditorClass) ? tools.options.circleEditorClass : L.Editable.CircleEditor
     }
 
-    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)
-    }
+  const keepEditable = function () {
+    // Make sure you can remove/readd an editable layer.
+    this.on('add', this._onEditableAdd)
+  }
 
-    L.LatLng.prototype.update = function (latlng) {
-      latlng = L.latLng(latlng)
-      this.lat = latlng.lat
-      this.lng = latlng.lng
-    }
-  }, window))
-}
+  const isFlat = L.LineUtil.isFlat || L.LineUtil._flat || L.Polyline._flat // <=> 1.1 compat.
 
-export default {
-  init
-}
+  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))

--
Gitblit v1.8.0