From 447b0a01c659f63216a70ba055c3c4279f16c7f6 Mon Sep 17 00:00:00 2001
From: wangqi <magical1908@outlook.com>
Date: 星期二, 16 三月 2021 16:43:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 src/assets/images/map-pages/icon/layer.png                                 |    0 
 src/assets/images/map-pages/icon/toolbox/Selecd/biaohui.png                |    0 
 src/components/plugin/Editable.js                                          | 3826 ++++++++++++++++++++++++++--------------------------
 src/assets/images/map-pages/icon/toolbox/biaohuimark/rectmark.png          |    0 
 src/assets/images/map-pages/icon/toolbox/biaohuimark/linemark.png          |    0 
 src/assets/images/map-pages/icon/toolbox/Selecd/tool.png                   |    0 
 src/assets/images/map-pages/icon/toolbox/biaohuimark/liubianxing2mark.png  |    0 
 src/assets/images/map-pages/icon/toolbox/Selecd/ditu.png                   |    0 
 src/assets/css/map/map-panel-style.less                                    |    2 
 src/assets/images/map-pages/icon/toolbox/Selecd/xiazai.png                 |    0 
 src/components/panel/ToolBoxPanel.vue                                      |   13 
 src/assets/images/map-pages/icon/toolbox/biaohuimark/circlemark.png        |    0 
 src/assets/images/map-pages/icon/toolbox/biaohuimark/shanchu.png           |    0 
 src/assets/images/map-pages/icon/toolbox/biaohuimark/dingweimark.png       |    0 
 src/components/LayerController/LayerController.vue                         |   55 
 src/components/LayerController/LayerController2.vue                        |  288 ++++
 src/components/LayerController/modules/LcServiceLayer.vue                  |   18 
 src/Sgis.js                                                                |    8 
 src/assets/images/map-pages/icon/toolbox/biaohuimark/mianjiceliangmark.png |    0 
 src/assets/images/map-pages/icon/toolbox/biaohuimark/juliceliangmark.png   |    0 
 src/conf/MapConfig.js                                                      |    3 
 src/assets/images/map-pages/icon/toolbox/Selecd/celiang1.png               |    0 
 src/conf/LayerWasteWater.js                                                |   43 
 src/App.vue                                                                |    2 
 24 files changed, 2,307 insertions(+), 1,951 deletions(-)

