派生自 wuyushui/SewerAndRainNetwork

wangqi
2021-03-16 447b0a01c659f63216a70ba055c3c4279f16c7f6
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))