Draw and edit shapes

Draw and edit shapes from a hosted feature service using Leaflet's Leaflet.Editable and L.Path.Drag plugins. The plugins help you edit the features from a hosted feature service and pass the edits back to the server.

Use dark colors for code blocksCopy
                                                                                                                                            
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<html>
  <head>
    <meta charset="utf-8" />
    <title>Draw and edit shapes</title>
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css" crossorigin="" />
    <script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js" crossorigin=""></script>

    <!-- Load Esri Leaflet from CDN -->
    <script src="https://unpkg.com/esri-leaflet@^3.0.8/dist/esri-leaflet.js"></script>

    <!-- Load Esri Leaflet Vector from CDN -->
    <script src="https://unpkg.com/esri-leaflet-vector@3.1.3/dist/esri-leaflet-vector.js" crossorigin=""></script>
    <style>
      html,
      body,
      #map {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
        font-family: Arial, Helvetica, sans-serif;
        font-size: 14px;
        color: #323232;
      }
    </style>
  </head>
  <body>
    <script src="https://unpkg.com/leaflet.path.drag@0.0.6/src/Path.Drag.js"></script>
    <script src="https://unpkg.com/leaflet-editable@1.2.0/src/Leaflet.Editable.js"></script>

    <div id="map"></div>
    <script type="text/javascript">
      // make sure double clicking the map *only* triggers the editing workflow
      const apiKey = "YOUR_API_KEY";

      var map = L.map("map", {
        editable: true,
        doubleClickZoom: false
      }).setView([37.345, -110.875], 5);

      L.esri.Vector.vectorBasemapLayer("ArcGIS:ChartedTerritory", {
        apikey: apiKey
      }).addTo(map);

      // create a feature layer and add it to the map
      var wildfireDistricts = L.esri
        .featureLayer({
          url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Wildfire/FeatureServer/2"
        })
        .addTo(map);

      // create a generic control to invoke editing
      L.EditControl = L.Control.extend({
        options: {
          position: "topleft",
          callback: null,
          kind: "",
          html: ""
        },
        // when the control is added to the map, wire up its DOM dynamically and add a click listener
        onAdd: function (map) {
          var container = L.DomUtil.create("div", "leaflet-control leaflet-bar");
          var link = L.DomUtil.create("a", "", container);
          link.href = "#";
          link.title = "Create a new " + this.options.kind;
          link.innerHTML = this.options.html;
          L.DomEvent.on(link, "click", L.DomEvent.stop).on(
            link,
            "click",
            function () {
              window.LAYER = this.options.callback.call(map.editTools);
            },
            this
          );
          return container;
        }
      });

      // extend the control to draw polygons
      L.NewPolygonControl = L.EditControl.extend({
        options: {
          position: "topleft",
          callback: map.editTools.startPolygon,
          kind: "polygon",
          html: "▰"
        }
      });

      // extend the control to draw rectangles
      L.NewRectangleControl = L.EditControl.extend({
        options: {
          position: "topleft",
          callback: map.editTools.startRectangle,
          kind: "rectangle",
          html: "⬛"
        }
      });

      // add the two new controls to the map
      map.addControl(new L.NewPolygonControl());
      map.addControl(new L.NewRectangleControl());

      // when users CMD/CTRL click an active editable feature,
      // remove it from the map and delete it from the service
      wildfireDistricts.on("click", function (e) {
        if ((e.originalEvent.ctrlKey || e.originalEvent.metaKey) && e.layer.editEnabled()) {
          // delete expects an id, not the whole geojson object
          wildfireDistricts.deleteFeature(e.layer.feature.id);
        }
      });

      // when users double click a graphic, toggle its editable status
      // but when deselecting via double click, pass the geometry update to the service
      wildfireDistricts.on("dblclick", function (e) {
        e.layer.toggleEdit();
        if (!e.layer.editEnabled()) {
          wildfireDistricts.updateFeature(e.layer.toGeoJSON());
        }
      });

      // when a new feature is drawn using one of the custom controls,
      // pass the edit to the featureLayer service
      map.on("editable:drawing:commit", function (e) {
        wildfireDistricts.addFeature(e.layer.toGeoJSON(), function (error, response) {
          if (error || !response.success) {
            console.log(error, response);
          }

          // now that the L.esri.featureLayer instance will manage this new feature,
          // remove any temporary features from the map that were created by the Editable plugin
          map.editTools.featuresLayer.clearLayers();
        });

        // disable editing
        e.layer.toggleEdit();
      });
    </script>
  </body>
</html>

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.