diff --git a/src/App.vue b/src/App.vue
index 89338ed..6b056a7 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -23,7 +23,7 @@
   overflow: hidden;
 }
 body .el-scrollbar__wrap {
-  overflow-x: hidden;
+  // overflow-x: hidden;
 }
 body{
   -ms-overflow-style: none;
diff --git a/src/Sgis.js b/src/Sgis.js
index 273ae8b..19c9dfb 100644
--- a/src/Sgis.js
+++ b/src/Sgis.js
@@ -1,12 +1,9 @@
 import BasemapHelper from '@components/helpers/BasemapHelper'
 import VectorLayerHelper from '@components/helpers/VectorLayerHelper'
 import ServiceLayerHelper from '@components/helpers/ServiceLayerHelper'
-
-import Editable from '@components/plugin/Editable'
 import PathDrag from '@components/plugin/PathDrag'
 // import MagicMarker from '@components/plugin/MagicMarker'
 // import WmtsSupport from '@components/plugin/wmts_plugins'
-
 import MapConfig from '@/conf/MapConfig'
 import '@components/plugin/PathDashFlow' // 娴佸姩绾垮浘
 // import CanvasMarkers from '@components/plugin/CanvasMarkers'
@@ -18,8 +15,9 @@
 import 'leaflet.markercluster'
 // import 'leaflet-canvas-markers'
 import './components/plugin/Leaflet.GridLayer.FadeOut' // 鐡︾墖鍥惧眰鍒囨崲娣″叆娣″嚭
-
 import './components/plugin/leaflet-canvas-markers' // 鐢诲竷marker
+import './components/plugin/Editable' // 鏍囩粯鎿嶄綔
+
 let map = null
 const L = window.L
 const initMap = (div) => {
@@ -28,7 +26,7 @@
   }
 
   // Leaflet鎵╁睍浠g爜
-  Editable.init(L) // 鍥惧眰缂栬緫
+  // Editable.init(L) // 鍥惧眰缂栬緫
   PathDrag.init(L) // 璺緞鎷栨嫿
   // MagicMarker.init(L) // 鍔ㄧ敾Marker
   // WmtsSupport.init(L) // 鎵╁睍锛屼娇鏀寔WMTS
diff --git a/src/assets/css/map/map-panel-style.less b/src/assets/css/map/map-panel-style.less
index 7827c9f..0a9adea 100644
--- a/src/assets/css/map/map-panel-style.less
+++ b/src/assets/css/map/map-panel-style.less
@@ -160,7 +160,7 @@
   border: 1px solid @background-color-tools;
   background: @background-color-tools;
   padding: 0;
-  //width: 90px;
+  width: 90px;
   display: flex;
   flex-wrap: wrap;
   justify-content: space-evenly;
diff --git a/src/assets/images/map-pages/icon/layer.png b/src/assets/images/map-pages/icon/layer.png
new file mode 100644
index 0000000..4c4587c
--- /dev/null
+++ b/src/assets/images/map-pages/icon/layer.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/Selecd/biaohui.png b/src/assets/images/map-pages/icon/toolbox/Selecd/biaohui.png
new file mode 100644
index 0000000..7768aa6
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/Selecd/biaohui.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/Selecd/celiang1.png b/src/assets/images/map-pages/icon/toolbox/Selecd/celiang1.png
new file mode 100644
index 0000000..572dbe2
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/Selecd/celiang1.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/Selecd/ditu.png b/src/assets/images/map-pages/icon/toolbox/Selecd/ditu.png
new file mode 100644
index 0000000..d70ff4d
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/Selecd/ditu.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/Selecd/tool.png b/src/assets/images/map-pages/icon/toolbox/Selecd/tool.png
new file mode 100644
index 0000000..2beeb93
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/Selecd/tool.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/Selecd/xiazai.png b/src/assets/images/map-pages/icon/toolbox/Selecd/xiazai.png
new file mode 100644
index 0000000..6b2eaac
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/Selecd/xiazai.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/biaohuimark/circlemark.png b/src/assets/images/map-pages/icon/toolbox/biaohuimark/circlemark.png
new file mode 100644
index 0000000..d73f362
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/biaohuimark/circlemark.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/biaohuimark/dingweimark.png b/src/assets/images/map-pages/icon/toolbox/biaohuimark/dingweimark.png
new file mode 100644
index 0000000..8e8525e
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/biaohuimark/dingweimark.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/biaohuimark/juliceliangmark.png b/src/assets/images/map-pages/icon/toolbox/biaohuimark/juliceliangmark.png
new file mode 100644
index 0000000..7d2c1e1
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/biaohuimark/juliceliangmark.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/biaohuimark/linemark.png b/src/assets/images/map-pages/icon/toolbox/biaohuimark/linemark.png
new file mode 100644
index 0000000..dd28323
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/biaohuimark/linemark.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/biaohuimark/liubianxing2mark.png b/src/assets/images/map-pages/icon/toolbox/biaohuimark/liubianxing2mark.png
new file mode 100644
index 0000000..923cfe9
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/biaohuimark/liubianxing2mark.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/biaohuimark/mianjiceliangmark.png b/src/assets/images/map-pages/icon/toolbox/biaohuimark/mianjiceliangmark.png
new file mode 100644
index 0000000..e813f50
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/biaohuimark/mianjiceliangmark.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/biaohuimark/rectmark.png b/src/assets/images/map-pages/icon/toolbox/biaohuimark/rectmark.png
new file mode 100644
index 0000000..5248070
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/biaohuimark/rectmark.png
Binary files differ
diff --git a/src/assets/images/map-pages/icon/toolbox/biaohuimark/shanchu.png b/src/assets/images/map-pages/icon/toolbox/biaohuimark/shanchu.png
new file mode 100644
index 0000000..689c53e
--- /dev/null
+++ b/src/assets/images/map-pages/icon/toolbox/biaohuimark/shanchu.png
Binary files differ
diff --git a/src/components/LayerController/LayerController.vue b/src/components/LayerController/LayerController.vue
index 8f24ad7..9a60145 100644
--- a/src/components/LayerController/LayerController.vue
+++ b/src/components/LayerController/LayerController.vue
@@ -1,14 +1,9 @@
 <template>
   <div class="float-panel">
-    <div class="title-text-border" @click="switchPanel">
-      <div class="title-icon"></div>
-      <div class="title-text">鍥惧眰鎺у埗</div>
-    </div>
-    <transition name="el-fade-in-linear">
-      <div class="body-box" id="panelContent" :style="{ width:width }">
-        <div v-show="isShow">
-          <slot></slot>
-        </div>
+    <div :class='["btn",layerControllerVisible ? "active" : ""]' @click="showPanel"><span><img src="@assets/images/map-pages/icon/layer.png" alt="" width="26px" style="display: block;margin: auto"><span class="icon-name">鍥惧眰</span></span></div>
+    <transition name="fade">
+      <div :class="'legend-content map-background'" style="position: absolute;left: 50px;top: 0" v-show="layerControllerVisible">
+        <lc-service-layer></lc-service-layer>
       </div>
     </transition>
   </div>
@@ -19,10 +14,12 @@
 import presets from './layerControllerPresets'
 
 import iconSetting from '@/assets/images/map-pages/icon/setting.png'
+import LcServiceLayer from './modules/LcServiceLayer'
 
+const cityOptions = ['涓婃捣', '鍖椾含', '骞垮窞', '娣卞湷']
 export default {
   name: 'LayerController',
-  components: {},
+  components: { LcServiceLayer },
   props: {
     preset: {
       type: String,
@@ -38,9 +35,6 @@
     },
     layerHelper () {
       return this.$store.state.map.layerHelper
-    },
-    layerControllerVisible () {
-      return this.$store.state.map.layerControllerVisible
     }
   },
   data () {
@@ -50,6 +44,11 @@
       icons: {
         setting: iconSetting
       },
+      checkAll: false,
+      checkedCities: ['涓婃捣', '鍖椾含'],
+      cities: cityOptions,
+      isIndeterminate: true,
+      layerControllerVisible: false,
       panelSwitch: {
         main: true // 涓荤獥鍙�
       }
@@ -61,6 +60,18 @@
     })
   },
   methods: {
+    showPanel () {
+      this.layerControllerVisible = !this.layerControllerVisible
+    },
+    handleCheckAllChange (val) {
+      this.checkedCities = val ? cityOptions : []
+      this.isIndeterminate = false
+    },
+    handleCheckedCitiesChange (value) {
+      const checkedCount = value.length
+      this.checkAll = checkedCount === this.cities.length
+      this.isIndeterminate = checkedCount > 0 && checkedCount < this.cities.length
+    },
     init () {
       this.initPreset()
     },
@@ -90,18 +101,30 @@
 </script>
 
 <style lang="less">
-
 .float-panel {
   position: absolute;
+  left: 2px;
   top: 120px;
   height: auto;
   font-size: 11px;
   z-index: 1000;
 
   div {
-    color: #90c8e0;
+    color: #00fff6;
   }
-
+  .btn {
+    width:45px;
+    text-align: center;
+    background: rgba(0, 16, 30, 0.5);
+    cursor: pointer;
+    color: #00fff6;
+    border: 0.00521rem solid #00fff6;
+    box-shadow: 0 0 0.03rem #00fff6;
+  }
+  .active {
+    border: 0.00521rem solid #fff700;
+    box-shadow: 0 0 0.03rem #fff700;
+  }
   .title-border {
     width: 100%;
     height: 28px;
diff --git a/src/components/LayerController/LayerController2.vue b/src/components/LayerController/LayerController2.vue
new file mode 100644
index 0000000..8f24ad7
--- /dev/null
+++ b/src/components/LayerController/LayerController2.vue
@@ -0,0 +1,288 @@
+<template>
+  <div class="float-panel">
+    <div class="title-text-border" @click="switchPanel">
+      <div class="title-icon"></div>
+      <div class="title-text">鍥惧眰鎺у埗</div>
+    </div>
+    <transition name="el-fade-in-linear">
+      <div class="body-box" id="panelContent" :style="{ width:width }">
+        <div v-show="isShow">
+          <slot></slot>
+        </div>
+      </div>
+    </transition>
+  </div>
+</template>
+
+<script>
+import '@assets/css/map/magic.min.css'
+import presets from './layerControllerPresets'
+
+import iconSetting from '@/assets/images/map-pages/icon/setting.png'
+
+export default {
+  name: 'LayerController',
+  components: {},
+  props: {
+    preset: {
+      type: String,
+      default: 'default'
+    }
+  },
+  computed: {
+    map () {
+      return this.$store.state.map.map
+    },
+    L () {
+      return this.$store.state.map.L
+    },
+    layerHelper () {
+      return this.$store.state.map.layerHelper
+    },
+    layerControllerVisible () {
+      return this.$store.state.map.layerControllerVisible
+    }
+  },
+  data () {
+    return {
+      width: '250px',
+      isShow: true,
+      icons: {
+        setting: iconSetting
+      },
+      panelSwitch: {
+        main: true // 涓荤獥鍙�
+      }
+    }
+  },
+  mounted () {
+    this.$nextTick(function () {
+      this.init()
+    })
+  },
+  methods: {
+    init () {
+      this.initPreset()
+    },
+    initPreset () {
+      if (this.preset !== 'default') {
+        const prmPreset = presets[this.preset]
+        Object.assign(this.layerControllerVisible, prmPreset) // 闃叉棰勮鍙傛暟涓庨粯璁ゅ弬鏁颁笉涓�鑷村鑷存姤閿欙紝濡傛灉娌℃湁鎸夌収鎮ㄧ殑閰嶇疆鍙戠敓鏀瑰彉锛岃妫�鏌ユ嫾鍐欐槸鍚︽纭�
+        if (prmPreset === 'undefined') {
+          console.log('璇ュ浘灞傛帶鍒堕潰鏉跨殑棰勮娌℃湁鎵惧埌锛岃妫�鏌ラ璁惧悕绉版槸鍚︽纭紒')
+        } else {
+          this.$store.commit('updateLayerControllerVisible', this.layerControllerVisible)
+        }
+      }
+    },
+    switchPanel () {
+      this.panelSwitch.main = !this.panelSwitch.main
+      if (this.panelSwitch.main) {
+        this.width = '250px'
+        this.isShow = true
+      } else {
+        this.width = '0px'
+        this.isShow = false
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+
+.float-panel {
+  position: absolute;
+  top: 120px;
+  height: auto;
+  font-size: 11px;
+  z-index: 1000;
+
+  div {
+    color: #90c8e0;
+  }
+
+  .title-border {
+    width: 100%;
+    height: 28px;
+    background: #10488c;
+    -webkit-clip-path: polygon(0px 0px, 0px 28px, 230px 28px, 230px 9px, 95px 9px, 86px 0px);
+    clip-path: polygon(0px 0px, 0px 28px, 230px 28px, 230px 9px, 95px 9px, 86px 0px);
+    position: relative;
+  }
+
+  .title-border:before {
+    content: "";
+    display: block;
+    position: absolute;
+    width: 6px;
+    height: 6px;
+    top: 0;
+    left: 0;
+    background-color: #38c8ef;
+  }
+
+  .title-border:after {
+    content: "";
+    display: block;
+    position: absolute;
+    width: 6px;
+    height: 6px;
+    top: 9px;
+    right: 0;
+    background-color: #38c8ef;
+    -webkit-clip-path: polygon(0px 0px, 0px 1px, 5px 1px, 5px 6px, 6px 6px, 6px 0px);
+    clip-path: polygon(0px 0px, 0px 1px, 5px 1px, 5px 6px, 6px 6px, 6px 0px);
+  }
+
+  .title-text-border {
+    width: 30px;
+    height: 120px;
+    float: left;
+    background: #091331;
+    // -webkit-clip-path: polygon(1px 1px, 1px 27px, 229px 27px, 229px 10px, 94px 10px, 85px 1px);
+    // clip-path: polygon(1px 1px, 1px 27px, 229px 27px, 229px 10px, 94px 10px, 85px 1px);
+  }
+
+  .title-icon {
+    float: left;
+    width: 22px;
+    height: 22px;
+    margin-top: 4px;
+    margin-left: 2px;
+    background-image: url(../../assets/images/map-pages/icon/setting.png);
+  }
+
+  .title-text {
+    width: 25px;
+    color: #00d0f9;
+    font-weight: bold;
+    margin-top: 6px;
+    text-align: center;
+    font-size: 14px;
+    filter: brightness(100%);
+    text-shadow: 0 0 5px #00d0f9, 0 0 0 #00d0f9, 0 0 0 #00d0f9, 0 0 0 #0258c5, 0 0 0 #0258c5, 0 0 2px #0258c5, 0 0 5px #0258c5, 0 0 15px #0258c5;
+  }
+
+  .title-line {
+    display: inline-block;
+    width: 120px;
+    height: 1px;
+    // margin-top: 14px;
+    margin-left: 4px;
+    background-color: #04527f;
+    line-height: 5px;
+    vertical-align: middle;
+  }
+
+  .title-point {
+    display: inline-block;
+    width: 5px;
+    height: 5px;
+    // margin-top: 12px;
+    background-color: #04527f;
+    line-height: 5px;
+    vertical-align: middle;
+  }
+
+  .title-button {
+    float: right;
+    width: 28px;
+    height: 28px;
+    cursor: pointer;
+
+    :hover {
+      font-weight: bold;
+      color: white;
+    }
+  }
+
+  .body-box {
+    background-color: rgba(44, 62, 80, 0.6);
+    border: 1px solid #10488c;
+    margin-top: -1px;
+    margin-left: 30px;
+    height: auto;
+  }
+
+  .switch-head-up {
+    width: 22px;
+    height: 16px;
+    float: right;
+    margin-top: 10px;
+    margin-right: 10px;
+    cursor: pointer;
+    background-image: url(../../assets/images/map-pages/icon/xljt1.png);
+    transform: rotateX(0deg);
+    transform-origin: 50% 50%;
+    transition: transform 0.5s linear 0s;
+  }
+
+  .switch-head-down {
+    transform: rotateX(180deg);
+    transform-origin: 50% 50%;
+    transition: transform 0.5s linear 0s;
+  }
+
+  select {
+    background: transparent;
+    margin: 6px;
+    border: .5px solid #569EB7;
+    width: 150px;
+    color: #569EB7;
+    padding: 0 16px;
+  }
+
+  .horn {
+    width: 6px;
+    height: 6px;
+    float: left;
+    position: absolute;
+  }
+
+  .horn-tl {
+    background-image: url(../../assets/images/map-pages/cosmetics/horn_tl.png);
+    left: -1px;
+    top: -1px;
+  }
+
+  .horn-tr {
+    background-image: url(../../assets/images/map-pages/cosmetics/horn_tr.png);
+    right: -1px;
+    top: -1px;
+  }
+
+  .horn-bl {
+    background-image: url(../../assets/images/map-pages/cosmetics/horn_bl.png);
+    left: -1px;
+    bottom: -1px;
+  }
+
+  .horn-br {
+    background-image: url(../../assets/images/map-pages/cosmetics/horn_br.png);
+    right: -1px;
+    bottom: -1px;
+  }
+
+  ::-webkit-scrollbar {
+    width: 7px;
+    height: 5px !important;
+  }
+
+  ::-webkit-scrollbar-thumb {
+    /*婊氬姩鏉¢噷闈㈠皬鏂瑰潡*/
+    border-radius: 10px;
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
+    background: #0661AE;
+    border: 1px solid transparent;
+  }
+
+  ::-webkit-scrollbar-track {
+    /*婊氬姩鏉¢噷闈㈣建閬�*/
+    // box-shadow   : inset 0 0 5px rgba(0, 0, 0, 0.2);
+    border-radius: 0px;
+    background: #0E3565;
+  }
+}
+
+</style>
diff --git a/src/components/LayerController/modules/LcServiceLayer.vue b/src/components/LayerController/modules/LcServiceLayer.vue
index b86a7e6..fddacf6 100644
--- a/src/components/LayerController/modules/LcServiceLayer.vue
+++ b/src/components/LayerController/modules/LcServiceLayer.vue
@@ -1,5 +1,8 @@
 <template>
     <div class="inner-panel">
+        <div class="title">
+            鍥惧眰鎺у埗
+        </div>
         <div class="wms-panel">
             <div v-for="item in serviceLayers" :key="item.code" class="layerbox">
                 <div><input type="checkbox" :name="'wmsLayer_'+item.code" :checked="item.checked" :value="item.code"
@@ -96,10 +99,13 @@
 
 <style scoped lang="less">
     .inner-panel {
-        display: flex;
-        justify-content: center;
-        align-items: center;
-
+        .title{
+            color: #ffffff;
+            font-size: 16px;
+            font-weight: 600;
+            margin: 10px;
+            text-align: center;
+        }
         .btn-filter {
             cursor: pointer;
             color: #ffffff;
@@ -107,13 +113,9 @@
 
         .wms-panel {
             width: 250px;
-            display: flex;
-            flex-flow: column;
 
             .layerbox {
                 width: 100%;
-                display: flex;
-                flex-flow: column;
 
                 .layerbox-item {
                     display: flex;
diff --git a/src/components/panel/ToolBoxPanel.vue b/src/components/panel/ToolBoxPanel.vue
index 3b1ab92..9448ccf 100644
--- a/src/components/panel/ToolBoxPanel.vue
+++ b/src/components/panel/ToolBoxPanel.vue
@@ -359,6 +359,7 @@
     // 宸︿笂鍔熻兘鎺у埗
     changeSelect () {
       this.selectGroup = !this.selectGroup
+      this.isShow = !this.isShow
     }
   }
 }
@@ -373,10 +374,8 @@
 
   .specific-tools {
     display: flex;
-    align-items: center;
-    justify-content: space-evenly;
-
     .el-button {
+      z-index: 999;
       padding: 0;
       margin: 0 0.015rem;
       width: 45px;
@@ -403,6 +402,7 @@
     }
 
     .specific-tools-group {
+      z-index: 1;
       .tools-panel-choose {
         border: none;
         box-shadow: 0 0 0.03rem @color-shadow;
@@ -425,4 +425,11 @@
     }
   }
 }
+.isD-enter-active, .isD-leave-active{
+  transition: all 0.5s;
+}
+.isD-enter, .isD-leave-to{
+  opacity: 0;
+  transform: translateX(-100px);
+}
 </style>
diff --git a/src/components/plugin/Editable.js b/src/components/plugin/Editable.js
index 79fc3ad..3f24a8d 100644
--- a/src/components/plugin/Editable.js
+++ b/src/components/plugin/Editable.js
@@ -1,2016 +1,2010 @@
-'use strict'
-const init = (L) => {
-  (function (factory, window) {
-    // define an AMD module that relies on 'leaflet'
-    if (typeof define === 'function' && window.define.amd) {
-      window.define(['leaflet'], factory)
+'use strict';
+(function (factory, window) {
+  // define an AMD module that relies on 'leaflet'
+  if (typeof define === 'function' && define.amd) {
+    define(['leaflet'], factory)
 
-      // define a Common JS module that relies on 'leaflet'
-    } else if (typeof exports === 'object') {
-      module.exports = factory(require('leaflet'))
-    }
+    // define a Common JS module that relies on 'leaflet'
+  } else if (typeof exports === 'object') {
+    module.exports = factory(require('leaflet'))
+  }
 
-    // attach your plugin to the global 'L' variable
-    if (typeof window !== 'undefined' && L) {
-      factory(L)
-    }
-  }(function (L) {
-    // 馃崅miniclass CancelableEvent (Event objects)
-    // 馃崅method cancel()
-    // Cancel any subsequent action.
+  // attach your plugin to the global 'L' variable
+  if (typeof window !== 'undefined' && window.L) {
+    factory(window.L)
+  }
+}(function (L) {
+  // 馃崅miniclass CancelableEvent (Event objects)
+  // 馃崅method cancel()
+  // Cancel any subsequent action.
 
-    // 馃崅miniclass VertexEvent (Event objects)
-    // 馃崅property vertex: VertexMarker
-    // The vertex that fires the event.
+  // 馃崅miniclass VertexEvent (Event objects)
+  // 馃崅property vertex: VertexMarker
+  // The vertex that fires the event.
 
-    // 馃崅miniclass ShapeEvent (Event objects)
-    // 馃崅property shape: Array
-    // The shape (LatLngs array) subject of the action.
+  // 馃崅miniclass ShapeEvent (Event objects)
+  // 馃崅property shape: Array
+  // The shape (LatLngs array) subject of the action.
 
-    // 馃崅miniclass CancelableVertexEvent (Event objects)
-    // 馃崅inherits VertexEvent
-    // 馃崅inherits CancelableEvent
+  // 馃崅miniclass CancelableVertexEvent (Event objects)
+  // 馃崅inherits VertexEvent
+  // 馃崅inherits CancelableEvent
 
-    // 馃崅miniclass CancelableShapeEvent (Event objects)
-    // 馃崅inherits ShapeEvent
-    // 馃崅inherits CancelableEvent
+  // 馃崅miniclass CancelableShapeEvent (Event objects)
+  // 馃崅inherits ShapeEvent
+  // 馃崅inherits CancelableEvent
 
-    // 馃崅miniclass LayerEvent (Event objects)
-    // 馃崅property layer: object
-    // The Layer (Marker, Polyline鈥�) subject of the action.
+  // 馃崅miniclass LayerEvent (Event objects)
+  // 馃崅property layer: object
+  // The Layer (Marker, Polyline鈥�) subject of the action.
 
-    // 馃崅namespace Editable; 馃崅class Editable; 馃崅aka L.Editable
-    // Main edition handler. By default, it is attached to the map
-    // as `map.editTools` property.
-    // Leaflet.Editable is made to be fully extendable. You have three ways to customize
-    // the behaviour: using options, listening to events, or extending.
-    L.Editable = L.Evented.extend({
+  // 馃崅namespace Editable; 馃崅class Editable; 馃崅aka L.Editable
+  // Main edition handler. By default, it is attached to the map
+  // as `map.editTools` property.
+  // Leaflet.Editable is made to be fully extendable. You have three ways to customize
+  // the behaviour: using options, listening to events, or extending.
+  L.Editable = L.Evented.extend({
 
-      statics: {
-        FORWARD: 1,
-        BACKWARD: -1
-      },
+    statics: {
+      FORWARD: 1,
+      BACKWARD: -1
+    },
 
-      options: {
+    options: {
 
-        // You can pass them when creating a map using the `editOptions` key.
-        // 馃崅option zIndex: int = 1000
-        // The default zIndex of the editing tools.
-        zIndex: 1000,
+      // You can pass them when creating a map using the `editOptions` key.
+      // 馃崅option zIndex: int = 1000
+      // The default zIndex of the editing tools.
+      zIndex: 1000,
 
-        // 馃崅option polygonClass: class = L.Polygon
-        // Class to be used when creating a new Polygon.
-        polygonClass: L.Polygon,
+      // 馃崅option polygonClass: class = L.Polygon
+      // Class to be used when creating a new Polygon.
+      polygonClass: L.Polygon,
 
-        // 馃崅option polylineClass: class = L.Polyline
-        // Class to be used when creating a new Polyline.
-        polylineClass: L.Polyline,
+      // 馃崅option polylineClass: class = L.Polyline
+      // Class to be used when creating a new Polyline.
+      polylineClass: L.Polyline,
 
-        // 馃崅option markerClass: class = L.Marker
-        // Class to be used when creating a new Marker.
-        markerClass: L.Marker,
+      // 馃崅option markerClass: class = L.Marker
+      // Class to be used when creating a new Marker.
+      markerClass: L.Marker,
 
-        // 馃崅option rectangleClass: class = L.Rectangle
-        // Class to be used when creating a new Rectangle.
-        rectangleClass: L.Rectangle,
+      // 馃崅option rectangleClass: class = L.Rectangle
+      // Class to be used when creating a new Rectangle.
+      rectangleClass: L.Rectangle,
 
-        // 馃崅option circleClass: class = L.Circle
-        // Class to be used when creating a new Circle.
-        circleClass: L.Circle,
+      // 馃崅option circleClass: class = L.Circle
+      // Class to be used when creating a new Circle.
+      circleClass: L.Circle,
 
-        // 馃崅option drawingCSSClass: string = 'leaflet-editable-drawing'
-        // CSS class to be added to the map container while drawing.
-        drawingCSSClass: 'leaflet-editable-drawing',
+      // 馃崅option drawingCSSClass: string = 'leaflet-editable-drawing'
+      // CSS class to be added to the map container while drawing.
+      drawingCSSClass: 'leaflet-editable-drawing',
 
-        // 馃崅option drawingCursor: const = 'crosshair'
-        // Cursor mode set to the map while drawing.
-        drawingCursor: 'crosshair',
+      // 馃崅option drawingCursor: const = 'crosshair'
+      // Cursor mode set to the map while drawing.
+      drawingCursor: 'crosshair',
 
-        // 馃崅option editLayer: Layer = new L.LayerGroup()
-        // Layer used to store edit tools (vertex, line guide鈥�).
-        editLayer: undefined,
+      // 馃崅option editLayer: Layer = new L.LayerGroup()
+      // Layer used to store edit tools (vertex, line guide鈥�).
+      editLayer: undefined,
 
-        // 馃崅option featuresLayer: Layer = new L.LayerGroup()
-        // Default layer used to store drawn features (Marker, Polyline鈥�).
-        featuresLayer: undefined,
+      // 馃崅option featuresLayer: Layer = new L.LayerGroup()
+      // Default layer used to store drawn features (Marker, Polyline鈥�).
+      featuresLayer: undefined,
 
-        // 馃崅option polylineEditorClass: class = PolylineEditor
-        // Class to be used as Polyline editor.
-        polylineEditorClass: undefined,
+      // 馃崅option polylineEditorClass: class = PolylineEditor
+      // Class to be used as Polyline editor.
+      polylineEditorClass: undefined,
 
-        // 馃崅option polygonEditorClass: class = PolygonEditor
-        // Class to be used as Polygon editor.
-        polygonEditorClass: undefined,
+      // 馃崅option polygonEditorClass: class = PolygonEditor
+      // Class to be used as Polygon editor.
+      polygonEditorClass: undefined,
 
-        // 馃崅option markerEditorClass: class = MarkerEditor
-        // Class to be used as Marker editor.
-        markerEditorClass: undefined,
+      // 馃崅option markerEditorClass: class = MarkerEditor
+      // Class to be used as Marker editor.
+      markerEditorClass: undefined,
 
-        // 馃崅option rectangleEditorClass: class = RectangleEditor
-        // Class to be used as Rectangle editor.
-        rectangleEditorClass: undefined,
+      // 馃崅option rectangleEditorClass: class = RectangleEditor
+      // Class to be used as Rectangle editor.
+      rectangleEditorClass: undefined,
 
-        // 馃崅option circleEditorClass: class = CircleEditor
-        // Class to be used as Circle editor.
-        circleEditorClass: undefined,
+      // 馃崅option circleEditorClass: class = CircleEditor
+      // Class to be used as Circle editor.
+      circleEditorClass: undefined,
 
-        // 馃崅option lineGuideOptions: hash = {}
-        // Options to be passed to the line guides.
-        lineGuideOptions: {},
+      // 馃崅option lineGuideOptions: hash = {}
+      // Options to be passed to the line guides.
+      lineGuideOptions: {},
 
-        // 馃崅option skipMiddleMarkers: boolean = false
-        // Set this to true if you don't want middle markers.
-        skipMiddleMarkers: false
+      // 馃崅option skipMiddleMarkers: boolean = false
+      // Set this to true if you don't want middle markers.
+      skipMiddleMarkers: false
 
-      },
+    },
 
-      initialize: function (map, options) {
-        L.setOptions(this, options)
-        this._lastZIndex = this.options.zIndex
-        this.map = map
-        this.editLayer = this.createEditLayer()
-        this.featuresLayer = this.createFeaturesLayer()
-        this.forwardLineGuide = this.createLineGuide()
-        this.backwardLineGuide = this.createLineGuide()
-      },
+    initialize: function (map, options) {
+      L.setOptions(this, options)
+      this._lastZIndex = this.options.zIndex
+      this.map = map
+      this.editLayer = this.createEditLayer()
+      this.featuresLayer = this.createFeaturesLayer()
+      this.forwardLineGuide = this.createLineGuide()
+      this.backwardLineGuide = this.createLineGuide()
+    },
 
-      fireAndForward: function (type, e) {
-        e = e || {}
-        e.editTools = this
-        this.fire(type, e)
-        this.map.fire(type, e)
-      },
+    fireAndForward: function (type, e) {
+      e = e || {}
+      e.editTools = this
+      this.fire(type, e)
+      this.map.fire(type, e)
+    },
 
-      createLineGuide: function () {
-        const options = L.extend({
-          dashArray: '5,10',
-          weight: 1,
-          interactive: false
-        }, this.options.lineGuideOptions)
-        return L.polyline([], options)
-      },
+    createLineGuide: function () {
+      const options = L.extend({
+        dashArray: '5,10',
+        weight: 1,
+        interactive: false
+      }, this.options.lineGuideOptions)
+      return L.polyline([], options)
+    },
 
-      createVertexIcon: function (options) {
-        return L.Browser.mobile && L.Browser.touch ? new L.Editable.TouchVertexIcon(options) : new L.Editable.VertexIcon(options)
-      },
+    createVertexIcon: function (options) {
+      return L.Browser.mobile && L.Browser.touch ? new L.Editable.TouchVertexIcon(options) : new L.Editable.VertexIcon(options)
+    },
 
-      createEditLayer: function () {
-        return this.options.editLayer || new L.LayerGroup().addTo(this.map)
-      },
+    createEditLayer: function () {
+      return this.options.editLayer || new L.LayerGroup().addTo(this.map)
+    },
 
-      createFeaturesLayer: function () {
-        return this.options.featuresLayer || new L.LayerGroup().addTo(this.map)
-      },
+    createFeaturesLayer: function () {
+      return this.options.featuresLayer || new L.LayerGroup().addTo(this.map)
+    },
 
-      moveForwardLineGuide: function (latlng) {
-        if (this.forwardLineGuide._latlngs.length) {
-          this.forwardLineGuide._latlngs[1] = latlng
-          this.forwardLineGuide._bounds.extend(latlng)
-          this.forwardLineGuide.redraw()
-        }
-      },
-
-      moveBackwardLineGuide: function (latlng) {
-        if (this.backwardLineGuide._latlngs.length) {
-          this.backwardLineGuide._latlngs[1] = latlng
-          this.backwardLineGuide._bounds.extend(latlng)
-          this.backwardLineGuide.redraw()
-        }
-      },
-
-      anchorForwardLineGuide: function (latlng) {
-        this.forwardLineGuide._latlngs[0] = latlng
+    moveForwardLineGuide: function (latlng) {
+      if (this.forwardLineGuide._latlngs.length) {
+        this.forwardLineGuide._latlngs[1] = latlng
         this.forwardLineGuide._bounds.extend(latlng)
         this.forwardLineGuide.redraw()
-      },
+      }
+    },
 
-      anchorBackwardLineGuide: function (latlng) {
-        this.backwardLineGuide._latlngs[0] = latlng
+    moveBackwardLineGuide: function (latlng) {
+      if (this.backwardLineGuide._latlngs.length) {
+        this.backwardLineGuide._latlngs[1] = latlng
         this.backwardLineGuide._bounds.extend(latlng)
         this.backwardLineGuide.redraw()
-      },
-
-      attachForwardLineGuide: function () {
-        this.editLayer.addLayer(this.forwardLineGuide)
-      },
-
-      attachBackwardLineGuide: function () {
-        this.editLayer.addLayer(this.backwardLineGuide)
-      },
-
-      detachForwardLineGuide: function () {
-        this.forwardLineGuide.setLatLngs([])
-        this.editLayer.removeLayer(this.forwardLineGuide)
-      },
-
-      detachBackwardLineGuide: function () {
-        this.backwardLineGuide.setLatLngs([])
-        this.editLayer.removeLayer(this.backwardLineGuide)
-      },
-
-      blockEvents: function () {
-        // Hack: force map not to listen to other layers events while drawing.
-        if (!this._oldTargets) {
-          this._oldTargets = this.map._targets
-          this.map._targets = {}
-        }
-      },
-
-      unblockEvents: function () {
-        if (this._oldTargets) {
-          // Reset, but keep targets created while drawing.
-          this.map._targets = L.extend(this.map._targets, this._oldTargets)
-          delete this._oldTargets
-        }
-      },
-
-      registerForDrawing: function (editor) {
-        if (this._drawingEditor) this.unregisterForDrawing(this._drawingEditor)
-        this.blockEvents()
-        editor.reset() // Make sure editor tools still receive events.
-        this._drawingEditor = editor
-        this.map.on('mousemove touchmove', editor.onDrawingMouseMove, editor)
-        this.map.on('mousedown', this.onMousedown, this)
-        this.map.on('mouseup', this.onMouseup, this)
-        L.DomUtil.addClass(this.map._container, this.options.drawingCSSClass)
-        this.defaultMapCursor = this.map._container.style.cursor
-        this.map._container.style.cursor = this.options.drawingCursor
-      },
-
-      unregisterForDrawing: function (editor) {
-        this.unblockEvents()
-        L.DomUtil.removeClass(this.map._container, this.options.drawingCSSClass)
-        this.map._container.style.cursor = this.defaultMapCursor
-        editor = editor || this._drawingEditor
-        if (!editor) return
-        this.map.off('mousemove touchmove', editor.onDrawingMouseMove, editor)
-        this.map.off('mousedown', this.onMousedown, this)
-        this.map.off('mouseup', this.onMouseup, this)
-        if (editor !== this._drawingEditor) return
-        delete this._drawingEditor
-        if (editor._drawing) editor.cancelDrawing()
-      },
-
-      onMousedown: function (e) {
-        if (e.originalEvent.which !== 1) return
-        this._mouseDown = e
-        this._drawingEditor.onDrawingMouseDown(e)
-      },
-
-      onMouseup: function (e) {
-        if (this._mouseDown) {
-          const editor = this._drawingEditor
-          const mouseDown = this._mouseDown
-          this._mouseDown = null
-          editor.onDrawingMouseUp(e)
-          if (this._drawingEditor !== editor) return // onDrawingMouseUp may call unregisterFromDrawing.
-          const origin = L.point(mouseDown.originalEvent.clientX, mouseDown.originalEvent.clientY)
-          const distance = L.point(e.originalEvent.clientX, e.originalEvent.clientY).distanceTo(origin)
-          if (Math.abs(distance) < 9 * (window.devicePixelRatio || 1)) this._drawingEditor.onDrawingClick(e)
-        }
-      },
-
-      // 馃崅section Public methods
-      // You will generally access them by the `map.editTools`
-      // instance:
-      //
-      // `map.editTools.startPolyline();`
-
-      // 馃崅method drawing(): boolean
-      // Return true if any drawing action is ongoing.
-      drawing: function () {
-        return this._drawingEditor && this._drawingEditor.drawing()
-      },
-
-      // 馃崅method stopDrawing()
-      // When you need to stop any ongoing drawing, without needing to know which editor is active.
-      stopDrawing: function () {
-        this.unregisterForDrawing()
-      },
-
-      // 馃崅method commitDrawing()
-      // When you need to commit any ongoing drawing, without needing to know which editor is active.
-      commitDrawing: function (e) {
-        if (!this._drawingEditor) return
-        this._drawingEditor.commitDrawing(e)
-      },
-
-      connectCreatedToMap: function (layer) {
-        return this.featuresLayer.addLayer(layer)
-      },
-      // 馃崅method startPolyline(latlng: L.LatLng, options: hash): L.Polyline
-      // Start drawing a Polyline. If `latlng` is given, a first point will be added. In any case, continuing on user click.
-      // If `options` is given, it will be passed to the Polyline class constructor.
-      // 鐢荤嚎
-      startPolyline: function (latlng, options) {
-        const line = this.createPolyline([], options)
-        line.enableEdit(this.map).newShape(latlng)
-        return line
-      },
-
-      // 馃崅method startPolygon(latlng: L.LatLng, options: hash): L.Polygon
-      // Start drawing a Polygon. If `latlng` is given, a first point will be added. In any case, continuing on user click.
-      // If `options` is given, it will be passed to the Polygon class constructor.
-      startPolygon: function (latlng, options) {
-        const polygon = this.createPolygon([], options)
-        polygon.enableEdit(this.map).newShape(latlng)
-        return polygon
-      },
-
-      // 馃崅method startMarker(latlng: L.LatLng, options: hash): L.Marker
-      // Start adding a Marker. If `latlng` is given, the Marker will be shown first at this point.
-      // In any case, it will follow the user mouse, and will have a final `latlng` on next click (or touch).
-      // If `options` is given, it will be passed to the Marker class constructor.
-      startMarker: function (latlng, options) {
-        latlng = latlng || this.map.getCenter().clone()
-        const marker = this.createMarker(latlng, options)
-        marker.enableEdit(this.map).startDrawing()
-        return marker
-      },
-
-      // 馃崅method startRectangle(latlng: L.LatLng, options: hash): L.Rectangle
-      // Start drawing a Rectangle. If `latlng` is given, the Rectangle anchor will be added. In any case, continuing on user drag.
-      // If `options` is given, it will be passed to the Rectangle class constructor.
-      startRectangle: function (latlng, options) {
-        const corner = latlng || L.latLng([0, 0])
-        const bounds = new L.LatLngBounds(corner, corner)
-        const rectangle = this.createRectangle(bounds, options)
-        rectangle.enableEdit(this.map).startDrawing()
-        return rectangle
-      },
-
-      // 馃崅method startCircle(latlng: L.LatLng, options: hash): L.Circle
-      // Start drawing a Circle. If `latlng` is given, the Circle anchor will be added. In any case, continuing on user drag.
-      // If `options` is given, it will be passed to the Circle class constructor.
-      startCircle: function (latlng, options) {
-        latlng = latlng || this.map.getCenter().clone()
-        const circle = this.createCircle(latlng, options)
-        circle.enableEdit(this.map).startDrawing()
-        return circle
-      },
-
-      startHole: function (editor, latlng) {
-        editor.newHole(latlng)
-      },
-
-      createLayer: function (Klass, latlngs, options) {
-        options = L.Util.extend({ editOptions: { editTools: this } }, options)
-        const layer = new Klass(latlngs, options)
-        // 馃崅namespace Editable
-        // 馃崅event editable:created: LayerEvent
-        // Fired when a new feature (Marker, Polyline鈥�) is created.
-        this.fireAndForward('editable:created', { layer: layer })
-        return layer
-      },
-
-      createPolyline: function (latlngs, options) {
-        return this.createLayer((options && options.polylineClass) || this.options.polylineClass, latlngs, options)
-      },
-
-      createPolygon: function (latlngs, options) {
-        return this.createLayer((options && options.polygonClass) || this.options.polygonClass, latlngs, options)
-      },
-
-      createMarker: function (latlng, options) {
-        return this.createLayer((options && options.markerClass) || this.options.markerClass, latlng, options)
-      },
-
-      createRectangle: function (bounds, options) {
-        return this.createLayer((options && options.rectangleClass) || this.options.rectangleClass, bounds, options)
-      },
-
-      createCircle: function (latlng, options) {
-        return this.createLayer((options && options.circleClass) || this.options.circleClass, latlng, options)
       }
+    },
 
-    })
+    anchorForwardLineGuide: function (latlng) {
+      this.forwardLineGuide._latlngs[0] = latlng
+      this.forwardLineGuide._bounds.extend(latlng)
+      this.forwardLineGuide.redraw()
+    },
 
-    L.extend(L.Editable, {
+    anchorBackwardLineGuide: function (latlng) {
+      this.backwardLineGuide._latlngs[0] = latlng
+      this.backwardLineGuide._bounds.extend(latlng)
+      this.backwardLineGuide.redraw()
+    },
 
-      makeCancellable: function (e) {
-        e.cancel = function () {
-          e._cancelled = true
-        }
+    attachForwardLineGuide: function () {
+      this.editLayer.addLayer(this.forwardLineGuide)
+    },
+
+    attachBackwardLineGuide: function () {
+      this.editLayer.addLayer(this.backwardLineGuide)
+    },
+
+    detachForwardLineGuide: function () {
+      this.forwardLineGuide.setLatLngs([])
+      this.editLayer.removeLayer(this.forwardLineGuide)
+    },
+
+    detachBackwardLineGuide: function () {
+      this.backwardLineGuide.setLatLngs([])
+      this.editLayer.removeLayer(this.backwardLineGuide)
+    },
+
+    blockEvents: function () {
+      // Hack: force map not to listen to other layers events while drawing.
+      if (!this._oldTargets) {
+        this._oldTargets = this.map._targets
+        this.map._targets = {}
       }
+    },
 
-    })
+    unblockEvents: function () {
+      if (this._oldTargets) {
+        // Reset, but keep targets created while drawing.
+        this.map._targets = L.extend(this.map._targets, this._oldTargets)
+        delete this._oldTargets
+      }
+    },
 
-    // 馃崅namespace Map; 馃崅class Map
-    // Leaflet.Editable add options and events to the `L.Map` object.
-    // See `Editable` events for the list of events fired on the Map.
-    // 馃崅example
+    registerForDrawing: function (editor) {
+      if (this._drawingEditor) this.unregisterForDrawing(this._drawingEditor)
+      this.blockEvents()
+      editor.reset() // Make sure editor tools still receive events.
+      this._drawingEditor = editor
+      this.map.on('mousemove touchmove', editor.onDrawingMouseMove, editor)
+      this.map.on('mousedown', this.onMousedown, this)
+      this.map.on('mouseup', this.onMouseup, this)
+      L.DomUtil.addClass(this.map._container, this.options.drawingCSSClass)
+      this.defaultMapCursor = this.map._container.style.cursor
+      this.map._container.style.cursor = this.options.drawingCursor
+    },
+
+    unregisterForDrawing: function (editor) {
+      this.unblockEvents()
+      L.DomUtil.removeClass(this.map._container, this.options.drawingCSSClass)
+      this.map._container.style.cursor = this.defaultMapCursor
+      editor = editor || this._drawingEditor
+      if (!editor) return
+      this.map.off('mousemove touchmove', editor.onDrawingMouseMove, editor)
+      this.map.off('mousedown', this.onMousedown, this)
+      this.map.off('mouseup', this.onMouseup, this)
+      if (editor !== this._drawingEditor) return
+      delete this._drawingEditor
+      if (editor._drawing) editor.cancelDrawing()
+    },
+
+    onMousedown: function (e) {
+      if (e.originalEvent.which !== 1) return
+      this._mouseDown = e
+      this._drawingEditor.onDrawingMouseDown(e)
+    },
+
+    onMouseup: function (e) {
+      if (this._mouseDown) {
+        const editor = this._drawingEditor
+        const mouseDown = this._mouseDown
+        this._mouseDown = null
+        editor.onDrawingMouseUp(e)
+        if (this._drawingEditor !== editor) return // onDrawingMouseUp may call unregisterFromDrawing.
+        const origin = L.point(mouseDown.originalEvent.clientX, mouseDown.originalEvent.clientY)
+        const distance = L.point(e.originalEvent.clientX, e.originalEvent.clientY).distanceTo(origin)
+        if (Math.abs(distance) < 9 * (window.devicePixelRatio || 1)) this._drawingEditor.onDrawingClick(e)
+      }
+    },
+
+    // 馃崅section Public methods
+    // You will generally access them by the `map.editTools`
+    // instance:
     //
-    // ```js
-    // let map = L.map('map', {
-    //  editable: true,
-    //  editOptions: {
-    //    鈥�
-    // }
-    // });
-    // ```
-    // 馃崅section Editable Map Options
-    L.Map.mergeOptions({
+    // `map.editTools.startPolyline();`
 
-      // 馃崅namespace Map
-      // 馃崅section Map Options
-      // 馃崅option EditToolsClass: class = L.Editable
-      // Class to be used as vertex, for path editing.
-      EditToolsClass: L.Editable,
+    // 馃崅method drawing(): boolean
+    // Return true if any drawing action is ongoing.
+    drawing: function () {
+      return this._drawingEditor && this._drawingEditor.drawing()
+    },
 
-      // 馃崅option editable: boolean = false
-      // Whether to create a L.Editable instance at map init.
-      editable: false,
+    // 馃崅method stopDrawing()
+    // When you need to stop any ongoing drawing, without needing to know which editor is active.
+    stopDrawing: function () {
+      this.unregisterForDrawing()
+    },
 
-      // 馃崅option editOptions: hash = {}
-      // Options to pass to L.Editable when instantiating.
-      editOptions: {}
+    // 馃崅method commitDrawing()
+    // When you need to commit any ongoing drawing, without needing to know which editor is active.
+    commitDrawing: function (e) {
+      if (!this._drawingEditor) return
+      this._drawingEditor.commitDrawing(e)
+    },
 
-    })
+    connectCreatedToMap: function (layer) {
+      return this.featuresLayer.addLayer(layer)
+    },
+    // 馃崅method startPolyline(latlng: L.LatLng, options: hash): L.Polyline
+    // Start drawing a Polyline. If `latlng` is given, a first point will be added. In any case, continuing on user click.
+    // If `options` is given, it will be passed to the Polyline class constructor.
+    // 鐢荤嚎
+    startPolyline: function (latlng, options) {
+      const line = this.createPolyline([], options)
+      line.enableEdit(this.map).newShape(latlng)
+      return line
+    },
 
-    L.Map.addInitHook(function () {
-      this.whenReady(function () {
-        if (this.options.editable) {
-          this.editTools = new this.options.EditToolsClass(this, this.options.editOptions)
-        }
-      })
-    })
+    // 馃崅method startPolygon(latlng: L.LatLng, options: hash): L.Polygon
+    // Start drawing a Polygon. If `latlng` is given, a first point will be added. In any case, continuing on user click.
+    // If `options` is given, it will be passed to the Polygon class constructor.
+    startPolygon: function (latlng, options) {
+      const polygon = this.createPolygon([], options)
+      polygon.enableEdit(this.map).newShape(latlng)
+      return polygon
+    },
 
-    L.Editable.VertexIcon = L.DivIcon.extend({
+    // 馃崅method startMarker(latlng: L.LatLng, options: hash): L.Marker
+    // Start adding a Marker. If `latlng` is given, the Marker will be shown first at this point.
+    // In any case, it will follow the user mouse, and will have a final `latlng` on next click (or touch).
+    // If `options` is given, it will be passed to the Marker class constructor.
+    startMarker: function (latlng, options) {
+      latlng = latlng || this.map.getCenter().clone()
+      const marker = this.createMarker(latlng, options)
+      marker.enableEdit(this.map).startDrawing()
+      return marker
+    },
 
-      options: {
-        iconSize: new L.Point(8, 8)
-      }
+    // 馃崅method startRectangle(latlng: L.LatLng, options: hash): L.Rectangle
+    // Start drawing a Rectangle. If `latlng` is given, the Rectangle anchor will be added. In any case, continuing on user drag.
+    // If `options` is given, it will be passed to the Rectangle class constructor.
+    startRectangle: function (latlng, options) {
+      const corner = latlng || L.latLng([0, 0])
+      const bounds = new L.LatLngBounds(corner, corner)
+      const rectangle = this.createRectangle(bounds, options)
+      rectangle.enableEdit(this.map).startDrawing()
+      return rectangle
+    },
 
-    })
+    // 馃崅method startCircle(latlng: L.LatLng, options: hash): L.Circle
+    // Start drawing a Circle. If `latlng` is given, the Circle anchor will be added. In any case, continuing on user drag.
+    // If `options` is given, it will be passed to the Circle class constructor.
+    startCircle: function (latlng, options) {
+      latlng = latlng || this.map.getCenter().clone()
+      const circle = this.createCircle(latlng, options)
+      circle.enableEdit(this.map).startDrawing()
+      return circle
+    },
 
-    L.Editable.TouchVertexIcon = L.Editable.VertexIcon.extend({
+    startHole: function (editor, latlng) {
+      editor.newHole(latlng)
+    },
 
-      options: {
-        iconSize: new L.Point(20, 20)
-      }
-
-    })
-
-    // 馃崅namespace Editable; 馃崅class VertexMarker; Handler for dragging path vertices.
-    L.Editable.VertexMarker = L.Marker.extend({
-
-      options: {
-        draggable: true,
-        className: 'leaflet-vertex-icon leaflet-custom-icon'
-      },
-
-      // 馃崅section Public methods
-      // The marker used to handle path vertex. You will usually interact with a `VertexMarker`
-      // instance when listening for events like `editable:vertex:ctrlclick`.
-
-      initialize: function (latlng, latlngs, editor, options) {
-        // We don't use this._latlng, because on drag Leaflet replace it while
-        // we want to keep reference.
-        this.latlng = latlng
-        this.latlngs = latlngs
-        this.editor = editor
-        L.Marker.prototype.initialize.call(this, latlng, options)
-        this.options.icon = this.editor.tools.createVertexIcon({ className: this.options.className })
-        this.latlng.__vertex = this
-        this.editor.editLayer.addLayer(this)
-        this.setZIndexOffset(editor.tools._lastZIndex + 1)
-      },
-
-      onAdd: function (map) {
-        L.Marker.prototype.onAdd.call(this, map)
-        this.on('drag', this.onDrag)
-        this.on('dragstart', this.onDragStart)
-        this.on('dragend', this.onDragEnd)
-        this.on('mouseup', this.onMouseup)
-        this.on('click', this.onClick)
-        this.on('contextmenu', this.onContextMenu)
-        this.on('mousedown touchstart', this.onMouseDown)
-        this.on('mouseover', this.onMouseOver)
-        this.on('mouseout', this.onMouseOut)
-        this.addMiddleMarkers()
-      },
-
-      onRemove: function (map) {
-        if (this.middleMarker) this.middleMarker.delete()
-        delete this.latlng.__vertex
-        this.off('drag', this.onDrag)
-        this.off('dragstart', this.onDragStart)
-        this.off('dragend', this.onDragEnd)
-        this.off('mouseup', this.onMouseup)
-        this.off('click', this.onClick)
-        this.off('contextmenu', this.onContextMenu)
-        this.off('mousedown touchstart', this.onMouseDown)
-        this.off('mouseover', this.onMouseOver)
-        this.off('mouseout', this.onMouseOut)
-        L.Marker.prototype.onRemove.call(this, map)
-      },
-
-      onDrag: function (e) {
-        e.vertex = this
-        this.editor.onVertexMarkerDrag(e)
-        const iconPos = L.DomUtil.getPosition(this._icon)
-        const latlng = this._map.layerPointToLatLng(iconPos)
-        this.latlng.update(latlng)
-        this._latlng = this.latlng // Push back to Leaflet our reference.
-        this.editor.refresh()
-        if (this.middleMarker) this.middleMarker.updateLatLng()
-        const next = this.getNext()
-        if (next && next.middleMarker) next.middleMarker.updateLatLng()
-      },
-
-      onDragStart: function (e) {
-        e.vertex = this
-        this.editor.onVertexMarkerDragStart(e)
-      },
-
-      onDragEnd: function (e) {
-        e.vertex = this
-        this.editor.onVertexMarkerDragEnd(e)
-      },
-
-      onClick: function (e) {
-        e.vertex = this
-        this.editor.onVertexMarkerClick(e)
-      },
-
-      onMouseup: function (e) {
-        L.DomEvent.stop(e)
-        e.vertex = this
-        this.editor.map.fire('mouseup', e)
-      },
-
-      onContextMenu: function (e) {
-        e.vertex = this
-        this.editor.onVertexMarkerContextMenu(e)
-      },
-
-      onMouseDown: function (e) {
-        e.vertex = this
-        this.editor.onVertexMarkerMouseDown(e)
-      },
-
-      onMouseOver: function (e) {
-        e.vertex = this
-        this.editor.onVertexMarkerMouseOver(e)
-      },
-
-      onMouseOut: function (e) {
-        e.vertex = this
-        this.editor.onVertexMarkerMouseOut(e)
-      },
-
-      // 馃崅method delete()
-      // Delete a vertex and the related LatLng.
-      delete: function () {
-        const next = this.getNext() // Compute before changing latlng
-        this.latlngs.splice(this.getIndex(), 1)
-        this.editor.editLayer.removeLayer(this)
-        this.editor.onVertexDeleted({
-          latlng: this.latlng,
-          vertex: this
-        })
-        if (!this.latlngs.length) this.editor.deleteShape(this.latlngs)
-        if (next) next.resetMiddleMarker()
-        this.editor.refresh()
-      },
-
-      // 馃崅method getIndex(): int
-      // Get the index of the current vertex among others of the same LatLngs group.
-      getIndex: function () {
-        return this.latlngs.indexOf(this.latlng)
-      },
-
-      // 馃崅method getLastIndex(): int
-      // Get last vertex index of the LatLngs group of the current vertex.
-      getLastIndex: function () {
-        return this.latlngs.length - 1
-      },
-
-      // 馃崅method getPrevious(): VertexMarker
-      // Get the previous VertexMarker in the same LatLngs group.
-      getPrevious: function () {
-        if (this.latlngs.length < 2) return
-        const index = this.getIndex()
-        let previousIndex = index - 1
-        if (index === 0 && this.editor.CLOSED) previousIndex = this.getLastIndex()
-        const previous = this.latlngs[previousIndex]
-        if (previous) return previous.__vertex
-      },
-
-      // 馃崅method getNext(): VertexMarker
-      // Get the next VertexMarker in the same LatLngs group.
-      getNext: function () {
-        if (this.latlngs.length < 2) return
-        const index = this.getIndex()
-        let nextIndex = index + 1
-        if (index === this.getLastIndex() && this.editor.CLOSED) nextIndex = 0
-        const next = this.latlngs[nextIndex]
-        if (next) return next.__vertex
-      },
-
-      addMiddleMarker: function (previous) {
-        if (!this.editor.hasMiddleMarkers()) return
-        previous = previous || this.getPrevious()
-        if (previous && !this.middleMarker) this.middleMarker = this.editor.addMiddleMarker(previous, this, this.latlngs, this.editor)
-      },
-
-      addMiddleMarkers: function () {
-        if (!this.editor.hasMiddleMarkers()) return
-        const previous = this.getPrevious()
-        if (previous) this.addMiddleMarker(previous)
-        const next = this.getNext()
-        if (next) next.resetMiddleMarker()
-      },
-
-      resetMiddleMarker: function () {
-        if (this.middleMarker) this.middleMarker.delete()
-        this.addMiddleMarker()
-      },
-
-      // 馃崅method split()
-      // Split the vertex LatLngs group at its index, if possible.
-      split: function () {
-        if (!this.editor.splitShape) return // Only for PolylineEditor
-        this.editor.splitShape(this.latlngs, this.getIndex())
-      },
-
-      // 馃崅method continue()
-      // Continue the vertex LatLngs from this vertex. Only active for first and last vertices of a Polyline.
-      continue: function () {
-        if (!this.editor.continueBackward) return // Only for PolylineEditor
-        const index = this.getIndex()
-        if (index === 0) {
-          this.editor.continueBackward(this.latlngs)
-        } else if (index === this.getLastIndex()) this.editor.continueForward(this.latlngs)
-      }
-
-    })
-
-    L.Editable.mergeOptions({
-
+    createLayer: function (Klass, latlngs, options) {
+      options = L.Util.extend({ editOptions: { editTools: this } }, options)
+      const layer = new Klass(latlngs, options)
       // 馃崅namespace Editable
-      // 馃崅option VertexMarkerClass: class = VertexMarker
-      // Class to be used as vertex, for path editing.
-      VertexMarkerClass: L.Editable.VertexMarker
+      // 馃崅event editable:created: LayerEvent
+      // Fired when a new feature (Marker, Polyline鈥�) is created.
+      this.fireAndForward('editable:created', { layer: layer })
+      return layer
+    },
 
-    })
+    createPolyline: function (latlngs, options) {
+      return this.createLayer((options && options.polylineClass) || this.options.polylineClass, latlngs, options)
+    },
 
-    L.Editable.MiddleMarker = L.Marker.extend({
+    createPolygon: function (latlngs, options) {
+      return this.createLayer((options && options.polygonClass) || this.options.polygonClass, latlngs, options)
+    },
 
-      options: {
-        opacity: 0.5,
-        className: 'leaflet-div-icon leaflet-middle-icon',
-        draggable: true
-      },
+    createMarker: function (latlng, options) {
+      return this.createLayer((options && options.markerClass) || this.options.markerClass, latlng, options)
+    },
 
-      initialize: function (left, right, latlngs, editor, options) {
-        this.left = left
-        this.right = right
-        this.editor = editor
-        this.latlngs = latlngs
-        L.Marker.prototype.initialize.call(this, this.computeLatLng(), options)
-        this._opacity = this.options.opacity
-        this.options.icon = this.editor.tools.createVertexIcon({ className: this.options.className })
-        this.editor.editLayer.addLayer(this)
-        this.setVisibility()
-      },
+    createRectangle: function (bounds, options) {
+      return this.createLayer((options && options.rectangleClass) || this.options.rectangleClass, bounds, options)
+    },
 
-      setVisibility: function () {
-        const leftPoint = this._map.latLngToContainerPoint(this.left.latlng)
-        const rightPoint = this._map.latLngToContainerPoint(this.right.latlng)
-        const size = L.point(this.options.icon.options.iconSize)
-        if (leftPoint.distanceTo(rightPoint) < size.x * 3) {
-          this.hide()
-        } else {
-          this.show()
-        }
-      },
-
-      show: function () {
-        this.setOpacity(this._opacity)
-      },
-
-      hide: function () {
-        this.setOpacity(0)
-      },
-
-      updateLatLng: function () {
-        this.setLatLng(this.computeLatLng())
-        this.setVisibility()
-      },
-
-      computeLatLng: function () {
-        const leftPoint = this.editor.map.latLngToContainerPoint(this.left.latlng)
-        const rightPoint = this.editor.map.latLngToContainerPoint(this.right.latlng)
-        const y = (leftPoint.y + rightPoint.y) / 2
-        const x = (leftPoint.x + rightPoint.x) / 2
-        return this.editor.map.containerPointToLatLng([x, y])
-      },
-
-      onAdd: function (map) {
-        L.Marker.prototype.onAdd.call(this, map)
-        L.DomEvent.on(this._icon, 'mousedown touchstart', this.onMouseDown, this)
-        map.on('zoomend', this.setVisibility, this)
-      },
-
-      onRemove: function (map) {
-        delete this.right.middleMarker
-        L.DomEvent.off(this._icon, 'mousedown touchstart', this.onMouseDown, this)
-        map.off('zoomend', this.setVisibility, this)
-        L.Marker.prototype.onRemove.call(this, map)
-      },
-
-      onMouseDown: function (e) {
-        const iconPos = L.DomUtil.getPosition(this._icon)
-        const latlng = this.editor.map.layerPointToLatLng(iconPos)
-        e = {
-          originalEvent: e,
-          latlng: latlng
-        }
-        if (this.options.opacity === 0) return
-        L.Editable.makeCancellable(e)
-        this.editor.onMiddleMarkerMouseDown(e)
-        if (e._cancelled) return
-        this.latlngs.splice(this.index(), 0, e.latlng)
-        this.editor.refresh()
-        const icon = this._icon
-        const marker = this.editor.addVertexMarker(e.latlng, this.latlngs)
-        this.editor.onNewVertex(marker)
-        /* Hack to workaround browser not firing touchend when element is no more on DOM */
-        const parent = marker._icon.parentNode
-        parent.removeChild(marker._icon)
-        marker._icon = icon
-        parent.appendChild(marker._icon)
-        marker._initIcon()
-        marker._initInteraction()
-        marker.setOpacity(1)
-        /* End hack */
-        // Transfer ongoing dragging to real marker
-        L.Draggable._dragging = false
-        marker.dragging._draggable._onDown(e.originalEvent)
-        this.delete()
-      },
-
-      delete: function () {
-        this.editor.editLayer.removeLayer(this)
-      },
-
-      index: function () {
-        return this.latlngs.indexOf(this.right.latlng)
-      }
-
-    })
-
-    L.Editable.mergeOptions({
-
-      // 馃崅namespace Editable
-      // 馃崅option MiddleMarkerClass: class = VertexMarker
-      // Class to be used as middle vertex, pulled by the user to create a new point in the middle of a path.
-      MiddleMarkerClass: L.Editable.MiddleMarker
-
-    })
-
-    // 馃崅namespace Editable; 馃崅class BaseEditor; 馃崅aka L.Editable.BaseEditor
-    // When editing a feature (Marker, Polyline鈥�), an editor is attached to it. This
-    // editor basically knows how to handle the edition.
-    L.Editable.BaseEditor = L.Handler.extend({
-
-      initialize: function (map, feature, options) {
-        L.setOptions(this, options)
-        this.map = map
-        this.feature = feature
-        this.feature.editor = this
-        this.editLayer = new L.LayerGroup()
-        this.tools = this.options.editTools || map.editTools
-      },
-
-      // 馃崅method enable(): this
-      // Set up the drawing tools for the feature to be editable.
-      addHooks: function () {
-        if (this.isConnected()) {
-          this.onFeatureAdd()
-        } else {
-          this.feature.once('add', this.onFeatureAdd, this)
-        }
-        this.onEnable()
-        this.feature.on(this._getEvents(), this)
-      },
-
-      // 馃崅method disable(): this
-      // Remove the drawing tools for the feature.
-      removeHooks: function () {
-        this.feature.off(this._getEvents(), this)
-        if (this.feature.dragging) this.feature.dragging.disable()
-        this.editLayer.clearLayers()
-        this.tools.editLayer.removeLayer(this.editLayer)
-        this.onDisable()
-        if (this._drawing) this.cancelDrawing()
-      },
-
-      // 馃崅method drawing(): boolean
-      // Return true if any drawing action is ongoing with this editor.
-      drawing: function () {
-        return !!this._drawing
-      },
-
-      reset: function () {
-      },
-
-      onFeatureAdd: function () {
-        this.tools.editLayer.addLayer(this.editLayer)
-        if (this.feature.dragging) this.feature.dragging.enable()
-      },
-
-      hasMiddleMarkers: function () {
-        return !this.options.skipMiddleMarkers && !this.tools.options.skipMiddleMarkers
-      },
-
-      fireAndForward: function (type, e) {
-        e = e || {}
-        e.layer = this.feature
-        this.feature.fire(type, e)
-        this.tools.fireAndForward(type, e)
-      },
-
-      onEnable: function () {
-        // 馃崅namespace Editable
-        // 馃崅event editable:enable: Event
-        // Fired when an existing feature is ready to be edited.
-        this.fireAndForward('editable:enable')
-      },
-
-      onDisable: function () {
-        // 馃崅namespace Editable
-        // 馃崅event editable:disable: Event
-        // Fired when an existing feature is not ready anymore to be edited.
-        this.fireAndForward('editable:disable')
-      },
-
-      onEditing: function () {
-        // 馃崅namespace Editable
-        // 馃崅event editable:editing: Event
-        // Fired as soon as any change is made to the feature geometry.
-        this.fireAndForward('editable:editing')
-      },
-
-      onStartDrawing: function () {
-        // 馃崅namespace Editable
-        // 馃崅section Drawing events
-        // 馃崅event editable:drawing:start: Event
-        // Fired when a feature is to be drawn.
-        this.fireAndForward('editable:drawing:start')
-      },
-
-      onEndDrawing: function () {
-        // 馃崅namespace Editable
-        // 馃崅section Drawing events
-        // 馃崅event editable:drawing:end: Event
-        // Fired when a feature is not drawn anymore.
-        this.fireAndForward('editable:drawing:end')
-      },
-
-      onCancelDrawing: function () {
-        // 馃崅namespace Editable
-        // 馃崅section Drawing events
-        // 馃崅event editable:drawing:cancel: Event
-        // Fired when user cancel drawing while a feature is being drawn.
-        this.fireAndForward('editable:drawing:cancel')
-      },
-
-      onCommitDrawing: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Drawing events
-        // 馃崅event editable:drawing:commit: Event
-        // Fired when user finish drawing a feature.
-        this.fireAndForward('editable:drawing:commit', e)
-      },
-
-      onDrawingMouseDown: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Drawing events
-        // 馃崅event editable:drawing:mousedown: Event
-        // Fired when user `mousedown` while drawing.
-        this.fireAndForward('editable:drawing:mousedown', e)
-      },
-
-      onDrawingMouseUp: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Drawing events
-        // 馃崅event editable:drawing:mouseup: Event
-        // Fired when user `mouseup` while drawing.
-        this.fireAndForward('editable:drawing:mouseup', e)
-      },
-
-      startDrawing: function () {
-        if (!this._drawing) this._drawing = L.Editable.FORWARD
-        this.tools.registerForDrawing(this)
-        this.onStartDrawing()
-      },
-
-      commitDrawing: function (e) {
-        this.onCommitDrawing(e)
-        this.endDrawing()
-      },
-
-      cancelDrawing: function () {
-        // If called during a vertex drag, the vertex will be removed before
-        // the mouseup fires on it. This is a workaround. Maybe better fix is
-        // To have L.Draggable reset it's status on disable (Leaflet side).
-        L.Draggable._dragging = false
-        this.onCancelDrawing()
-        this.endDrawing()
-      },
-
-      endDrawing: function () {
-        this._drawing = false
-        this.tools.unregisterForDrawing(this)
-        this.onEndDrawing()
-      },
-
-      onDrawingClick: function (e) {
-        if (!this.drawing()) return
-        L.Editable.makeCancellable(e)
-        // 馃崅namespace Editable
-        // 馃崅section Drawing events
-        // 馃崅event editable:drawing:click: CancelableEvent
-        // Fired when user `click` while drawing, before any internal action is being processed.
-        this.fireAndForward('editable:drawing:click', e)
-        if (e._cancelled) return
-        if (!this.isConnected()) this.connect(e)
-        this.processDrawingClick(e)
-      },
-
-      isConnected: function () {
-        return this.map.hasLayer(this.feature)
-      },
-
-      connect: function () {
-        this.tools.connectCreatedToMap(this.feature)
-        this.tools.editLayer.addLayer(this.editLayer)
-      },
-
-      onMove: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Drawing events
-        // 馃崅event editable:drawing:move: Event
-        // Fired when `move` mouse while drawing, while dragging a marker, and while dragging a vertex.
-        this.fireAndForward('editable:drawing:move', e)
-      },
-
-      onDrawingMouseMove: function (e) {
-        this.onMove(e)
-      },
-
-      _getEvents: function () {
-        return {
-          dragstart: this.onDragStart,
-          drag: this.onDrag,
-          dragend: this.onDragEnd,
-          remove: this.disable
-        }
-      },
-
-      onDragStart: function (e) {
-        this.onEditing()
-        // 馃崅namespace Editable
-        // 馃崅event editable:dragstart: Event
-        // Fired before a path feature is dragged.
-        this.fireAndForward('editable:dragstart', e)
-      },
-
-      onDrag: function (e) {
-        this.onMove(e)
-        // 馃崅namespace Editable
-        // 馃崅event editable:drag: Event
-        // Fired when a path feature is being dragged.
-        this.fireAndForward('editable:drag', e)
-      },
-
-      onDragEnd: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅event editable:dragend: Event
-        // Fired after a path feature has been dragged.
-        this.fireAndForward('editable:dragend', e)
-      }
-
-    })
-
-    // 馃崅namespace Editable; 馃崅class MarkerEditor; 馃崅aka L.Editable.MarkerEditor
-    // 馃崅inherits BaseEditor
-    // Editor for Marker.
-    L.Editable.MarkerEditor = L.Editable.BaseEditor.extend({
-
-      onDrawingMouseMove: function (e) {
-        L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e)
-        if (this._drawing) this.feature.setLatLng(e.latlng)
-      },
-
-      processDrawingClick: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Drawing events
-        // 馃崅event editable:drawing:clicked: Event
-        // Fired when user `click` while drawing, after all internal actions.
-        this.fireAndForward('editable:drawing:clicked', e)
-        this.commitDrawing(e)
-      },
-
-      connect: function (e) {
-        // On touch, the latlng has not been updated because there is
-        // no mousemove.
-        if (e) this.feature._latlng = e.latlng
-        L.Editable.BaseEditor.prototype.connect.call(this, e)
-      }
-
-    })
-
-    // 馃崅namespace Editable; 馃崅class PathEditor; 馃崅aka L.Editable.PathEditor
-    // 馃崅inherits BaseEditor
-    // Base class for all path editors.
-    L.Editable.PathEditor = L.Editable.BaseEditor.extend({
-
-      CLOSED: false,
-      MIN_VERTEX: 2,
-
-      addHooks: function () {
-        L.Editable.BaseEditor.prototype.addHooks.call(this)
-        if (this.feature) this.initVertexMarkers()
-        return this
-      },
-
-      initVertexMarkers: function (latlngs) {
-        if (!this.enabled()) return
-        latlngs = latlngs || this.getLatLngs()
-        if (isFlat(latlngs)) {
-          this.addVertexMarkers(latlngs)
-        } else {
-          for (let i = 0; i < latlngs.length; i++) this.initVertexMarkers(latlngs[i])
-        }
-      },
-
-      getLatLngs: function () {
-        return this.feature.getLatLngs()
-      },
-
-      // 馃崅method reset()
-      // Rebuild edit elements (Vertex, MiddleMarker, etc.).
-      reset: function () {
-        this.editLayer.clearLayers()
-        this.initVertexMarkers()
-      },
-
-      addVertexMarker: function (latlng, latlngs) {
-        return new this.tools.options.VertexMarkerClass(latlng, latlngs, this)
-      },
-
-      onNewVertex: function (vertex) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:new: VertexEvent
-        // Fired when a new vertex is created.
-        this.fireAndForward('editable:vertex:new', {
-          latlng: vertex.latlng,
-          vertex: vertex
-        })
-      },
-
-      addVertexMarkers: function (latlngs) {
-        for (let i = 0; i < latlngs.length; i++) {
-          this.addVertexMarker(latlngs[i], latlngs)
-        }
-      },
-
-      refreshVertexMarkers: function (latlngs) {
-        latlngs = latlngs || this.getDefaultLatLngs()
-        for (let i = 0; i < latlngs.length; i++) {
-          latlngs[i].__vertex.update()
-        }
-      },
-
-      addMiddleMarker: function (left, right, latlngs) {
-        return new this.tools.options.MiddleMarkerClass(left, right, latlngs, this)
-      },
-
-      onVertexMarkerClick: function (e) {
-        L.Editable.makeCancellable(e)
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:click: CancelableVertexEvent
-        // Fired when a `click` is issued on a vertex, before any internal action is being processed.
-        this.fireAndForward('editable:vertex:click', e)
-        if (e._cancelled) return
-        if (this.tools.drawing() && this.tools._drawingEditor !== this) return
-        const index = e.vertex.getIndex()
-        let commit
-        if (e.originalEvent.ctrlKey) {
-          this.onVertexMarkerCtrlClick(e)
-        } else if (e.originalEvent.altKey) {
-          this.onVertexMarkerAltClick(e)
-        } else if (e.originalEvent.shiftKey) {
-          this.onVertexMarkerShiftClick(e)
-        } else if (e.originalEvent.metaKey) {
-          this.onVertexMarkerMetaKeyClick(e)
-        } else if (index === e.vertex.getLastIndex() && this._drawing === L.Editable.FORWARD) {
-          if (index >= this.MIN_VERTEX - 1) commit = true
-        } else if (index === 0 && this._drawing === L.Editable.BACKWARD && this._drawnLatLngs.length >= this.MIN_VERTEX) {
-          commit = true
-        } else if (index === 0 && this._drawing === L.Editable.FORWARD && this._drawnLatLngs.length >= this.MIN_VERTEX && this.CLOSED) {
-          commit = true // Allow to close on first point also for polygons
-        } else {
-          this.onVertexRawMarkerClick(e)
-        }
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:clicked: VertexEvent
-        // Fired when a `click` is issued on a vertex, after all internal actions.
-        this.fireAndForward('editable:vertex:clicked', e)
-        if (commit) this.commitDrawing(e)
-      },
-
-      onVertexRawMarkerClick: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:rawclick: CancelableVertexEvent
-        // Fired when a `click` is issued on a vertex without any special key and without being in drawing mode.
-        this.fireAndForward('editable:vertex:rawclick', e)
-        if (e._cancelled) return
-        if (!this.vertexCanBeDeleted(e.vertex)) return
-        e.vertex.delete()
-      },
-
-      vertexCanBeDeleted: function (vertex) {
-        return vertex.latlngs.length > this.MIN_VERTEX
-      },
-
-      onVertexDeleted: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:deleted: VertexEvent
-        // Fired after a vertex has been deleted by user.
-        this.fireAndForward('editable:vertex:deleted', e)
-      },
-
-      onVertexMarkerCtrlClick: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:ctrlclick: VertexEvent
-        // Fired when a `click` with `ctrlKey` is issued on a vertex.
-        this.fireAndForward('editable:vertex:ctrlclick', e)
-      },
-
-      onVertexMarkerShiftClick: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:shiftclick: VertexEvent
-        // Fired when a `click` with `shiftKey` is issued on a vertex.
-        this.fireAndForward('editable:vertex:shiftclick', e)
-      },
-
-      onVertexMarkerMetaKeyClick: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:metakeyclick: VertexEvent
-        // Fired when a `click` with `metaKey` is issued on a vertex.
-        this.fireAndForward('editable:vertex:metakeyclick', e)
-      },
-
-      onVertexMarkerAltClick: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:altclick: VertexEvent
-        // Fired when a `click` with `altKey` is issued on a vertex.
-        this.fireAndForward('editable:vertex:altclick', e)
-      },
-
-      onVertexMarkerContextMenu: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:contextmenu: VertexEvent
-        // Fired when a `contextmenu` is issued on a vertex.
-        this.fireAndForward('editable:vertex:contextmenu', e)
-      },
-
-      onVertexMarkerMouseDown: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:mousedown: VertexEvent
-        // Fired when user `mousedown` a vertex.
-        this.fireAndForward('editable:vertex:mousedown', e)
-      },
-
-      onVertexMarkerMouseOver: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:mouseover: VertexEvent
-        // Fired when a user's mouse enters the vertex
-        this.fireAndForward('editable:vertex:mouseover', e)
-      },
-
-      onVertexMarkerMouseOut: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:mouseout: VertexEvent
-        // Fired when a user's mouse leaves the vertex
-        this.fireAndForward('editable:vertex:mouseout', e)
-      },
-
-      onMiddleMarkerMouseDown: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section MiddleMarker events
-        // 馃崅event editable:middlemarker:mousedown: VertexEvent
-        // Fired when user `mousedown` a middle marker.
-        this.fireAndForward('editable:middlemarker:mousedown', e)
-      },
-
-      onVertexMarkerDrag: function (e) {
-        this.onMove(e)
-        if (this.feature._bounds) this.extendBounds(e)
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:drag: VertexEvent
-        // Fired when a vertex is dragged by user.
-        this.fireAndForward('editable:vertex:drag', e)
-      },
-
-      onVertexMarkerDragStart: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:dragstart: VertexEvent
-        // Fired before a vertex is dragged by user.
-        this.fireAndForward('editable:vertex:dragstart', e)
-      },
-
-      onVertexMarkerDragEnd: function (e) {
-        // 馃崅namespace Editable
-        // 馃崅section Vertex events
-        // 馃崅event editable:vertex:dragend: VertexEvent
-        // Fired after a vertex is dragged by user.
-        this.fireAndForward('editable:vertex:dragend', e)
-      },
-
-      setDrawnLatLngs: function (latlngs) {
-        this._drawnLatLngs = latlngs || this.getDefaultLatLngs()
-      },
-
-      startDrawing: function () {
-        if (!this._drawnLatLngs) this.setDrawnLatLngs()
-        L.Editable.BaseEditor.prototype.startDrawing.call(this)
-      },
-
-      startDrawingForward: function () {
-        this.startDrawing()
-      },
-
-      endDrawing: function () {
-        this.tools.detachForwardLineGuide()
-        this.tools.detachBackwardLineGuide()
-        if (this._drawnLatLngs && this._drawnLatLngs.length < this.MIN_VERTEX) this.deleteShape(this._drawnLatLngs)
-        L.Editable.BaseEditor.prototype.endDrawing.call(this)
-        delete this._drawnLatLngs
-      },
-
-      addLatLng: function (latlng) {
-        if (this._drawing === L.Editable.FORWARD) {
-          this._drawnLatLngs.push(latlng)
-        } else {
-          this._drawnLatLngs.unshift(latlng)
-        }
-        this.feature._bounds.extend(latlng)
-        const vertex = this.addVertexMarker(latlng, this._drawnLatLngs)
-        this.onNewVertex(vertex)
-        this.refresh()
-      },
-
-      newPointForward: function (latlng) {
-        this.addLatLng(latlng)
-        this.tools.attachForwardLineGuide()
-        this.tools.anchorForwardLineGuide(latlng)
-      },
-
-      newPointBackward: function (latlng) {
-        this.addLatLng(latlng)
-        this.tools.anchorBackwardLineGuide(latlng)
-      },
-
-      // 馃崅namespace PathEditor
-      // 馃崅method push()
-      // Programmatically add a point while drawing.
-      push: function (latlng) {
-        if (!latlng) return console.error('L.Editable.PathEditor.push expect a valid latlng as parameter')
-        if (this._drawing === L.Editable.FORWARD) {
-          this.newPointForward(latlng)
-        } else {
-          this.newPointBackward(latlng)
-        }
-      },
-
-      removeLatLng: function (latlng) {
-        latlng.__vertex.delete()
-        this.refresh()
-      },
-
-      // 馃崅method pop(): L.LatLng or null
-      // Programmatically remove last point (if any) while drawing.
-      pop: function () {
-        if (this._drawnLatLngs.length <= 1) return
-        let latlng
-        if (this._drawing === L.Editable.FORWARD) {
-          latlng = this._drawnLatLngs[this._drawnLatLngs.length - 1]
-        } else {
-          latlng = this._drawnLatLngs[0]
-        }
-        this.removeLatLng(latlng)
-        if (this._drawing === L.Editable.FORWARD) {
-          this.tools.anchorForwardLineGuide(this._drawnLatLngs[this._drawnLatLngs.length - 1])
-        } else {
-          this.tools.anchorForwardLineGuide(this._drawnLatLngs[0])
-        }
-        return latlng
-      },
-
-      processDrawingClick: function (e) {
-        if (e.vertex && e.vertex.editor === this) return
-        if (this._drawing === L.Editable.FORWARD) {
-          this.newPointForward(e.latlng)
-        } else {
-          this.newPointBackward(e.latlng)
-        }
-        this.fireAndForward('editable:drawing:clicked', e)
-      },
-
-      onDrawingMouseMove: function (e) {
-        L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e)
-        if (this._drawing) {
-          this.tools.moveForwardLineGuide(e.latlng)
-          this.tools.moveBackwardLineGuide(e.latlng)
-        }
-      },
-
-      refresh: function () {
-        this.feature.redraw()
-        this.onEditing()
-      },
-
-      // 馃崅namespace PathEditor
-      // 馃崅method newShape(latlng?: L.LatLng)
-      // Add a new shape (Polyline, Polygon) in a multi, and setup up drawing tools to draw it;
-      // if optional `latlng` is given, start a path at this point.
-      newShape: function (latlng) {
-        const shape = this.addNewEmptyShape()
-        if (!shape) return
-        this.setDrawnLatLngs(shape[0] || shape) // Polygon or polyline
-        this.startDrawingForward()
-        // 馃崅namespace Editable
-        // 馃崅section Shape events
-        // 馃崅event editable:shape:new: ShapeEvent
-        // Fired when a new shape is created in a multi (Polygon or Polyline).
-        this.fireAndForward('editable:shape:new', { shape: shape })
-        if (latlng) this.newPointForward(latlng)
-      },
-
-      deleteShape: function (shape, latlngs) {
-        const e = { shape: shape }
-        L.Editable.makeCancellable(e)
-        // 馃崅namespace Editable
-        // 馃崅section Shape events
-        // 馃崅event editable:shape:delete: CancelableShapeEvent
-        // Fired before a new shape is deleted in a multi (Polygon or Polyline).
-        this.fireAndForward('editable:shape:delete', e)
-        if (e._cancelled) return
-        shape = this._deleteShape(shape, latlngs)
-        if (this.ensureNotFlat) this.ensureNotFlat() // Polygon.
-        this.feature.setLatLngs(this.getLatLngs()) // Force bounds reset.
-        this.refresh()
-        this.reset()
-        // 馃崅namespace Editable
-        // 馃崅section Shape events
-        // 馃崅event editable:shape:deleted: ShapeEvent
-        // Fired after a new shape is deleted in a multi (Polygon or Polyline).
-        this.fireAndForward('editable:shape:deleted', { shape: shape })
-        return shape
-      },
-
-      _deleteShape: function (shape, latlngs) {
-        latlngs = latlngs || this.getLatLngs()
-        if (!latlngs.length) return
-        const self = this
-        const inplaceDelete = function (latlngs, shape) {
-          // Called when deleting a flat latlngs
-          shape = latlngs.splice(0, Number.MAX_VALUE)
-          return shape
-        }
-        const spliceDelete = function (latlngs, shape) {
-          // Called when removing a latlngs inside an array
-          latlngs.splice(latlngs.indexOf(shape), 1)
-          if (!latlngs.length) self._deleteShape(latlngs)
-          return shape
-        }
-        if (latlngs === shape) return inplaceDelete(latlngs, shape)
-        for (let i = 0; i < latlngs.length; i++) {
-          if (latlngs[i] === shape) {
-            return spliceDelete(latlngs, shape)
-          } else if (latlngs[i].indexOf(shape) !== -1) return spliceDelete(latlngs[i], shape)
-        }
-      },
-
-      // 馃崅namespace PathEditor
-      // 馃崅method deleteShapeAt(latlng: L.LatLng): Array
-      // Remove a path shape at the given `latlng`.
-      deleteShapeAt: function (latlng) {
-        const shape = this.feature.shapeAt(latlng)
-        if (shape) return this.deleteShape(shape)
-      },
-
-      // 馃崅method appendShape(shape: Array)
-      // Append a new shape to the Polygon or Polyline.
-      appendShape: function (shape) {
-        this.insertShape(shape)
-      },
-
-      // 馃崅method prependShape(shape: Array)
-      // Prepend a new shape to the Polygon or Polyline.
-      prependShape: function (shape) {
-        this.insertShape(shape, 0)
-      },
-
-      // 馃崅method insertShape(shape: Array, index: int)
-      // Insert a new shape to the Polygon or Polyline at given index (default is to append).
-      insertShape: function (shape, index) {
-        this.ensureMulti()
-        shape = this.formatShape(shape)
-        if (typeof index === 'undefined') index = this.feature._latlngs.length
-        this.feature._latlngs.splice(index, 0, shape)
-        this.feature.redraw()
-        if (this._enabled) this.reset()
-      },
-
-      extendBounds: function (e) {
-        this.feature._bounds.extend(e.vertex.latlng)
-      },
-
-      onDragStart: function (e) {
-        this.editLayer.clearLayers()
-        L.Editable.BaseEditor.prototype.onDragStart.call(this, e)
-      },
-
-      onDragEnd: function (e) {
-        this.initVertexMarkers()
-        L.Editable.BaseEditor.prototype.onDragEnd.call(this, e)
-      }
-
-    })
-
-    // 馃崅namespace Editable; 馃崅class PolylineEditor; 馃崅aka L.Editable.PolylineEditor
-    // 馃崅inherits PathEditor
-    L.Editable.PolylineEditor = L.Editable.PathEditor.extend({
-
-      startDrawingBackward: function () {
-        this._drawing = L.Editable.BACKWARD
-        this.startDrawing()
-      },
-
-      // 馃崅method continueBackward(latlngs?: Array)
-      // Set up drawing tools to continue the line backward.
-      continueBackward: function (latlngs) {
-        if (this.drawing()) return
-        latlngs = latlngs || this.getDefaultLatLngs()
-        this.setDrawnLatLngs(latlngs)
-        if (latlngs.length > 0) {
-          this.tools.attachBackwardLineGuide()
-          this.tools.anchorBackwardLineGuide(latlngs[0])
-        }
-        this.startDrawingBackward()
-      },
-
-      // 馃崅method continueForward(latlngs?: Array)
-      // Set up drawing tools to continue the line forward.
-      continueForward: function (latlngs) {
-        if (this.drawing()) return
-        latlngs = latlngs || this.getDefaultLatLngs()
-        this.setDrawnLatLngs(latlngs)
-        if (latlngs.length > 0) {
-          this.tools.attachForwardLineGuide()
-          this.tools.anchorForwardLineGuide(latlngs[latlngs.length - 1])
-        }
-        this.startDrawingForward()
-      },
-
-      getDefaultLatLngs: function (latlngs) {
-        latlngs = latlngs || this.feature._latlngs
-        if (!latlngs.length || latlngs[0] instanceof L.LatLng) {
-          return latlngs
-        } else {
-          return this.getDefaultLatLngs(latlngs[0])
-        }
-      },
-
-      ensureMulti: function () {
-        if (this.feature._latlngs.length && isFlat(this.feature._latlngs)) {
-          this.feature._latlngs = [this.feature._latlngs]
-        }
-      },
-
-      addNewEmptyShape: function () {
-        if (this.feature._latlngs.length) {
-          const shape = []
-          this.appendShape(shape)
-          return shape
-        } else {
-          return this.feature._latlngs
-        }
-      },
-
-      formatShape: function (shape) {
-        if (isFlat(shape)) {
-          return shape
-        } else if (shape[0]) return this.formatShape(shape[0])
-      },
-
-      // 馃崅method splitShape(latlngs?: Array, index: int)
-      // Split the given `latlngs` shape at index `index` and integrate new shape in instance `latlngs`.
-      splitShape: function (shape, index) {
-        if (!index || index >= shape.length - 1) return
-        this.ensureMulti()
-        const shapeIndex = this.feature._latlngs.indexOf(shape)
-        if (shapeIndex === -1) return
-        const first = shape.slice(0, index + 1)
-        const second = shape.slice(index)
-        // We deal with reference, we don't want twice the same latlng around.
-        second[0] = L.latLng(second[0].lat, second[0].lng, second[0].alt)
-        this.feature._latlngs.splice(shapeIndex, 1, first, second)
-        this.refresh()
-        this.reset()
-      }
-
-    })
-
-    // 馃崅namespace Editable; 馃崅class PolygonEditor; 馃崅aka L.Editable.PolygonEditor
-    // 馃崅inherits PathEditor
-    L.Editable.PolygonEditor = L.Editable.PathEditor.extend({
-
-      CLOSED: true,
-      MIN_VERTEX: 3,
-
-      newPointForward: function (latlng) {
-        L.Editable.PathEditor.prototype.newPointForward.call(this, latlng)
-        if (!this.tools.backwardLineGuide._latlngs.length) this.tools.anchorBackwardLineGuide(latlng)
-        if (this._drawnLatLngs.length === 2) this.tools.attachBackwardLineGuide()
-      },
-
-      addNewEmptyHole: function (latlng) {
-        this.ensureNotFlat()
-        const latlngs = this.feature.shapeAt(latlng)
-        if (!latlngs) return
-        const holes = []
-        latlngs.push(holes)
-        return holes
-      },
-
-      // 馃崅method newHole(latlng?: L.LatLng, index: int)
-      // Set up drawing tools for creating a new hole on the Polygon. If the `latlng` param is given, a first point is created.
-      newHole: function (latlng) {
-        const holes = this.addNewEmptyHole(latlng)
-        if (!holes) return
-        this.setDrawnLatLngs(holes)
-        this.startDrawingForward()
-        if (latlng) this.newPointForward(latlng)
-      },
-
-      addNewEmptyShape: function () {
-        if (this.feature._latlngs.length && this.feature._latlngs[0].length) {
-          const shape = []
-          this.appendShape(shape)
-          return shape
-        } else {
-          return this.feature._latlngs
-        }
-      },
-
-      ensureMulti: function () {
-        if (this.feature._latlngs.length && isFlat(this.feature._latlngs[0])) {
-          this.feature._latlngs = [this.feature._latlngs]
-        }
-      },
-
-      ensureNotFlat: function () {
-        if (!this.feature._latlngs.length || isFlat(this.feature._latlngs)) this.feature._latlngs = [this.feature._latlngs]
-      },
-
-      vertexCanBeDeleted: function (vertex) {
-        const parent = this.feature.parentShape(vertex.latlngs)
-        const idx = L.Util.indexOf(parent, vertex.latlngs)
-        if (idx > 0) return true // Holes can be totally deleted without removing the layer itself.
-        return L.Editable.PathEditor.prototype.vertexCanBeDeleted.call(this, vertex)
-      },
-
-      getDefaultLatLngs: function () {
-        if (!this.feature._latlngs.length) this.feature._latlngs.push([])
-        return this.feature._latlngs[0]
-      },
-
-      formatShape: function (shape) {
-        // [[1, 2], [3, 4]] => must be nested
-        // [] => must be nested
-        // [[]] => is already nested
-        if (isFlat(shape) && (!shape[0] || shape[0].length !== 0)) {
-          return [shape]
-        } else {
-          return shape
-        }
-      }
-
-    })
-
-    // 馃崅namespace Editable; 馃崅class RectangleEditor; 馃崅aka L.Editable.RectangleEditor
-    // 馃崅inherits PathEditor
-    L.Editable.RectangleEditor = L.Editable.PathEditor.extend({
-
-      CLOSED: true,
-      MIN_VERTEX: 4,
-
-      options: {
-        skipMiddleMarkers: true
-      },
-
-      extendBounds: function (e) {
-        const index = e.vertex.getIndex()
-        const next = e.vertex.getNext()
-        const previous = e.vertex.getPrevious()
-        const oppositeIndex = (index + 2) % 4
-        const opposite = e.vertex.latlngs[oppositeIndex]
-        const bounds = new L.LatLngBounds(e.latlng, opposite)
-        // Update latlngs by hand to preserve order.
-        previous.latlng.update([e.latlng.lat, opposite.lng])
-        next.latlng.update([opposite.lat, e.latlng.lng])
-        this.updateBounds(bounds)
-        this.refreshVertexMarkers()
-      },
-
-      onDrawingMouseDown: function (e) {
-        L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e)
-        this.connect()
-        const latlngs = this.getDefaultLatLngs()
-        // L.Polygon._convertLatLngs removes last latlng if it equals first point,
-        // which is the case here as all latlngs are [0, 0]
-        if (latlngs.length === 3) latlngs.push(e.latlng)
-        const bounds = new L.LatLngBounds(e.latlng, e.latlng)
-        this.updateBounds(bounds)
-        this.updateLatLngs(bounds)
-        this.refresh()
-        this.reset()
-        // Stop dragging map.
-        // L.Draggable has two workflows:
-        // - mousedown => mousemove => mouseup
-        // - touchstart => touchmove => touchend
-        // Problem: L.Map.Tap does not allow us to listen to touchstart, so we only
-        // can deal with mousedown, but then when in a touch device, we are dealing with
-        // simulated events (actually simulated by L.Map.Tap), which are no more taken
-        // into account by L.Draggable.
-        // Ref.: https://github.com/Leaflet/Leaflet.Editable/issues/103
-        e.originalEvent._simulated = false
-        this.map.dragging._draggable._onUp(e.originalEvent)
-        // Now transfer ongoing drag action to the bottom right corner.
-        // Should we refine which corner will handle the drag according to
-        // drag direction?
-        latlngs[3].__vertex.dragging._draggable._onDown(e.originalEvent)
-      },
-
-      onDrawingMouseUp: function (e) {
-        this.commitDrawing(e)
-        e.originalEvent._simulated = false
-        L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e)
-      },
-
-      onDrawingMouseMove: function (e) {
-        e.originalEvent._simulated = false
-        L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e)
-      },
-
-      getDefaultLatLngs: function (latlngs) {
-        return latlngs || this.feature._latlngs[0]
-      },
-
-      updateBounds: function (bounds) {
-        this.feature._bounds = bounds
-      },
-
-      updateLatLngs: function (bounds) {
-        const latlngs = this.getDefaultLatLngs()
-        const newLatlngs = this.feature._boundsToLatLngs(bounds)
-        // Keep references.
-        for (let i = 0; i < latlngs.length; i++) {
-          latlngs[i].update(newLatlngs[i])
-        }
-      }
-
-    })
-
-    // 馃崅namespace Editable; 馃崅class CircleEditor; 馃崅aka L.Editable.CircleEditor
-    // 馃崅inherits PathEditor
-    L.Editable.CircleEditor = L.Editable.PathEditor.extend({
-
-      MIN_VERTEX: 2,
-
-      options: {
-        skipMiddleMarkers: true
-      },
-
-      initialize: function (map, feature, options) {
-        L.Editable.PathEditor.prototype.initialize.call(this, map, feature, options)
-        // C.Y.B Modify
-
-        const latlng = this.computeResizeLatLng()
-
-        // latlng.lat = latlng.lat-0.007855;
-        // latlng.lng= latlng.lng-0.1;
-        this._resizeLatLng = latlng
-        // 鍘熷鏂规硶
-        // this._resizeLatLng = this.computeResizeLatLng();
-      },
-
-      computeResizeLatLng: function () {
-        // While circle is not added to the map, _radius is not set.
-        // let delta = (this.feature._radius || this.feature._mRadius) * Math.cos(Math.PI / 4)
-        const delta = (this.feature._radius || this.feature._mRadius)
-        const point = this.map.project(this.feature._latlng)
-        // return this.map.unproject([point.x + delta, point.y - delta])
-        return this.map.unproject([point.x + delta, point.y])
-      },
-
-      updateResizeLatLng: function () {
-        this._resizeLatLng.update(this.computeResizeLatLng())
-        this._resizeLatLng.__vertex.update()
-      },
-
-      getLatLngs: function () {
-        return [this.feature._latlng, this._resizeLatLng]
-      },
-
-      getDefaultLatLngs: function () {
-        return this.getLatLngs()
-      },
-
-      onVertexMarkerDrag: function (e) {
-        if (e.vertex.getIndex() === 1) {
-          this.resize(e)
-        } else {
-          this.updateResizeLatLng(e)
-        }
-        L.Editable.PathEditor.prototype.onVertexMarkerDrag.call(this, e)
-      },
-
-      resize: function (e) {
-        const radius = this.feature._latlng.distanceTo(e.latlng)
-        this.feature.setRadius(radius)
-      },
-
-      onDrawingMouseDown: function (e) {
-        L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e)
-        this._resizeLatLng.update(e.latlng)
-        this.feature._latlng.update(e.latlng)
-        this.connect()
-        // Stop dragging map.
-        e.originalEvent._simulated = false
-        this.map.dragging._draggable._onUp(e.originalEvent)
-        // Now transfer ongoing drag action to the radius handler.
-        this._resizeLatLng.__vertex.dragging._draggable._onDown(e.originalEvent)
-      },
-
-      onDrawingMouseUp: function (e) {
-        this.commitDrawing(e)
-        e.originalEvent._simulated = false
-        L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e)
-      },
-
-      onDrawingMouseMove: function (e) {
-        e.originalEvent._simulated = false
-        L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e)
-      },
-
-      onDrag: function (e) {
-        L.Editable.PathEditor.prototype.onDrag.call(this, e)
-        this.feature.dragging.updateLatLng(this._resizeLatLng)
-      }
-
-    })
-
-    // 馃崅namespace Editable; 馃崅class EditableMixin
-    // `EditableMixin` is included to `L.Polyline`, `L.Polygon`, `L.Rectangle`, `L.Circle`
-    // and `L.Marker`. It adds some methods to them.
-    // *When editing is enabled, the editor is accessible on the instance with the
-    // `editor` property.*
-    const EditableMixin = {
-
-      createEditor: function (map) {
-        map = map || this._map
-        const tools = (this.options.editOptions || {}).editTools || map.editTools
-        if (!tools) throw Error('Unable to detect Editable instance.')
-        const Klass = this.options.editorClass || this.getEditorClass(tools)
-        return new Klass(map, this, this.options.editOptions)
-      },
-
-      // 馃崅method enableEdit(map?: L.Map): this.editor
-      // Enable editing, by creating an editor if not existing, and then calling `enable` on it.
-      enableEdit: function (map) {
-        if (!this.editor) this.createEditor(map)
-        this.editor.enable()
-        return this.editor
-      },
-
-      // 馃崅method editEnabled(): boolean
-      // Return true if current instance has an editor attached, and this editor is enabled.
-      editEnabled: function () {
-        return this.editor && this.editor.enabled()
-      },
-
-      // 馃崅method disableEdit()
-      // Disable editing, also remove the editor property reference.
-      disableEdit: function () {
-        if (this.editor) {
-          this.editor.disable()
-          delete this.editor
-        }
-      },
-
-      // 馃崅method toggleEdit()
-      // Enable or disable editing, according to current status.
-      toggleEdit: function () {
-        if (this.editEnabled()) {
-          this.disableEdit()
-        } else {
-          this.enableEdit()
-        }
-      },
-
-      _onEditableAdd: function () {
-        if (this.editor) this.enableEdit()
-      }
-
+    createCircle: function (latlng, options) {
+      return this.createLayer((options && options.circleClass) || this.options.circleClass, latlng, options)
     }
 
-    const PolylineMixin = {
+  })
 
-      getEditorClass: function (tools) {
-        return (tools && tools.options.polylineEditorClass) ? tools.options.polylineEditorClass : L.Editable.PolylineEditor
-      },
+  L.extend(L.Editable, {
 
-      shapeAt: function (latlng, latlngs) {
-        // We can have those cases:
-        // - latlngs are just a flat array of latlngs, use this
-        // - latlngs is an array of arrays of latlngs, loop over
-        let shape = null
-        latlngs = latlngs || this._latlngs
-        if (!latlngs.length) {
-          return shape
-        } else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) {
-          shape = latlngs
-        } else {
-          for (let i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i])) return latlngs[i]
-        }
+    makeCancellable: function (e) {
+      e.cancel = function () {
+        e._cancelled = true
+      }
+    }
+
+  })
+
+  // 馃崅namespace Map; 馃崅class Map
+  // Leaflet.Editable add options and events to the `L.Map` object.
+  // See `Editable` events for the list of events fired on the Map.
+  // 馃崅example
+  //
+  // ```js
+  // let map = L.map('map', {
+  //  editable: true,
+  //  editOptions: {
+  //    鈥�
+  // }
+  // });
+  // ```
+  // 馃崅section Editable Map Options
+  L.Map.mergeOptions({
+
+    // 馃崅namespace Map
+    // 馃崅section Map Options
+    // 馃崅option EditToolsClass: class = L.Editable
+    // Class to be used as vertex, for path editing.
+    EditToolsClass: L.Editable,
+
+    // 馃崅option editable: boolean = false
+    // Whether to create a L.Editable instance at map init.
+    editable: false,
+
+    // 馃崅option editOptions: hash = {}
+    // Options to pass to L.Editable when instantiating.
+    editOptions: {}
+
+  })
+
+  L.Map.addInitHook(function () {
+    this.whenReady(function () {
+      if (this.options.editable) {
+        this.editTools = new this.options.EditToolsClass(this, this.options.editOptions)
+      }
+    })
+  })
+
+  L.Editable.VertexIcon = L.DivIcon.extend({
+
+    options: {
+      iconSize: new L.Point(8, 8)
+    }
+
+  })
+
+  L.Editable.TouchVertexIcon = L.Editable.VertexIcon.extend({
+
+    options: {
+      iconSize: new L.Point(20, 20)
+    }
+
+  })
+
+  // 馃崅namespace Editable; 馃崅class VertexMarker; Handler for dragging path vertices.
+  L.Editable.VertexMarker = L.Marker.extend({
+
+    options: {
+      draggable: true,
+      className: 'leaflet-vertex-icon leaflet-custom-icon'
+    },
+
+    // 馃崅section Public methods
+    // The marker used to handle path vertex. You will usually interact with a `VertexMarker`
+    // instance when listening for events like `editable:vertex:ctrlclick`.
+
+    initialize: function (latlng, latlngs, editor, options) {
+      // We don't use this._latlng, because on drag Leaflet replace it while
+      // we want to keep reference.
+      this.latlng = latlng
+      this.latlngs = latlngs
+      this.editor = editor
+      L.Marker.prototype.initialize.call(this, latlng, options)
+      this.options.icon = this.editor.tools.createVertexIcon({ className: this.options.className })
+      this.latlng.__vertex = this
+      this.editor.editLayer.addLayer(this)
+      this.setZIndexOffset(editor.tools._lastZIndex + 1)
+    },
+
+    onAdd: function (map) {
+      L.Marker.prototype.onAdd.call(this, map)
+      this.on('drag', this.onDrag)
+      this.on('dragstart', this.onDragStart)
+      this.on('dragend', this.onDragEnd)
+      this.on('mouseup', this.onMouseup)
+      this.on('click', this.onClick)
+      this.on('contextmenu', this.onContextMenu)
+      this.on('mousedown touchstart', this.onMouseDown)
+      this.on('mouseover', this.onMouseOver)
+      this.on('mouseout', this.onMouseOut)
+      this.addMiddleMarkers()
+    },
+
+    onRemove: function (map) {
+      if (this.middleMarker) this.middleMarker.delete()
+      delete this.latlng.__vertex
+      this.off('drag', this.onDrag)
+      this.off('dragstart', this.onDragStart)
+      this.off('dragend', this.onDragEnd)
+      this.off('mouseup', this.onMouseup)
+      this.off('click', this.onClick)
+      this.off('contextmenu', this.onContextMenu)
+      this.off('mousedown touchstart', this.onMouseDown)
+      this.off('mouseover', this.onMouseOver)
+      this.off('mouseout', this.onMouseOut)
+      L.Marker.prototype.onRemove.call(this, map)
+    },
+
+    onDrag: function (e) {
+      e.vertex = this
+      this.editor.onVertexMarkerDrag(e)
+      const iconPos = L.DomUtil.getPosition(this._icon)
+      const latlng = this._map.layerPointToLatLng(iconPos)
+      this.latlng.update(latlng)
+      this._latlng = this.latlng // Push back to Leaflet our reference.
+      this.editor.refresh()
+      if (this.middleMarker) this.middleMarker.updateLatLng()
+      const next = this.getNext()
+      if (next && next.middleMarker) next.middleMarker.updateLatLng()
+    },
+
+    onDragStart: function (e) {
+      e.vertex = this
+      this.editor.onVertexMarkerDragStart(e)
+    },
+
+    onDragEnd: function (e) {
+      e.vertex = this
+      this.editor.onVertexMarkerDragEnd(e)
+    },
+
+    onClick: function (e) {
+      e.vertex = this
+      this.editor.onVertexMarkerClick(e)
+    },
+
+    onMouseup: function (e) {
+      L.DomEvent.stop(e)
+      e.vertex = this
+      this.editor.map.fire('mouseup', e)
+    },
+
+    onContextMenu: function (e) {
+      e.vertex = this
+      this.editor.onVertexMarkerContextMenu(e)
+    },
+
+    onMouseDown: function (e) {
+      e.vertex = this
+      this.editor.onVertexMarkerMouseDown(e)
+    },
+
+    onMouseOver: function (e) {
+      e.vertex = this
+      this.editor.onVertexMarkerMouseOver(e)
+    },
+
+    onMouseOut: function (e) {
+      e.vertex = this
+      this.editor.onVertexMarkerMouseOut(e)
+    },
+
+    // 馃崅method delete()
+    // Delete a vertex and the related LatLng.
+    delete: function () {
+      const next = this.getNext() // Compute before changing latlng
+      this.latlngs.splice(this.getIndex(), 1)
+      this.editor.editLayer.removeLayer(this)
+      this.editor.onVertexDeleted({
+        latlng: this.latlng,
+        vertex: this
+      })
+      if (!this.latlngs.length) this.editor.deleteShape(this.latlngs)
+      if (next) next.resetMiddleMarker()
+      this.editor.refresh()
+    },
+
+    // 馃崅method getIndex(): int
+    // Get the index of the current vertex among others of the same LatLngs group.
+    getIndex: function () {
+      return this.latlngs.indexOf(this.latlng)
+    },
+
+    // 馃崅method getLastIndex(): int
+    // Get last vertex index of the LatLngs group of the current vertex.
+    getLastIndex: function () {
+      return this.latlngs.length - 1
+    },
+
+    // 馃崅method getPrevious(): VertexMarker
+    // Get the previous VertexMarker in the same LatLngs group.
+    getPrevious: function () {
+      if (this.latlngs.length < 2) return
+      const index = this.getIndex()
+      let previousIndex = index - 1
+      if (index === 0 && this.editor.CLOSED) previousIndex = this.getLastIndex()
+      const previous = this.latlngs[previousIndex]
+      if (previous) return previous.__vertex
+    },
+
+    // 馃崅method getNext(): VertexMarker
+    // Get the next VertexMarker in the same LatLngs group.
+    getNext: function () {
+      if (this.latlngs.length < 2) return
+      const index = this.getIndex()
+      let nextIndex = index + 1
+      if (index === this.getLastIndex() && this.editor.CLOSED) nextIndex = 0
+      const next = this.latlngs[nextIndex]
+      if (next) return next.__vertex
+    },
+
+    addMiddleMarker: function (previous) {
+      if (!this.editor.hasMiddleMarkers()) return
+      previous = previous || this.getPrevious()
+      if (previous && !this.middleMarker) this.middleMarker = this.editor.addMiddleMarker(previous, this, this.latlngs, this.editor)
+    },
+
+    addMiddleMarkers: function () {
+      if (!this.editor.hasMiddleMarkers()) return
+      const previous = this.getPrevious()
+      if (previous) this.addMiddleMarker(previous)
+      const next = this.getNext()
+      if (next) next.resetMiddleMarker()
+    },
+
+    resetMiddleMarker: function () {
+      if (this.middleMarker) this.middleMarker.delete()
+      this.addMiddleMarker()
+    },
+
+    // 馃崅method split()
+    // Split the vertex LatLngs group at its index, if possible.
+    split: function () {
+      if (!this.editor.splitShape) return // Only for PolylineEditor
+      this.editor.splitShape(this.latlngs, this.getIndex())
+    },
+
+    // 馃崅method continue()
+    // Continue the vertex LatLngs from this vertex. Only active for first and last vertices of a Polyline.
+    continue: function () {
+      if (!this.editor.continueBackward) return // Only for PolylineEditor
+      const index = this.getIndex()
+      if (index === 0) {
+        this.editor.continueBackward(this.latlngs)
+      } else if (index === this.getLastIndex()) this.editor.continueForward(this.latlngs)
+    }
+
+  })
+
+  L.Editable.mergeOptions({
+
+    // 馃崅namespace Editable
+    // 馃崅option VertexMarkerClass: class = VertexMarker
+    // Class to be used as vertex, for path editing.
+    VertexMarkerClass: L.Editable.VertexMarker
+
+  })
+
+  L.Editable.MiddleMarker = L.Marker.extend({
+
+    options: {
+      opacity: 0.5,
+      className: 'leaflet-div-icon leaflet-middle-icon',
+      draggable: true
+    },
+
+    initialize: function (left, right, latlngs, editor, options) {
+      this.left = left
+      this.right = right
+      this.editor = editor
+      this.latlngs = latlngs
+      L.Marker.prototype.initialize.call(this, this.computeLatLng(), options)
+      this._opacity = this.options.opacity
+      this.options.icon = this.editor.tools.createVertexIcon({ className: this.options.className })
+      this.editor.editLayer.addLayer(this)
+      this.setVisibility()
+    },
+
+    setVisibility: function () {
+      const leftPoint = this._map.latLngToContainerPoint(this.left.latlng)
+      const rightPoint = this._map.latLngToContainerPoint(this.right.latlng)
+      const size = L.point(this.options.icon.options.iconSize)
+      if (leftPoint.distanceTo(rightPoint) < size.x * 3) {
+        this.hide()
+      } else {
+        this.show()
+      }
+    },
+
+    show: function () {
+      this.setOpacity(this._opacity)
+    },
+
+    hide: function () {
+      this.setOpacity(0)
+    },
+
+    updateLatLng: function () {
+      this.setLatLng(this.computeLatLng())
+      this.setVisibility()
+    },
+
+    computeLatLng: function () {
+      const leftPoint = this.editor.map.latLngToContainerPoint(this.left.latlng)
+      const rightPoint = this.editor.map.latLngToContainerPoint(this.right.latlng)
+      const y = (leftPoint.y + rightPoint.y) / 2
+      const x = (leftPoint.x + rightPoint.x) / 2
+      return this.editor.map.containerPointToLatLng([x, y])
+    },
+
+    onAdd: function (map) {
+      L.Marker.prototype.onAdd.call(this, map)
+      L.DomEvent.on(this._icon, 'mousedown touchstart', this.onMouseDown, this)
+      map.on('zoomend', this.setVisibility, this)
+    },
+
+    onRemove: function (map) {
+      delete this.right.middleMarker
+      L.DomEvent.off(this._icon, 'mousedown touchstart', this.onMouseDown, this)
+      map.off('zoomend', this.setVisibility, this)
+      L.Marker.prototype.onRemove.call(this, map)
+    },
+
+    onMouseDown: function (e) {
+      const iconPos = L.DomUtil.getPosition(this._icon)
+      const latlng = this.editor.map.layerPointToLatLng(iconPos)
+      e = {
+        originalEvent: e,
+        latlng: latlng
+      }
+      if (this.options.opacity === 0) return
+      L.Editable.makeCancellable(e)
+      this.editor.onMiddleMarkerMouseDown(e)
+      if (e._cancelled) return
+      this.latlngs.splice(this.index(), 0, e.latlng)
+      this.editor.refresh()
+      const icon = this._icon
+      const marker = this.editor.addVertexMarker(e.latlng, this.latlngs)
+      this.editor.onNewVertex(marker)
+      /* Hack to workaround browser not firing touchend when element is no more on DOM */
+      const parent = marker._icon.parentNode
+      parent.removeChild(marker._icon)
+      marker._icon = icon
+      parent.appendChild(marker._icon)
+      marker._initIcon()
+      marker._initInteraction()
+      marker.setOpacity(1)
+      /* End hack */
+      // Transfer ongoing dragging to real marker
+      L.Draggable._dragging = false
+      marker.dragging._draggable._onDown(e.originalEvent)
+      this.delete()
+    },
+
+    delete: function () {
+      this.editor.editLayer.removeLayer(this)
+    },
+
+    index: function () {
+      return this.latlngs.indexOf(this.right.latlng)
+    }
+
+  })
+
+  L.Editable.mergeOptions({
+
+    // 馃崅namespace Editable
+    // 馃崅option MiddleMarkerClass: class = VertexMarker
+    // Class to be used as middle vertex, pulled by the user to create a new point in the middle of a path.
+    MiddleMarkerClass: L.Editable.MiddleMarker
+
+  })
+
+  // 馃崅namespace Editable; 馃崅class BaseEditor; 馃崅aka L.Editable.BaseEditor
+  // When editing a feature (Marker, Polyline鈥�), an editor is attached to it. This
+  // editor basically knows how to handle the edition.
+  L.Editable.BaseEditor = L.Handler.extend({
+
+    initialize: function (map, feature, options) {
+      L.setOptions(this, options)
+      this.map = map
+      this.feature = feature
+      this.feature.editor = this
+      this.editLayer = new L.LayerGroup()
+      this.tools = this.options.editTools || map.editTools
+    },
+
+    // 馃崅method enable(): this
+    // Set up the drawing tools for the feature to be editable.
+    addHooks: function () {
+      if (this.isConnected()) {
+        this.onFeatureAdd()
+      } else {
+        this.feature.once('add', this.onFeatureAdd, this)
+      }
+      this.onEnable()
+      this.feature.on(this._getEvents(), this)
+    },
+
+    // 馃崅method disable(): this
+    // Remove the drawing tools for the feature.
+    removeHooks: function () {
+      this.feature.off(this._getEvents(), this)
+      if (this.feature.dragging) this.feature.dragging.disable()
+      this.editLayer.clearLayers()
+      this.tools.editLayer.removeLayer(this.editLayer)
+      this.onDisable()
+      if (this._drawing) this.cancelDrawing()
+    },
+
+    // 馃崅method drawing(): boolean
+    // Return true if any drawing action is ongoing with this editor.
+    drawing: function () {
+      return !!this._drawing
+    },
+
+    reset: function () {
+    },
+
+    onFeatureAdd: function () {
+      this.tools.editLayer.addLayer(this.editLayer)
+      if (this.feature.dragging) this.feature.dragging.enable()
+    },
+
+    hasMiddleMarkers: function () {
+      return !this.options.skipMiddleMarkers && !this.tools.options.skipMiddleMarkers
+    },
+
+    fireAndForward: function (type, e) {
+      e = e || {}
+      e.layer = this.feature
+      this.feature.fire(type, e)
+      this.tools.fireAndForward(type, e)
+    },
+
+    onEnable: function () {
+      // 馃崅namespace Editable
+      // 馃崅event editable:enable: Event
+      // Fired when an existing feature is ready to be edited.
+      this.fireAndForward('editable:enable')
+    },
+
+    onDisable: function () {
+      // 馃崅namespace Editable
+      // 馃崅event editable:disable: Event
+      // Fired when an existing feature is not ready anymore to be edited.
+      this.fireAndForward('editable:disable')
+    },
+
+    onEditing: function () {
+      // 馃崅namespace Editable
+      // 馃崅event editable:editing: Event
+      // Fired as soon as any change is made to the feature geometry.
+      this.fireAndForward('editable:editing')
+    },
+
+    onStartDrawing: function () {
+      // 馃崅namespace Editable
+      // 馃崅section Drawing events
+      // 馃崅event editable:drawing:start: Event
+      // Fired when a feature is to be drawn.
+      this.fireAndForward('editable:drawing:start')
+    },
+
+    onEndDrawing: function () {
+      // 馃崅namespace Editable
+      // 馃崅section Drawing events
+      // 馃崅event editable:drawing:end: Event
+      // Fired when a feature is not drawn anymore.
+      this.fireAndForward('editable:drawing:end')
+    },
+
+    onCancelDrawing: function () {
+      // 馃崅namespace Editable
+      // 馃崅section Drawing events
+      // 馃崅event editable:drawing:cancel: Event
+      // Fired when user cancel drawing while a feature is being drawn.
+      this.fireAndForward('editable:drawing:cancel')
+    },
+
+    onCommitDrawing: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Drawing events
+      // 馃崅event editable:drawing:commit: Event
+      // Fired when user finish drawing a feature.
+      this.fireAndForward('editable:drawing:commit', e)
+    },
+
+    onDrawingMouseDown: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Drawing events
+      // 馃崅event editable:drawing:mousedown: Event
+      // Fired when user `mousedown` while drawing.
+      this.fireAndForward('editable:drawing:mousedown', e)
+    },
+
+    onDrawingMouseUp: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Drawing events
+      // 馃崅event editable:drawing:mouseup: Event
+      // Fired when user `mouseup` while drawing.
+      this.fireAndForward('editable:drawing:mouseup', e)
+    },
+
+    startDrawing: function () {
+      if (!this._drawing) this._drawing = L.Editable.FORWARD
+      this.tools.registerForDrawing(this)
+      this.onStartDrawing()
+    },
+
+    commitDrawing: function (e) {
+      this.onCommitDrawing(e)
+      this.endDrawing()
+    },
+
+    cancelDrawing: function () {
+      // If called during a vertex drag, the vertex will be removed before
+      // the mouseup fires on it. This is a workaround. Maybe better fix is
+      // To have L.Draggable reset it's status on disable (Leaflet side).
+      L.Draggable._dragging = false
+      this.onCancelDrawing()
+      this.endDrawing()
+    },
+
+    endDrawing: function () {
+      this._drawing = false
+      this.tools.unregisterForDrawing(this)
+      this.onEndDrawing()
+    },
+
+    onDrawingClick: function (e) {
+      if (!this.drawing()) return
+      L.Editable.makeCancellable(e)
+      // 馃崅namespace Editable
+      // 馃崅section Drawing events
+      // 馃崅event editable:drawing:click: CancelableEvent
+      // Fired when user `click` while drawing, before any internal action is being processed.
+      this.fireAndForward('editable:drawing:click', e)
+      if (e._cancelled) return
+      if (!this.isConnected()) this.connect(e)
+      this.processDrawingClick(e)
+    },
+
+    isConnected: function () {
+      return this.map.hasLayer(this.feature)
+    },
+
+    connect: function () {
+      this.tools.connectCreatedToMap(this.feature)
+      this.tools.editLayer.addLayer(this.editLayer)
+    },
+
+    onMove: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Drawing events
+      // 馃崅event editable:drawing:move: Event
+      // Fired when `move` mouse while drawing, while dragging a marker, and while dragging a vertex.
+      this.fireAndForward('editable:drawing:move', e)
+    },
+
+    onDrawingMouseMove: function (e) {
+      this.onMove(e)
+    },
+
+    _getEvents: function () {
+      return {
+        dragstart: this.onDragStart,
+        drag: this.onDrag,
+        dragend: this.onDragEnd,
+        remove: this.disable
+      }
+    },
+
+    onDragStart: function (e) {
+      this.onEditing()
+      // 馃崅namespace Editable
+      // 馃崅event editable:dragstart: Event
+      // Fired before a path feature is dragged.
+      this.fireAndForward('editable:dragstart', e)
+    },
+
+    onDrag: function (e) {
+      this.onMove(e)
+      // 馃崅namespace Editable
+      // 馃崅event editable:drag: Event
+      // Fired when a path feature is being dragged.
+      this.fireAndForward('editable:drag', e)
+    },
+
+    onDragEnd: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅event editable:dragend: Event
+      // Fired after a path feature has been dragged.
+      this.fireAndForward('editable:dragend', e)
+    }
+
+  })
+
+  // 馃崅namespace Editable; 馃崅class MarkerEditor; 馃崅aka L.Editable.MarkerEditor
+  // 馃崅inherits BaseEditor
+  // Editor for Marker.
+  L.Editable.MarkerEditor = L.Editable.BaseEditor.extend({
+
+    onDrawingMouseMove: function (e) {
+      L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e)
+      if (this._drawing) this.feature.setLatLng(e.latlng)
+    },
+
+    processDrawingClick: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Drawing events
+      // 馃崅event editable:drawing:clicked: Event
+      // Fired when user `click` while drawing, after all internal actions.
+      this.fireAndForward('editable:drawing:clicked', e)
+      this.commitDrawing(e)
+    },
+
+    connect: function (e) {
+      // On touch, the latlng has not been updated because there is
+      // no mousemove.
+      if (e) this.feature._latlng = e.latlng
+      L.Editable.BaseEditor.prototype.connect.call(this, e)
+    }
+
+  })
+
+  // 馃崅namespace Editable; 馃崅class PathEditor; 馃崅aka L.Editable.PathEditor
+  // 馃崅inherits BaseEditor
+  // Base class for all path editors.
+  L.Editable.PathEditor = L.Editable.BaseEditor.extend({
+
+    CLOSED: false,
+    MIN_VERTEX: 2,
+
+    addHooks: function () {
+      L.Editable.BaseEditor.prototype.addHooks.call(this)
+      if (this.feature) this.initVertexMarkers()
+      return this
+    },
+
+    initVertexMarkers: function (latlngs) {
+      if (!this.enabled()) return
+      latlngs = latlngs || this.getLatLngs()
+      if (isFlat(latlngs)) {
+        this.addVertexMarkers(latlngs)
+      } else {
+        for (let i = 0; i < latlngs.length; i++) this.initVertexMarkers(latlngs[i])
+      }
+    },
+
+    getLatLngs: function () {
+      return this.feature.getLatLngs()
+    },
+
+    // 馃崅method reset()
+    // Rebuild edit elements (Vertex, MiddleMarker, etc.).
+    reset: function () {
+      this.editLayer.clearLayers()
+      this.initVertexMarkers()
+    },
+
+    addVertexMarker: function (latlng, latlngs) {
+      return new this.tools.options.VertexMarkerClass(latlng, latlngs, this)
+    },
+
+    onNewVertex: function (vertex) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:new: VertexEvent
+      // Fired when a new vertex is created.
+      this.fireAndForward('editable:vertex:new', {
+        latlng: vertex.latlng,
+        vertex: vertex
+      })
+    },
+
+    addVertexMarkers: function (latlngs) {
+      for (let i = 0; i < latlngs.length; i++) {
+        this.addVertexMarker(latlngs[i], latlngs)
+      }
+    },
+
+    refreshVertexMarkers: function (latlngs) {
+      latlngs = latlngs || this.getDefaultLatLngs()
+      for (let i = 0; i < latlngs.length; i++) {
+        latlngs[i].__vertex.update()
+      }
+    },
+
+    addMiddleMarker: function (left, right, latlngs) {
+      return new this.tools.options.MiddleMarkerClass(left, right, latlngs, this)
+    },
+
+    onVertexMarkerClick: function (e) {
+      L.Editable.makeCancellable(e)
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:click: CancelableVertexEvent
+      // Fired when a `click` is issued on a vertex, before any internal action is being processed.
+      this.fireAndForward('editable:vertex:click', e)
+      if (e._cancelled) return
+      if (this.tools.drawing() && this.tools._drawingEditor !== this) return
+      const index = e.vertex.getIndex()
+      let commit
+      if (e.originalEvent.ctrlKey) {
+        this.onVertexMarkerCtrlClick(e)
+      } else if (e.originalEvent.altKey) {
+        this.onVertexMarkerAltClick(e)
+      } else if (e.originalEvent.shiftKey) {
+        this.onVertexMarkerShiftClick(e)
+      } else if (e.originalEvent.metaKey) {
+        this.onVertexMarkerMetaKeyClick(e)
+      } else if (index === e.vertex.getLastIndex() && this._drawing === L.Editable.FORWARD) {
+        if (index >= this.MIN_VERTEX - 1) commit = true
+      } else if (index === 0 && this._drawing === L.Editable.BACKWARD && this._drawnLatLngs.length >= this.MIN_VERTEX) {
+        commit = true
+      } else if (index === 0 && this._drawing === L.Editable.FORWARD && this._drawnLatLngs.length >= this.MIN_VERTEX && this.CLOSED) {
+        commit = true // Allow to close on first point also for polygons
+      } else {
+        this.onVertexRawMarkerClick(e)
+      }
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:clicked: VertexEvent
+      // Fired when a `click` is issued on a vertex, after all internal actions.
+      this.fireAndForward('editable:vertex:clicked', e)
+      if (commit) this.commitDrawing(e)
+    },
+
+    onVertexRawMarkerClick: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:rawclick: CancelableVertexEvent
+      // Fired when a `click` is issued on a vertex without any special key and without being in drawing mode.
+      this.fireAndForward('editable:vertex:rawclick', e)
+      if (e._cancelled) return
+      if (!this.vertexCanBeDeleted(e.vertex)) return
+      e.vertex.delete()
+    },
+
+    vertexCanBeDeleted: function (vertex) {
+      return vertex.latlngs.length > this.MIN_VERTEX
+    },
+
+    onVertexDeleted: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:deleted: VertexEvent
+      // Fired after a vertex has been deleted by user.
+      this.fireAndForward('editable:vertex:deleted', e)
+    },
+
+    onVertexMarkerCtrlClick: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:ctrlclick: VertexEvent
+      // Fired when a `click` with `ctrlKey` is issued on a vertex.
+      this.fireAndForward('editable:vertex:ctrlclick', e)
+    },
+
+    onVertexMarkerShiftClick: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:shiftclick: VertexEvent
+      // Fired when a `click` with `shiftKey` is issued on a vertex.
+      this.fireAndForward('editable:vertex:shiftclick', e)
+    },
+
+    onVertexMarkerMetaKeyClick: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:metakeyclick: VertexEvent
+      // Fired when a `click` with `metaKey` is issued on a vertex.
+      this.fireAndForward('editable:vertex:metakeyclick', e)
+    },
+
+    onVertexMarkerAltClick: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:altclick: VertexEvent
+      // Fired when a `click` with `altKey` is issued on a vertex.
+      this.fireAndForward('editable:vertex:altclick', e)
+    },
+
+    onVertexMarkerContextMenu: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:contextmenu: VertexEvent
+      // Fired when a `contextmenu` is issued on a vertex.
+      this.fireAndForward('editable:vertex:contextmenu', e)
+    },
+
+    onVertexMarkerMouseDown: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:mousedown: VertexEvent
+      // Fired when user `mousedown` a vertex.
+      this.fireAndForward('editable:vertex:mousedown', e)
+    },
+
+    onVertexMarkerMouseOver: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:mouseover: VertexEvent
+      // Fired when a user's mouse enters the vertex
+      this.fireAndForward('editable:vertex:mouseover', e)
+    },
+
+    onVertexMarkerMouseOut: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:mouseout: VertexEvent
+      // Fired when a user's mouse leaves the vertex
+      this.fireAndForward('editable:vertex:mouseout', e)
+    },
+
+    onMiddleMarkerMouseDown: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section MiddleMarker events
+      // 馃崅event editable:middlemarker:mousedown: VertexEvent
+      // Fired when user `mousedown` a middle marker.
+      this.fireAndForward('editable:middlemarker:mousedown', e)
+    },
+
+    onVertexMarkerDrag: function (e) {
+      this.onMove(e)
+      if (this.feature._bounds) this.extendBounds(e)
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:drag: VertexEvent
+      // Fired when a vertex is dragged by user.
+      this.fireAndForward('editable:vertex:drag', e)
+    },
+
+    onVertexMarkerDragStart: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:dragstart: VertexEvent
+      // Fired before a vertex is dragged by user.
+      this.fireAndForward('editable:vertex:dragstart', e)
+    },
+
+    onVertexMarkerDragEnd: function (e) {
+      // 馃崅namespace Editable
+      // 馃崅section Vertex events
+      // 馃崅event editable:vertex:dragend: VertexEvent
+      // Fired after a vertex is dragged by user.
+      this.fireAndForward('editable:vertex:dragend', e)
+    },
+
+    setDrawnLatLngs: function (latlngs) {
+      this._drawnLatLngs = latlngs || this.getDefaultLatLngs()
+    },
+
+    startDrawing: function () {
+      if (!this._drawnLatLngs) this.setDrawnLatLngs()
+      L.Editable.BaseEditor.prototype.startDrawing.call(this)
+    },
+
+    startDrawingForward: function () {
+      this.startDrawing()
+    },
+
+    endDrawing: function () {
+      this.tools.detachForwardLineGuide()
+      this.tools.detachBackwardLineGuide()
+      if (this._drawnLatLngs && this._drawnLatLngs.length < this.MIN_VERTEX) this.deleteShape(this._drawnLatLngs)
+      L.Editable.BaseEditor.prototype.endDrawing.call(this)
+      delete this._drawnLatLngs
+    },
+
+    addLatLng: function (latlng) {
+      if (this._drawing === L.Editable.FORWARD) {
+        this._drawnLatLngs.push(latlng)
+      } else {
+        this._drawnLatLngs.unshift(latlng)
+      }
+      this.feature._bounds.extend(latlng)
+      const vertex = this.addVertexMarker(latlng, this._drawnLatLngs)
+      this.onNewVertex(vertex)
+      this.refresh()
+    },
+
+    newPointForward: function (latlng) {
+      this.addLatLng(latlng)
+      this.tools.attachForwardLineGuide()
+      this.tools.anchorForwardLineGuide(latlng)
+    },
+
+    newPointBackward: function (latlng) {
+      this.addLatLng(latlng)
+      this.tools.anchorBackwardLineGuide(latlng)
+    },
+
+    // 馃崅namespace PathEditor
+    // 馃崅method push()
+    // Programmatically add a point while drawing.
+    push: function (latlng) {
+      if (!latlng) return console.error('L.Editable.PathEditor.push expect a valid latlng as parameter')
+      if (this._drawing === L.Editable.FORWARD) {
+        this.newPointForward(latlng)
+      } else {
+        this.newPointBackward(latlng)
+      }
+    },
+
+    removeLatLng: function (latlng) {
+      latlng.__vertex.delete()
+      this.refresh()
+    },
+
+    // 馃崅method pop(): L.LatLng or null
+    // Programmatically remove last point (if any) while drawing.
+    pop: function () {
+      if (this._drawnLatLngs.length <= 1) return
+      let latlng
+      if (this._drawing === L.Editable.FORWARD) {
+        latlng = this._drawnLatLngs[this._drawnLatLngs.length - 1]
+      } else {
+        latlng = this._drawnLatLngs[0]
+      }
+      this.removeLatLng(latlng)
+      if (this._drawing === L.Editable.FORWARD) {
+        this.tools.anchorForwardLineGuide(this._drawnLatLngs[this._drawnLatLngs.length - 1])
+      } else {
+        this.tools.anchorForwardLineGuide(this._drawnLatLngs[0])
+      }
+      return latlng
+    },
+
+    processDrawingClick: function (e) {
+      if (e.vertex && e.vertex.editor === this) return
+      if (this._drawing === L.Editable.FORWARD) {
+        this.newPointForward(e.latlng)
+      } else {
+        this.newPointBackward(e.latlng)
+      }
+      this.fireAndForward('editable:drawing:clicked', e)
+    },
+
+    onDrawingMouseMove: function (e) {
+      L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e)
+      if (this._drawing) {
+        this.tools.moveForwardLineGuide(e.latlng)
+        this.tools.moveBackwardLineGuide(e.latlng)
+      }
+    },
+
+    refresh: function () {
+      this.feature.redraw()
+      this.onEditing()
+    },
+
+    // 馃崅namespace PathEditor
+    // 馃崅method newShape(latlng?: L.LatLng)
+    // Add a new shape (Polyline, Polygon) in a multi, and setup up drawing tools to draw it;
+    // if optional `latlng` is given, start a path at this point.
+    newShape: function (latlng) {
+      const shape = this.addNewEmptyShape()
+      if (!shape) return
+      this.setDrawnLatLngs(shape[0] || shape) // Polygon or polyline
+      this.startDrawingForward()
+      // 馃崅namespace Editable
+      // 馃崅section Shape events
+      // 馃崅event editable:shape:new: ShapeEvent
+      // Fired when a new shape is created in a multi (Polygon or Polyline).
+      this.fireAndForward('editable:shape:new', { shape: shape })
+      if (latlng) this.newPointForward(latlng)
+    },
+
+    deleteShape: function (shape, latlngs) {
+      const e = { shape: shape }
+      L.Editable.makeCancellable(e)
+      // 馃崅namespace Editable
+      // 馃崅section Shape events
+      // 馃崅event editable:shape:delete: CancelableShapeEvent
+      // Fired before a new shape is deleted in a multi (Polygon or Polyline).
+      this.fireAndForward('editable:shape:delete', e)
+      if (e._cancelled) return
+      shape = this._deleteShape(shape, latlngs)
+      if (this.ensureNotFlat) this.ensureNotFlat() // Polygon.
+      this.feature.setLatLngs(this.getLatLngs()) // Force bounds reset.
+      this.refresh()
+      this.reset()
+      // 馃崅namespace Editable
+      // 馃崅section Shape events
+      // 馃崅event editable:shape:deleted: ShapeEvent
+      // Fired after a new shape is deleted in a multi (Polygon or Polyline).
+      this.fireAndForward('editable:shape:deleted', { shape: shape })
+      return shape
+    },
+
+    _deleteShape: function (shape, latlngs) {
+      latlngs = latlngs || this.getLatLngs()
+      if (!latlngs.length) return
+      const self = this
+      const inplaceDelete = function (latlngs, shape) {
+        // Called when deleting a flat latlngs
+        shape = latlngs.splice(0, Number.MAX_VALUE)
         return shape
-      },
+      }
+      const spliceDelete = function (latlngs, shape) {
+        // Called when removing a latlngs inside an array
+        latlngs.splice(latlngs.indexOf(shape), 1)
+        if (!latlngs.length) self._deleteShape(latlngs)
+        return shape
+      }
+      if (latlngs === shape) return inplaceDelete(latlngs, shape)
+      for (let i = 0; i < latlngs.length; i++) {
+        if (latlngs[i] === shape) {
+          return spliceDelete(latlngs, shape)
+        } else if (latlngs[i].indexOf(shape) !== -1) return spliceDelete(latlngs[i], shape)
+      }
+    },
 
-      isInLatLngs: function (l, latlngs) {
-        if (!latlngs) return false
-        let i, k, len
-        let part = []
-        const w = this._clickTolerance()
-        this._projectLatlngs(latlngs, part, this._pxBounds)
-        part = part[0]
-        const p = this._map.latLngToLayerPoint(l)
+    // 馃崅namespace PathEditor
+    // 馃崅method deleteShapeAt(latlng: L.LatLng): Array
+    // Remove a path shape at the given `latlng`.
+    deleteShapeAt: function (latlng) {
+      const shape = this.feature.shapeAt(latlng)
+      if (shape) return this.deleteShape(shape)
+    },
 
-        if (!this._pxBounds.contains(p)) {
-          return false
-        }
-        for (i = 1, len = part.length, k = 0; i < len; k = i++) {
-          if (L.LineUtil.pointToSegmentDistance(p, part[k], part[i]) <= w) {
-            return true
-          }
-        }
+    // 馃崅method appendShape(shape: Array)
+    // Append a new shape to the Polygon or Polyline.
+    appendShape: function (shape) {
+      this.insertShape(shape)
+    },
+
+    // 馃崅method prependShape(shape: Array)
+    // Prepend a new shape to the Polygon or Polyline.
+    prependShape: function (shape) {
+      this.insertShape(shape, 0)
+    },
+
+    // 馃崅method insertShape(shape: Array, index: int)
+    // Insert a new shape to the Polygon or Polyline at given index (default is to append).
+    insertShape: function (shape, index) {
+      this.ensureMulti()
+      shape = this.formatShape(shape)
+      if (typeof index === 'undefined') index = this.feature._latlngs.length
+      this.feature._latlngs.splice(index, 0, shape)
+      this.feature.redraw()
+      if (this._enabled) this.reset()
+    },
+
+    extendBounds: function (e) {
+      this.feature._bounds.extend(e.vertex.latlng)
+    },
+
+    onDragStart: function (e) {
+      this.editLayer.clearLayers()
+      L.Editable.BaseEditor.prototype.onDragStart.call(this, e)
+    },
+
+    onDragEnd: function (e) {
+      this.initVertexMarkers()
+      L.Editable.BaseEditor.prototype.onDragEnd.call(this, e)
+    }
+
+  })
+
+  // 馃崅namespace Editable; 馃崅class PolylineEditor; 馃崅aka L.Editable.PolylineEditor
+  // 馃崅inherits PathEditor
+  L.Editable.PolylineEditor = L.Editable.PathEditor.extend({
+
+    startDrawingBackward: function () {
+      this._drawing = L.Editable.BACKWARD
+      this.startDrawing()
+    },
+
+    // 馃崅method continueBackward(latlngs?: Array)
+    // Set up drawing tools to continue the line backward.
+    continueBackward: function (latlngs) {
+      if (this.drawing()) return
+      latlngs = latlngs || this.getDefaultLatLngs()
+      this.setDrawnLatLngs(latlngs)
+      if (latlngs.length > 0) {
+        this.tools.attachBackwardLineGuide()
+        this.tools.anchorBackwardLineGuide(latlngs[0])
+      }
+      this.startDrawingBackward()
+    },
+
+    // 馃崅method continueForward(latlngs?: Array)
+    // Set up drawing tools to continue the line forward.
+    continueForward: function (latlngs) {
+      if (this.drawing()) return
+      latlngs = latlngs || this.getDefaultLatLngs()
+      this.setDrawnLatLngs(latlngs)
+      if (latlngs.length > 0) {
+        this.tools.attachForwardLineGuide()
+        this.tools.anchorForwardLineGuide(latlngs[latlngs.length - 1])
+      }
+      this.startDrawingForward()
+    },
+
+    getDefaultLatLngs: function (latlngs) {
+      latlngs = latlngs || this.feature._latlngs
+      if (!latlngs.length || latlngs[0] instanceof L.LatLng) {
+        return latlngs
+      } else {
+        return this.getDefaultLatLngs(latlngs[0])
+      }
+    },
+
+    ensureMulti: function () {
+      if (this.feature._latlngs.length && isFlat(this.feature._latlngs)) {
+        this.feature._latlngs = [this.feature._latlngs]
+      }
+    },
+
+    addNewEmptyShape: function () {
+      if (this.feature._latlngs.length) {
+        const shape = []
+        this.appendShape(shape)
+        return shape
+      } else {
+        return this.feature._latlngs
+      }
+    },
+
+    formatShape: function (shape) {
+      if (isFlat(shape)) {
+        return shape
+      } else if (shape[0]) return this.formatShape(shape[0])
+    },
+
+    // 馃崅method splitShape(latlngs?: Array, index: int)
+    // Split the given `latlngs` shape at index `index` and integrate new shape in instance `latlngs`.
+    splitShape: function (shape, index) {
+      if (!index || index >= shape.length - 1) return
+      this.ensureMulti()
+      const shapeIndex = this.feature._latlngs.indexOf(shape)
+      if (shapeIndex === -1) return
+      const first = shape.slice(0, index + 1)
+      const second = shape.slice(index)
+      // We deal with reference, we don't want twice the same latlng around.
+      second[0] = L.latLng(second[0].lat, second[0].lng, second[0].alt)
+      this.feature._latlngs.splice(shapeIndex, 1, first, second)
+      this.refresh()
+      this.reset()
+    }
+
+  })
+
+  // 馃崅namespace Editable; 馃崅class PolygonEditor; 馃崅aka L.Editable.PolygonEditor
+  // 馃崅inherits PathEditor
+  L.Editable.PolygonEditor = L.Editable.PathEditor.extend({
+
+    CLOSED: true,
+    MIN_VERTEX: 3,
+
+    newPointForward: function (latlng) {
+      L.Editable.PathEditor.prototype.newPointForward.call(this, latlng)
+      if (!this.tools.backwardLineGuide._latlngs.length) this.tools.anchorBackwardLineGuide(latlng)
+      if (this._drawnLatLngs.length === 2) this.tools.attachBackwardLineGuide()
+    },
+
+    addNewEmptyHole: function (latlng) {
+      this.ensureNotFlat()
+      const latlngs = this.feature.shapeAt(latlng)
+      if (!latlngs) return
+      const holes = []
+      latlngs.push(holes)
+      return holes
+    },
+
+    // 馃崅method newHole(latlng?: L.LatLng, index: int)
+    // Set up drawing tools for creating a new hole on the Polygon. If the `latlng` param is given, a first point is created.
+    newHole: function (latlng) {
+      const holes = this.addNewEmptyHole(latlng)
+      if (!holes) return
+      this.setDrawnLatLngs(holes)
+      this.startDrawingForward()
+      if (latlng) this.newPointForward(latlng)
+    },
+
+    addNewEmptyShape: function () {
+      if (this.feature._latlngs.length && this.feature._latlngs[0].length) {
+        const shape = []
+        this.appendShape(shape)
+        return shape
+      } else {
+        return this.feature._latlngs
+      }
+    },
+
+    ensureMulti: function () {
+      if (this.feature._latlngs.length && isFlat(this.feature._latlngs[0])) {
+        this.feature._latlngs = [this.feature._latlngs]
+      }
+    },
+
+    ensureNotFlat: function () {
+      if (!this.feature._latlngs.length || isFlat(this.feature._latlngs)) this.feature._latlngs = [this.feature._latlngs]
+    },
+
+    vertexCanBeDeleted: function (vertex) {
+      const parent = this.feature.parentShape(vertex.latlngs)
+      const idx = L.Util.indexOf(parent, vertex.latlngs)
+      if (idx > 0) return true // Holes can be totally deleted without removing the layer itself.
+      return L.Editable.PathEditor.prototype.vertexCanBeDeleted.call(this, vertex)
+    },
+
+    getDefaultLatLngs: function () {
+      if (!this.feature._latlngs.length) this.feature._latlngs.push([])
+      return this.feature._latlngs[0]
+    },
+
+    formatShape: function (shape) {
+      // [[1, 2], [3, 4]] => must be nested
+      // [] => must be nested
+      // [[]] => is already nested
+      if (isFlat(shape) && (!shape[0] || shape[0].length !== 0)) {
+        return [shape]
+      } else {
+        return shape
+      }
+    }
+
+  })
+
+  // 馃崅namespace Editable; 馃崅class RectangleEditor; 馃崅aka L.Editable.RectangleEditor
+  // 馃崅inherits PathEditor
+  L.Editable.RectangleEditor = L.Editable.PathEditor.extend({
+
+    CLOSED: true,
+    MIN_VERTEX: 4,
+
+    options: {
+      skipMiddleMarkers: true
+    },
+
+    extendBounds: function (e) {
+      const index = e.vertex.getIndex()
+      const next = e.vertex.getNext()
+      const previous = e.vertex.getPrevious()
+      const oppositeIndex = (index + 2) % 4
+      const opposite = e.vertex.latlngs[oppositeIndex]
+      const bounds = new L.LatLngBounds(e.latlng, opposite)
+      // Update latlngs by hand to preserve order.
+      previous.latlng.update([e.latlng.lat, opposite.lng])
+      next.latlng.update([opposite.lat, e.latlng.lng])
+      this.updateBounds(bounds)
+      this.refreshVertexMarkers()
+    },
+
+    onDrawingMouseDown: function (e) {
+      L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e)
+      this.connect()
+      const latlngs = this.getDefaultLatLngs()
+      // L.Polygon._convertLatLngs removes last latlng if it equals first point,
+      // which is the case here as all latlngs are [0, 0]
+      if (latlngs.length === 3) latlngs.push(e.latlng)
+      const bounds = new L.LatLngBounds(e.latlng, e.latlng)
+      this.updateBounds(bounds)
+      this.updateLatLngs(bounds)
+      this.refresh()
+      this.reset()
+      // Stop dragging map.
+      // L.Draggable has two workflows:
+      // - mousedown => mousemove => mouseup
+      // - touchstart => touchmove => touchend
+      // Problem: L.Map.Tap does not allow us to listen to touchstart, so we only
+      // can deal with mousedown, but then when in a touch device, we are dealing with
+      // simulated events (actually simulated by L.Map.Tap), which are no more taken
+      // into account by L.Draggable.
+      // Ref.: https://github.com/Leaflet/Leaflet.Editable/issues/103
+      e.originalEvent._simulated = false
+      this.map.dragging._draggable._onUp(e.originalEvent)
+      // Now transfer ongoing drag action to the bottom right corner.
+      // Should we refine which corner will handle the drag according to
+      // drag direction?
+      latlngs[3].__vertex.dragging._draggable._onDown(e.originalEvent)
+    },
+
+    onDrawingMouseUp: function (e) {
+      this.commitDrawing(e)
+      e.originalEvent._simulated = false
+      L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e)
+    },
+
+    onDrawingMouseMove: function (e) {
+      e.originalEvent._simulated = false
+      L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e)
+    },
+
+    getDefaultLatLngs: function (latlngs) {
+      return latlngs || this.feature._latlngs[0]
+    },
+
+    updateBounds: function (bounds) {
+      this.feature._bounds = bounds
+    },
+
+    updateLatLngs: function (bounds) {
+      const latlngs = this.getDefaultLatLngs()
+      const newLatlngs = this.feature._boundsToLatLngs(bounds)
+      // Keep references.
+      for (let i = 0; i < latlngs.length; i++) {
+        latlngs[i].update(newLatlngs[i])
+      }
+    }
+
+  })
+
+  // 馃崅namespace Editable; 馃崅class CircleEditor; 馃崅aka L.Editable.CircleEditor
+  // 馃崅inherits PathEditor
+  L.Editable.CircleEditor = L.Editable.PathEditor.extend({
+
+    MIN_VERTEX: 2,
+
+    options: {
+      skipMiddleMarkers: true
+    },
+
+    initialize: function (map, feature, options) {
+      L.Editable.PathEditor.prototype.initialize.call(this, map, feature, options)
+      // C.Y.B Modify
+
+      const latlng = this.computeResizeLatLng()
+
+      // latlng.lat = latlng.lat-0.007855;
+      // latlng.lng= latlng.lng-0.1;
+      this._resizeLatLng = latlng
+      // 鍘熷鏂规硶
+      // this._resizeLatLng = this.computeResizeLatLng();
+    },
+
+    computeResizeLatLng: function () {
+      // While circle is not added to the map, _radius is not set.
+      // let delta = (this.feature._radius || this.feature._mRadius) * Math.cos(Math.PI / 4)
+      const delta = (this.feature._radius || this.feature._mRadius)
+      const point = this.map.project(this.feature._latlng)
+      // return this.map.unproject([point.x + delta, point.y - delta])
+      return this.map.unproject([point.x + delta, point.y])
+    },
+
+    updateResizeLatLng: function () {
+      this._resizeLatLng.update(this.computeResizeLatLng())
+      this._resizeLatLng.__vertex.update()
+    },
+
+    getLatLngs: function () {
+      return [this.feature._latlng, this._resizeLatLng]
+    },
+
+    getDefaultLatLngs: function () {
+      return this.getLatLngs()
+    },
+
+    onVertexMarkerDrag: function (e) {
+      if (e.vertex.getIndex() === 1) {
+        this.resize(e)
+      } else {
+        this.updateResizeLatLng(e)
+      }
+      L.Editable.PathEditor.prototype.onVertexMarkerDrag.call(this, e)
+    },
+
+    resize: function (e) {
+      const radius = this.feature._latlng.distanceTo(e.latlng)
+      this.feature.setRadius(radius)
+    },
+
+    onDrawingMouseDown: function (e) {
+      L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e)
+      this._resizeLatLng.update(e.latlng)
+      this.feature._latlng.update(e.latlng)
+      this.connect()
+      // Stop dragging map.
+      e.originalEvent._simulated = false
+      this.map.dragging._draggable._onUp(e.originalEvent)
+      // Now transfer ongoing drag action to the radius handler.
+      this._resizeLatLng.__vertex.dragging._draggable._onDown(e.originalEvent)
+    },
+
+    onDrawingMouseUp: function (e) {
+      this.commitDrawing(e)
+      e.originalEvent._simulated = false
+      L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e)
+    },
+
+    onDrawingMouseMove: function (e) {
+      e.originalEvent._simulated = false
+      L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e)
+    },
+
+    onDrag: function (e) {
+      L.Editable.PathEditor.prototype.onDrag.call(this, e)
+      this.feature.dragging.updateLatLng(this._resizeLatLng)
+    }
+
+  })
+
+  // 馃崅namespace Editable; 馃崅class EditableMixin
+  // `EditableMixin` is included to `L.Polyline`, `L.Polygon`, `L.Rectangle`, `L.Circle`
+  // and `L.Marker`. It adds some methods to them.
+  // *When editing is enabled, the editor is accessible on the instance with the
+  // `editor` property.*
+  const EditableMixin = {
+
+    createEditor: function (map) {
+      map = map || this._map
+      const tools = (this.options.editOptions || {}).editTools || map.editTools
+      if (!tools) throw Error('Unable to detect Editable instance.')
+      const Klass = this.options.editorClass || this.getEditorClass(tools)
+      return new Klass(map, this, this.options.editOptions)
+    },
+
+    // 馃崅method enableEdit(map?: L.Map): this.editor
+    // Enable editing, by creating an editor if not existing, and then calling `enable` on it.
+    enableEdit: function (map) {
+      if (!this.editor) this.createEditor(map)
+      this.editor.enable()
+      return this.editor
+    },
+
+    // 馃崅method editEnabled(): boolean
+    // Return true if current instance has an editor attached, and this editor is enabled.
+    editEnabled: function () {
+      return this.editor && this.editor.enabled()
+    },
+
+    // 馃崅method disableEdit()
+    // Disable editing, also remove the editor property reference.
+    disableEdit: function () {
+      if (this.editor) {
+        this.editor.disable()
+        delete this.editor
+      }
+    },
+
+    // 馃崅method toggleEdit()
+    // Enable or disable editing, according to current status.
+    toggleEdit: function () {
+      if (this.editEnabled()) {
+        this.disableEdit()
+      } else {
+        this.enableEdit()
+      }
+    },
+
+    _onEditableAdd: function () {
+      if (this.editor) this.enableEdit()
+    }
+
+  }
+
+  const PolylineMixin = {
+
+    getEditorClass: function (tools) {
+      return (tools && tools.options.polylineEditorClass) ? tools.options.polylineEditorClass : L.Editable.PolylineEditor
+    },
+
+    shapeAt: function (latlng, latlngs) {
+      // We can have those cases:
+      // - latlngs are just a flat array of latlngs, use this
+      // - latlngs is an array of arrays of latlngs, loop over
+      let shape = null
+      latlngs = latlngs || this._latlngs
+      if (!latlngs.length) {
+        return shape
+      } else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) {
+        shape = latlngs
+      } else {
+        for (let i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i])) return latlngs[i]
+      }
+      return shape
+    },
+
+    isInLatLngs: function (l, latlngs) {
+      if (!latlngs) return false
+      let i, k, len
+      let part = []
+      const w = this._clickTolerance()
+      this._projectLatlngs(latlngs, part, this._pxBounds)
+      part = part[0]
+      const p = this._map.latLngToLayerPoint(l)
+
+      if (!this._pxBounds.contains(p)) {
         return false
       }
-
+      for (i = 1, len = part.length, k = 0; i < len; k = i++) {
+        if (L.LineUtil.pointToSegmentDistance(p, part[k], part[i]) <= w) {
+          return true
+        }
+      }
+      return false
     }
 
-    const PolygonMixin = {
+  }
 
-      getEditorClass: function (tools) {
-        return (tools && tools.options.polygonEditorClass) ? tools.options.polygonEditorClass : L.Editable.PolygonEditor
-      },
+  const PolygonMixin = {
 
-      shapeAt: function (latlng, latlngs) {
-        // We can have those cases:
-        // - latlngs are just a flat array of latlngs, use this
-        // - latlngs is an array of arrays of latlngs, this is a simple polygon (maybe with holes), use the first
-        // - latlngs is an array of arrays of arrays, this is a multi, loop over
-        let shape = null
-        latlngs = latlngs || this._latlngs
-        if (!latlngs.length) {
-          return shape
-        } else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) {
-          shape = latlngs
-        } else if (isFlat(latlngs[0]) && this.isInLatLngs(latlng, latlngs[0])) {
-          shape = latlngs
-        } else {
-          for (let i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i][0])) return latlngs[i]
-        }
+    getEditorClass: function (tools) {
+      return (tools && tools.options.polygonEditorClass) ? tools.options.polygonEditorClass : L.Editable.PolygonEditor
+    },
+
+    shapeAt: function (latlng, latlngs) {
+      // We can have those cases:
+      // - latlngs are just a flat array of latlngs, use this
+      // - latlngs is an array of arrays of latlngs, this is a simple polygon (maybe with holes), use the first
+      // - latlngs is an array of arrays of arrays, this is a multi, loop over
+      let shape = null
+      latlngs = latlngs || this._latlngs
+      if (!latlngs.length) {
         return shape
-      },
+      } else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) {
+        shape = latlngs
+      } else if (isFlat(latlngs[0]) && this.isInLatLngs(latlng, latlngs[0])) {
+        shape = latlngs
+      } else {
+        for (let i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i][0])) return latlngs[i]
+      }
+      return shape
+    },
 
-      isInLatLngs: function (l, latlngs) {
-        let inside = false
-        let l1
-        let l2
-        let j
-        let k
-        let len2
-        for (j = 0, len2 = latlngs.length, k = len2 - 1; j < len2; k = j++) {
-          l1 = latlngs[j]
-          l2 = latlngs[k]
+    isInLatLngs: function (l, latlngs) {
+      let inside = false
+      let l1
+      let l2
+      let j
+      let k
+      let len2
+      for (j = 0, len2 = latlngs.length, k = len2 - 1; j < len2; k = j++) {
+        l1 = latlngs[j]
+        l2 = latlngs[k]
 
-          if (((l1.lat > l.lat) !== (l2.lat > l.lat)) &&
-            (l.lng < (l2.lng - l1.lng) * (l.lat - l1.lat) / (l2.lat - l1.lat) + l1.lng)) {
-            inside = !inside
-          }
-        }
-
-        return inside
-      },
-
-      parentShape: function (shape, latlngs) {
-        latlngs = latlngs || this._latlngs
-        if (!latlngs) return
-        let idx = L.Util.indexOf(latlngs, shape)
-        if (idx !== -1) return latlngs
-        for (let i = 0; i < latlngs.length; i++) {
-          idx = L.Util.indexOf(latlngs[i], shape)
-          if (idx !== -1) return latlngs[i]
+        if (((l1.lat > l.lat) !== (l2.lat > l.lat)) &&
+          (l.lng < (l2.lng - l1.lng) * (l.lat - l1.lat) / (l2.lat - l1.lat) + l1.lng)) {
+          inside = !inside
         }
       }
 
-    }
+      return inside
+    },
 
-    const MarkerMixin = {
-
-      getEditorClass: function (tools) {
-        return (tools && tools.options.markerEditorClass) ? tools.options.markerEditorClass : L.Editable.MarkerEditor
+    parentShape: function (shape, latlngs) {
+      latlngs = latlngs || this._latlngs
+      if (!latlngs) return
+      let idx = L.Util.indexOf(latlngs, shape)
+      if (idx !== -1) return latlngs
+      for (let i = 0; i < latlngs.length; i++) {
+        idx = L.Util.indexOf(latlngs[i], shape)
+        if (idx !== -1) return latlngs[i]
       }
-
     }
 
-    const RectangleMixin = {
+  }
 
-      getEditorClass: function (tools) {
-        return (tools && tools.options.rectangleEditorClass) ? tools.options.rectangleEditorClass : L.Editable.RectangleEditor
-      }
+  const MarkerMixin = {
 
+    getEditorClass: function (tools) {
+      return (tools && tools.options.markerEditorClass) ? tools.options.markerEditorClass : L.Editable.MarkerEditor
     }
 
-    const CircleMixin = {
+  }
 
-      getEditorClass: function (tools) {
-        return (tools && tools.options.circleEditorClass) ? tools.options.circleEditorClass : L.Editable.CircleEditor
-      }
+  const RectangleMixin = {
 
+    getEditorClass: function (tools) {
+      return (tools && tools.options.rectangleEditorClass) ? tools.options.rectangleEditorClass : L.Editable.RectangleEditor
     }
 
-    const keepEditable = function () {
-      // Make sure you can remove/readd an editable layer.
-      this.on('add', this._onEditableAdd)
+  }
+
+  const CircleMixin = {
+
+    getEditorClass: function (tools) {
+      return (tools && tools.options.circleEditorClass) ? tools.options.circleEditorClass : L.Editable.CircleEditor
     }
 
-    const isFlat = L.LineUtil.isFlat || L.LineUtil._flat || L.Polyline._flat // <=> 1.1 compat.
+  }
 
-    if (L.Polyline) {
-      L.Polyline.include(EditableMixin)
-      L.Polyline.include(PolylineMixin)
-      L.Polyline.addInitHook(keepEditable)
-    }
-    if (L.Polygon) {
-      L.Polygon.include(EditableMixin)
-      L.Polygon.include(PolygonMixin)
-    }
-    if (L.Marker) {
-      L.Marker.include(EditableMixin)
-      L.Marker.include(MarkerMixin)
-      L.Marker.addInitHook(keepEditable)
-    }
-    if (L.Rectangle) {
-      L.Rectangle.include(EditableMixin)
-      L.Rectangle.include(RectangleMixin)
-    }
-    if (L.Circle) {
-      L.Circle.include(EditableMixin)
-      L.Circle.include(CircleMixin)
-    }
+  const keepEditable = function () {
+    // Make sure you can remove/readd an editable layer.
+    this.on('add', this._onEditableAdd)
+  }
 
-    L.LatLng.prototype.update = function (latlng) {
-      latlng = L.latLng(latlng)
-      this.lat = latlng.lat
-      this.lng = latlng.lng
-    }
-  }, window))
-}
+  const isFlat = L.LineUtil.isFlat || L.LineUtil._flat || L.Polyline._flat // <=> 1.1 compat.
 
-export default {
-  init
-}
+  if (L.Polyline) {
+    L.Polyline.include(EditableMixin)
+    L.Polyline.include(PolylineMixin)
+    L.Polyline.addInitHook(keepEditable)
+  }
+  if (L.Polygon) {
+    L.Polygon.include(EditableMixin)
+    L.Polygon.include(PolygonMixin)
+  }
+  if (L.Marker) {
+    L.Marker.include(EditableMixin)
+    L.Marker.include(MarkerMixin)
+    L.Marker.addInitHook(keepEditable)
+  }
+  if (L.Rectangle) {
+    L.Rectangle.include(EditableMixin)
+    L.Rectangle.include(RectangleMixin)
+  }
+  if (L.Circle) {
+    L.Circle.include(EditableMixin)
+    L.Circle.include(CircleMixin)
+  }
+
+  L.LatLng.prototype.update = function (latlng) {
+    latlng = L.latLng(latlng)
+    this.lat = latlng.lat
+    this.lng = latlng.lng
+  }
+}, window))
diff --git a/src/conf/LayerWasteWater.js b/src/conf/LayerWasteWater.js
new file mode 100644
index 0000000..982bd28
--- /dev/null
+++ b/src/conf/LayerWasteWater.js
@@ -0,0 +1,43 @@
+/**
+ * 搴熸按鍥惧眰
+ * @type {string}
+ */
+const APP_GIS_HOST_2 = 'http://xearth.cn:6289'
+export const LayerWasteWater = {
+  code: 'pipeline',
+  name: '搴熸按',
+  type: 'geojson',
+  // url: APP_GIS_HOST_2 + '/server/ogcserver/PipeLineTest/wms?version=1.1.1',
+  // url: APP_GIS_HOST_2 + '/layer/findLayer?layerName={sname}',
+  url: APP_GIS_HOST_2 + '/server/ogcserver/PipeLine/wfs?version=1.0.0&TYPENAME={sname}&REQUEST=getfeature&OUTPUTFORMAT=json&maxFeatures=20000',
+  checked: true,
+  layers: [
+    {
+      code: 'rainline',
+      name: '浼佷笟',
+      sname: '浼佷笟', // 琛ㄥ悕
+      checked: true, // 榛樿閫変腑鐘舵��
+      filter: {},
+      minZoom: 10, // 鍦ㄦ寚瀹氱骇鍒樉绀�
+      childLayer: 'fsss,hbss' // 鍏宠仈PointLayers
+    },
+    {
+      code: 'oilline',
+      name: '鐩戞祴鐐�',
+      sname: '鐩戞祴鐐�',
+      checked: true, // 榛樿閫変腑鐘舵��
+      filter: {},
+      minZoom: 10,
+      childLayer: 'fsss,hbss' // 鍏宠仈PointLayers
+    },
+    {
+      code: 'saltline',
+      name: '鎺掓斁鍙�',
+      sname: '鎺掓斁鍙�',
+      checked: true, // 榛樿閫変腑鐘舵��
+      filter: {},
+      minZoom: 10,
+      childLayer: 'fsss,hbss' // 鍏宠仈PointLayers
+    }
+  ]
+}
diff --git a/src/conf/MapConfig.js b/src/conf/MapConfig.js
index 8e502d3..2fb7b12 100644
--- a/src/conf/MapConfig.js
+++ b/src/conf/MapConfig.js
@@ -1,6 +1,7 @@
 锘縤mport * as L from 'leaflet'
 import TDT from './TDT'
 import { LayerSewersLine, LayerSewersPoint } from './LayerSewers'
+import { LayerWasteWater } from './LayerWasteWater'
 const curWwwPath = window.document.location.href
 const pathname = window.document.location.pathname
 const pos = curWwwPath.indexOf(pathname)
@@ -37,7 +38,7 @@
   // defaultBasemapCode: 'tianditu_img', // 榛樿鏄剧ず 鍦板浘绫诲瀷
   IntranetBaseMaps: TDT.intranet,
   InternetBaseMaps: TDT.internet,
-  Layers: { LayerSewersLine: [LayerSewersLine], layerSewersPoint: LayerSewersPoint } // 姹¢洦姘村浘灞傞厤缃�
+  Layers: { LayerSewersLine: [LayerSewersLine, LayerWasteWater], layerSewersPoint: LayerSewersPoint } // 姹¢洦姘村浘灞傞厤缃�
 }
 
 /**

--
Gitblit v1.8.0