ekylibre-cartography 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +3 -0
- data/Rakefile +10 -0
- data/app/assets/javascripts/cartography.coffee +535 -0
- data/app/assets/javascripts/cartography/base.coffee +11 -0
- data/app/assets/javascripts/cartography/controls.coffee +463 -0
- data/app/assets/javascripts/cartography/events.coffee +36 -0
- data/app/assets/javascripts/cartography/layers.coffee +127 -0
- data/app/assets/javascripts/cartography/layers/simple.coffee +37 -0
- data/app/assets/javascripts/cartography/leaflet/controls.coffee +420 -0
- data/app/assets/javascripts/cartography/leaflet/handlers.coffee +461 -0
- data/app/assets/javascripts/cartography/leaflet/i18n.coffee +31 -0
- data/app/assets/javascripts/cartography/leaflet/layers.coffee +60 -0
- data/app/assets/javascripts/cartography/leaflet/toolbars.coffee +450 -0
- data/app/assets/javascripts/cartography/patches.js +8 -0
- data/app/assets/javascripts/cartography/util.coffee +18 -0
- data/app/assets/javascripts/main.js +18 -0
- data/app/assets/stylesheets/cartography.css +86 -0
- data/app/helpers/cartography_helper.rb +55 -0
- data/lib/cartography.rb +1 -0
- data/lib/cartography/engine.rb +11 -0
- data/lib/cartography/version.rb +3 -0
- data/vendor/assets/components/d3-array/dist/d3-array.js +590 -0
- data/vendor/assets/components/d3-array/dist/d3-array.min.js +2 -0
- data/vendor/assets/components/geojson-equality/dist/geojson-equality.js +295 -0
- data/vendor/assets/components/geojson-equality/dist/geojson-equality.js.map +21 -0
- data/vendor/assets/components/geojson-equality/dist/geojson-equality.min.js +1 -0
- data/vendor/assets/components/leaflet-controlpanel/dist/leaflet.controlpanel.css +29 -0
- data/vendor/assets/components/leaflet-controlpanel/dist/leaflet.controlpanel.js +269 -0
- data/vendor/assets/components/leaflet-draw-cut/dist/leaflet.draw.cut.css +1 -0
- data/vendor/assets/components/leaflet-draw-cut/dist/leaflet.draw.cut.js +8 -0
- data/vendor/assets/components/leaflet-draw-merge/dist/leaflet.draw.merge.css +0 -0
- data/vendor/assets/components/leaflet-draw-merge/dist/leaflet.draw.merge.js +48026 -0
- data/vendor/assets/components/leaflet-draw/dist/leaflet.draw-src.css +326 -0
- data/vendor/assets/components/leaflet-draw/dist/leaflet.draw-src.js +4653 -0
- data/vendor/assets/components/leaflet-draw/dist/leaflet.draw-src.map +1 -0
- data/vendor/assets/components/leaflet-draw/dist/leaflet.draw.css +10 -0
- data/vendor/assets/components/leaflet-draw/dist/leaflet.draw.js +10 -0
- data/vendor/assets/components/leaflet-geographicutil/dist/leaflet.geographicutil.js +3220 -0
- data/vendor/assets/components/leaflet-reactive_measure/dist/reactive_measure.css +30 -0
- data/vendor/assets/components/leaflet-reactive_measure/dist/reactive_measure.js +3764 -0
- data/vendor/assets/components/leaflet/dist/leaflet-src.js +13609 -0
- data/vendor/assets/components/leaflet/dist/leaflet-src.js.map +1 -0
- data/vendor/assets/components/leaflet/dist/leaflet-src.map +1 -0
- data/vendor/assets/components/leaflet/dist/leaflet.css +632 -0
- data/vendor/assets/components/leaflet/dist/leaflet.js +5 -0
- data/vendor/assets/components/leaflet/dist/leaflet.js.map +1 -0
- data/vendor/assets/components/martinez-polygon-clipping/dist/martinez.min.js +9 -0
- data/vendor/assets/components/martinez-polygon-clipping/dist/martinez.umd.js +1716 -0
- data/vendor/assets/components/martinez-polygon-clipping/dist/martinez.umd.js.map +1 -0
- data/vendor/assets/components/polygon-clipping/dist/polygon-clipping.js +279 -0
- data/vendor/assets/components/polygon-clipping/dist/polygon-clipping.min.js +1 -0
- data/vendor/assets/components/rtree/dist/rtree.js +911 -0
- data/vendor/assets/components/rtree/dist/rtree.min.js +1 -0
- data/vendor/assets/components/splaytree/dist/splay.es6.js +765 -0
- data/vendor/assets/components/splaytree/dist/splay.es6.js.map +1 -0
- data/vendor/assets/components/splaytree/dist/splay.js +797 -0
- data/vendor/assets/components/splaytree/dist/splay.js.map +1 -0
- metadata +156 -0
@@ -0,0 +1,326 @@
|
|
1
|
+
/* ================================================================== */
|
2
|
+
/* Toolbars
|
3
|
+
/* ================================================================== */
|
4
|
+
|
5
|
+
.leaflet-draw-section {
|
6
|
+
position: relative;
|
7
|
+
}
|
8
|
+
|
9
|
+
.leaflet-draw-toolbar {
|
10
|
+
margin-top: 12px;
|
11
|
+
}
|
12
|
+
|
13
|
+
.leaflet-draw-toolbar-top {
|
14
|
+
margin-top: 0;
|
15
|
+
}
|
16
|
+
|
17
|
+
.leaflet-draw-toolbar-notop a:first-child {
|
18
|
+
border-top-right-radius: 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
.leaflet-draw-toolbar-nobottom a:last-child {
|
22
|
+
border-bottom-right-radius: 0;
|
23
|
+
}
|
24
|
+
|
25
|
+
.leaflet-draw-toolbar a {
|
26
|
+
background-image: url('images/spritesheet.png');
|
27
|
+
background-image: linear-gradient(transparent, transparent), url('images/spritesheet.svg');
|
28
|
+
background-repeat: no-repeat;
|
29
|
+
background-size: 300px 30px;
|
30
|
+
background-clip: padding-box;
|
31
|
+
}
|
32
|
+
|
33
|
+
.leaflet-retina .leaflet-draw-toolbar a {
|
34
|
+
background-image: url('images/spritesheet-2x.png');
|
35
|
+
background-image: linear-gradient(transparent, transparent), url('images/spritesheet.svg');
|
36
|
+
}
|
37
|
+
|
38
|
+
.leaflet-draw a {
|
39
|
+
display: block;
|
40
|
+
text-align: center;
|
41
|
+
text-decoration: none;
|
42
|
+
}
|
43
|
+
|
44
|
+
.leaflet-draw a .sr-only {
|
45
|
+
position: absolute;
|
46
|
+
width: 1px;
|
47
|
+
height: 1px;
|
48
|
+
padding: 0;
|
49
|
+
margin: -1px;
|
50
|
+
overflow: hidden;
|
51
|
+
clip: rect(0,0,0,0);
|
52
|
+
border: 0;
|
53
|
+
}
|
54
|
+
|
55
|
+
/* ================================================================== */
|
56
|
+
/* Toolbar actions menu
|
57
|
+
/* ================================================================== */
|
58
|
+
|
59
|
+
.leaflet-draw-actions {
|
60
|
+
display: none;
|
61
|
+
list-style: none;
|
62
|
+
margin: 0;
|
63
|
+
padding: 0;
|
64
|
+
position: absolute;
|
65
|
+
left: 26px; /* leaflet-draw-toolbar.left + leaflet-draw-toolbar.width */
|
66
|
+
top: 0;
|
67
|
+
white-space: nowrap;
|
68
|
+
}
|
69
|
+
|
70
|
+
.leaflet-touch .leaflet-draw-actions {
|
71
|
+
left: 32px;
|
72
|
+
}
|
73
|
+
|
74
|
+
.leaflet-right .leaflet-draw-actions {
|
75
|
+
right: 26px;
|
76
|
+
left: auto;
|
77
|
+
}
|
78
|
+
|
79
|
+
.leaflet-touch .leaflet-right .leaflet-draw-actions {
|
80
|
+
right: 32px;
|
81
|
+
left: auto;
|
82
|
+
}
|
83
|
+
|
84
|
+
.leaflet-draw-actions li {
|
85
|
+
display: inline-block;
|
86
|
+
}
|
87
|
+
|
88
|
+
.leaflet-draw-actions li:first-child a {
|
89
|
+
border-left: none;
|
90
|
+
}
|
91
|
+
|
92
|
+
.leaflet-draw-actions li:last-child a {
|
93
|
+
-webkit-border-radius: 0 4px 4px 0;
|
94
|
+
border-radius: 0 4px 4px 0;
|
95
|
+
}
|
96
|
+
|
97
|
+
.leaflet-right .leaflet-draw-actions li:last-child a {
|
98
|
+
-webkit-border-radius: 0;
|
99
|
+
border-radius: 0;
|
100
|
+
}
|
101
|
+
|
102
|
+
.leaflet-right .leaflet-draw-actions li:first-child a {
|
103
|
+
-webkit-border-radius: 4px 0 0 4px;
|
104
|
+
border-radius: 4px 0 0 4px;
|
105
|
+
}
|
106
|
+
|
107
|
+
.leaflet-draw-actions a {
|
108
|
+
background-color: #919187;
|
109
|
+
border-left: 1px solid #AAA;
|
110
|
+
color: #FFF;
|
111
|
+
font: 11px/19px "Helvetica Neue", Arial, Helvetica, sans-serif;
|
112
|
+
line-height: 28px;
|
113
|
+
text-decoration: none;
|
114
|
+
padding-left: 10px;
|
115
|
+
padding-right: 10px;
|
116
|
+
height: 28px;
|
117
|
+
}
|
118
|
+
|
119
|
+
.leaflet-touch .leaflet-draw-actions a {
|
120
|
+
font-size: 12px;
|
121
|
+
line-height: 30px;
|
122
|
+
height: 30px;
|
123
|
+
}
|
124
|
+
|
125
|
+
.leaflet-draw-actions-bottom {
|
126
|
+
margin-top: 0;
|
127
|
+
}
|
128
|
+
|
129
|
+
.leaflet-draw-actions-top {
|
130
|
+
margin-top: 1px;
|
131
|
+
}
|
132
|
+
|
133
|
+
.leaflet-draw-actions-top a,
|
134
|
+
.leaflet-draw-actions-bottom a {
|
135
|
+
height: 27px;
|
136
|
+
line-height: 27px;
|
137
|
+
}
|
138
|
+
|
139
|
+
.leaflet-draw-actions a:hover {
|
140
|
+
background-color: #A0A098;
|
141
|
+
}
|
142
|
+
|
143
|
+
.leaflet-draw-actions-top.leaflet-draw-actions-bottom a {
|
144
|
+
height: 26px;
|
145
|
+
line-height: 26px;
|
146
|
+
}
|
147
|
+
|
148
|
+
/* ================================================================== */
|
149
|
+
/* Draw toolbar
|
150
|
+
/* ================================================================== */
|
151
|
+
|
152
|
+
.leaflet-draw-toolbar .leaflet-draw-draw-polyline {
|
153
|
+
background-position: -2px -2px;
|
154
|
+
}
|
155
|
+
|
156
|
+
.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-polyline {
|
157
|
+
background-position: 0 -1px;
|
158
|
+
}
|
159
|
+
|
160
|
+
.leaflet-draw-toolbar .leaflet-draw-draw-polygon {
|
161
|
+
background-position: -31px -2px;
|
162
|
+
}
|
163
|
+
|
164
|
+
.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-polygon {
|
165
|
+
background-position: -29px -1px;
|
166
|
+
}
|
167
|
+
|
168
|
+
.leaflet-draw-toolbar .leaflet-draw-draw-rectangle {
|
169
|
+
background-position: -62px -2px;
|
170
|
+
}
|
171
|
+
|
172
|
+
.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-rectangle {
|
173
|
+
background-position: -60px -1px;
|
174
|
+
}
|
175
|
+
|
176
|
+
.leaflet-draw-toolbar .leaflet-draw-draw-circle {
|
177
|
+
background-position: -92px -2px;
|
178
|
+
}
|
179
|
+
|
180
|
+
.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-circle {
|
181
|
+
background-position: -90px -1px;
|
182
|
+
}
|
183
|
+
|
184
|
+
.leaflet-draw-toolbar .leaflet-draw-draw-marker {
|
185
|
+
background-position: -122px -2px;
|
186
|
+
}
|
187
|
+
|
188
|
+
.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-marker {
|
189
|
+
background-position: -120px -1px;
|
190
|
+
}
|
191
|
+
|
192
|
+
.leaflet-draw-toolbar .leaflet-draw-draw-circlemarker {
|
193
|
+
background-position: -273px -2px;
|
194
|
+
}
|
195
|
+
|
196
|
+
.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-circlemarker {
|
197
|
+
background-position: -271px -1px;
|
198
|
+
}
|
199
|
+
|
200
|
+
|
201
|
+
/* ================================================================== */
|
202
|
+
/* Edit toolbar
|
203
|
+
/* ================================================================== */
|
204
|
+
|
205
|
+
.leaflet-draw-toolbar .leaflet-draw-edit-edit {
|
206
|
+
background-position: -152px -2px;
|
207
|
+
}
|
208
|
+
|
209
|
+
.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-edit {
|
210
|
+
background-position: -150px -1px;
|
211
|
+
}
|
212
|
+
|
213
|
+
.leaflet-draw-toolbar .leaflet-draw-edit-remove {
|
214
|
+
background-position: -182px -2px;
|
215
|
+
}
|
216
|
+
|
217
|
+
.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-remove {
|
218
|
+
background-position: -180px -1px;
|
219
|
+
}
|
220
|
+
|
221
|
+
.leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled {
|
222
|
+
background-position: -212px -2px;
|
223
|
+
}
|
224
|
+
|
225
|
+
.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled {
|
226
|
+
background-position: -210px -1px;
|
227
|
+
}
|
228
|
+
|
229
|
+
.leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled {
|
230
|
+
background-position: -242px -2px;
|
231
|
+
}
|
232
|
+
|
233
|
+
.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled {
|
234
|
+
background-position: -240px -2px;
|
235
|
+
}
|
236
|
+
|
237
|
+
/* ================================================================== */
|
238
|
+
/* Drawing styles
|
239
|
+
/* ================================================================== */
|
240
|
+
|
241
|
+
.leaflet-mouse-marker {
|
242
|
+
background-color: #fff;
|
243
|
+
cursor: crosshair;
|
244
|
+
}
|
245
|
+
|
246
|
+
.leaflet-draw-tooltip {
|
247
|
+
background: rgb(54, 54, 54);
|
248
|
+
background: rgba(0, 0, 0, 0.5);
|
249
|
+
border: 1px solid transparent;
|
250
|
+
-webkit-border-radius: 4px;
|
251
|
+
border-radius: 4px;
|
252
|
+
color: #fff;
|
253
|
+
font: 12px/18px "Helvetica Neue", Arial, Helvetica, sans-serif;
|
254
|
+
margin-left: 20px;
|
255
|
+
margin-top: -21px;
|
256
|
+
padding: 4px 8px;
|
257
|
+
position: absolute;
|
258
|
+
visibility: hidden;
|
259
|
+
white-space: nowrap;
|
260
|
+
z-index: 6;
|
261
|
+
}
|
262
|
+
|
263
|
+
.leaflet-draw-tooltip:before {
|
264
|
+
border-right: 6px solid black;
|
265
|
+
border-right-color: rgba(0, 0, 0, 0.5);
|
266
|
+
border-top: 6px solid transparent;
|
267
|
+
border-bottom: 6px solid transparent;
|
268
|
+
content: "";
|
269
|
+
position: absolute;
|
270
|
+
top: 7px;
|
271
|
+
left: -7px;
|
272
|
+
}
|
273
|
+
|
274
|
+
.leaflet-error-draw-tooltip {
|
275
|
+
background-color: #F2DEDE;
|
276
|
+
border: 1px solid #E6B6BD;
|
277
|
+
color: #B94A48;
|
278
|
+
}
|
279
|
+
|
280
|
+
.leaflet-error-draw-tooltip:before {
|
281
|
+
border-right-color: #E6B6BD;
|
282
|
+
}
|
283
|
+
|
284
|
+
.leaflet-draw-tooltip-single {
|
285
|
+
margin-top: -12px
|
286
|
+
}
|
287
|
+
|
288
|
+
.leaflet-draw-tooltip-subtext {
|
289
|
+
color: #f8d5e4;
|
290
|
+
}
|
291
|
+
|
292
|
+
.leaflet-draw-guide-dash {
|
293
|
+
font-size: 1%;
|
294
|
+
opacity: 0.6;
|
295
|
+
position: absolute;
|
296
|
+
width: 5px;
|
297
|
+
height: 5px;
|
298
|
+
}
|
299
|
+
|
300
|
+
/* ================================================================== */
|
301
|
+
/* Edit styles
|
302
|
+
/* ================================================================== */
|
303
|
+
|
304
|
+
.leaflet-edit-marker-selected {
|
305
|
+
background-color: rgba(254, 87, 161, 0.1);
|
306
|
+
border: 4px dashed rgba(254, 87, 161, 0.6);
|
307
|
+
-webkit-border-radius: 4px;
|
308
|
+
border-radius: 4px;
|
309
|
+
box-sizing: content-box;
|
310
|
+
}
|
311
|
+
|
312
|
+
.leaflet-edit-move {
|
313
|
+
cursor: move;
|
314
|
+
}
|
315
|
+
|
316
|
+
.leaflet-edit-resize {
|
317
|
+
cursor: pointer;
|
318
|
+
}
|
319
|
+
|
320
|
+
/* ================================================================== */
|
321
|
+
/* Old IE styles
|
322
|
+
/* ================================================================== */
|
323
|
+
|
324
|
+
.leaflet-oldie .leaflet-draw-toolbar {
|
325
|
+
border: 1px solid #999;
|
326
|
+
}
|
@@ -0,0 +1,4653 @@
|
|
1
|
+
/*
|
2
|
+
Leaflet.draw 0.4.12, a plugin that adds drawing and editing tools to Leaflet powered maps.
|
3
|
+
(c) 2012-2017, Jacob Toye, Jon West, Smartrak, Leaflet
|
4
|
+
|
5
|
+
https://github.com/Leaflet/Leaflet.draw
|
6
|
+
http://leafletjs.com
|
7
|
+
*/
|
8
|
+
(function (window, document, undefined) {/**
|
9
|
+
* Leaflet.draw assumes that you have already included the Leaflet library.
|
10
|
+
*/
|
11
|
+
L.drawVersion = "0.4.12";
|
12
|
+
/**
|
13
|
+
* @class L.Draw
|
14
|
+
* @aka Draw
|
15
|
+
*
|
16
|
+
*
|
17
|
+
* To add the draw toolbar set the option drawControl: true in the map options.
|
18
|
+
*
|
19
|
+
* @example
|
20
|
+
* ```js
|
21
|
+
* var map = L.map('map', {drawControl: true}).setView([51.505, -0.09], 13);
|
22
|
+
*
|
23
|
+
* L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
|
24
|
+
* attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
|
25
|
+
* }).addTo(map);
|
26
|
+
* ```
|
27
|
+
*
|
28
|
+
* ### Adding the edit toolbar
|
29
|
+
* To use the edit toolbar you must initialise the Leaflet.draw control and manually add it to the map.
|
30
|
+
*
|
31
|
+
* ```js
|
32
|
+
* var map = L.map('map').setView([51.505, -0.09], 13);
|
33
|
+
*
|
34
|
+
* L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
|
35
|
+
* attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
|
36
|
+
* }).addTo(map);
|
37
|
+
*
|
38
|
+
* // FeatureGroup is to store editable layers
|
39
|
+
* var drawnItems = new L.FeatureGroup();
|
40
|
+
* map.addLayer(drawnItems);
|
41
|
+
*
|
42
|
+
* var drawControl = new L.Control.Draw({
|
43
|
+
* edit: {
|
44
|
+
* featureGroup: drawnItems
|
45
|
+
* }
|
46
|
+
* });
|
47
|
+
* map.addControl(drawControl);
|
48
|
+
* ```
|
49
|
+
*
|
50
|
+
* The key here is the featureGroup option. This tells the plugin which FeatureGroup contains the layers that
|
51
|
+
* should be editable. The featureGroup can contain 0 or more features with geometry types Point, LineString, and Polygon.
|
52
|
+
* Leaflet.draw does not work with multigeometry features such as MultiPoint, MultiLineString, MultiPolygon,
|
53
|
+
* or GeometryCollection. If you need to add multigeometry features to the draw plugin, convert them to a
|
54
|
+
* FeatureCollection of non-multigeometries (Points, LineStrings, or Polygons).
|
55
|
+
*/
|
56
|
+
L.Draw = {};
|
57
|
+
|
58
|
+
/**
|
59
|
+
* @class L.drawLocal
|
60
|
+
* @aka L.drawLocal
|
61
|
+
*
|
62
|
+
* The core toolbar class of the API — it is used to create the toolbar ui
|
63
|
+
*
|
64
|
+
* @example
|
65
|
+
* ```js
|
66
|
+
* var modifiedDraw = L.drawLocal.extend({
|
67
|
+
* draw: {
|
68
|
+
* toolbar: {
|
69
|
+
* buttons: {
|
70
|
+
* polygon: 'Draw an awesome polygon'
|
71
|
+
* }
|
72
|
+
* }
|
73
|
+
* }
|
74
|
+
* });
|
75
|
+
* ```
|
76
|
+
*
|
77
|
+
* The default state for the control is the draw toolbar just below the zoom control.
|
78
|
+
* This will allow map users to draw vectors and markers.
|
79
|
+
* **Please note the edit toolbar is not enabled by default.**
|
80
|
+
*/
|
81
|
+
L.drawLocal = {
|
82
|
+
// format: {
|
83
|
+
// numeric: {
|
84
|
+
// delimiters: {
|
85
|
+
// thousands: ',',
|
86
|
+
// decimal: '.'
|
87
|
+
// }
|
88
|
+
// }
|
89
|
+
// },
|
90
|
+
draw: {
|
91
|
+
toolbar: {
|
92
|
+
// #TODO: this should be reorganized where actions are nested in actions
|
93
|
+
// ex: actions.undo or actions.cancel
|
94
|
+
actions: {
|
95
|
+
title: 'Cancel drawing',
|
96
|
+
text: 'Cancel'
|
97
|
+
},
|
98
|
+
finish: {
|
99
|
+
title: 'Finish drawing',
|
100
|
+
text: 'Finish'
|
101
|
+
},
|
102
|
+
undo: {
|
103
|
+
title: 'Delete last point drawn',
|
104
|
+
text: 'Delete last point'
|
105
|
+
},
|
106
|
+
buttons: {
|
107
|
+
polyline: 'Draw a polyline',
|
108
|
+
polygon: 'Draw a polygon',
|
109
|
+
rectangle: 'Draw a rectangle',
|
110
|
+
circle: 'Draw a circle',
|
111
|
+
marker: 'Draw a marker',
|
112
|
+
circlemarker: 'Draw a circlemarker'
|
113
|
+
}
|
114
|
+
},
|
115
|
+
handlers: {
|
116
|
+
circle: {
|
117
|
+
tooltip: {
|
118
|
+
start: 'Click and drag to draw circle.'
|
119
|
+
},
|
120
|
+
radius: 'Radius'
|
121
|
+
},
|
122
|
+
circlemarker: {
|
123
|
+
tooltip: {
|
124
|
+
start: 'Click map to place circle marker.'
|
125
|
+
}
|
126
|
+
},
|
127
|
+
marker: {
|
128
|
+
tooltip: {
|
129
|
+
start: 'Click map to place marker.'
|
130
|
+
}
|
131
|
+
},
|
132
|
+
polygon: {
|
133
|
+
tooltip: {
|
134
|
+
start: 'Click to start drawing shape.',
|
135
|
+
cont: 'Click to continue drawing shape.',
|
136
|
+
end: 'Click first point to close this shape.'
|
137
|
+
}
|
138
|
+
},
|
139
|
+
polyline: {
|
140
|
+
error: '<strong>Error:</strong> shape edges cannot cross!',
|
141
|
+
tooltip: {
|
142
|
+
start: 'Click to start drawing line.',
|
143
|
+
cont: 'Click to continue drawing line.',
|
144
|
+
end: 'Click last point to finish line.'
|
145
|
+
}
|
146
|
+
},
|
147
|
+
rectangle: {
|
148
|
+
tooltip: {
|
149
|
+
start: 'Click and drag to draw rectangle.'
|
150
|
+
}
|
151
|
+
},
|
152
|
+
simpleshape: {
|
153
|
+
tooltip: {
|
154
|
+
end: 'Release mouse to finish drawing.'
|
155
|
+
}
|
156
|
+
}
|
157
|
+
}
|
158
|
+
},
|
159
|
+
edit: {
|
160
|
+
toolbar: {
|
161
|
+
actions: {
|
162
|
+
save: {
|
163
|
+
title: 'Save changes',
|
164
|
+
text: 'Save'
|
165
|
+
},
|
166
|
+
cancel: {
|
167
|
+
title: 'Cancel editing, discards all changes',
|
168
|
+
text: 'Cancel'
|
169
|
+
},
|
170
|
+
clearAll:{
|
171
|
+
title: 'Clear all layers',
|
172
|
+
text: 'Clear All'
|
173
|
+
}
|
174
|
+
},
|
175
|
+
buttons: {
|
176
|
+
edit: 'Edit layers',
|
177
|
+
editDisabled: 'No layers to edit',
|
178
|
+
remove: 'Delete layers',
|
179
|
+
removeDisabled: 'No layers to delete'
|
180
|
+
}
|
181
|
+
},
|
182
|
+
handlers: {
|
183
|
+
edit: {
|
184
|
+
tooltip: {
|
185
|
+
text: 'Drag handles or markers to edit features.',
|
186
|
+
subtext: 'Click cancel to undo changes.'
|
187
|
+
}
|
188
|
+
},
|
189
|
+
remove: {
|
190
|
+
tooltip: {
|
191
|
+
text: 'Click on a feature to remove.'
|
192
|
+
}
|
193
|
+
}
|
194
|
+
}
|
195
|
+
}
|
196
|
+
};
|
197
|
+
|
198
|
+
|
199
|
+
|
200
|
+
/**
|
201
|
+
* ### Events
|
202
|
+
* Once you have successfully added the Leaflet.draw plugin to your map you will want to respond to the different
|
203
|
+
* actions users can initiate. The following events will be triggered on the map:
|
204
|
+
*
|
205
|
+
* @class L.Draw.Event
|
206
|
+
* @aka Draw.Event
|
207
|
+
*
|
208
|
+
* Use `L.Draw.Event.EVENTNAME` constants to ensure events are correct.
|
209
|
+
*
|
210
|
+
* @example
|
211
|
+
* ```js
|
212
|
+
* map.on(L.Draw.Event.CREATED; function (e) {
|
213
|
+
* var type = e.layerType,
|
214
|
+
* layer = e.layer;
|
215
|
+
*
|
216
|
+
* if (type === 'marker') {
|
217
|
+
* // Do marker specific actions
|
218
|
+
* }
|
219
|
+
*
|
220
|
+
* // Do whatever else you need to. (save to db; add to map etc)
|
221
|
+
* map.addLayer(layer);
|
222
|
+
*});
|
223
|
+
* ```
|
224
|
+
*/
|
225
|
+
L.Draw.Event = {};
|
226
|
+
/**
|
227
|
+
* @event draw:created: PolyLine; Polygon; Rectangle; Circle; Marker | String
|
228
|
+
*
|
229
|
+
* Layer that was just created.
|
230
|
+
* The type of layer this is. One of: `polyline`; `polygon`; `rectangle`; `circle`; `marker`
|
231
|
+
* Triggered when a new vector or marker has been created.
|
232
|
+
*
|
233
|
+
*/
|
234
|
+
L.Draw.Event.CREATED = 'draw:created';
|
235
|
+
|
236
|
+
/**
|
237
|
+
* @event draw:edited: LayerGroup
|
238
|
+
*
|
239
|
+
* List of all layers just edited on the map.
|
240
|
+
*
|
241
|
+
*
|
242
|
+
* Triggered when layers in the FeatureGroup; initialised with the plugin; have been edited and saved.
|
243
|
+
*
|
244
|
+
* @example
|
245
|
+
* ```js
|
246
|
+
* map.on('draw:edited', function (e) {
|
247
|
+
* var layers = e.layers;
|
248
|
+
* layers.eachLayer(function (layer) {
|
249
|
+
* //do whatever you want; most likely save back to db
|
250
|
+
* });
|
251
|
+
* });
|
252
|
+
* ```
|
253
|
+
*/
|
254
|
+
L.Draw.Event.EDITED = 'draw:edited';
|
255
|
+
|
256
|
+
/**
|
257
|
+
* @event draw:deleted: LayerGroup
|
258
|
+
*
|
259
|
+
* List of all layers just removed from the map.
|
260
|
+
*
|
261
|
+
* Triggered when layers have been removed (and saved) from the FeatureGroup.
|
262
|
+
*/
|
263
|
+
L.Draw.Event.DELETED = 'draw:deleted';
|
264
|
+
|
265
|
+
/**
|
266
|
+
* @event draw:drawstart: String
|
267
|
+
*
|
268
|
+
* The type of layer this is. One of:`polyline`; `polygon`; `rectangle`; `circle`; `marker`
|
269
|
+
*
|
270
|
+
* Triggered when the user has chosen to draw a particular vector or marker.
|
271
|
+
*/
|
272
|
+
L.Draw.Event.DRAWSTART = 'draw:drawstart';
|
273
|
+
|
274
|
+
/**
|
275
|
+
* @event draw:drawstop: String
|
276
|
+
*
|
277
|
+
* The type of layer this is. One of: `polyline`; `polygon`; `rectangle`; `circle`; `marker`
|
278
|
+
*
|
279
|
+
* Triggered when the user has finished a particular vector or marker.
|
280
|
+
*/
|
281
|
+
|
282
|
+
L.Draw.Event.DRAWSTOP = 'draw:drawstop';
|
283
|
+
|
284
|
+
/**
|
285
|
+
* @event draw:drawvertex: LayerGroup
|
286
|
+
*
|
287
|
+
* List of all layers just being added from the map.
|
288
|
+
*
|
289
|
+
* Triggered when a vertex is created on a polyline or polygon.
|
290
|
+
*/
|
291
|
+
L.Draw.Event.DRAWVERTEX = 'draw:drawvertex';
|
292
|
+
|
293
|
+
/**
|
294
|
+
* @event draw:editstart: String
|
295
|
+
*
|
296
|
+
* The type of edit this is. One of: `edit`
|
297
|
+
*
|
298
|
+
* Triggered when the user starts edit mode by clicking the edit tool button.
|
299
|
+
*/
|
300
|
+
|
301
|
+
L.Draw.Event.EDITSTART = 'draw:editstart';
|
302
|
+
|
303
|
+
/**
|
304
|
+
* @event draw:editmove: ILayer
|
305
|
+
*
|
306
|
+
* Layer that was just moved.
|
307
|
+
*
|
308
|
+
* Triggered as the user moves a rectangle; circle or marker.
|
309
|
+
*/
|
310
|
+
L.Draw.Event.EDITMOVE = 'draw:editmove';
|
311
|
+
|
312
|
+
/**
|
313
|
+
* @event draw:editresize: ILayer
|
314
|
+
*
|
315
|
+
* Layer that was just moved.
|
316
|
+
*
|
317
|
+
* Triggered as the user resizes a rectangle or circle.
|
318
|
+
*/
|
319
|
+
L.Draw.Event.EDITRESIZE = 'draw:editresize';
|
320
|
+
|
321
|
+
/**
|
322
|
+
* @event draw:editvertex: LayerGroup
|
323
|
+
*
|
324
|
+
* List of all layers just being edited from the map.
|
325
|
+
*
|
326
|
+
* Triggered when a vertex is edited on a polyline or polygon.
|
327
|
+
*/
|
328
|
+
L.Draw.Event.EDITVERTEX = 'draw:editvertex';
|
329
|
+
|
330
|
+
/**
|
331
|
+
* @event draw:editstop: String
|
332
|
+
*
|
333
|
+
* The type of edit this is. One of: `edit`
|
334
|
+
*
|
335
|
+
* Triggered when the user has finshed editing (edit mode) and saves edits.
|
336
|
+
*/
|
337
|
+
L.Draw.Event.EDITSTOP = 'draw:editstop';
|
338
|
+
|
339
|
+
/**
|
340
|
+
* @event draw:deletestart: String
|
341
|
+
*
|
342
|
+
* The type of edit this is. One of: `remove`
|
343
|
+
*
|
344
|
+
* Triggered when the user starts remove mode by clicking the remove tool button.
|
345
|
+
*/
|
346
|
+
L.Draw.Event.DELETESTART = 'draw:deletestart';
|
347
|
+
|
348
|
+
/**
|
349
|
+
* @event draw:deletestop: String
|
350
|
+
*
|
351
|
+
* The type of edit this is. One of: `remove`
|
352
|
+
*
|
353
|
+
* Triggered when the user has finished removing shapes (remove mode) and saves.
|
354
|
+
*/
|
355
|
+
L.Draw.Event.DELETESTOP = 'draw:deletestop';
|
356
|
+
|
357
|
+
|
358
|
+
|
359
|
+
L.Draw = L.Draw || {};
|
360
|
+
|
361
|
+
/**
|
362
|
+
* @class L.Draw.Feature
|
363
|
+
* @aka Draw.Feature
|
364
|
+
*/
|
365
|
+
L.Draw.Feature = L.Handler.extend({
|
366
|
+
includes: L.Mixin.Events,
|
367
|
+
|
368
|
+
// @method initialize(): void
|
369
|
+
initialize: function (map, options) {
|
370
|
+
this._map = map;
|
371
|
+
this._container = map._container;
|
372
|
+
this._overlayPane = map._panes.overlayPane;
|
373
|
+
this._popupPane = map._panes.popupPane;
|
374
|
+
|
375
|
+
// Merge default shapeOptions options with custom shapeOptions
|
376
|
+
if (options && options.shapeOptions) {
|
377
|
+
options.shapeOptions = L.Util.extend({}, this.options.shapeOptions, options.shapeOptions);
|
378
|
+
}
|
379
|
+
L.setOptions(this, options);
|
380
|
+
},
|
381
|
+
|
382
|
+
// @method enable(): void
|
383
|
+
// Enables this handler
|
384
|
+
enable: function () {
|
385
|
+
if (this._enabled) {
|
386
|
+
return;
|
387
|
+
}
|
388
|
+
|
389
|
+
L.Handler.prototype.enable.call(this);
|
390
|
+
|
391
|
+
this.fire('enabled', { handler: this.type });
|
392
|
+
|
393
|
+
this._map.fire(L.Draw.Event.DRAWSTART, { layerType: this.type });
|
394
|
+
},
|
395
|
+
|
396
|
+
// @method disable(): void
|
397
|
+
disable: function () {
|
398
|
+
if (!this._enabled) {
|
399
|
+
return;
|
400
|
+
}
|
401
|
+
|
402
|
+
L.Handler.prototype.disable.call(this);
|
403
|
+
|
404
|
+
this._map.fire(L.Draw.Event.DRAWSTOP, { layerType: this.type });
|
405
|
+
|
406
|
+
this.fire('disabled', { handler: this.type });
|
407
|
+
},
|
408
|
+
|
409
|
+
// @method addHooks(): void
|
410
|
+
// Add's event listeners to this handler
|
411
|
+
addHooks: function () {
|
412
|
+
var map = this._map;
|
413
|
+
|
414
|
+
if (map) {
|
415
|
+
L.DomUtil.disableTextSelection();
|
416
|
+
|
417
|
+
map.getContainer().focus();
|
418
|
+
|
419
|
+
this._tooltip = new L.Draw.Tooltip(this._map);
|
420
|
+
|
421
|
+
L.DomEvent.on(this._container, 'keyup', this._cancelDrawing, this);
|
422
|
+
}
|
423
|
+
},
|
424
|
+
|
425
|
+
// @method removeHooks(): void
|
426
|
+
// Removes event listeners from this handler
|
427
|
+
removeHooks: function () {
|
428
|
+
if (this._map) {
|
429
|
+
L.DomUtil.enableTextSelection();
|
430
|
+
|
431
|
+
this._tooltip.dispose();
|
432
|
+
this._tooltip = null;
|
433
|
+
|
434
|
+
L.DomEvent.off(this._container, 'keyup', this._cancelDrawing, this);
|
435
|
+
}
|
436
|
+
},
|
437
|
+
|
438
|
+
// @method setOptions(object): void
|
439
|
+
// Sets new options to this handler
|
440
|
+
setOptions: function (options) {
|
441
|
+
L.setOptions(this, options);
|
442
|
+
},
|
443
|
+
|
444
|
+
_fireCreatedEvent: function (layer) {
|
445
|
+
this._map.fire(L.Draw.Event.CREATED, { layer: layer, layerType: this.type });
|
446
|
+
},
|
447
|
+
|
448
|
+
// Cancel drawing when the escape key is pressed
|
449
|
+
_cancelDrawing: function (e) {
|
450
|
+
if (e.keyCode === 27) {
|
451
|
+
this._map.fire('draw:canceled', { layerType: this.type });
|
452
|
+
this.disable();
|
453
|
+
}
|
454
|
+
}
|
455
|
+
});
|
456
|
+
|
457
|
+
|
458
|
+
|
459
|
+
/**
|
460
|
+
* @class L.Draw.Polyline
|
461
|
+
* @aka Draw.Polyline
|
462
|
+
* @inherits L.Draw.Feature
|
463
|
+
*/
|
464
|
+
L.Draw.Polyline = L.Draw.Feature.extend({
|
465
|
+
statics: {
|
466
|
+
TYPE: 'polyline'
|
467
|
+
},
|
468
|
+
|
469
|
+
Poly: L.Polyline,
|
470
|
+
|
471
|
+
options: {
|
472
|
+
allowIntersection: true,
|
473
|
+
repeatMode: false,
|
474
|
+
drawError: {
|
475
|
+
color: '#b00b00',
|
476
|
+
timeout: 2500
|
477
|
+
},
|
478
|
+
icon: new L.DivIcon({
|
479
|
+
iconSize: new L.Point(8, 8),
|
480
|
+
className: 'leaflet-div-icon leaflet-editing-icon'
|
481
|
+
}),
|
482
|
+
touchIcon: new L.DivIcon({
|
483
|
+
iconSize: new L.Point(20, 20),
|
484
|
+
className: 'leaflet-div-icon leaflet-editing-icon leaflet-touch-icon'
|
485
|
+
}),
|
486
|
+
guidelineDistance: 20,
|
487
|
+
maxGuideLineLength: 4000,
|
488
|
+
shapeOptions: {
|
489
|
+
stroke: true,
|
490
|
+
color: '#3388ff',
|
491
|
+
weight: 4,
|
492
|
+
opacity: 0.5,
|
493
|
+
fill: false,
|
494
|
+
clickable: true
|
495
|
+
},
|
496
|
+
metric: true, // Whether to use the metric measurement system or imperial
|
497
|
+
feet: true, // When not metric, to use feet instead of yards for display.
|
498
|
+
nautic: false, // When not metric, not feet use nautic mile for display
|
499
|
+
showLength: true, // Whether to display distance in the tooltip
|
500
|
+
zIndexOffset: 2000, // This should be > than the highest z-index any map layers
|
501
|
+
factor: 1 // To change distance calculation
|
502
|
+
},
|
503
|
+
|
504
|
+
// @method initialize(): void
|
505
|
+
initialize: function (map, options) {
|
506
|
+
// if touch, switch to touch icon
|
507
|
+
if (L.Browser.touch) {
|
508
|
+
this.options.icon = this.options.touchIcon;
|
509
|
+
}
|
510
|
+
|
511
|
+
// Need to set this here to ensure the correct message is used.
|
512
|
+
this.options.drawError.message = L.drawLocal.draw.handlers.polyline.error;
|
513
|
+
|
514
|
+
// Merge default drawError options with custom options
|
515
|
+
if (options && options.drawError) {
|
516
|
+
options.drawError = L.Util.extend({}, this.options.drawError, options.drawError);
|
517
|
+
}
|
518
|
+
|
519
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
520
|
+
this.type = L.Draw.Polyline.TYPE;
|
521
|
+
|
522
|
+
L.Draw.Feature.prototype.initialize.call(this, map, options);
|
523
|
+
},
|
524
|
+
|
525
|
+
// @method addHooks(): void
|
526
|
+
// Add listener hooks to this handler
|
527
|
+
addHooks: function () {
|
528
|
+
L.Draw.Feature.prototype.addHooks.call(this);
|
529
|
+
if (this._map) {
|
530
|
+
this._markers = [];
|
531
|
+
|
532
|
+
this._markerGroup = new L.LayerGroup();
|
533
|
+
this._map.addLayer(this._markerGroup);
|
534
|
+
|
535
|
+
this._poly = new L.Polyline([], this.options.shapeOptions);
|
536
|
+
|
537
|
+
this._tooltip.updateContent(this._getTooltipText());
|
538
|
+
|
539
|
+
// Make a transparent marker that will used to catch click events. These click
|
540
|
+
// events will create the vertices. We need to do this so we can ensure that
|
541
|
+
// we can create vertices over other map layers (markers, vector layers). We
|
542
|
+
// also do not want to trigger any click handlers of objects we are clicking on
|
543
|
+
// while drawing.
|
544
|
+
if (!this._mouseMarker) {
|
545
|
+
this._mouseMarker = L.marker(this._map.getCenter(), {
|
546
|
+
icon: L.divIcon({
|
547
|
+
className: 'leaflet-mouse-marker',
|
548
|
+
iconAnchor: [20, 20],
|
549
|
+
iconSize: [40, 40]
|
550
|
+
}),
|
551
|
+
opacity: 0,
|
552
|
+
zIndexOffset: this.options.zIndexOffset
|
553
|
+
});
|
554
|
+
}
|
555
|
+
|
556
|
+
this._mouseMarker
|
557
|
+
.on('mouseout', this._onMouseOut, this)
|
558
|
+
.on('mousemove', this._onMouseMove, this) // Necessary to prevent 0.8 stutter
|
559
|
+
.on('mousedown', this._onMouseDown, this)
|
560
|
+
.on('mouseup', this._onMouseUp, this) // Necessary for 0.8 compatibility
|
561
|
+
.addTo(this._map);
|
562
|
+
|
563
|
+
this._map
|
564
|
+
.on('mouseup', this._onMouseUp, this) // Necessary for 0.7 compatibility
|
565
|
+
.on('mousemove', this._onMouseMove, this)
|
566
|
+
.on('zoomlevelschange', this._onZoomEnd, this)
|
567
|
+
.on('touchstart', this._onTouch, this)
|
568
|
+
.on('zoomend', this._onZoomEnd, this);
|
569
|
+
|
570
|
+
}
|
571
|
+
},
|
572
|
+
|
573
|
+
// @method removeHooks(): void
|
574
|
+
// Remove listener hooks from this handler.
|
575
|
+
removeHooks: function () {
|
576
|
+
L.Draw.Feature.prototype.removeHooks.call(this);
|
577
|
+
|
578
|
+
this._clearHideErrorTimeout();
|
579
|
+
|
580
|
+
this._cleanUpShape();
|
581
|
+
|
582
|
+
// remove markers from map
|
583
|
+
this._map.removeLayer(this._markerGroup);
|
584
|
+
delete this._markerGroup;
|
585
|
+
delete this._markers;
|
586
|
+
|
587
|
+
this._map.removeLayer(this._poly);
|
588
|
+
delete this._poly;
|
589
|
+
|
590
|
+
this._mouseMarker
|
591
|
+
.off('mousedown', this._onMouseDown, this)
|
592
|
+
.off('mouseout', this._onMouseOut, this)
|
593
|
+
.off('mouseup', this._onMouseUp, this)
|
594
|
+
.off('mousemove', this._onMouseMove, this);
|
595
|
+
this._map.removeLayer(this._mouseMarker);
|
596
|
+
delete this._mouseMarker;
|
597
|
+
|
598
|
+
// clean up DOM
|
599
|
+
this._clearGuides();
|
600
|
+
|
601
|
+
this._map
|
602
|
+
.off('mouseup', this._onMouseUp, this)
|
603
|
+
.off('mousemove', this._onMouseMove, this)
|
604
|
+
.off('zoomlevelschange', this._onZoomEnd, this)
|
605
|
+
.off('zoomend', this._onZoomEnd, this)
|
606
|
+
.off('touchstart', this._onTouch, this)
|
607
|
+
.off('click', this._onTouch, this);
|
608
|
+
},
|
609
|
+
|
610
|
+
// @method deleteLastVertex(): void
|
611
|
+
// Remove the last vertex from the polyline, removes polyline from map if only one point exists.
|
612
|
+
deleteLastVertex: function () {
|
613
|
+
if (this._markers.length <= 1) {
|
614
|
+
return;
|
615
|
+
}
|
616
|
+
|
617
|
+
var lastMarker = this._markers.pop(),
|
618
|
+
poly = this._poly,
|
619
|
+
// Replaces .spliceLatLngs()
|
620
|
+
latlngs = poly.getLatLngs(),
|
621
|
+
latlng = latlngs.splice(-1, 1)[0];
|
622
|
+
this._poly.setLatLngs(latlngs);
|
623
|
+
|
624
|
+
this._markerGroup.removeLayer(lastMarker);
|
625
|
+
|
626
|
+
if (poly.getLatLngs().length < 2) {
|
627
|
+
this._map.removeLayer(poly);
|
628
|
+
}
|
629
|
+
|
630
|
+
this._vertexChanged(latlng, false);
|
631
|
+
},
|
632
|
+
|
633
|
+
// @method addVertex(): void
|
634
|
+
// Add a vertex to the end of the polyline
|
635
|
+
addVertex: function (latlng) {
|
636
|
+
var markersLength = this._markers.length;
|
637
|
+
// markersLength must be greater than or equal to 2 before intersections can occur
|
638
|
+
if (markersLength >= 2 && !this.options.allowIntersection && this._poly.newLatLngIntersects(latlng)) {
|
639
|
+
this._showErrorTooltip();
|
640
|
+
return;
|
641
|
+
}
|
642
|
+
else if (this._errorShown) {
|
643
|
+
this._hideErrorTooltip();
|
644
|
+
}
|
645
|
+
|
646
|
+
this._markers.push(this._createMarker(latlng));
|
647
|
+
|
648
|
+
this._poly.addLatLng(latlng);
|
649
|
+
|
650
|
+
if (this._poly.getLatLngs().length === 2) {
|
651
|
+
this._map.addLayer(this._poly);
|
652
|
+
}
|
653
|
+
|
654
|
+
this._vertexChanged(latlng, true);
|
655
|
+
},
|
656
|
+
|
657
|
+
// @method completeShape(): void
|
658
|
+
// Closes the polyline between the first and last points
|
659
|
+
completeShape: function () {
|
660
|
+
if (this._markers.length <= 1) {
|
661
|
+
return;
|
662
|
+
}
|
663
|
+
|
664
|
+
this._fireCreatedEvent();
|
665
|
+
this.disable();
|
666
|
+
|
667
|
+
if (this.options.repeatMode) {
|
668
|
+
this.enable();
|
669
|
+
}
|
670
|
+
},
|
671
|
+
|
672
|
+
_finishShape: function () {
|
673
|
+
var latlngs = this._poly._defaultShape ? this._poly._defaultShape() : this._poly.getLatLngs();
|
674
|
+
var intersects = this._poly.newLatLngIntersects(latlngs[latlngs.length - 1]);
|
675
|
+
|
676
|
+
if ((!this.options.allowIntersection && intersects) || !this._shapeIsValid()) {
|
677
|
+
this._showErrorTooltip();
|
678
|
+
return;
|
679
|
+
}
|
680
|
+
|
681
|
+
this._fireCreatedEvent();
|
682
|
+
this.disable();
|
683
|
+
if (this.options.repeatMode) {
|
684
|
+
this.enable();
|
685
|
+
}
|
686
|
+
},
|
687
|
+
|
688
|
+
// Called to verify the shape is valid when the user tries to finish it
|
689
|
+
// Return false if the shape is not valid
|
690
|
+
_shapeIsValid: function () {
|
691
|
+
return true;
|
692
|
+
},
|
693
|
+
|
694
|
+
_onZoomEnd: function () {
|
695
|
+
if (this._markers !== null) {
|
696
|
+
this._updateGuide();
|
697
|
+
}
|
698
|
+
},
|
699
|
+
|
700
|
+
_onMouseMove: function (e) {
|
701
|
+
var newPos = this._map.mouseEventToLayerPoint(e.originalEvent);
|
702
|
+
var latlng = this._map.layerPointToLatLng(newPos);
|
703
|
+
|
704
|
+
// Save latlng
|
705
|
+
// should this be moved to _updateGuide() ?
|
706
|
+
this._currentLatLng = latlng;
|
707
|
+
|
708
|
+
this._updateTooltip(latlng);
|
709
|
+
|
710
|
+
// Update the guide line
|
711
|
+
this._updateGuide(newPos);
|
712
|
+
|
713
|
+
// Update the mouse marker position
|
714
|
+
this._mouseMarker.setLatLng(latlng);
|
715
|
+
|
716
|
+
L.DomEvent.preventDefault(e.originalEvent);
|
717
|
+
},
|
718
|
+
|
719
|
+
_vertexChanged: function (latlng, added) {
|
720
|
+
this._map.fire(L.Draw.Event.DRAWVERTEX, { layers: this._markerGroup });
|
721
|
+
this._updateFinishHandler();
|
722
|
+
|
723
|
+
this._updateRunningMeasure(latlng, added);
|
724
|
+
|
725
|
+
this._clearGuides();
|
726
|
+
|
727
|
+
this._updateTooltip();
|
728
|
+
},
|
729
|
+
|
730
|
+
_onMouseDown: function (e) {
|
731
|
+
if (!this._clickHandled && !this._touchHandled && !this._disableMarkers) {
|
732
|
+
this._onMouseMove(e);
|
733
|
+
this._clickHandled = true;
|
734
|
+
this._disableNewMarkers();
|
735
|
+
var originalEvent = e.originalEvent;
|
736
|
+
var clientX = originalEvent.clientX;
|
737
|
+
var clientY = originalEvent.clientY;
|
738
|
+
this._startPoint.call(this, clientX, clientY);
|
739
|
+
}
|
740
|
+
},
|
741
|
+
|
742
|
+
_startPoint: function (clientX, clientY) {
|
743
|
+
this._mouseDownOrigin = L.point(clientX, clientY);
|
744
|
+
},
|
745
|
+
|
746
|
+
_onMouseUp: function (e) {
|
747
|
+
var originalEvent = e.originalEvent;
|
748
|
+
var clientX = originalEvent.clientX;
|
749
|
+
var clientY = originalEvent.clientY;
|
750
|
+
this._endPoint.call(this, clientX, clientY, e);
|
751
|
+
this._clickHandled = null;
|
752
|
+
},
|
753
|
+
|
754
|
+
_endPoint: function (clientX, clientY, e) {
|
755
|
+
if (this._mouseDownOrigin) {
|
756
|
+
var dragCheckDistance = L.point(clientX, clientY)
|
757
|
+
.distanceTo(this._mouseDownOrigin);
|
758
|
+
var lastPtDistance = this._calculateFinishDistance(e.latlng);
|
759
|
+
if (lastPtDistance < 10 && L.Browser.touch) {
|
760
|
+
this._finishShape();
|
761
|
+
} else if (Math.abs(dragCheckDistance) < 9 * (window.devicePixelRatio || 1)) {
|
762
|
+
this.addVertex(e.latlng);
|
763
|
+
}
|
764
|
+
this._enableNewMarkers(); // after a short pause, enable new markers
|
765
|
+
}
|
766
|
+
this._mouseDownOrigin = null;
|
767
|
+
},
|
768
|
+
|
769
|
+
// ontouch prevented by clickHandled flag because some browsers fire both click/touch events,
|
770
|
+
// causing unwanted behavior
|
771
|
+
_onTouch: function (e) {
|
772
|
+
var originalEvent = e.originalEvent;
|
773
|
+
var clientX;
|
774
|
+
var clientY;
|
775
|
+
if (originalEvent.touches && originalEvent.touches[0] && !this._clickHandled && !this._touchHandled && !this._disableMarkers) {
|
776
|
+
clientX = originalEvent.touches[0].clientX;
|
777
|
+
clientY = originalEvent.touches[0].clientY;
|
778
|
+
this._disableNewMarkers();
|
779
|
+
this._touchHandled = true;
|
780
|
+
this._startPoint.call(this, clientX, clientY);
|
781
|
+
this._endPoint.call(this, clientX, clientY, e);
|
782
|
+
this._touchHandled = null;
|
783
|
+
}
|
784
|
+
this._clickHandled = null;
|
785
|
+
},
|
786
|
+
|
787
|
+
_onMouseOut: function () {
|
788
|
+
if (this._tooltip) {
|
789
|
+
this._tooltip._onMouseOut.call(this._tooltip);
|
790
|
+
}
|
791
|
+
},
|
792
|
+
|
793
|
+
// calculate if we are currently within close enough distance
|
794
|
+
// of the closing point (first point for shapes, last point for lines)
|
795
|
+
// this is semi-ugly code but the only reliable way i found to get the job done
|
796
|
+
// note: calculating point.distanceTo between mouseDownOrigin and last marker did NOT work
|
797
|
+
_calculateFinishDistance: function (potentialLatLng) {
|
798
|
+
var lastPtDistance
|
799
|
+
if (this._markers.length > 0) {
|
800
|
+
var finishMarker;
|
801
|
+
if (this.type === L.Draw.Polyline.TYPE) {
|
802
|
+
finishMarker = this._markers[this._markers.length - 1];
|
803
|
+
} else if (this.type === L.Draw.Polygon.TYPE) {
|
804
|
+
finishMarker = this._markers[0];
|
805
|
+
} else {
|
806
|
+
return Infinity;
|
807
|
+
}
|
808
|
+
var lastMarkerPoint = this._map.latLngToContainerPoint(finishMarker.getLatLng()),
|
809
|
+
potentialMarker = new L.Marker(potentialLatLng, {
|
810
|
+
icon: this.options.icon,
|
811
|
+
zIndexOffset: this.options.zIndexOffset * 2
|
812
|
+
});
|
813
|
+
var potentialMarkerPint = this._map.latLngToContainerPoint(potentialMarker.getLatLng());
|
814
|
+
lastPtDistance = lastMarkerPoint.distanceTo(potentialMarkerPint);
|
815
|
+
} else {
|
816
|
+
lastPtDistance = Infinity;
|
817
|
+
}
|
818
|
+
return lastPtDistance;
|
819
|
+
},
|
820
|
+
|
821
|
+
_updateFinishHandler: function () {
|
822
|
+
var markerCount = this._markers.length;
|
823
|
+
// The last marker should have a click handler to close the polyline
|
824
|
+
if (markerCount > 1) {
|
825
|
+
this._markers[markerCount - 1].on('click', this._finishShape, this);
|
826
|
+
}
|
827
|
+
|
828
|
+
// Remove the old marker click handler (as only the last point should close the polyline)
|
829
|
+
if (markerCount > 2) {
|
830
|
+
this._markers[markerCount - 2].off('click', this._finishShape, this);
|
831
|
+
}
|
832
|
+
},
|
833
|
+
|
834
|
+
_createMarker: function (latlng) {
|
835
|
+
var marker = new L.Marker(latlng, {
|
836
|
+
icon: this.options.icon,
|
837
|
+
zIndexOffset: this.options.zIndexOffset * 2
|
838
|
+
});
|
839
|
+
|
840
|
+
this._markerGroup.addLayer(marker);
|
841
|
+
|
842
|
+
return marker;
|
843
|
+
},
|
844
|
+
|
845
|
+
_updateGuide: function (newPos) {
|
846
|
+
var markerCount = this._markers ? this._markers.length : 0;
|
847
|
+
|
848
|
+
if (markerCount > 0) {
|
849
|
+
newPos = newPos || this._map.latLngToLayerPoint(this._currentLatLng);
|
850
|
+
|
851
|
+
// draw the guide line
|
852
|
+
this._clearGuides();
|
853
|
+
this._drawGuide(
|
854
|
+
this._map.latLngToLayerPoint(this._markers[markerCount - 1].getLatLng()),
|
855
|
+
newPos
|
856
|
+
);
|
857
|
+
}
|
858
|
+
},
|
859
|
+
|
860
|
+
_updateTooltip: function (latLng) {
|
861
|
+
var text = this._getTooltipText();
|
862
|
+
|
863
|
+
if (latLng) {
|
864
|
+
this._tooltip.updatePosition(latLng);
|
865
|
+
}
|
866
|
+
|
867
|
+
if (!this._errorShown) {
|
868
|
+
this._tooltip.updateContent(text);
|
869
|
+
}
|
870
|
+
},
|
871
|
+
|
872
|
+
_drawGuide: function (pointA, pointB) {
|
873
|
+
var length = Math.floor(Math.sqrt(Math.pow((pointB.x - pointA.x), 2) + Math.pow((pointB.y - pointA.y), 2))),
|
874
|
+
guidelineDistance = this.options.guidelineDistance,
|
875
|
+
maxGuideLineLength = this.options.maxGuideLineLength,
|
876
|
+
// Only draw a guideline with a max length
|
877
|
+
i = length > maxGuideLineLength ? length - maxGuideLineLength : guidelineDistance,
|
878
|
+
fraction,
|
879
|
+
dashPoint,
|
880
|
+
dash;
|
881
|
+
|
882
|
+
//create the guides container if we haven't yet
|
883
|
+
if (!this._guidesContainer) {
|
884
|
+
this._guidesContainer = L.DomUtil.create('div', 'leaflet-draw-guides', this._overlayPane);
|
885
|
+
}
|
886
|
+
|
887
|
+
//draw a dash every GuildeLineDistance
|
888
|
+
for (; i < length; i += this.options.guidelineDistance) {
|
889
|
+
//work out fraction along line we are
|
890
|
+
fraction = i / length;
|
891
|
+
|
892
|
+
//calculate new x,y point
|
893
|
+
dashPoint = {
|
894
|
+
x: Math.floor((pointA.x * (1 - fraction)) + (fraction * pointB.x)),
|
895
|
+
y: Math.floor((pointA.y * (1 - fraction)) + (fraction * pointB.y))
|
896
|
+
};
|
897
|
+
|
898
|
+
//add guide dash to guide container
|
899
|
+
dash = L.DomUtil.create('div', 'leaflet-draw-guide-dash', this._guidesContainer);
|
900
|
+
dash.style.backgroundColor =
|
901
|
+
!this._errorShown ? this.options.shapeOptions.color : this.options.drawError.color;
|
902
|
+
|
903
|
+
L.DomUtil.setPosition(dash, dashPoint);
|
904
|
+
}
|
905
|
+
},
|
906
|
+
|
907
|
+
_updateGuideColor: function (color) {
|
908
|
+
if (this._guidesContainer) {
|
909
|
+
for (var i = 0, l = this._guidesContainer.childNodes.length; i < l; i++) {
|
910
|
+
this._guidesContainer.childNodes[i].style.backgroundColor = color;
|
911
|
+
}
|
912
|
+
}
|
913
|
+
},
|
914
|
+
|
915
|
+
// removes all child elements (guide dashes) from the guides container
|
916
|
+
_clearGuides: function () {
|
917
|
+
if (this._guidesContainer) {
|
918
|
+
while (this._guidesContainer.firstChild) {
|
919
|
+
this._guidesContainer.removeChild(this._guidesContainer.firstChild);
|
920
|
+
}
|
921
|
+
}
|
922
|
+
},
|
923
|
+
|
924
|
+
_getTooltipText: function () {
|
925
|
+
var showLength = this.options.showLength,
|
926
|
+
labelText, distanceStr;
|
927
|
+
if (L.Browser.touch) {
|
928
|
+
showLength = false; // if there's a better place to put this, feel free to move it
|
929
|
+
}
|
930
|
+
if (this._markers.length === 0) {
|
931
|
+
labelText = {
|
932
|
+
text: L.drawLocal.draw.handlers.polyline.tooltip.start
|
933
|
+
};
|
934
|
+
} else {
|
935
|
+
distanceStr = showLength ? this._getMeasurementString() : '';
|
936
|
+
|
937
|
+
if (this._markers.length === 1) {
|
938
|
+
labelText = {
|
939
|
+
text: L.drawLocal.draw.handlers.polyline.tooltip.cont,
|
940
|
+
subtext: distanceStr
|
941
|
+
};
|
942
|
+
} else {
|
943
|
+
labelText = {
|
944
|
+
text: L.drawLocal.draw.handlers.polyline.tooltip.end,
|
945
|
+
subtext: distanceStr
|
946
|
+
};
|
947
|
+
}
|
948
|
+
}
|
949
|
+
return labelText;
|
950
|
+
},
|
951
|
+
|
952
|
+
_updateRunningMeasure: function (latlng, added) {
|
953
|
+
var markersLength = this._markers.length,
|
954
|
+
previousMarkerIndex, distance;
|
955
|
+
|
956
|
+
if (this._markers.length === 1) {
|
957
|
+
this._measurementRunningTotal = 0;
|
958
|
+
} else {
|
959
|
+
previousMarkerIndex = markersLength - (added ? 2 : 1);
|
960
|
+
distance = this._map.distance(latlng, this._markers[previousMarkerIndex].getLatLng()) * (this.options.factor || 1);
|
961
|
+
|
962
|
+
this._measurementRunningTotal += distance * (added ? 1 : -1);
|
963
|
+
}
|
964
|
+
},
|
965
|
+
|
966
|
+
_getMeasurementString: function () {
|
967
|
+
var currentLatLng = this._currentLatLng,
|
968
|
+
previousLatLng = this._markers[this._markers.length - 1].getLatLng(),
|
969
|
+
distance;
|
970
|
+
|
971
|
+
// calculate the distance from the last fixed point to the mouse position
|
972
|
+
distance = previousLatLng && currentLatLng ? this._measurementRunningTotal + this._map.distance(currentLatLng, previousLatLng) * (this.options.factor || 1) : this._measurementRunningTotal || 0 ;
|
973
|
+
|
974
|
+
return L.GeometryUtil.readableDistance(distance, this.options.metric, this.options.feet, this.options.nautic, this.options.precision);
|
975
|
+
},
|
976
|
+
|
977
|
+
_showErrorTooltip: function () {
|
978
|
+
this._errorShown = true;
|
979
|
+
|
980
|
+
// Update tooltip
|
981
|
+
this._tooltip
|
982
|
+
.showAsError()
|
983
|
+
.updateContent({ text: this.options.drawError.message });
|
984
|
+
|
985
|
+
// Update shape
|
986
|
+
this._updateGuideColor(this.options.drawError.color);
|
987
|
+
this._poly.setStyle({ color: this.options.drawError.color });
|
988
|
+
|
989
|
+
// Hide the error after 2 seconds
|
990
|
+
this._clearHideErrorTimeout();
|
991
|
+
this._hideErrorTimeout = setTimeout(L.Util.bind(this._hideErrorTooltip, this), this.options.drawError.timeout);
|
992
|
+
},
|
993
|
+
|
994
|
+
_hideErrorTooltip: function () {
|
995
|
+
this._errorShown = false;
|
996
|
+
|
997
|
+
this._clearHideErrorTimeout();
|
998
|
+
|
999
|
+
// Revert tooltip
|
1000
|
+
this._tooltip
|
1001
|
+
.removeError()
|
1002
|
+
.updateContent(this._getTooltipText());
|
1003
|
+
|
1004
|
+
// Revert shape
|
1005
|
+
this._updateGuideColor(this.options.shapeOptions.color);
|
1006
|
+
this._poly.setStyle({ color: this.options.shapeOptions.color });
|
1007
|
+
},
|
1008
|
+
|
1009
|
+
_clearHideErrorTimeout: function () {
|
1010
|
+
if (this._hideErrorTimeout) {
|
1011
|
+
clearTimeout(this._hideErrorTimeout);
|
1012
|
+
this._hideErrorTimeout = null;
|
1013
|
+
}
|
1014
|
+
},
|
1015
|
+
|
1016
|
+
// disable new markers temporarily;
|
1017
|
+
// this is to prevent duplicated touch/click events in some browsers
|
1018
|
+
_disableNewMarkers: function () {
|
1019
|
+
this._disableMarkers = true;
|
1020
|
+
},
|
1021
|
+
|
1022
|
+
// see _disableNewMarkers
|
1023
|
+
_enableNewMarkers: function () {
|
1024
|
+
setTimeout(function() {
|
1025
|
+
this._disableMarkers = false;
|
1026
|
+
}.bind(this), 50);
|
1027
|
+
},
|
1028
|
+
|
1029
|
+
_cleanUpShape: function () {
|
1030
|
+
if (this._markers.length > 1) {
|
1031
|
+
this._markers[this._markers.length - 1].off('click', this._finishShape, this);
|
1032
|
+
}
|
1033
|
+
},
|
1034
|
+
|
1035
|
+
_fireCreatedEvent: function () {
|
1036
|
+
var poly = new this.Poly(this._poly.getLatLngs(), this.options.shapeOptions);
|
1037
|
+
L.Draw.Feature.prototype._fireCreatedEvent.call(this, poly);
|
1038
|
+
}
|
1039
|
+
});
|
1040
|
+
|
1041
|
+
|
1042
|
+
|
1043
|
+
/**
|
1044
|
+
* @class L.Draw.Polygon
|
1045
|
+
* @aka Draw.Polygon
|
1046
|
+
* @inherits L.Draw.Polyline
|
1047
|
+
*/
|
1048
|
+
L.Draw.Polygon = L.Draw.Polyline.extend({
|
1049
|
+
statics: {
|
1050
|
+
TYPE: 'polygon'
|
1051
|
+
},
|
1052
|
+
|
1053
|
+
Poly: L.Polygon,
|
1054
|
+
|
1055
|
+
options: {
|
1056
|
+
showArea: false,
|
1057
|
+
showLength: false,
|
1058
|
+
shapeOptions: {
|
1059
|
+
stroke: true,
|
1060
|
+
color: '#3388ff',
|
1061
|
+
weight: 4,
|
1062
|
+
opacity: 0.5,
|
1063
|
+
fill: true,
|
1064
|
+
fillColor: null, //same as color by default
|
1065
|
+
fillOpacity: 0.2,
|
1066
|
+
clickable: true
|
1067
|
+
},
|
1068
|
+
// Whether to use the metric measurement system (truthy) or not (falsy).
|
1069
|
+
// Also defines the units to use for the metric system as an array of
|
1070
|
+
// strings (e.g. `['ha', 'm']`).
|
1071
|
+
metric: true,
|
1072
|
+
feet: true, // When not metric, to use feet instead of yards for display.
|
1073
|
+
nautic: false, // When not metric, not feet use nautic mile for display
|
1074
|
+
// Defines the precision for each type of unit (e.g. {km: 2, ft: 0}
|
1075
|
+
precision: {}
|
1076
|
+
},
|
1077
|
+
|
1078
|
+
// @method initialize(): void
|
1079
|
+
initialize: function (map, options) {
|
1080
|
+
L.Draw.Polyline.prototype.initialize.call(this, map, options);
|
1081
|
+
|
1082
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
1083
|
+
this.type = L.Draw.Polygon.TYPE;
|
1084
|
+
},
|
1085
|
+
|
1086
|
+
_updateFinishHandler: function () {
|
1087
|
+
var markerCount = this._markers.length;
|
1088
|
+
|
1089
|
+
// The first marker should have a click handler to close the polygon
|
1090
|
+
if (markerCount === 1) {
|
1091
|
+
this._markers[0].on('click', this._finishShape, this);
|
1092
|
+
}
|
1093
|
+
|
1094
|
+
// Add and update the double click handler
|
1095
|
+
if (markerCount > 2) {
|
1096
|
+
this._markers[markerCount - 1].on('dblclick', this._finishShape, this);
|
1097
|
+
// Only need to remove handler if has been added before
|
1098
|
+
if (markerCount > 3) {
|
1099
|
+
this._markers[markerCount - 2].off('dblclick', this._finishShape, this);
|
1100
|
+
}
|
1101
|
+
}
|
1102
|
+
},
|
1103
|
+
|
1104
|
+
_getTooltipText: function () {
|
1105
|
+
var text, subtext;
|
1106
|
+
|
1107
|
+
if (this._markers.length === 0) {
|
1108
|
+
text = L.drawLocal.draw.handlers.polygon.tooltip.start;
|
1109
|
+
} else if (this._markers.length < 3) {
|
1110
|
+
text = L.drawLocal.draw.handlers.polygon.tooltip.cont;
|
1111
|
+
subtext = this._getMeasurementString();
|
1112
|
+
} else {
|
1113
|
+
text = L.drawLocal.draw.handlers.polygon.tooltip.end;
|
1114
|
+
subtext = this._getMeasurementString();
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
return {
|
1118
|
+
text: text,
|
1119
|
+
subtext: subtext
|
1120
|
+
};
|
1121
|
+
},
|
1122
|
+
|
1123
|
+
_getMeasurementString: function () {
|
1124
|
+
var area = this._area,
|
1125
|
+
measurementString = '';
|
1126
|
+
|
1127
|
+
|
1128
|
+
if (!area && !this.options.showLength) {
|
1129
|
+
return null;
|
1130
|
+
}
|
1131
|
+
|
1132
|
+
if (this.options.showLength) {
|
1133
|
+
measurementString = L.Draw.Polyline.prototype._getMeasurementString.call(this);
|
1134
|
+
}
|
1135
|
+
|
1136
|
+
if (area) {
|
1137
|
+
measurementString += '<br>' + L.GeometryUtil.readableArea(area, this.options.metric, this.options.precision);
|
1138
|
+
}
|
1139
|
+
|
1140
|
+
return measurementString;
|
1141
|
+
},
|
1142
|
+
|
1143
|
+
_shapeIsValid: function () {
|
1144
|
+
return this._markers.length >= 3;
|
1145
|
+
},
|
1146
|
+
|
1147
|
+
_vertexChanged: function (latlng, added) {
|
1148
|
+
var latLngs;
|
1149
|
+
|
1150
|
+
// Check to see if we should show the area
|
1151
|
+
if (!this.options.allowIntersection && this.options.showArea) {
|
1152
|
+
latLngs = this._poly.getLatLngs();
|
1153
|
+
|
1154
|
+
this._area = L.GeometryUtil.geodesicArea(latLngs);
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
L.Draw.Polyline.prototype._vertexChanged.call(this, latlng, added);
|
1158
|
+
},
|
1159
|
+
|
1160
|
+
_cleanUpShape: function () {
|
1161
|
+
var markerCount = this._markers.length;
|
1162
|
+
|
1163
|
+
if (markerCount > 0) {
|
1164
|
+
this._markers[0].off('click', this._finishShape, this);
|
1165
|
+
|
1166
|
+
if (markerCount > 2) {
|
1167
|
+
this._markers[markerCount - 1].off('dblclick', this._finishShape, this);
|
1168
|
+
}
|
1169
|
+
}
|
1170
|
+
}
|
1171
|
+
});
|
1172
|
+
|
1173
|
+
|
1174
|
+
|
1175
|
+
L.SimpleShape = {};
|
1176
|
+
/**
|
1177
|
+
* @class L.Draw.SimpleShape
|
1178
|
+
* @aka Draw.SimpleShape
|
1179
|
+
* @inherits L.Draw.Feature
|
1180
|
+
*/
|
1181
|
+
L.Draw.SimpleShape = L.Draw.Feature.extend({
|
1182
|
+
options: {
|
1183
|
+
repeatMode: false
|
1184
|
+
},
|
1185
|
+
|
1186
|
+
// @method initialize(): void
|
1187
|
+
initialize: function (map, options) {
|
1188
|
+
this._endLabelText = L.drawLocal.draw.handlers.simpleshape.tooltip.end;
|
1189
|
+
|
1190
|
+
L.Draw.Feature.prototype.initialize.call(this, map, options);
|
1191
|
+
},
|
1192
|
+
|
1193
|
+
// @method addHooks(): void
|
1194
|
+
// Add listener hooks to this handler.
|
1195
|
+
addHooks: function () {
|
1196
|
+
L.Draw.Feature.prototype.addHooks.call(this);
|
1197
|
+
if (this._map) {
|
1198
|
+
this._mapDraggable = this._map.dragging.enabled();
|
1199
|
+
|
1200
|
+
if (this._mapDraggable) {
|
1201
|
+
this._map.dragging.disable();
|
1202
|
+
}
|
1203
|
+
|
1204
|
+
//TODO refactor: move cursor to styles
|
1205
|
+
this._container.style.cursor = 'crosshair';
|
1206
|
+
|
1207
|
+
this._tooltip.updateContent({ text: this._initialLabelText });
|
1208
|
+
|
1209
|
+
this._map
|
1210
|
+
.on('mousedown', this._onMouseDown, this)
|
1211
|
+
.on('mousemove', this._onMouseMove, this)
|
1212
|
+
.on('touchstart', this._onMouseDown, this)
|
1213
|
+
.on('touchmove', this._onMouseMove, this);
|
1214
|
+
}
|
1215
|
+
},
|
1216
|
+
|
1217
|
+
// @method removeHooks(): void
|
1218
|
+
// Remove listener hooks from this handler.
|
1219
|
+
removeHooks: function () {
|
1220
|
+
L.Draw.Feature.prototype.removeHooks.call(this);
|
1221
|
+
if (this._map) {
|
1222
|
+
if (this._mapDraggable) {
|
1223
|
+
this._map.dragging.enable();
|
1224
|
+
}
|
1225
|
+
|
1226
|
+
//TODO refactor: move cursor to styles
|
1227
|
+
this._container.style.cursor = '';
|
1228
|
+
|
1229
|
+
this._map
|
1230
|
+
.off('mousedown', this._onMouseDown, this)
|
1231
|
+
.off('mousemove', this._onMouseMove, this)
|
1232
|
+
.off('touchstart', this._onMouseDown, this)
|
1233
|
+
.off('touchmove', this._onMouseMove, this);
|
1234
|
+
|
1235
|
+
L.DomEvent.off(document, 'mouseup', this._onMouseUp, this);
|
1236
|
+
L.DomEvent.off(document, 'touchend', this._onMouseUp, this);
|
1237
|
+
|
1238
|
+
// If the box element doesn't exist they must not have moved the mouse, so don't need to destroy/return
|
1239
|
+
if (this._shape) {
|
1240
|
+
this._map.removeLayer(this._shape);
|
1241
|
+
delete this._shape;
|
1242
|
+
}
|
1243
|
+
}
|
1244
|
+
this._isDrawing = false;
|
1245
|
+
},
|
1246
|
+
|
1247
|
+
_getTooltipText: function () {
|
1248
|
+
return {
|
1249
|
+
text: this._endLabelText
|
1250
|
+
};
|
1251
|
+
},
|
1252
|
+
|
1253
|
+
_onMouseDown: function (e) {
|
1254
|
+
this._isDrawing = true;
|
1255
|
+
this._startLatLng = e.latlng;
|
1256
|
+
|
1257
|
+
L.DomEvent
|
1258
|
+
.on(document, 'mouseup', this._onMouseUp, this)
|
1259
|
+
.on(document, 'touchend', this._onMouseUp, this)
|
1260
|
+
.preventDefault(e.originalEvent);
|
1261
|
+
},
|
1262
|
+
|
1263
|
+
_onMouseMove: function (e) {
|
1264
|
+
var latlng = e.latlng;
|
1265
|
+
|
1266
|
+
this._tooltip.updatePosition(latlng);
|
1267
|
+
if (this._isDrawing) {
|
1268
|
+
this._tooltip.updateContent(this._getTooltipText());
|
1269
|
+
this._drawShape(latlng);
|
1270
|
+
}
|
1271
|
+
},
|
1272
|
+
|
1273
|
+
_onMouseUp: function () {
|
1274
|
+
if (this._shape) {
|
1275
|
+
this._fireCreatedEvent();
|
1276
|
+
}
|
1277
|
+
|
1278
|
+
this.disable();
|
1279
|
+
if (this.options.repeatMode) {
|
1280
|
+
this.enable();
|
1281
|
+
}
|
1282
|
+
}
|
1283
|
+
});
|
1284
|
+
|
1285
|
+
|
1286
|
+
/**
|
1287
|
+
* @class L.Draw.Rectangle
|
1288
|
+
* @aka Draw.Rectangle
|
1289
|
+
* @inherits L.Draw.SimpleShape
|
1290
|
+
*/
|
1291
|
+
L.Draw.Rectangle = L.Draw.SimpleShape.extend({
|
1292
|
+
statics: {
|
1293
|
+
TYPE: 'rectangle'
|
1294
|
+
},
|
1295
|
+
|
1296
|
+
options: {
|
1297
|
+
shapeOptions: {
|
1298
|
+
stroke: true,
|
1299
|
+
color: '#3388ff',
|
1300
|
+
weight: 4,
|
1301
|
+
opacity: 0.5,
|
1302
|
+
fill: true,
|
1303
|
+
fillColor: null, //same as color by default
|
1304
|
+
fillOpacity: 0.2,
|
1305
|
+
showArea: true,
|
1306
|
+
clickable: true
|
1307
|
+
},
|
1308
|
+
metric: true // Whether to use the metric measurement system or imperial
|
1309
|
+
},
|
1310
|
+
|
1311
|
+
// @method initialize(): void
|
1312
|
+
initialize: function (map, options) {
|
1313
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
1314
|
+
this.type = L.Draw.Rectangle.TYPE;
|
1315
|
+
|
1316
|
+
this._initialLabelText = L.drawLocal.draw.handlers.rectangle.tooltip.start;
|
1317
|
+
|
1318
|
+
L.Draw.SimpleShape.prototype.initialize.call(this, map, options);
|
1319
|
+
},
|
1320
|
+
|
1321
|
+
// @method disable(): void
|
1322
|
+
disable: function () {
|
1323
|
+
if (!this._enabled) {
|
1324
|
+
return;
|
1325
|
+
}
|
1326
|
+
|
1327
|
+
this._isCurrentlyTwoClickDrawing = false;
|
1328
|
+
L.Draw.SimpleShape.prototype.disable.call(this);
|
1329
|
+
},
|
1330
|
+
|
1331
|
+
_onMouseUp: function (e) {
|
1332
|
+
if (!this._shape && !this._isCurrentlyTwoClickDrawing) {
|
1333
|
+
this._isCurrentlyTwoClickDrawing = true;
|
1334
|
+
return;
|
1335
|
+
}
|
1336
|
+
|
1337
|
+
// Make sure closing click is on map
|
1338
|
+
if (this._isCurrentlyTwoClickDrawing && !_hasAncestor(e.target, 'leaflet-pane')) {
|
1339
|
+
return;
|
1340
|
+
}
|
1341
|
+
|
1342
|
+
L.Draw.SimpleShape.prototype._onMouseUp.call(this);
|
1343
|
+
},
|
1344
|
+
|
1345
|
+
_drawShape: function (latlng) {
|
1346
|
+
if (!this._shape) {
|
1347
|
+
this._shape = new L.Rectangle(new L.LatLngBounds(this._startLatLng, latlng), this.options.shapeOptions);
|
1348
|
+
this._map.addLayer(this._shape);
|
1349
|
+
} else {
|
1350
|
+
this._shape.setBounds(new L.LatLngBounds(this._startLatLng, latlng));
|
1351
|
+
}
|
1352
|
+
},
|
1353
|
+
|
1354
|
+
_fireCreatedEvent: function () {
|
1355
|
+
var rectangle = new L.Rectangle(this._shape.getBounds(), this.options.shapeOptions);
|
1356
|
+
L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this, rectangle);
|
1357
|
+
},
|
1358
|
+
|
1359
|
+
_getTooltipText: function () {
|
1360
|
+
var tooltipText = L.Draw.SimpleShape.prototype._getTooltipText.call(this),
|
1361
|
+
shape = this._shape,
|
1362
|
+
showArea = this.options.showArea,
|
1363
|
+
latLngs, area, subtext;
|
1364
|
+
|
1365
|
+
if (shape) {
|
1366
|
+
latLngs = this._shape._defaultShape ? this._shape._defaultShape() : this._shape.getLatLngs();
|
1367
|
+
area = L.GeometryUtil.geodesicArea(latLngs);
|
1368
|
+
subtext = showArea ? L.GeometryUtil.readableArea(area, this.options.metric) : ''
|
1369
|
+
}
|
1370
|
+
|
1371
|
+
return {
|
1372
|
+
text: tooltipText.text,
|
1373
|
+
subtext: subtext
|
1374
|
+
};
|
1375
|
+
}
|
1376
|
+
});
|
1377
|
+
|
1378
|
+
function _hasAncestor (el, cls) {
|
1379
|
+
while ((el = el.parentElement) && !el.classList.contains(cls));
|
1380
|
+
return el;
|
1381
|
+
}
|
1382
|
+
|
1383
|
+
|
1384
|
+
|
1385
|
+
/**
|
1386
|
+
* @class L.Draw.Marker
|
1387
|
+
* @aka Draw.Marker
|
1388
|
+
* @inherits L.Draw.Feature
|
1389
|
+
*/
|
1390
|
+
L.Draw.Marker = L.Draw.Feature.extend({
|
1391
|
+
statics: {
|
1392
|
+
TYPE: 'marker'
|
1393
|
+
},
|
1394
|
+
|
1395
|
+
options: {
|
1396
|
+
icon: new L.Icon.Default(),
|
1397
|
+
repeatMode: false,
|
1398
|
+
zIndexOffset: 2000 // This should be > than the highest z-index any markers
|
1399
|
+
},
|
1400
|
+
|
1401
|
+
// @method initialize(): void
|
1402
|
+
initialize: function (map, options) {
|
1403
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
1404
|
+
this.type = L.Draw.Marker.TYPE;
|
1405
|
+
|
1406
|
+
this._initialLabelText = L.drawLocal.draw.handlers.marker.tooltip.start;
|
1407
|
+
|
1408
|
+
L.Draw.Feature.prototype.initialize.call(this, map, options);
|
1409
|
+
},
|
1410
|
+
|
1411
|
+
// @method addHooks(): void
|
1412
|
+
// Add listener hooks to this handler.
|
1413
|
+
addHooks: function () {
|
1414
|
+
L.Draw.Feature.prototype.addHooks.call(this);
|
1415
|
+
|
1416
|
+
if (this._map) {
|
1417
|
+
this._tooltip.updateContent({ text: this._initialLabelText });
|
1418
|
+
|
1419
|
+
// Same mouseMarker as in Draw.Polyline
|
1420
|
+
if (!this._mouseMarker) {
|
1421
|
+
this._mouseMarker = L.marker(this._map.getCenter(), {
|
1422
|
+
icon: L.divIcon({
|
1423
|
+
className: 'leaflet-mouse-marker',
|
1424
|
+
iconAnchor: [20, 20],
|
1425
|
+
iconSize: [40, 40]
|
1426
|
+
}),
|
1427
|
+
opacity: 0,
|
1428
|
+
zIndexOffset: this.options.zIndexOffset
|
1429
|
+
});
|
1430
|
+
}
|
1431
|
+
|
1432
|
+
this._mouseMarker
|
1433
|
+
.on('click', this._onClick, this)
|
1434
|
+
.addTo(this._map);
|
1435
|
+
|
1436
|
+
this._map.on('mousemove', this._onMouseMove, this);
|
1437
|
+
this._map.on('click', this._onTouch, this);
|
1438
|
+
}
|
1439
|
+
},
|
1440
|
+
|
1441
|
+
// @method removeHooks(): void
|
1442
|
+
// Remove listener hooks from this handler.
|
1443
|
+
removeHooks: function () {
|
1444
|
+
L.Draw.Feature.prototype.removeHooks.call(this);
|
1445
|
+
|
1446
|
+
if (this._map) {
|
1447
|
+
if (this._marker) {
|
1448
|
+
this._marker.off('click', this._onClick, this);
|
1449
|
+
this._map
|
1450
|
+
.off('click', this._onClick, this)
|
1451
|
+
.off('click', this._onTouch, this)
|
1452
|
+
.removeLayer(this._marker);
|
1453
|
+
delete this._marker;
|
1454
|
+
}
|
1455
|
+
|
1456
|
+
this._mouseMarker.off('click', this._onClick, this);
|
1457
|
+
this._map.removeLayer(this._mouseMarker);
|
1458
|
+
delete this._mouseMarker;
|
1459
|
+
|
1460
|
+
this._map.off('mousemove', this._onMouseMove, this);
|
1461
|
+
}
|
1462
|
+
},
|
1463
|
+
|
1464
|
+
_onMouseMove: function (e) {
|
1465
|
+
var latlng = e.latlng;
|
1466
|
+
|
1467
|
+
this._tooltip.updatePosition(latlng);
|
1468
|
+
this._mouseMarker.setLatLng(latlng);
|
1469
|
+
|
1470
|
+
if (!this._marker) {
|
1471
|
+
this._marker = this._createMarker(latlng);
|
1472
|
+
// Bind to both marker and map to make sure we get the click event.
|
1473
|
+
this._marker.on('click', this._onClick, this);
|
1474
|
+
this._map
|
1475
|
+
.on('click', this._onClick, this)
|
1476
|
+
.addLayer(this._marker);
|
1477
|
+
}
|
1478
|
+
else {
|
1479
|
+
latlng = this._mouseMarker.getLatLng();
|
1480
|
+
this._marker.setLatLng(latlng);
|
1481
|
+
}
|
1482
|
+
},
|
1483
|
+
|
1484
|
+
_createMarker: function (latlng) {
|
1485
|
+
return new L.Marker(latlng, {
|
1486
|
+
icon: this.options.icon,
|
1487
|
+
zIndexOffset: this.options.zIndexOffset
|
1488
|
+
});
|
1489
|
+
},
|
1490
|
+
|
1491
|
+
_onClick: function () {
|
1492
|
+
this._fireCreatedEvent();
|
1493
|
+
|
1494
|
+
this.disable();
|
1495
|
+
if (this.options.repeatMode) {
|
1496
|
+
this.enable();
|
1497
|
+
}
|
1498
|
+
},
|
1499
|
+
|
1500
|
+
_onTouch: function (e) {
|
1501
|
+
// called on click & tap, only really does any thing on tap
|
1502
|
+
this._onMouseMove(e); // creates & places marker
|
1503
|
+
this._onClick(); // permanently places marker & ends interaction
|
1504
|
+
},
|
1505
|
+
|
1506
|
+
_fireCreatedEvent: function () {
|
1507
|
+
var marker = new L.Marker.Touch(this._marker.getLatLng(), { icon: this.options.icon });
|
1508
|
+
L.Draw.Feature.prototype._fireCreatedEvent.call(this, marker);
|
1509
|
+
}
|
1510
|
+
});
|
1511
|
+
|
1512
|
+
|
1513
|
+
|
1514
|
+
/**
|
1515
|
+
* @class L.Draw.CircleMarker
|
1516
|
+
* @aka Draw.CircleMarker
|
1517
|
+
* @inherits L.Draw.Marker
|
1518
|
+
*/
|
1519
|
+
L.Draw.CircleMarker = L.Draw.Marker.extend({
|
1520
|
+
statics: {
|
1521
|
+
TYPE: 'circlemarker'
|
1522
|
+
},
|
1523
|
+
|
1524
|
+
options: {
|
1525
|
+
stroke: true,
|
1526
|
+
color: '#3388ff',
|
1527
|
+
weight: 4,
|
1528
|
+
opacity: 0.5,
|
1529
|
+
fill: true,
|
1530
|
+
fillColor: null, //same as color by default
|
1531
|
+
fillOpacity: 0.2,
|
1532
|
+
clickable: true,
|
1533
|
+
zIndexOffset: 2000 // This should be > than the highest z-index any markers
|
1534
|
+
},
|
1535
|
+
|
1536
|
+
// @method initialize(): void
|
1537
|
+
initialize: function (map, options) {
|
1538
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
1539
|
+
this.type = L.Draw.CircleMarker.TYPE;
|
1540
|
+
|
1541
|
+
this._initialLabelText = L.drawLocal.draw.handlers.circlemarker.tooltip.start;
|
1542
|
+
|
1543
|
+
L.Draw.Feature.prototype.initialize.call(this, map, options);
|
1544
|
+
},
|
1545
|
+
|
1546
|
+
|
1547
|
+
_fireCreatedEvent: function () {
|
1548
|
+
var circleMarker = new L.CircleMarker(this._marker.getLatLng(), this.options);
|
1549
|
+
L.Draw.Feature.prototype._fireCreatedEvent.call(this, circleMarker);
|
1550
|
+
},
|
1551
|
+
|
1552
|
+
_createMarker: function (latlng) {
|
1553
|
+
return new L.CircleMarker(latlng, this.options);
|
1554
|
+
}
|
1555
|
+
});
|
1556
|
+
|
1557
|
+
|
1558
|
+
|
1559
|
+
/**
|
1560
|
+
* @class L.Draw.Circle
|
1561
|
+
* @aka Draw.Circle
|
1562
|
+
* @inherits L.Draw.SimpleShape
|
1563
|
+
*/
|
1564
|
+
L.Draw.Circle = L.Draw.SimpleShape.extend({
|
1565
|
+
statics: {
|
1566
|
+
TYPE: 'circle'
|
1567
|
+
},
|
1568
|
+
|
1569
|
+
options: {
|
1570
|
+
shapeOptions: {
|
1571
|
+
stroke: true,
|
1572
|
+
color: '#3388ff',
|
1573
|
+
weight: 4,
|
1574
|
+
opacity: 0.5,
|
1575
|
+
fill: true,
|
1576
|
+
fillColor: null, //same as color by default
|
1577
|
+
fillOpacity: 0.2,
|
1578
|
+
clickable: true
|
1579
|
+
},
|
1580
|
+
showRadius: true,
|
1581
|
+
metric: true, // Whether to use the metric measurement system or imperial
|
1582
|
+
feet: true, // When not metric, use feet instead of yards for display
|
1583
|
+
nautic: false // When not metric, not feet use nautic mile for display
|
1584
|
+
},
|
1585
|
+
|
1586
|
+
// @method initialize(): void
|
1587
|
+
initialize: function (map, options) {
|
1588
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
1589
|
+
this.type = L.Draw.Circle.TYPE;
|
1590
|
+
|
1591
|
+
this._initialLabelText = L.drawLocal.draw.handlers.circle.tooltip.start;
|
1592
|
+
|
1593
|
+
L.Draw.SimpleShape.prototype.initialize.call(this, map, options);
|
1594
|
+
},
|
1595
|
+
|
1596
|
+
_drawShape: function (latlng) {
|
1597
|
+
var distance = this._map.distance(this._startLatLng, latlng);
|
1598
|
+
if (!this._shape) {
|
1599
|
+
this._shape = new L.Circle(this._startLatLng, distance, this.options.shapeOptions);
|
1600
|
+
this._map.addLayer(this._shape);
|
1601
|
+
} else {
|
1602
|
+
this._shape.setRadius(distance);
|
1603
|
+
}
|
1604
|
+
},
|
1605
|
+
|
1606
|
+
_fireCreatedEvent: function () {
|
1607
|
+
var circle = new L.Circle(this._startLatLng, this._shape.getRadius(), this.options.shapeOptions);
|
1608
|
+
L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this, circle);
|
1609
|
+
},
|
1610
|
+
|
1611
|
+
_onMouseMove: function (e) {
|
1612
|
+
var latlng = e.latlng,
|
1613
|
+
showRadius = this.options.showRadius,
|
1614
|
+
useMetric = this.options.metric,
|
1615
|
+
radius;
|
1616
|
+
|
1617
|
+
this._tooltip.updatePosition(latlng);
|
1618
|
+
if (this._isDrawing) {
|
1619
|
+
this._drawShape(latlng);
|
1620
|
+
|
1621
|
+
// Get the new radius (rounded to 1 dp)
|
1622
|
+
radius = this._shape.getRadius().toFixed(1);
|
1623
|
+
|
1624
|
+
var subtext = '';
|
1625
|
+
if (showRadius) {
|
1626
|
+
subtext = L.drawLocal.draw.handlers.circle.radius + ': ' +
|
1627
|
+
L.GeometryUtil.readableDistance(radius, useMetric, this.options.feet, this.options.nautic);
|
1628
|
+
}
|
1629
|
+
this._tooltip.updateContent({
|
1630
|
+
text: this._endLabelText,
|
1631
|
+
subtext: subtext
|
1632
|
+
});
|
1633
|
+
}
|
1634
|
+
}
|
1635
|
+
});
|
1636
|
+
|
1637
|
+
|
1638
|
+
|
1639
|
+
L.Edit = L.Edit || {};
|
1640
|
+
|
1641
|
+
/**
|
1642
|
+
* @class L.Edit.Marker
|
1643
|
+
* @aka Edit.Marker
|
1644
|
+
*/
|
1645
|
+
L.Edit.Marker = L.Handler.extend({
|
1646
|
+
// @method initialize(): void
|
1647
|
+
initialize: function (marker, options) {
|
1648
|
+
this._marker = marker;
|
1649
|
+
L.setOptions(this, options);
|
1650
|
+
},
|
1651
|
+
|
1652
|
+
// @method addHooks(): void
|
1653
|
+
// Add listener hooks to this handler
|
1654
|
+
addHooks: function () {
|
1655
|
+
var marker = this._marker;
|
1656
|
+
|
1657
|
+
marker.dragging.enable();
|
1658
|
+
marker.on('dragend', this._onDragEnd, marker);
|
1659
|
+
this._toggleMarkerHighlight();
|
1660
|
+
},
|
1661
|
+
|
1662
|
+
// @method removeHooks(): void
|
1663
|
+
// Remove listener hooks from this handler
|
1664
|
+
removeHooks: function () {
|
1665
|
+
var marker = this._marker;
|
1666
|
+
|
1667
|
+
marker.dragging.disable();
|
1668
|
+
marker.off('dragend', this._onDragEnd, marker);
|
1669
|
+
this._toggleMarkerHighlight();
|
1670
|
+
},
|
1671
|
+
|
1672
|
+
_onDragEnd: function (e) {
|
1673
|
+
var layer = e.target;
|
1674
|
+
layer.edited = true;
|
1675
|
+
this._map.fire(L.Draw.Event.EDITMOVE, { layer: layer });
|
1676
|
+
},
|
1677
|
+
|
1678
|
+
_toggleMarkerHighlight: function () {
|
1679
|
+
var icon = this._marker._icon;
|
1680
|
+
|
1681
|
+
// Don't do anything if this layer is a marker but doesn't have an icon. Markers
|
1682
|
+
// should usually have icons. If using Leaflet.draw with Leaflet.markercluster there
|
1683
|
+
// is a chance that a marker doesn't.
|
1684
|
+
if (!icon) {
|
1685
|
+
return;
|
1686
|
+
}
|
1687
|
+
|
1688
|
+
// This is quite naughty, but I don't see another way of doing it. (short of setting a new icon)
|
1689
|
+
icon.style.display = 'none';
|
1690
|
+
|
1691
|
+
if (L.DomUtil.hasClass(icon, 'leaflet-edit-marker-selected')) {
|
1692
|
+
L.DomUtil.removeClass(icon, 'leaflet-edit-marker-selected');
|
1693
|
+
// Offset as the border will make the icon move.
|
1694
|
+
this._offsetMarker(icon, -4);
|
1695
|
+
|
1696
|
+
} else {
|
1697
|
+
L.DomUtil.addClass(icon, 'leaflet-edit-marker-selected');
|
1698
|
+
// Offset as the border will make the icon move.
|
1699
|
+
this._offsetMarker(icon, 4);
|
1700
|
+
}
|
1701
|
+
|
1702
|
+
icon.style.display = '';
|
1703
|
+
},
|
1704
|
+
|
1705
|
+
_offsetMarker: function (icon, offset) {
|
1706
|
+
var iconMarginTop = parseInt(icon.style.marginTop, 10) - offset,
|
1707
|
+
iconMarginLeft = parseInt(icon.style.marginLeft, 10) - offset;
|
1708
|
+
|
1709
|
+
icon.style.marginTop = iconMarginTop + 'px';
|
1710
|
+
icon.style.marginLeft = iconMarginLeft + 'px';
|
1711
|
+
}
|
1712
|
+
});
|
1713
|
+
|
1714
|
+
L.Marker.addInitHook(function () {
|
1715
|
+
if (L.Edit.Marker) {
|
1716
|
+
this.editing = new L.Edit.Marker(this);
|
1717
|
+
|
1718
|
+
if (this.options.editable) {
|
1719
|
+
this.editing.enable();
|
1720
|
+
}
|
1721
|
+
}
|
1722
|
+
});
|
1723
|
+
|
1724
|
+
|
1725
|
+
|
1726
|
+
L.Edit = L.Edit || {};
|
1727
|
+
|
1728
|
+
/**
|
1729
|
+
* @class L.Edit.Polyline
|
1730
|
+
* @aka L.Edit.Poly
|
1731
|
+
* @aka Edit.Poly
|
1732
|
+
*/
|
1733
|
+
L.Edit.Poly = L.Handler.extend({
|
1734
|
+
options: {},
|
1735
|
+
|
1736
|
+
// @method initialize(): void
|
1737
|
+
initialize: function (poly, options) {
|
1738
|
+
|
1739
|
+
this.latlngs = [poly._latlngs];
|
1740
|
+
if (poly._holes) {
|
1741
|
+
this.latlngs = this.latlngs.concat(poly._holes);
|
1742
|
+
}
|
1743
|
+
|
1744
|
+
this._poly = poly;
|
1745
|
+
L.setOptions(this, options);
|
1746
|
+
|
1747
|
+
this._poly.on('revert-edited', this._updateLatLngs, this);
|
1748
|
+
},
|
1749
|
+
|
1750
|
+
// Compatibility method to normalize Poly* objects
|
1751
|
+
// between 0.7.x and 1.0+
|
1752
|
+
_defaultShape: function () {
|
1753
|
+
if (!L.Polyline._flat) {
|
1754
|
+
return this._poly._latlngs;
|
1755
|
+
}
|
1756
|
+
return L.Polyline._flat(this._poly._latlngs) ? this._poly._latlngs : this._poly._latlngs[0];
|
1757
|
+
},
|
1758
|
+
|
1759
|
+
_eachVertexHandler: function (callback) {
|
1760
|
+
for (var i = 0; i < this._verticesHandlers.length; i++) {
|
1761
|
+
callback(this._verticesHandlers[i]);
|
1762
|
+
}
|
1763
|
+
},
|
1764
|
+
|
1765
|
+
// @method addHooks(): void
|
1766
|
+
// Add listener hooks to this handler
|
1767
|
+
addHooks: function () {
|
1768
|
+
this._initHandlers();
|
1769
|
+
this._eachVertexHandler(function (handler) {
|
1770
|
+
handler.addHooks();
|
1771
|
+
});
|
1772
|
+
},
|
1773
|
+
|
1774
|
+
// @method removeHooks(): void
|
1775
|
+
// Remove listener hooks from this handler
|
1776
|
+
removeHooks: function () {
|
1777
|
+
this._eachVertexHandler(function (handler) {
|
1778
|
+
handler.removeHooks();
|
1779
|
+
});
|
1780
|
+
},
|
1781
|
+
|
1782
|
+
// @method updateMarkers(): void
|
1783
|
+
// Fire an update for each vertex handler
|
1784
|
+
updateMarkers: function () {
|
1785
|
+
this._eachVertexHandler(function (handler) {
|
1786
|
+
handler.updateMarkers();
|
1787
|
+
});
|
1788
|
+
},
|
1789
|
+
|
1790
|
+
_initHandlers: function () {
|
1791
|
+
this._verticesHandlers = [];
|
1792
|
+
for (var i = 0; i < this.latlngs.length; i++) {
|
1793
|
+
this._verticesHandlers.push(new L.Edit.PolyVerticesEdit(this._poly, this.latlngs[i], this.options));
|
1794
|
+
}
|
1795
|
+
},
|
1796
|
+
|
1797
|
+
_updateLatLngs: function (e) {
|
1798
|
+
this.latlngs = [e.layer._latlngs];
|
1799
|
+
if (e.layer._holes) {
|
1800
|
+
this.latlngs = this.latlngs.concat(e.layer._holes);
|
1801
|
+
}
|
1802
|
+
}
|
1803
|
+
|
1804
|
+
});
|
1805
|
+
|
1806
|
+
/**
|
1807
|
+
* @class L.Edit.PolyVerticesEdit
|
1808
|
+
* @aka Edit.PolyVerticesEdit
|
1809
|
+
*/
|
1810
|
+
L.Edit.PolyVerticesEdit = L.Handler.extend({
|
1811
|
+
options: {
|
1812
|
+
icon: new L.DivIcon({
|
1813
|
+
iconSize: new L.Point(8, 8),
|
1814
|
+
className: 'leaflet-div-icon leaflet-editing-icon'
|
1815
|
+
}),
|
1816
|
+
touchIcon: new L.DivIcon({
|
1817
|
+
iconSize: new L.Point(20, 20),
|
1818
|
+
className: 'leaflet-div-icon leaflet-editing-icon leaflet-touch-icon'
|
1819
|
+
}),
|
1820
|
+
drawError: {
|
1821
|
+
color: '#b00b00',
|
1822
|
+
timeout: 1000
|
1823
|
+
}
|
1824
|
+
|
1825
|
+
|
1826
|
+
},
|
1827
|
+
|
1828
|
+
// @method intialize(): void
|
1829
|
+
initialize: function (poly, latlngs, options) {
|
1830
|
+
// if touch, switch to touch icon
|
1831
|
+
if (L.Browser.touch) {
|
1832
|
+
this.options.icon = this.options.touchIcon;
|
1833
|
+
}
|
1834
|
+
this._poly = poly;
|
1835
|
+
|
1836
|
+
if (options && options.drawError) {
|
1837
|
+
options.drawError = L.Util.extend({}, this.options.drawError, options.drawError);
|
1838
|
+
}
|
1839
|
+
|
1840
|
+
this._latlngs = latlngs;
|
1841
|
+
|
1842
|
+
L.setOptions(this, options);
|
1843
|
+
},
|
1844
|
+
|
1845
|
+
// Compatibility method to normalize Poly* objects
|
1846
|
+
// between 0.7.x and 1.0+
|
1847
|
+
_defaultShape: function () {
|
1848
|
+
if (!L.Polyline._flat) {
|
1849
|
+
return this._latlngs;
|
1850
|
+
}
|
1851
|
+
return L.Polyline._flat(this._latlngs) ? this._latlngs : this._latlngs[0];
|
1852
|
+
},
|
1853
|
+
|
1854
|
+
// @method addHooks(): void
|
1855
|
+
// Add listener hooks to this handler.
|
1856
|
+
addHooks: function () {
|
1857
|
+
var poly = this._poly;
|
1858
|
+
|
1859
|
+
if (!(poly instanceof L.Polygon)) {
|
1860
|
+
poly.options.fill = false;
|
1861
|
+
if (poly.options.editing) {
|
1862
|
+
poly.options.editing.fill = false;
|
1863
|
+
}
|
1864
|
+
}
|
1865
|
+
|
1866
|
+
poly.setStyle(poly.options.editing);
|
1867
|
+
|
1868
|
+
if (this._poly._map) {
|
1869
|
+
|
1870
|
+
this._map = this._poly._map; // Set map
|
1871
|
+
|
1872
|
+
if (!this._markerGroup) {
|
1873
|
+
this._initMarkers();
|
1874
|
+
}
|
1875
|
+
this._poly._map.addLayer(this._markerGroup);
|
1876
|
+
}
|
1877
|
+
},
|
1878
|
+
|
1879
|
+
// @method removeHooks(): void
|
1880
|
+
// Remove listener hooks from this handler.
|
1881
|
+
removeHooks: function () {
|
1882
|
+
var poly = this._poly;
|
1883
|
+
|
1884
|
+
poly.setStyle(poly.options.original);
|
1885
|
+
|
1886
|
+
if (poly._map) {
|
1887
|
+
poly._map.removeLayer(this._markerGroup);
|
1888
|
+
delete this._markerGroup;
|
1889
|
+
delete this._markers;
|
1890
|
+
}
|
1891
|
+
},
|
1892
|
+
|
1893
|
+
// @method updateMarkers(): void
|
1894
|
+
// Clear markers and update their location
|
1895
|
+
updateMarkers: function () {
|
1896
|
+
this._markerGroup.clearLayers();
|
1897
|
+
this._initMarkers();
|
1898
|
+
},
|
1899
|
+
|
1900
|
+
_initMarkers: function () {
|
1901
|
+
if (!this._markerGroup) {
|
1902
|
+
this._markerGroup = new L.LayerGroup();
|
1903
|
+
}
|
1904
|
+
this._markers = [];
|
1905
|
+
|
1906
|
+
var latlngs = this._defaultShape(),
|
1907
|
+
i, j, len, marker;
|
1908
|
+
|
1909
|
+
for (i = 0, len = latlngs.length; i < len; i++) {
|
1910
|
+
|
1911
|
+
marker = this._createMarker(latlngs[i], i);
|
1912
|
+
marker.on('click', this._onMarkerClick, this);
|
1913
|
+
this._markers.push(marker);
|
1914
|
+
}
|
1915
|
+
|
1916
|
+
var markerLeft, markerRight;
|
1917
|
+
|
1918
|
+
for (i = 0, j = len - 1; i < len; j = i++) {
|
1919
|
+
if (i === 0 && !(L.Polygon && (this._poly instanceof L.Polygon))) {
|
1920
|
+
continue;
|
1921
|
+
}
|
1922
|
+
|
1923
|
+
markerLeft = this._markers[j];
|
1924
|
+
markerRight = this._markers[i];
|
1925
|
+
|
1926
|
+
this._createMiddleMarker(markerLeft, markerRight);
|
1927
|
+
this._updatePrevNext(markerLeft, markerRight);
|
1928
|
+
}
|
1929
|
+
},
|
1930
|
+
|
1931
|
+
_createMarker: function (latlng, index) {
|
1932
|
+
// Extending L.Marker in TouchEvents.js to include touch.
|
1933
|
+
var marker = new L.Marker.Touch(latlng, {
|
1934
|
+
draggable: true,
|
1935
|
+
icon: this.options.icon,
|
1936
|
+
});
|
1937
|
+
|
1938
|
+
marker._origLatLng = latlng;
|
1939
|
+
marker._index = index;
|
1940
|
+
|
1941
|
+
marker
|
1942
|
+
.on('dragstart', this._onMarkerDragStart, this)
|
1943
|
+
.on('drag', this._onMarkerDrag, this)
|
1944
|
+
.on('dragend', this._fireEdit, this)
|
1945
|
+
.on('touchmove', this._onTouchMove, this)
|
1946
|
+
.on('touchend', this._fireEdit, this)
|
1947
|
+
.on('MSPointerMove', this._onTouchMove, this)
|
1948
|
+
.on('MSPointerUp', this._fireEdit, this);
|
1949
|
+
|
1950
|
+
this._markerGroup.addLayer(marker);
|
1951
|
+
|
1952
|
+
return marker;
|
1953
|
+
},
|
1954
|
+
|
1955
|
+
_onMarkerDragStart: function () {
|
1956
|
+
this._poly.fire('editstart');
|
1957
|
+
},
|
1958
|
+
|
1959
|
+
_spliceLatLngs: function () {
|
1960
|
+
var latlngs = this._defaultShape();
|
1961
|
+
var removed = [].splice.apply(latlngs, arguments);
|
1962
|
+
this._poly._convertLatLngs(latlngs, true);
|
1963
|
+
this._poly.redraw();
|
1964
|
+
return removed;
|
1965
|
+
},
|
1966
|
+
|
1967
|
+
_removeMarker: function (marker) {
|
1968
|
+
var i = marker._index;
|
1969
|
+
|
1970
|
+
this._markerGroup.removeLayer(marker);
|
1971
|
+
this._markers.splice(i, 1);
|
1972
|
+
this._spliceLatLngs(i, 1);
|
1973
|
+
this._updateIndexes(i, -1);
|
1974
|
+
|
1975
|
+
marker
|
1976
|
+
.off('dragstart', this._onMarkerDragStart, this)
|
1977
|
+
.off('drag', this._onMarkerDrag, this)
|
1978
|
+
.off('dragend', this._fireEdit, this)
|
1979
|
+
.off('touchmove', this._onMarkerDrag, this)
|
1980
|
+
.off('touchend', this._fireEdit, this)
|
1981
|
+
.off('click', this._onMarkerClick, this)
|
1982
|
+
.off('MSPointerMove', this._onTouchMove, this)
|
1983
|
+
.off('MSPointerUp', this._fireEdit, this);
|
1984
|
+
},
|
1985
|
+
|
1986
|
+
_fireEdit: function () {
|
1987
|
+
this._poly.edited = true;
|
1988
|
+
this._poly.fire('edit');
|
1989
|
+
this._poly._map.fire(L.Draw.Event.EDITVERTEX, { layers: this._markerGroup, poly: this._poly });
|
1990
|
+
},
|
1991
|
+
|
1992
|
+
_onMarkerDrag: function (e) {
|
1993
|
+
var marker = e.target;
|
1994
|
+
var poly = this._poly;
|
1995
|
+
|
1996
|
+
L.extend(marker._origLatLng, marker._latlng);
|
1997
|
+
|
1998
|
+
if (marker._middleLeft) {
|
1999
|
+
marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
|
2000
|
+
}
|
2001
|
+
if (marker._middleRight) {
|
2002
|
+
marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
|
2003
|
+
}
|
2004
|
+
|
2005
|
+
if (poly.options.poly) {
|
2006
|
+
var tooltip = poly._map._editTooltip; // Access the tooltip
|
2007
|
+
|
2008
|
+
// If we don't allow intersections and the polygon intersects
|
2009
|
+
if (!poly.options.poly.allowIntersection && poly.intersects()) {
|
2010
|
+
|
2011
|
+
var originalColor = poly.options.color;
|
2012
|
+
poly.setStyle({ color: this.options.drawError.color });
|
2013
|
+
|
2014
|
+
// Manually trigger 'dragend' behavior on marker we are about to remove
|
2015
|
+
// WORKAROUND: introduced in 1.0.0-rc2, may be related to #4484
|
2016
|
+
if (L.version.indexOf('0.7') !== 0) {
|
2017
|
+
marker.dragging._draggable._onUp(e);
|
2018
|
+
}
|
2019
|
+
this._onMarkerClick(e); // Remove violating marker
|
2020
|
+
// FIXME: Reset the marker to it's original position (instead of remove)
|
2021
|
+
|
2022
|
+
if (tooltip) {
|
2023
|
+
tooltip.updateContent({
|
2024
|
+
text: L.drawLocal.draw.handlers.polyline.error
|
2025
|
+
});
|
2026
|
+
}
|
2027
|
+
|
2028
|
+
// Reset everything back to normal after a second
|
2029
|
+
setTimeout(function () {
|
2030
|
+
poly.setStyle({ color: originalColor });
|
2031
|
+
if (tooltip) {
|
2032
|
+
tooltip.updateContent({
|
2033
|
+
text: L.drawLocal.edit.handlers.edit.tooltip.text,
|
2034
|
+
subtext: L.drawLocal.edit.handlers.edit.tooltip.subtext
|
2035
|
+
});
|
2036
|
+
}
|
2037
|
+
}, 1000);
|
2038
|
+
}
|
2039
|
+
}
|
2040
|
+
|
2041
|
+
this._poly.redraw();
|
2042
|
+
this._poly.fire('editdrag');
|
2043
|
+
},
|
2044
|
+
|
2045
|
+
_onMarkerClick: function (e) {
|
2046
|
+
|
2047
|
+
var minPoints = L.Polygon && (this._poly instanceof L.Polygon) ? 4 : 3,
|
2048
|
+
marker = e.target;
|
2049
|
+
|
2050
|
+
// If removing this point would create an invalid polyline/polygon don't remove
|
2051
|
+
if (this._defaultShape().length < minPoints) {
|
2052
|
+
return;
|
2053
|
+
}
|
2054
|
+
|
2055
|
+
// remove the marker
|
2056
|
+
this._removeMarker(marker);
|
2057
|
+
|
2058
|
+
// update prev/next links of adjacent markers
|
2059
|
+
this._updatePrevNext(marker._prev, marker._next);
|
2060
|
+
|
2061
|
+
// remove ghost markers near the removed marker
|
2062
|
+
if (marker._middleLeft) {
|
2063
|
+
this._markerGroup.removeLayer(marker._middleLeft);
|
2064
|
+
}
|
2065
|
+
if (marker._middleRight) {
|
2066
|
+
this._markerGroup.removeLayer(marker._middleRight);
|
2067
|
+
}
|
2068
|
+
|
2069
|
+
// create a ghost marker in place of the removed one
|
2070
|
+
if (marker._prev && marker._next) {
|
2071
|
+
this._createMiddleMarker(marker._prev, marker._next);
|
2072
|
+
|
2073
|
+
} else if (!marker._prev) {
|
2074
|
+
marker._next._middleLeft = null;
|
2075
|
+
|
2076
|
+
} else if (!marker._next) {
|
2077
|
+
marker._prev._middleRight = null;
|
2078
|
+
}
|
2079
|
+
|
2080
|
+
this._fireEdit();
|
2081
|
+
},
|
2082
|
+
|
2083
|
+
_onTouchMove: function (e) {
|
2084
|
+
|
2085
|
+
var layerPoint = this._map.mouseEventToLayerPoint(e.originalEvent.touches[0]),
|
2086
|
+
latlng = this._map.layerPointToLatLng(layerPoint),
|
2087
|
+
marker = e.target;
|
2088
|
+
|
2089
|
+
L.extend(marker._origLatLng, latlng);
|
2090
|
+
|
2091
|
+
if (marker._middleLeft) {
|
2092
|
+
marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
|
2093
|
+
}
|
2094
|
+
if (marker._middleRight) {
|
2095
|
+
marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
|
2096
|
+
}
|
2097
|
+
|
2098
|
+
this._poly.redraw();
|
2099
|
+
this.updateMarkers();
|
2100
|
+
},
|
2101
|
+
|
2102
|
+
_updateIndexes: function (index, delta) {
|
2103
|
+
this._markerGroup.eachLayer(function (marker) {
|
2104
|
+
if (marker._index > index) {
|
2105
|
+
marker._index += delta;
|
2106
|
+
}
|
2107
|
+
});
|
2108
|
+
},
|
2109
|
+
|
2110
|
+
_createMiddleMarker: function (marker1, marker2) {
|
2111
|
+
var latlng = this._getMiddleLatLng(marker1, marker2),
|
2112
|
+
marker = this._createMarker(latlng),
|
2113
|
+
onClick,
|
2114
|
+
onDragStart,
|
2115
|
+
onDragEnd;
|
2116
|
+
|
2117
|
+
marker.setOpacity(0.6);
|
2118
|
+
|
2119
|
+
marker1._middleRight = marker2._middleLeft = marker;
|
2120
|
+
|
2121
|
+
onDragStart = function () {
|
2122
|
+
marker.off('touchmove', onDragStart, this);
|
2123
|
+
var i = marker2._index;
|
2124
|
+
|
2125
|
+
marker._index = i;
|
2126
|
+
|
2127
|
+
marker
|
2128
|
+
.off('click', onClick, this)
|
2129
|
+
.on('click', this._onMarkerClick, this);
|
2130
|
+
|
2131
|
+
latlng.lat = marker.getLatLng().lat;
|
2132
|
+
latlng.lng = marker.getLatLng().lng;
|
2133
|
+
this._spliceLatLngs(i, 0, latlng);
|
2134
|
+
this._markers.splice(i, 0, marker);
|
2135
|
+
|
2136
|
+
marker.setOpacity(1);
|
2137
|
+
|
2138
|
+
this._updateIndexes(i, 1);
|
2139
|
+
marker2._index++;
|
2140
|
+
this._updatePrevNext(marker1, marker);
|
2141
|
+
this._updatePrevNext(marker, marker2);
|
2142
|
+
|
2143
|
+
this._poly.fire('editstart');
|
2144
|
+
};
|
2145
|
+
|
2146
|
+
onDragEnd = function () {
|
2147
|
+
marker.off('dragstart', onDragStart, this);
|
2148
|
+
marker.off('dragend', onDragEnd, this);
|
2149
|
+
marker.off('touchmove', onDragStart, this);
|
2150
|
+
|
2151
|
+
this._createMiddleMarker(marker1, marker);
|
2152
|
+
this._createMiddleMarker(marker, marker2);
|
2153
|
+
};
|
2154
|
+
|
2155
|
+
onClick = function () {
|
2156
|
+
onDragStart.call(this);
|
2157
|
+
onDragEnd.call(this);
|
2158
|
+
this._fireEdit();
|
2159
|
+
};
|
2160
|
+
|
2161
|
+
marker
|
2162
|
+
.on('click', onClick, this)
|
2163
|
+
.on('dragstart', onDragStart, this)
|
2164
|
+
.on('dragend', onDragEnd, this)
|
2165
|
+
.on('touchmove', onDragStart, this);
|
2166
|
+
|
2167
|
+
this._markerGroup.addLayer(marker);
|
2168
|
+
},
|
2169
|
+
|
2170
|
+
_updatePrevNext: function (marker1, marker2) {
|
2171
|
+
if (marker1) {
|
2172
|
+
marker1._next = marker2;
|
2173
|
+
}
|
2174
|
+
if (marker2) {
|
2175
|
+
marker2._prev = marker1;
|
2176
|
+
}
|
2177
|
+
},
|
2178
|
+
|
2179
|
+
_getMiddleLatLng: function (marker1, marker2) {
|
2180
|
+
var map = this._poly._map,
|
2181
|
+
p1 = map.project(marker1.getLatLng()),
|
2182
|
+
p2 = map.project(marker2.getLatLng());
|
2183
|
+
|
2184
|
+
return map.unproject(p1._add(p2)._divideBy(2));
|
2185
|
+
}
|
2186
|
+
});
|
2187
|
+
|
2188
|
+
L.Polyline.addInitHook(function () {
|
2189
|
+
|
2190
|
+
// Check to see if handler has already been initialized. This is to support versions of Leaflet that still have L.Handler.PolyEdit
|
2191
|
+
if (this.editing) {
|
2192
|
+
return;
|
2193
|
+
}
|
2194
|
+
|
2195
|
+
if (L.Edit.Poly) {
|
2196
|
+
|
2197
|
+
this.editing = new L.Edit.Poly(this, this.options.poly);
|
2198
|
+
|
2199
|
+
if (this.options.editable) {
|
2200
|
+
this.editing.enable();
|
2201
|
+
}
|
2202
|
+
}
|
2203
|
+
|
2204
|
+
this.on('add', function () {
|
2205
|
+
if (this.editing && this.editing.enabled()) {
|
2206
|
+
this.editing.addHooks();
|
2207
|
+
}
|
2208
|
+
});
|
2209
|
+
|
2210
|
+
this.on('remove', function () {
|
2211
|
+
if (this.editing && this.editing.enabled()) {
|
2212
|
+
this.editing.removeHooks();
|
2213
|
+
}
|
2214
|
+
});
|
2215
|
+
});
|
2216
|
+
|
2217
|
+
|
2218
|
+
|
2219
|
+
L.Edit = L.Edit || {};
|
2220
|
+
/**
|
2221
|
+
* @class L.Edit.SimpleShape
|
2222
|
+
* @aka Edit.SimpleShape
|
2223
|
+
*/
|
2224
|
+
L.Edit.SimpleShape = L.Handler.extend({
|
2225
|
+
options: {
|
2226
|
+
moveIcon: new L.DivIcon({
|
2227
|
+
iconSize: new L.Point(8, 8),
|
2228
|
+
className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-move'
|
2229
|
+
}),
|
2230
|
+
resizeIcon: new L.DivIcon({
|
2231
|
+
iconSize: new L.Point(8, 8),
|
2232
|
+
className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-resize'
|
2233
|
+
}),
|
2234
|
+
touchMoveIcon: new L.DivIcon({
|
2235
|
+
iconSize: new L.Point(20, 20),
|
2236
|
+
className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-move leaflet-touch-icon'
|
2237
|
+
}),
|
2238
|
+
touchResizeIcon: new L.DivIcon({
|
2239
|
+
iconSize: new L.Point(20, 20),
|
2240
|
+
className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-resize leaflet-touch-icon'
|
2241
|
+
}),
|
2242
|
+
},
|
2243
|
+
|
2244
|
+
// @method intialize(): void
|
2245
|
+
initialize: function (shape, options) {
|
2246
|
+
// if touch, switch to touch icon
|
2247
|
+
if (L.Browser.touch) {
|
2248
|
+
this.options.moveIcon = this.options.touchMoveIcon;
|
2249
|
+
this.options.resizeIcon = this.options.touchResizeIcon;
|
2250
|
+
}
|
2251
|
+
|
2252
|
+
this._shape = shape;
|
2253
|
+
L.Util.setOptions(this, options);
|
2254
|
+
},
|
2255
|
+
|
2256
|
+
// @method addHooks(): void
|
2257
|
+
// Add listener hooks to this handler
|
2258
|
+
addHooks: function () {
|
2259
|
+
var shape = this._shape;
|
2260
|
+
if (this._shape._map) {
|
2261
|
+
this._map = this._shape._map;
|
2262
|
+
shape.setStyle(shape.options.editing);
|
2263
|
+
|
2264
|
+
if (shape._map) {
|
2265
|
+
this._map = shape._map;
|
2266
|
+
if (!this._markerGroup) {
|
2267
|
+
this._initMarkers();
|
2268
|
+
}
|
2269
|
+
this._map.addLayer(this._markerGroup);
|
2270
|
+
}
|
2271
|
+
}
|
2272
|
+
},
|
2273
|
+
|
2274
|
+
// @method removeHooks(): void
|
2275
|
+
// Remove listener hooks from this handler
|
2276
|
+
removeHooks: function () {
|
2277
|
+
var shape = this._shape;
|
2278
|
+
|
2279
|
+
shape.setStyle(shape.options.original);
|
2280
|
+
|
2281
|
+
if (shape._map) {
|
2282
|
+
this._unbindMarker(this._moveMarker);
|
2283
|
+
|
2284
|
+
for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
|
2285
|
+
this._unbindMarker(this._resizeMarkers[i]);
|
2286
|
+
}
|
2287
|
+
this._resizeMarkers = null;
|
2288
|
+
|
2289
|
+
this._map.removeLayer(this._markerGroup);
|
2290
|
+
delete this._markerGroup;
|
2291
|
+
}
|
2292
|
+
|
2293
|
+
this._map = null;
|
2294
|
+
},
|
2295
|
+
|
2296
|
+
// @method updateMarkers(): void
|
2297
|
+
// Remove the edit markers from this layer
|
2298
|
+
updateMarkers: function () {
|
2299
|
+
this._markerGroup.clearLayers();
|
2300
|
+
this._initMarkers();
|
2301
|
+
},
|
2302
|
+
|
2303
|
+
_initMarkers: function () {
|
2304
|
+
if (!this._markerGroup) {
|
2305
|
+
this._markerGroup = new L.LayerGroup();
|
2306
|
+
}
|
2307
|
+
|
2308
|
+
// Create center marker
|
2309
|
+
this._createMoveMarker();
|
2310
|
+
|
2311
|
+
// Create edge marker
|
2312
|
+
this._createResizeMarker();
|
2313
|
+
},
|
2314
|
+
|
2315
|
+
_createMoveMarker: function () {
|
2316
|
+
// Children override
|
2317
|
+
},
|
2318
|
+
|
2319
|
+
_createResizeMarker: function () {
|
2320
|
+
// Children override
|
2321
|
+
},
|
2322
|
+
|
2323
|
+
_createMarker: function (latlng, icon) {
|
2324
|
+
// Extending L.Marker in TouchEvents.js to include touch.
|
2325
|
+
var marker = new L.Marker.Touch(latlng, {
|
2326
|
+
draggable: true,
|
2327
|
+
icon: icon,
|
2328
|
+
zIndexOffset: 10
|
2329
|
+
});
|
2330
|
+
|
2331
|
+
this._bindMarker(marker);
|
2332
|
+
|
2333
|
+
this._markerGroup.addLayer(marker);
|
2334
|
+
|
2335
|
+
return marker;
|
2336
|
+
},
|
2337
|
+
|
2338
|
+
_bindMarker: function (marker) {
|
2339
|
+
marker
|
2340
|
+
.on('dragstart', this._onMarkerDragStart, this)
|
2341
|
+
.on('drag', this._onMarkerDrag, this)
|
2342
|
+
.on('dragend', this._onMarkerDragEnd, this)
|
2343
|
+
.on('touchstart', this._onTouchStart, this)
|
2344
|
+
.on('touchmove', this._onTouchMove, this)
|
2345
|
+
.on('MSPointerMove', this._onTouchMove, this)
|
2346
|
+
.on('touchend', this._onTouchEnd, this)
|
2347
|
+
.on('MSPointerUp', this._onTouchEnd, this);
|
2348
|
+
},
|
2349
|
+
|
2350
|
+
_unbindMarker: function (marker) {
|
2351
|
+
marker
|
2352
|
+
.off('dragstart', this._onMarkerDragStart, this)
|
2353
|
+
.off('drag', this._onMarkerDrag, this)
|
2354
|
+
.off('dragend', this._onMarkerDragEnd, this)
|
2355
|
+
.off('touchstart', this._onTouchStart, this)
|
2356
|
+
.off('touchmove', this._onTouchMove, this)
|
2357
|
+
.off('MSPointerMove', this._onTouchMove, this)
|
2358
|
+
.off('touchend', this._onTouchEnd, this)
|
2359
|
+
.off('MSPointerUp', this._onTouchEnd, this);
|
2360
|
+
},
|
2361
|
+
|
2362
|
+
_onMarkerDragStart: function (e) {
|
2363
|
+
var marker = e.target;
|
2364
|
+
marker.setOpacity(0);
|
2365
|
+
|
2366
|
+
this._shape.fire('editstart');
|
2367
|
+
},
|
2368
|
+
|
2369
|
+
_fireEdit: function () {
|
2370
|
+
this._shape.edited = true;
|
2371
|
+
this._shape.fire('edit');
|
2372
|
+
},
|
2373
|
+
|
2374
|
+
_onMarkerDrag: function (e) {
|
2375
|
+
var marker = e.target,
|
2376
|
+
latlng = marker.getLatLng();
|
2377
|
+
|
2378
|
+
if (marker === this._moveMarker) {
|
2379
|
+
this._move(latlng);
|
2380
|
+
} else {
|
2381
|
+
this._resize(latlng);
|
2382
|
+
}
|
2383
|
+
|
2384
|
+
this._shape.redraw();
|
2385
|
+
this._shape.fire('editdrag');
|
2386
|
+
},
|
2387
|
+
|
2388
|
+
_onMarkerDragEnd: function (e) {
|
2389
|
+
var marker = e.target;
|
2390
|
+
marker.setOpacity(1);
|
2391
|
+
|
2392
|
+
this._fireEdit();
|
2393
|
+
},
|
2394
|
+
|
2395
|
+
_onTouchStart: function (e) {
|
2396
|
+
L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this, e);
|
2397
|
+
|
2398
|
+
if (typeof(this._getCorners) === 'function') {
|
2399
|
+
// Save a reference to the opposite point
|
2400
|
+
var corners = this._getCorners(),
|
2401
|
+
marker = e.target,
|
2402
|
+
currentCornerIndex = marker._cornerIndex;
|
2403
|
+
|
2404
|
+
marker.setOpacity(0);
|
2405
|
+
|
2406
|
+
// Copyed from Edit.Rectangle.js line 23 _onMarkerDragStart()
|
2407
|
+
// Latlng is null otherwise.
|
2408
|
+
this._oppositeCorner = corners[(currentCornerIndex + 2) % 4];
|
2409
|
+
this._toggleCornerMarkers(0, currentCornerIndex);
|
2410
|
+
}
|
2411
|
+
|
2412
|
+
this._shape.fire('editstart');
|
2413
|
+
},
|
2414
|
+
|
2415
|
+
_onTouchMove: function (e) {
|
2416
|
+
var layerPoint = this._map.mouseEventToLayerPoint(e.originalEvent.touches[0]),
|
2417
|
+
latlng = this._map.layerPointToLatLng(layerPoint),
|
2418
|
+
marker = e.target;
|
2419
|
+
|
2420
|
+
if (marker === this._moveMarker) {
|
2421
|
+
this._move(latlng);
|
2422
|
+
} else {
|
2423
|
+
this._resize(latlng);
|
2424
|
+
}
|
2425
|
+
|
2426
|
+
this._shape.redraw();
|
2427
|
+
|
2428
|
+
// prevent touchcancel in IOS
|
2429
|
+
// e.preventDefault();
|
2430
|
+
return false;
|
2431
|
+
},
|
2432
|
+
|
2433
|
+
_onTouchEnd: function (e) {
|
2434
|
+
var marker = e.target;
|
2435
|
+
marker.setOpacity(1);
|
2436
|
+
this.updateMarkers();
|
2437
|
+
this._fireEdit();
|
2438
|
+
},
|
2439
|
+
|
2440
|
+
_move: function () {
|
2441
|
+
// Children override
|
2442
|
+
},
|
2443
|
+
|
2444
|
+
_resize: function () {
|
2445
|
+
// Children override
|
2446
|
+
}
|
2447
|
+
});
|
2448
|
+
|
2449
|
+
|
2450
|
+
|
2451
|
+
L.Edit = L.Edit || {};
|
2452
|
+
/**
|
2453
|
+
* @class L.Edit.Rectangle
|
2454
|
+
* @aka Edit.Rectangle
|
2455
|
+
* @inherits L.Edit.SimpleShape
|
2456
|
+
*/
|
2457
|
+
L.Edit.Rectangle = L.Edit.SimpleShape.extend({
|
2458
|
+
_createMoveMarker: function () {
|
2459
|
+
var bounds = this._shape.getBounds(),
|
2460
|
+
center = bounds.getCenter();
|
2461
|
+
|
2462
|
+
this._moveMarker = this._createMarker(center, this.options.moveIcon);
|
2463
|
+
},
|
2464
|
+
|
2465
|
+
_createResizeMarker: function () {
|
2466
|
+
var corners = this._getCorners();
|
2467
|
+
|
2468
|
+
this._resizeMarkers = [];
|
2469
|
+
|
2470
|
+
for (var i = 0, l = corners.length; i < l; i++) {
|
2471
|
+
this._resizeMarkers.push(this._createMarker(corners[i], this.options.resizeIcon));
|
2472
|
+
// Monkey in the corner index as we will need to know this for dragging
|
2473
|
+
this._resizeMarkers[i]._cornerIndex = i;
|
2474
|
+
}
|
2475
|
+
},
|
2476
|
+
|
2477
|
+
_onMarkerDragStart: function (e) {
|
2478
|
+
L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this, e);
|
2479
|
+
|
2480
|
+
// Save a reference to the opposite point
|
2481
|
+
var corners = this._getCorners(),
|
2482
|
+
marker = e.target,
|
2483
|
+
currentCornerIndex = marker._cornerIndex;
|
2484
|
+
|
2485
|
+
this._oppositeCorner = corners[(currentCornerIndex + 2) % 4];
|
2486
|
+
|
2487
|
+
this._toggleCornerMarkers(0, currentCornerIndex);
|
2488
|
+
},
|
2489
|
+
|
2490
|
+
_onMarkerDragEnd: function (e) {
|
2491
|
+
var marker = e.target,
|
2492
|
+
bounds, center;
|
2493
|
+
|
2494
|
+
// Reset move marker position to the center
|
2495
|
+
if (marker === this._moveMarker) {
|
2496
|
+
bounds = this._shape.getBounds();
|
2497
|
+
center = bounds.getCenter();
|
2498
|
+
|
2499
|
+
marker.setLatLng(center);
|
2500
|
+
}
|
2501
|
+
|
2502
|
+
this._toggleCornerMarkers(1);
|
2503
|
+
|
2504
|
+
this._repositionCornerMarkers();
|
2505
|
+
|
2506
|
+
L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this, e);
|
2507
|
+
},
|
2508
|
+
|
2509
|
+
_move: function (newCenter) {
|
2510
|
+
var latlngs = this._shape._defaultShape ? this._shape._defaultShape() : this._shape.getLatLngs(),
|
2511
|
+
bounds = this._shape.getBounds(),
|
2512
|
+
center = bounds.getCenter(),
|
2513
|
+
offset, newLatLngs = [];
|
2514
|
+
|
2515
|
+
// Offset the latlngs to the new center
|
2516
|
+
for (var i = 0, l = latlngs.length; i < l; i++) {
|
2517
|
+
offset = [latlngs[i].lat - center.lat, latlngs[i].lng - center.lng];
|
2518
|
+
newLatLngs.push([newCenter.lat + offset[0], newCenter.lng + offset[1]]);
|
2519
|
+
}
|
2520
|
+
|
2521
|
+
this._shape.setLatLngs(newLatLngs);
|
2522
|
+
|
2523
|
+
// Reposition the resize markers
|
2524
|
+
this._repositionCornerMarkers();
|
2525
|
+
|
2526
|
+
this._map.fire(L.Draw.Event.EDITMOVE, { layer: this._shape });
|
2527
|
+
},
|
2528
|
+
|
2529
|
+
_resize: function (latlng) {
|
2530
|
+
var bounds;
|
2531
|
+
|
2532
|
+
// Update the shape based on the current position of this corner and the opposite point
|
2533
|
+
this._shape.setBounds(L.latLngBounds(latlng, this._oppositeCorner));
|
2534
|
+
|
2535
|
+
// Reposition the move marker
|
2536
|
+
bounds = this._shape.getBounds();
|
2537
|
+
this._moveMarker.setLatLng(bounds.getCenter());
|
2538
|
+
|
2539
|
+
this._map.fire(L.Draw.Event.EDITRESIZE, { layer: this._shape });
|
2540
|
+
},
|
2541
|
+
|
2542
|
+
_getCorners: function () {
|
2543
|
+
var bounds = this._shape.getBounds(),
|
2544
|
+
nw = bounds.getNorthWest(),
|
2545
|
+
ne = bounds.getNorthEast(),
|
2546
|
+
se = bounds.getSouthEast(),
|
2547
|
+
sw = bounds.getSouthWest();
|
2548
|
+
|
2549
|
+
return [nw, ne, se, sw];
|
2550
|
+
},
|
2551
|
+
|
2552
|
+
_toggleCornerMarkers: function (opacity) {
|
2553
|
+
for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
|
2554
|
+
this._resizeMarkers[i].setOpacity(opacity);
|
2555
|
+
}
|
2556
|
+
},
|
2557
|
+
|
2558
|
+
_repositionCornerMarkers: function () {
|
2559
|
+
var corners = this._getCorners();
|
2560
|
+
|
2561
|
+
for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
|
2562
|
+
this._resizeMarkers[i].setLatLng(corners[i]);
|
2563
|
+
}
|
2564
|
+
}
|
2565
|
+
});
|
2566
|
+
|
2567
|
+
L.Rectangle.addInitHook(function () {
|
2568
|
+
if (L.Edit.Rectangle) {
|
2569
|
+
this.editing = new L.Edit.Rectangle(this);
|
2570
|
+
|
2571
|
+
if (this.options.editable) {
|
2572
|
+
this.editing.enable();
|
2573
|
+
}
|
2574
|
+
}
|
2575
|
+
});
|
2576
|
+
|
2577
|
+
|
2578
|
+
|
2579
|
+
L.Edit = L.Edit || {};
|
2580
|
+
/**
|
2581
|
+
* @class L.Edit.CircleMarker
|
2582
|
+
* @aka Edit.Circle
|
2583
|
+
* @inherits L.Edit.SimpleShape
|
2584
|
+
*/
|
2585
|
+
L.Edit.CircleMarker = L.Edit.SimpleShape.extend({
|
2586
|
+
_createMoveMarker: function () {
|
2587
|
+
var center = this._shape.getLatLng();
|
2588
|
+
|
2589
|
+
this._moveMarker = this._createMarker(center, this.options.moveIcon);
|
2590
|
+
},
|
2591
|
+
|
2592
|
+
_createResizeMarker: function () {
|
2593
|
+
// To avoid an undefined check in L.Edit.SimpleShape.removeHooks
|
2594
|
+
this._resizeMarkers = [];
|
2595
|
+
},
|
2596
|
+
|
2597
|
+
_move: function (latlng) {
|
2598
|
+
if (this._resizeMarkers.length) {
|
2599
|
+
var resizemarkerPoint = this._getResizeMarkerPoint(latlng);
|
2600
|
+
// Move the resize marker
|
2601
|
+
this._resizeMarkers[0].setLatLng(resizemarkerPoint);
|
2602
|
+
}
|
2603
|
+
|
2604
|
+
// Move the circle
|
2605
|
+
this._shape.setLatLng(latlng);
|
2606
|
+
|
2607
|
+
this._map.fire(L.Draw.Event.EDITMOVE, { layer: this._shape });
|
2608
|
+
},
|
2609
|
+
});
|
2610
|
+
|
2611
|
+
L.CircleMarker.addInitHook(function () {
|
2612
|
+
if (L.Edit.CircleMarker) {
|
2613
|
+
this.editing = new L.Edit.CircleMarker(this);
|
2614
|
+
|
2615
|
+
if (this.options.editable) {
|
2616
|
+
this.editing.enable();
|
2617
|
+
}
|
2618
|
+
}
|
2619
|
+
|
2620
|
+
this.on('add', function () {
|
2621
|
+
if (this.editing && this.editing.enabled()) {
|
2622
|
+
this.editing.addHooks();
|
2623
|
+
}
|
2624
|
+
});
|
2625
|
+
|
2626
|
+
this.on('remove', function () {
|
2627
|
+
if (this.editing && this.editing.enabled()) {
|
2628
|
+
this.editing.removeHooks();
|
2629
|
+
}
|
2630
|
+
});
|
2631
|
+
});
|
2632
|
+
|
2633
|
+
|
2634
|
+
|
2635
|
+
L.Edit = L.Edit || {};
|
2636
|
+
/**
|
2637
|
+
* @class L.Edit.Circle
|
2638
|
+
* @aka Edit.Circle
|
2639
|
+
* @inherits L.Edit.CircleMarker
|
2640
|
+
*/
|
2641
|
+
L.Edit.Circle = L.Edit.CircleMarker.extend({
|
2642
|
+
|
2643
|
+
_createResizeMarker: function () {
|
2644
|
+
var center = this._shape.getLatLng(),
|
2645
|
+
resizemarkerPoint = this._getResizeMarkerPoint(center);
|
2646
|
+
|
2647
|
+
this._resizeMarkers = [];
|
2648
|
+
this._resizeMarkers.push(this._createMarker(resizemarkerPoint, this.options.resizeIcon));
|
2649
|
+
},
|
2650
|
+
|
2651
|
+
_getResizeMarkerPoint: function (latlng) {
|
2652
|
+
// From L.shape.getBounds()
|
2653
|
+
var delta = this._shape._radius * Math.cos(Math.PI / 4),
|
2654
|
+
point = this._map.project(latlng);
|
2655
|
+
return this._map.unproject([point.x + delta, point.y - delta]);
|
2656
|
+
},
|
2657
|
+
|
2658
|
+
_resize: function (latlng) {
|
2659
|
+
var moveLatLng = this._moveMarker.getLatLng(),
|
2660
|
+
radius = this._map.distance(moveLatLng, latlng);
|
2661
|
+
|
2662
|
+
this._shape.setRadius(radius);
|
2663
|
+
|
2664
|
+
this._map.fire(L.Draw.Event.EDITRESIZE, { layer: this._shape });
|
2665
|
+
}
|
2666
|
+
});
|
2667
|
+
|
2668
|
+
L.Circle.addInitHook(function () {
|
2669
|
+
if (L.Edit.Circle) {
|
2670
|
+
this.editing = new L.Edit.Circle(this);
|
2671
|
+
|
2672
|
+
if (this.options.editable) {
|
2673
|
+
this.editing.enable();
|
2674
|
+
}
|
2675
|
+
}
|
2676
|
+
|
2677
|
+
this.on('add', function () {
|
2678
|
+
if (this.editing && this.editing.enabled()) {
|
2679
|
+
this.editing.addHooks();
|
2680
|
+
}
|
2681
|
+
});
|
2682
|
+
|
2683
|
+
this.on('remove', function () {
|
2684
|
+
if (this.editing && this.editing.enabled()) {
|
2685
|
+
this.editing.removeHooks();
|
2686
|
+
}
|
2687
|
+
});
|
2688
|
+
});
|
2689
|
+
|
2690
|
+
|
2691
|
+
|
2692
|
+
L.Map.mergeOptions({
|
2693
|
+
touchExtend: true
|
2694
|
+
});
|
2695
|
+
|
2696
|
+
/**
|
2697
|
+
* @class L.Map.TouchExtend
|
2698
|
+
* @aka TouchExtend
|
2699
|
+
*/
|
2700
|
+
L.Map.TouchExtend = L.Handler.extend({
|
2701
|
+
|
2702
|
+
// @method initialize(): void
|
2703
|
+
// Sets TouchExtend private accessor variables
|
2704
|
+
initialize: function (map) {
|
2705
|
+
this._map = map;
|
2706
|
+
this._container = map._container;
|
2707
|
+
this._pane = map._panes.overlayPane;
|
2708
|
+
},
|
2709
|
+
|
2710
|
+
// @method addHooks(): void
|
2711
|
+
// Adds dom listener events to the map container
|
2712
|
+
addHooks: function () {
|
2713
|
+
L.DomEvent.on(this._container, 'touchstart', this._onTouchStart, this);
|
2714
|
+
L.DomEvent.on(this._container, 'touchend', this._onTouchEnd, this);
|
2715
|
+
L.DomEvent.on(this._container, 'touchmove', this._onTouchMove, this);
|
2716
|
+
if (this._detectIE()) {
|
2717
|
+
L.DomEvent.on(this._container, 'MSPointerDown', this._onTouchStart, this);
|
2718
|
+
L.DomEvent.on(this._container, 'MSPointerUp', this._onTouchEnd, this);
|
2719
|
+
L.DomEvent.on(this._container, 'MSPointerMove', this._onTouchMove, this);
|
2720
|
+
L.DomEvent.on(this._container, 'MSPointerCancel', this._onTouchCancel, this);
|
2721
|
+
|
2722
|
+
} else {
|
2723
|
+
L.DomEvent.on(this._container, 'touchcancel', this._onTouchCancel, this);
|
2724
|
+
L.DomEvent.on(this._container, 'touchleave', this._onTouchLeave, this);
|
2725
|
+
}
|
2726
|
+
},
|
2727
|
+
|
2728
|
+
// @method removeHooks(): void
|
2729
|
+
// Removes dom listener events from the map container
|
2730
|
+
removeHooks: function () {
|
2731
|
+
L.DomEvent.off(this._container, 'touchstart', this._onTouchStart);
|
2732
|
+
L.DomEvent.off(this._container, 'touchend', this._onTouchEnd);
|
2733
|
+
L.DomEvent.off(this._container, 'touchmove', this._onTouchMove);
|
2734
|
+
if (this._detectIE()) {
|
2735
|
+
L.DomEvent.off(this._container, 'MSPointerDowm', this._onTouchStart);
|
2736
|
+
L.DomEvent.off(this._container, 'MSPointerUp', this._onTouchEnd);
|
2737
|
+
L.DomEvent.off(this._container, 'MSPointerMove', this._onTouchMove);
|
2738
|
+
L.DomEvent.off(this._container, 'MSPointerCancel', this._onTouchCancel);
|
2739
|
+
} else {
|
2740
|
+
L.DomEvent.off(this._container, 'touchcancel', this._onTouchCancel);
|
2741
|
+
L.DomEvent.off(this._container, 'touchleave', this._onTouchLeave);
|
2742
|
+
}
|
2743
|
+
},
|
2744
|
+
|
2745
|
+
_touchEvent: function (e, type) {
|
2746
|
+
// #TODO: fix the pageX error that is do a bug in Android where a single touch triggers two click events
|
2747
|
+
// _filterClick is what leaflet uses as a workaround.
|
2748
|
+
// This is a problem with more things than just android. Another problem is touchEnd has no touches in
|
2749
|
+
// its touch list.
|
2750
|
+
var touchEvent = {};
|
2751
|
+
if (typeof e.touches !== 'undefined') {
|
2752
|
+
if (!e.touches.length) {
|
2753
|
+
return;
|
2754
|
+
}
|
2755
|
+
touchEvent = e.touches[0];
|
2756
|
+
} else if (e.pointerType === 'touch') {
|
2757
|
+
touchEvent = e;
|
2758
|
+
if (!this._filterClick(e)) {
|
2759
|
+
return;
|
2760
|
+
}
|
2761
|
+
} else {
|
2762
|
+
return;
|
2763
|
+
}
|
2764
|
+
|
2765
|
+
var containerPoint = this._map.mouseEventToContainerPoint(touchEvent),
|
2766
|
+
layerPoint = this._map.mouseEventToLayerPoint(touchEvent),
|
2767
|
+
latlng = this._map.layerPointToLatLng(layerPoint);
|
2768
|
+
|
2769
|
+
this._map.fire(type, {
|
2770
|
+
latlng: latlng,
|
2771
|
+
layerPoint: layerPoint,
|
2772
|
+
containerPoint: containerPoint,
|
2773
|
+
pageX: touchEvent.pageX,
|
2774
|
+
pageY: touchEvent.pageY,
|
2775
|
+
originalEvent: e
|
2776
|
+
});
|
2777
|
+
},
|
2778
|
+
|
2779
|
+
/** Borrowed from Leaflet and modified for bool ops **/
|
2780
|
+
_filterClick: function (e) {
|
2781
|
+
var timeStamp = (e.timeStamp || e.originalEvent.timeStamp),
|
2782
|
+
elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick);
|
2783
|
+
|
2784
|
+
// are they closer together than 500ms yet more than 100ms?
|
2785
|
+
// Android typically triggers them ~300ms apart while multiple listeners
|
2786
|
+
// on the same event should be triggered far faster;
|
2787
|
+
// or check if click is simulated on the element, and if it is, reject any non-simulated events
|
2788
|
+
if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) {
|
2789
|
+
L.DomEvent.stop(e);
|
2790
|
+
return false;
|
2791
|
+
}
|
2792
|
+
L.DomEvent._lastClick = timeStamp;
|
2793
|
+
return true;
|
2794
|
+
},
|
2795
|
+
|
2796
|
+
_onTouchStart: function (e) {
|
2797
|
+
if (!this._map._loaded) {
|
2798
|
+
return;
|
2799
|
+
}
|
2800
|
+
|
2801
|
+
var type = 'touchstart';
|
2802
|
+
this._touchEvent(e, type);
|
2803
|
+
|
2804
|
+
},
|
2805
|
+
|
2806
|
+
_onTouchEnd: function (e) {
|
2807
|
+
if (!this._map._loaded) {
|
2808
|
+
return;
|
2809
|
+
}
|
2810
|
+
|
2811
|
+
var type = 'touchend';
|
2812
|
+
this._touchEvent(e, type);
|
2813
|
+
},
|
2814
|
+
|
2815
|
+
_onTouchCancel: function (e) {
|
2816
|
+
if (!this._map._loaded) {
|
2817
|
+
return;
|
2818
|
+
}
|
2819
|
+
|
2820
|
+
var type = 'touchcancel';
|
2821
|
+
if (this._detectIE()) {
|
2822
|
+
type = 'pointercancel';
|
2823
|
+
}
|
2824
|
+
this._touchEvent(e, type);
|
2825
|
+
},
|
2826
|
+
|
2827
|
+
_onTouchLeave: function (e) {
|
2828
|
+
if (!this._map._loaded) {
|
2829
|
+
return;
|
2830
|
+
}
|
2831
|
+
|
2832
|
+
var type = 'touchleave';
|
2833
|
+
this._touchEvent(e, type);
|
2834
|
+
},
|
2835
|
+
|
2836
|
+
_onTouchMove: function (e) {
|
2837
|
+
if (!this._map._loaded) {
|
2838
|
+
return;
|
2839
|
+
}
|
2840
|
+
|
2841
|
+
var type = 'touchmove';
|
2842
|
+
this._touchEvent(e, type);
|
2843
|
+
},
|
2844
|
+
|
2845
|
+
_detectIE: function () {
|
2846
|
+
var ua = window.navigator.userAgent;
|
2847
|
+
|
2848
|
+
var msie = ua.indexOf('MSIE ');
|
2849
|
+
if (msie > 0) {
|
2850
|
+
// IE 10 or older => return version number
|
2851
|
+
return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
|
2852
|
+
}
|
2853
|
+
|
2854
|
+
var trident = ua.indexOf('Trident/');
|
2855
|
+
if (trident > 0) {
|
2856
|
+
// IE 11 => return version number
|
2857
|
+
var rv = ua.indexOf('rv:');
|
2858
|
+
return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
|
2859
|
+
}
|
2860
|
+
|
2861
|
+
var edge = ua.indexOf('Edge/');
|
2862
|
+
if (edge > 0) {
|
2863
|
+
// IE 12 => return version number
|
2864
|
+
return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
|
2865
|
+
}
|
2866
|
+
|
2867
|
+
// other browser
|
2868
|
+
return false;
|
2869
|
+
}
|
2870
|
+
});
|
2871
|
+
|
2872
|
+
L.Map.addInitHook('addHandler', 'touchExtend', L.Map.TouchExtend);
|
2873
|
+
|
2874
|
+
|
2875
|
+
/**
|
2876
|
+
* @class L.Marker.Touch
|
2877
|
+
* @aka Marker.Touch
|
2878
|
+
*
|
2879
|
+
* This isn't full Touch support. This is just to get markers to also support dom touch events after creation
|
2880
|
+
* #TODO: find a better way of getting markers to support touch.
|
2881
|
+
*/
|
2882
|
+
L.Marker.Touch = L.Marker.extend({
|
2883
|
+
|
2884
|
+
_initInteraction: function () {
|
2885
|
+
if (!this.addInteractiveTarget) {
|
2886
|
+
// 0.7.x support
|
2887
|
+
return this._initInteractionLegacy();
|
2888
|
+
}
|
2889
|
+
// TODO this may need be updated to re-add touch events for 1.0+
|
2890
|
+
return L.Marker.prototype._initInteraction.apply(this);
|
2891
|
+
},
|
2892
|
+
|
2893
|
+
// This is an exact copy of https://github.com/Leaflet/Leaflet/blob/v0.7/src/layer/marker/Marker.js
|
2894
|
+
// with the addition of the touch events
|
2895
|
+
_initInteractionLegacy: function () {
|
2896
|
+
|
2897
|
+
if (!this.options.clickable) {
|
2898
|
+
return;
|
2899
|
+
}
|
2900
|
+
|
2901
|
+
// TODO refactor into something shared with Map/Path/etc. to DRY it up
|
2902
|
+
|
2903
|
+
var icon = this._icon,
|
2904
|
+
events = ['dblclick',
|
2905
|
+
'mousedown',
|
2906
|
+
'mouseover',
|
2907
|
+
'mouseout',
|
2908
|
+
'contextmenu',
|
2909
|
+
'touchstart',
|
2910
|
+
'touchend',
|
2911
|
+
'touchmove'];
|
2912
|
+
if (this._detectIE) {
|
2913
|
+
events.concat(['MSPointerDown',
|
2914
|
+
'MSPointerUp',
|
2915
|
+
'MSPointerMove',
|
2916
|
+
'MSPointerCancel']);
|
2917
|
+
} else {
|
2918
|
+
events.concat(['touchcancel']);
|
2919
|
+
}
|
2920
|
+
|
2921
|
+
L.DomUtil.addClass(icon, 'leaflet-clickable');
|
2922
|
+
L.DomEvent.on(icon, 'click', this._onMouseClick, this);
|
2923
|
+
L.DomEvent.on(icon, 'keypress', this._onKeyPress, this);
|
2924
|
+
|
2925
|
+
for (var i = 0; i < events.length; i++) {
|
2926
|
+
L.DomEvent.on(icon, events[i], this._fireMouseEvent, this);
|
2927
|
+
}
|
2928
|
+
|
2929
|
+
if (L.Handler.MarkerDrag) {
|
2930
|
+
this.dragging = new L.Handler.MarkerDrag(this);
|
2931
|
+
|
2932
|
+
if (this.options.draggable) {
|
2933
|
+
this.dragging.enable();
|
2934
|
+
}
|
2935
|
+
}
|
2936
|
+
},
|
2937
|
+
|
2938
|
+
_detectIE: function () {
|
2939
|
+
var ua = window.navigator.userAgent;
|
2940
|
+
|
2941
|
+
var msie = ua.indexOf('MSIE ');
|
2942
|
+
if (msie > 0) {
|
2943
|
+
// IE 10 or older => return version number
|
2944
|
+
return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
|
2945
|
+
}
|
2946
|
+
|
2947
|
+
var trident = ua.indexOf('Trident/');
|
2948
|
+
if (trident > 0) {
|
2949
|
+
// IE 11 => return version number
|
2950
|
+
var rv = ua.indexOf('rv:');
|
2951
|
+
return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
|
2952
|
+
}
|
2953
|
+
|
2954
|
+
var edge = ua.indexOf('Edge/');
|
2955
|
+
if (edge > 0) {
|
2956
|
+
// IE 12 => return version number
|
2957
|
+
return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
|
2958
|
+
}
|
2959
|
+
|
2960
|
+
// other browser
|
2961
|
+
return false;
|
2962
|
+
}
|
2963
|
+
});
|
2964
|
+
|
2965
|
+
|
2966
|
+
|
2967
|
+
/**
|
2968
|
+
* @class L.LatLngUtil
|
2969
|
+
* @aka LatLngUtil
|
2970
|
+
*/
|
2971
|
+
L.LatLngUtil = {
|
2972
|
+
// Clones a LatLngs[], returns [][]
|
2973
|
+
|
2974
|
+
// @method cloneLatLngs(LatLngs[]): L.LatLngs[]
|
2975
|
+
// Clone the latLng point or points or nested points and return an array with those points
|
2976
|
+
cloneLatLngs: function (latlngs) {
|
2977
|
+
var clone = [];
|
2978
|
+
for (var i = 0, l = latlngs.length; i < l; i++) {
|
2979
|
+
// Check for nested array (Polyline/Polygon)
|
2980
|
+
if (Array.isArray(latlngs[i])) {
|
2981
|
+
clone.push(L.LatLngUtil.cloneLatLngs(latlngs[i]));
|
2982
|
+
} else {
|
2983
|
+
clone.push(this.cloneLatLng(latlngs[i]));
|
2984
|
+
}
|
2985
|
+
}
|
2986
|
+
return clone;
|
2987
|
+
},
|
2988
|
+
|
2989
|
+
// @method cloneLatLng(LatLng): L.LatLng
|
2990
|
+
// Clone the latLng and return a new LatLng object.
|
2991
|
+
cloneLatLng: function (latlng) {
|
2992
|
+
return L.latLng(latlng.lat, latlng.lng);
|
2993
|
+
}
|
2994
|
+
};
|
2995
|
+
|
2996
|
+
|
2997
|
+
|
2998
|
+
(function() {
|
2999
|
+
|
3000
|
+
var defaultPrecision = {
|
3001
|
+
km: 2,
|
3002
|
+
ha: 2,
|
3003
|
+
m: 0,
|
3004
|
+
mi: 2,
|
3005
|
+
ac: 2,
|
3006
|
+
yd: 0,
|
3007
|
+
ft: 0,
|
3008
|
+
nm: 2
|
3009
|
+
};
|
3010
|
+
|
3011
|
+
|
3012
|
+
/**
|
3013
|
+
* @class L.GeometryUtil
|
3014
|
+
* @aka GeometryUtil
|
3015
|
+
*/
|
3016
|
+
L.GeometryUtil = L.extend(L.GeometryUtil || {}, {
|
3017
|
+
// Ported from the OpenLayers implementation. See https://github.com/openlayers/openlayers/blob/master/lib/OpenLayers/Geometry/LinearRing.js#L270
|
3018
|
+
|
3019
|
+
// @method geodesicArea(): number
|
3020
|
+
geodesicArea: function (latLngs) {
|
3021
|
+
var pointsCount = latLngs.length,
|
3022
|
+
area = 0.0,
|
3023
|
+
d2r = Math.PI / 180,
|
3024
|
+
p1, p2;
|
3025
|
+
|
3026
|
+
if (pointsCount > 2) {
|
3027
|
+
for (var i = 0; i < pointsCount; i++) {
|
3028
|
+
p1 = latLngs[i];
|
3029
|
+
p2 = latLngs[(i + 1) % pointsCount];
|
3030
|
+
area += ((p2.lng - p1.lng) * d2r) *
|
3031
|
+
(2 + Math.sin(p1.lat * d2r) + Math.sin(p2.lat * d2r));
|
3032
|
+
}
|
3033
|
+
area = area * 6378137.0 * 6378137.0 / 2.0;
|
3034
|
+
}
|
3035
|
+
|
3036
|
+
return Math.abs(area);
|
3037
|
+
},
|
3038
|
+
|
3039
|
+
// @method formattedNumber(n, precision): string
|
3040
|
+
// Returns n in specified number format (if defined) and precision
|
3041
|
+
formattedNumber: function (n, precision) {
|
3042
|
+
var formatted = parseFloat(n).toFixed(precision),
|
3043
|
+
format = L.drawLocal.format && L.drawLocal.format.numeric,
|
3044
|
+
delimiters = format && format.delimiters,
|
3045
|
+
thousands = delimiters && delimiters.thousands,
|
3046
|
+
decimal = delimiters && delimiters.decimal;
|
3047
|
+
|
3048
|
+
if (thousands || decimal) {
|
3049
|
+
var splitValue = formatted.split('.');
|
3050
|
+
formatted = thousands ? splitValue[0].replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + thousands) : splitValue[0];
|
3051
|
+
decimal = decimal || '.';
|
3052
|
+
if (splitValue.length > 1) {
|
3053
|
+
formatted = formatted + decimal + splitValue[1];
|
3054
|
+
}
|
3055
|
+
}
|
3056
|
+
|
3057
|
+
return formatted;
|
3058
|
+
},
|
3059
|
+
|
3060
|
+
// @method readableArea(area, isMetric, precision): string
|
3061
|
+
// Returns a readable area string in yards or metric.
|
3062
|
+
// The value will be rounded as defined by the precision option object.
|
3063
|
+
readableArea: function (area, isMetric, precision) {
|
3064
|
+
var areaStr,
|
3065
|
+
units,
|
3066
|
+
precision = L.Util.extend({}, defaultPrecision, precision);
|
3067
|
+
|
3068
|
+
if (isMetric) {
|
3069
|
+
units = ['ha', 'm'];
|
3070
|
+
type = typeof isMetric;
|
3071
|
+
if (type === 'string') {
|
3072
|
+
units = [isMetric];
|
3073
|
+
} else if (type !== 'boolean') {
|
3074
|
+
units = isMetric;
|
3075
|
+
}
|
3076
|
+
|
3077
|
+
if (area >= 1000000 && units.indexOf('km') !== -1) {
|
3078
|
+
areaStr = L.GeometryUtil.formattedNumber(area * 0.000001, precision['km']) + ' km²';
|
3079
|
+
} else if (area >= 10000 && units.indexOf('ha') !== -1) {
|
3080
|
+
areaStr = L.GeometryUtil.formattedNumber(area * 0.0001, precision['ha']) + ' ha';
|
3081
|
+
} else {
|
3082
|
+
areaStr = L.GeometryUtil.formattedNumber(area, precision['m']) + ' m²';
|
3083
|
+
}
|
3084
|
+
} else {
|
3085
|
+
area /= 0.836127; // Square yards in 1 meter
|
3086
|
+
|
3087
|
+
if (area >= 3097600) { //3097600 square yards in 1 square mile
|
3088
|
+
areaStr = L.GeometryUtil.formattedNumber(area / 3097600, precision['mi']) + ' mi²';
|
3089
|
+
} else if (area >= 4840) { //4840 square yards in 1 acre
|
3090
|
+
areaStr = L.GeometryUtil.formattedNumber(area / 4840, precision['ac']) + ' acres';
|
3091
|
+
} else {
|
3092
|
+
areaStr = L.GeometryUtil.formattedNumber(area, precision['yd']) + ' yd²';
|
3093
|
+
}
|
3094
|
+
}
|
3095
|
+
|
3096
|
+
return areaStr;
|
3097
|
+
},
|
3098
|
+
|
3099
|
+
// @method readableDistance(distance, units): string
|
3100
|
+
// Converts a metric distance to one of [ feet, nauticalMile, metric or yards ] string
|
3101
|
+
//
|
3102
|
+
// @alternative
|
3103
|
+
// @method readableDistance(distance, isMetric, useFeet, isNauticalMile, precision): string
|
3104
|
+
// Converts metric distance to distance string.
|
3105
|
+
// The value will be rounded as defined by the precision option object.
|
3106
|
+
readableDistance: function (distance, isMetric, isFeet, isNauticalMile, precision) {
|
3107
|
+
var distanceStr,
|
3108
|
+
units,
|
3109
|
+
precision = L.Util.extend({}, defaultPrecision, precision);
|
3110
|
+
|
3111
|
+
if (isMetric) {
|
3112
|
+
units = typeof isMetric == 'string' ? isMetric : 'metric';
|
3113
|
+
} else if (isFeet) {
|
3114
|
+
units = 'feet';
|
3115
|
+
} else if (isNauticalMile) {
|
3116
|
+
units = 'nauticalMile';
|
3117
|
+
} else {
|
3118
|
+
units = 'yards';
|
3119
|
+
}
|
3120
|
+
|
3121
|
+
switch (units) {
|
3122
|
+
case 'metric':
|
3123
|
+
// show metres when distance is < 1km, then show km
|
3124
|
+
if (distance > 1000) {
|
3125
|
+
distanceStr = L.GeometryUtil.formattedNumber(distance / 1000, precision['km']) + ' km';
|
3126
|
+
} else {
|
3127
|
+
distanceStr = L.GeometryUtil.formattedNumber(distance, precision['m']) + ' m';
|
3128
|
+
}
|
3129
|
+
break;
|
3130
|
+
case 'feet':
|
3131
|
+
distance *= 1.09361 * 3;
|
3132
|
+
distanceStr = L.GeometryUtil.formattedNumber(distance, precision['ft']) + ' ft';
|
3133
|
+
|
3134
|
+
break;
|
3135
|
+
case 'nauticalMile':
|
3136
|
+
distance *= 0.53996;
|
3137
|
+
distanceStr = L.GeometryUtil.formattedNumber(distance / 1000, precision['nm']) + ' nm';
|
3138
|
+
break;
|
3139
|
+
case 'yards':
|
3140
|
+
default:
|
3141
|
+
distance *= 1.09361;
|
3142
|
+
|
3143
|
+
if (distance > 1760) {
|
3144
|
+
distanceStr = L.GeometryUtil.formattedNumber(distance / 1760, precision['mi']) + ' miles';
|
3145
|
+
} else {
|
3146
|
+
distanceStr = L.GeometryUtil.formattedNumber(distance, precision['yd']) + ' yd';
|
3147
|
+
}
|
3148
|
+
break;
|
3149
|
+
}
|
3150
|
+
return distanceStr;
|
3151
|
+
}
|
3152
|
+
});
|
3153
|
+
|
3154
|
+
})();
|
3155
|
+
|
3156
|
+
|
3157
|
+
|
3158
|
+
/**
|
3159
|
+
* @class L.LineUtil
|
3160
|
+
* @aka Util
|
3161
|
+
* @aka L.Utils
|
3162
|
+
*/
|
3163
|
+
L.Util.extend(L.LineUtil, {
|
3164
|
+
|
3165
|
+
// @method segmentsIntersect(): boolean
|
3166
|
+
// Checks to see if two line segments intersect. Does not handle degenerate cases.
|
3167
|
+
// http://compgeom.cs.uiuc.edu/~jeffe/teaching/373/notes/x06-sweepline.pdf
|
3168
|
+
segmentsIntersect: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2, /*Point*/ p3) {
|
3169
|
+
return this._checkCounterclockwise(p, p2, p3) !==
|
3170
|
+
this._checkCounterclockwise(p1, p2, p3) &&
|
3171
|
+
this._checkCounterclockwise(p, p1, p2) !==
|
3172
|
+
this._checkCounterclockwise(p, p1, p3);
|
3173
|
+
},
|
3174
|
+
|
3175
|
+
// check to see if points are in counterclockwise order
|
3176
|
+
_checkCounterclockwise: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) {
|
3177
|
+
return (p2.y - p.y) * (p1.x - p.x) > (p1.y - p.y) * (p2.x - p.x);
|
3178
|
+
}
|
3179
|
+
});
|
3180
|
+
|
3181
|
+
|
3182
|
+
/**
|
3183
|
+
* @class L.Polyline
|
3184
|
+
* @aka Polyline
|
3185
|
+
*/
|
3186
|
+
L.Polyline.include({
|
3187
|
+
|
3188
|
+
// @method intersects(): boolean
|
3189
|
+
// Check to see if this polyline has any linesegments that intersect.
|
3190
|
+
// NOTE: does not support detecting intersection for degenerate cases.
|
3191
|
+
intersects: function () {
|
3192
|
+
var points = this._getProjectedPoints(),
|
3193
|
+
len = points ? points.length : 0,
|
3194
|
+
i, p, p1;
|
3195
|
+
|
3196
|
+
if (this._tooFewPointsForIntersection()) {
|
3197
|
+
return false;
|
3198
|
+
}
|
3199
|
+
|
3200
|
+
for (i = len - 1; i >= 3; i--) {
|
3201
|
+
p = points[i - 1];
|
3202
|
+
p1 = points[i];
|
3203
|
+
|
3204
|
+
|
3205
|
+
if (this._lineSegmentsIntersectsRange(p, p1, i - 2)) {
|
3206
|
+
return true;
|
3207
|
+
}
|
3208
|
+
}
|
3209
|
+
|
3210
|
+
return false;
|
3211
|
+
},
|
3212
|
+
|
3213
|
+
// @method newLatLngIntersects(): boolean
|
3214
|
+
// Check for intersection if new latlng was added to this polyline.
|
3215
|
+
// NOTE: does not support detecting intersection for degenerate cases.
|
3216
|
+
newLatLngIntersects: function (latlng, skipFirst) {
|
3217
|
+
// Cannot check a polyline for intersecting lats/lngs when not added to the map
|
3218
|
+
if (!this._map) {
|
3219
|
+
return false;
|
3220
|
+
}
|
3221
|
+
|
3222
|
+
return this.newPointIntersects(this._map.latLngToLayerPoint(latlng), skipFirst);
|
3223
|
+
},
|
3224
|
+
|
3225
|
+
// @method newPointIntersects(): boolean
|
3226
|
+
// Check for intersection if new point was added to this polyline.
|
3227
|
+
// newPoint must be a layer point.
|
3228
|
+
// NOTE: does not support detecting intersection for degenerate cases.
|
3229
|
+
newPointIntersects: function (newPoint, skipFirst) {
|
3230
|
+
var points = this._getProjectedPoints(),
|
3231
|
+
len = points ? points.length : 0,
|
3232
|
+
lastPoint = points ? points[len - 1] : null,
|
3233
|
+
// The previous previous line segment. Previous line segment doesn't need testing.
|
3234
|
+
maxIndex = len - 2;
|
3235
|
+
|
3236
|
+
if (this._tooFewPointsForIntersection(1)) {
|
3237
|
+
return false;
|
3238
|
+
}
|
3239
|
+
|
3240
|
+
return this._lineSegmentsIntersectsRange(lastPoint, newPoint, maxIndex, skipFirst ? 1 : 0);
|
3241
|
+
},
|
3242
|
+
|
3243
|
+
// Polylines with 2 sides can only intersect in cases where points are collinear (we don't support detecting these).
|
3244
|
+
// Cannot have intersection when < 3 line segments (< 4 points)
|
3245
|
+
_tooFewPointsForIntersection: function (extraPoints) {
|
3246
|
+
var points = this._getProjectedPoints(),
|
3247
|
+
len = points ? points.length : 0;
|
3248
|
+
// Increment length by extraPoints if present
|
3249
|
+
len += extraPoints || 0;
|
3250
|
+
|
3251
|
+
return !points || len <= 3;
|
3252
|
+
},
|
3253
|
+
|
3254
|
+
// Checks a line segment intersections with any line segments before its predecessor.
|
3255
|
+
// Don't need to check the predecessor as will never intersect.
|
3256
|
+
_lineSegmentsIntersectsRange: function (p, p1, maxIndex, minIndex) {
|
3257
|
+
var points = this._getProjectedPoints(),
|
3258
|
+
p2, p3;
|
3259
|
+
|
3260
|
+
minIndex = minIndex || 0;
|
3261
|
+
|
3262
|
+
// Check all previous line segments (beside the immediately previous) for intersections
|
3263
|
+
for (var j = maxIndex; j > minIndex; j--) {
|
3264
|
+
p2 = points[j - 1];
|
3265
|
+
p3 = points[j];
|
3266
|
+
|
3267
|
+
if (L.LineUtil.segmentsIntersect(p, p1, p2, p3)) {
|
3268
|
+
return true;
|
3269
|
+
}
|
3270
|
+
}
|
3271
|
+
|
3272
|
+
return false;
|
3273
|
+
},
|
3274
|
+
|
3275
|
+
_getProjectedPoints: function () {
|
3276
|
+
if (!this._defaultShape) {
|
3277
|
+
return this._originalPoints;
|
3278
|
+
}
|
3279
|
+
var points = [],
|
3280
|
+
_shape = this._defaultShape();
|
3281
|
+
|
3282
|
+
for (var i = 0; i < _shape.length; i++) {
|
3283
|
+
points.push(this._map.latLngToLayerPoint(_shape[i]));
|
3284
|
+
}
|
3285
|
+
return points;
|
3286
|
+
}
|
3287
|
+
});
|
3288
|
+
|
3289
|
+
|
3290
|
+
|
3291
|
+
/**
|
3292
|
+
* @class L.Polygon
|
3293
|
+
* @aka Polygon
|
3294
|
+
*/
|
3295
|
+
L.Polygon.include({
|
3296
|
+
|
3297
|
+
// @method intersects(): boolean
|
3298
|
+
// Checks a polygon for any intersecting line segments. Ignores holes.
|
3299
|
+
intersects: function () {
|
3300
|
+
var polylineIntersects,
|
3301
|
+
points = this._getProjectedPoints(),
|
3302
|
+
len, firstPoint, lastPoint, maxIndex;
|
3303
|
+
|
3304
|
+
if (this._tooFewPointsForIntersection()) {
|
3305
|
+
return false;
|
3306
|
+
}
|
3307
|
+
|
3308
|
+
polylineIntersects = L.Polyline.prototype.intersects.call(this);
|
3309
|
+
|
3310
|
+
// If already found an intersection don't need to check for any more.
|
3311
|
+
if (polylineIntersects) {
|
3312
|
+
return true;
|
3313
|
+
}
|
3314
|
+
|
3315
|
+
len = points.length;
|
3316
|
+
firstPoint = points[0];
|
3317
|
+
lastPoint = points[len - 1];
|
3318
|
+
maxIndex = len - 2;
|
3319
|
+
|
3320
|
+
// Check the line segment between last and first point. Don't need to check the first line segment (minIndex = 1)
|
3321
|
+
return this._lineSegmentsIntersectsRange(lastPoint, firstPoint, maxIndex, 1);
|
3322
|
+
}
|
3323
|
+
});
|
3324
|
+
|
3325
|
+
|
3326
|
+
|
3327
|
+
/**
|
3328
|
+
* @class L.Control.Draw
|
3329
|
+
* @aka L.Draw
|
3330
|
+
*/
|
3331
|
+
L.Control.Draw = L.Control.extend({
|
3332
|
+
|
3333
|
+
// Options
|
3334
|
+
options: {
|
3335
|
+
position: 'topleft',
|
3336
|
+
draw: {},
|
3337
|
+
edit: false
|
3338
|
+
},
|
3339
|
+
|
3340
|
+
// @method initialize(): void
|
3341
|
+
// Initializes draw control, toolbars from the options
|
3342
|
+
initialize: function (options) {
|
3343
|
+
if (L.version < '0.7') {
|
3344
|
+
throw new Error('Leaflet.draw 0.2.3+ requires Leaflet 0.7.0+. Download latest from https://github.com/Leaflet/Leaflet/');
|
3345
|
+
}
|
3346
|
+
|
3347
|
+
L.Control.prototype.initialize.call(this, options);
|
3348
|
+
|
3349
|
+
var toolbar;
|
3350
|
+
|
3351
|
+
this._toolbars = {};
|
3352
|
+
|
3353
|
+
// Initialize toolbars
|
3354
|
+
if (L.DrawToolbar && this.options.draw) {
|
3355
|
+
toolbar = new L.DrawToolbar(this.options.draw);
|
3356
|
+
|
3357
|
+
this._toolbars[L.DrawToolbar.TYPE] = toolbar;
|
3358
|
+
|
3359
|
+
// Listen for when toolbar is enabled
|
3360
|
+
this._toolbars[L.DrawToolbar.TYPE].on('enable', this._toolbarEnabled, this);
|
3361
|
+
}
|
3362
|
+
|
3363
|
+
if (L.EditToolbar && this.options.edit) {
|
3364
|
+
toolbar = new L.EditToolbar(this.options.edit);
|
3365
|
+
|
3366
|
+
this._toolbars[L.EditToolbar.TYPE] = toolbar;
|
3367
|
+
|
3368
|
+
// Listen for when toolbar is enabled
|
3369
|
+
this._toolbars[L.EditToolbar.TYPE].on('enable', this._toolbarEnabled, this);
|
3370
|
+
}
|
3371
|
+
L.toolbar = this; //set global var for editing the toolbar
|
3372
|
+
},
|
3373
|
+
|
3374
|
+
// @method onAdd(): container
|
3375
|
+
// Adds the toolbar container to the map
|
3376
|
+
onAdd: function (map) {
|
3377
|
+
var container = L.DomUtil.create('div', 'leaflet-draw'),
|
3378
|
+
addedTopClass = false,
|
3379
|
+
topClassName = 'leaflet-draw-toolbar-top',
|
3380
|
+
toolbarContainer;
|
3381
|
+
|
3382
|
+
for (var toolbarId in this._toolbars) {
|
3383
|
+
if (this._toolbars.hasOwnProperty(toolbarId)) {
|
3384
|
+
toolbarContainer = this._toolbars[toolbarId].addToolbar(map);
|
3385
|
+
|
3386
|
+
if (toolbarContainer) {
|
3387
|
+
// Add class to the first toolbar to remove the margin
|
3388
|
+
if (!addedTopClass) {
|
3389
|
+
if (!L.DomUtil.hasClass(toolbarContainer, topClassName)) {
|
3390
|
+
L.DomUtil.addClass(toolbarContainer.childNodes[0], topClassName);
|
3391
|
+
}
|
3392
|
+
addedTopClass = true;
|
3393
|
+
}
|
3394
|
+
|
3395
|
+
container.appendChild(toolbarContainer);
|
3396
|
+
}
|
3397
|
+
}
|
3398
|
+
}
|
3399
|
+
|
3400
|
+
return container;
|
3401
|
+
},
|
3402
|
+
|
3403
|
+
// @method onRemove(): void
|
3404
|
+
// Removes the toolbars from the map toolbar container
|
3405
|
+
onRemove: function () {
|
3406
|
+
for (var toolbarId in this._toolbars) {
|
3407
|
+
if (this._toolbars.hasOwnProperty(toolbarId)) {
|
3408
|
+
this._toolbars[toolbarId].removeToolbar();
|
3409
|
+
}
|
3410
|
+
}
|
3411
|
+
},
|
3412
|
+
|
3413
|
+
// @method setDrawingOptions(options): void
|
3414
|
+
// Sets options to all toolbar instances
|
3415
|
+
setDrawingOptions: function (options) {
|
3416
|
+
for (var toolbarId in this._toolbars) {
|
3417
|
+
if (this._toolbars[toolbarId] instanceof L.DrawToolbar) {
|
3418
|
+
this._toolbars[toolbarId].setOptions(options);
|
3419
|
+
}
|
3420
|
+
}
|
3421
|
+
},
|
3422
|
+
|
3423
|
+
_toolbarEnabled: function (e) {
|
3424
|
+
var enabledToolbar = e.target;
|
3425
|
+
|
3426
|
+
for (var toolbarId in this._toolbars) {
|
3427
|
+
if (this._toolbars[toolbarId] !== enabledToolbar) {
|
3428
|
+
this._toolbars[toolbarId].disable();
|
3429
|
+
}
|
3430
|
+
}
|
3431
|
+
}
|
3432
|
+
});
|
3433
|
+
|
3434
|
+
L.Map.mergeOptions({
|
3435
|
+
drawControlTooltips: true,
|
3436
|
+
drawControl: false
|
3437
|
+
});
|
3438
|
+
|
3439
|
+
L.Map.addInitHook(function () {
|
3440
|
+
if (this.options.drawControl) {
|
3441
|
+
this.drawControl = new L.Control.Draw();
|
3442
|
+
this.addControl(this.drawControl);
|
3443
|
+
}
|
3444
|
+
});
|
3445
|
+
|
3446
|
+
|
3447
|
+
|
3448
|
+
/**
|
3449
|
+
* @class L.Draw.Toolbar
|
3450
|
+
* @aka Toolbar
|
3451
|
+
*
|
3452
|
+
* The toolbar class of the API — it is used to create the ui
|
3453
|
+
* This will be depreciated
|
3454
|
+
*
|
3455
|
+
* @example
|
3456
|
+
*
|
3457
|
+
* ```js
|
3458
|
+
* var toolbar = L.Toolbar();
|
3459
|
+
* toolbar.addToolbar(map);
|
3460
|
+
* ```
|
3461
|
+
*
|
3462
|
+
* ### Disabling a toolbar
|
3463
|
+
*
|
3464
|
+
* If you do not want a particular toolbar in your app you can turn it off by setting the toolbar to false.
|
3465
|
+
*
|
3466
|
+
* ```js
|
3467
|
+
* var drawControl = new L.Control.Draw({
|
3468
|
+
* draw: false,
|
3469
|
+
* edit: {
|
3470
|
+
* featureGroup: editableLayers
|
3471
|
+
* }
|
3472
|
+
* });
|
3473
|
+
* ```
|
3474
|
+
*
|
3475
|
+
* ### Disabling a toolbar item
|
3476
|
+
*
|
3477
|
+
* If you want to turn off a particular toolbar item, set it to false. The following disables drawing polygons and
|
3478
|
+
* markers. It also turns off the ability to edit layers.
|
3479
|
+
*
|
3480
|
+
* ```js
|
3481
|
+
* var drawControl = new L.Control.Draw({
|
3482
|
+
* draw: {
|
3483
|
+
* polygon: false,
|
3484
|
+
* marker: false
|
3485
|
+
* },
|
3486
|
+
* edit: {
|
3487
|
+
* featureGroup: editableLayers,
|
3488
|
+
* edit: false
|
3489
|
+
* }
|
3490
|
+
* });
|
3491
|
+
* ```
|
3492
|
+
*/
|
3493
|
+
L.Toolbar = L.Class.extend({
|
3494
|
+
includes: [L.Mixin.Events],
|
3495
|
+
|
3496
|
+
// @section Methods for modifying the toolbar
|
3497
|
+
|
3498
|
+
// @method initialize(options): void
|
3499
|
+
// Toolbar constructor
|
3500
|
+
initialize: function (options) {
|
3501
|
+
L.setOptions(this, options);
|
3502
|
+
|
3503
|
+
this._modes = {};
|
3504
|
+
this._actionButtons = [];
|
3505
|
+
this._activeMode = null;
|
3506
|
+
},
|
3507
|
+
|
3508
|
+
// @method enabled(): boolean
|
3509
|
+
// Gets a true/false of whether the toolbar is enabled
|
3510
|
+
enabled: function () {
|
3511
|
+
return this._activeMode !== null;
|
3512
|
+
},
|
3513
|
+
|
3514
|
+
// @method disable(): void
|
3515
|
+
// Disables the toolbar
|
3516
|
+
disable: function () {
|
3517
|
+
if (!this.enabled()) {
|
3518
|
+
return;
|
3519
|
+
}
|
3520
|
+
|
3521
|
+
this._activeMode.handler.disable();
|
3522
|
+
},
|
3523
|
+
|
3524
|
+
// @method addToolbar(map): L.DomUtil
|
3525
|
+
// Adds the toolbar to the map and returns the toolbar dom element
|
3526
|
+
addToolbar: function (map) {
|
3527
|
+
var container = L.DomUtil.create('div', 'leaflet-draw-section'),
|
3528
|
+
buttonIndex = 0,
|
3529
|
+
buttonClassPrefix = this._toolbarClass || '',
|
3530
|
+
modeHandlers = this.getModeHandlers(map),
|
3531
|
+
i;
|
3532
|
+
|
3533
|
+
this._toolbarContainer = L.DomUtil.create('div', 'leaflet-draw-toolbar leaflet-bar');
|
3534
|
+
this._map = map;
|
3535
|
+
|
3536
|
+
for (i = 0; i < modeHandlers.length; i++) {
|
3537
|
+
if (modeHandlers[i].enabled) {
|
3538
|
+
this._initModeHandler(
|
3539
|
+
modeHandlers[i].handler,
|
3540
|
+
this._toolbarContainer,
|
3541
|
+
buttonIndex++,
|
3542
|
+
buttonClassPrefix,
|
3543
|
+
modeHandlers[i].title
|
3544
|
+
);
|
3545
|
+
}
|
3546
|
+
}
|
3547
|
+
|
3548
|
+
// if no buttons were added, do not add the toolbar
|
3549
|
+
if (!buttonIndex) {
|
3550
|
+
return;
|
3551
|
+
}
|
3552
|
+
|
3553
|
+
// Save button index of the last button, -1 as we would have ++ after the last button
|
3554
|
+
this._lastButtonIndex = --buttonIndex;
|
3555
|
+
|
3556
|
+
// Create empty actions part of the toolbar
|
3557
|
+
this._actionsContainer = L.DomUtil.create('ul', 'leaflet-draw-actions');
|
3558
|
+
|
3559
|
+
// Add draw and cancel containers to the control container
|
3560
|
+
container.appendChild(this._toolbarContainer);
|
3561
|
+
container.appendChild(this._actionsContainer);
|
3562
|
+
|
3563
|
+
return container;
|
3564
|
+
},
|
3565
|
+
|
3566
|
+
// @method removeToolbar(): void
|
3567
|
+
// Removes the toolbar and drops the handler event listeners
|
3568
|
+
removeToolbar: function () {
|
3569
|
+
// Dispose each handler
|
3570
|
+
for (var handlerId in this._modes) {
|
3571
|
+
if (this._modes.hasOwnProperty(handlerId)) {
|
3572
|
+
// Unbind handler button
|
3573
|
+
this._disposeButton(
|
3574
|
+
this._modes[handlerId].button,
|
3575
|
+
this._modes[handlerId].handler.enable,
|
3576
|
+
this._modes[handlerId].handler
|
3577
|
+
);
|
3578
|
+
|
3579
|
+
// Make sure is disabled
|
3580
|
+
this._modes[handlerId].handler.disable();
|
3581
|
+
|
3582
|
+
// Unbind handler
|
3583
|
+
this._modes[handlerId].handler
|
3584
|
+
.off('enabled', this._handlerActivated, this)
|
3585
|
+
.off('disabled', this._handlerDeactivated, this);
|
3586
|
+
}
|
3587
|
+
}
|
3588
|
+
this._modes = {};
|
3589
|
+
|
3590
|
+
// Dispose the actions toolbar
|
3591
|
+
for (var i = 0, l = this._actionButtons.length; i < l; i++) {
|
3592
|
+
this._disposeButton(
|
3593
|
+
this._actionButtons[i].button,
|
3594
|
+
this._actionButtons[i].callback,
|
3595
|
+
this
|
3596
|
+
);
|
3597
|
+
}
|
3598
|
+
this._actionButtons = [];
|
3599
|
+
this._actionsContainer = null;
|
3600
|
+
},
|
3601
|
+
|
3602
|
+
_initModeHandler: function (handler, container, buttonIndex, classNamePredix, buttonTitle) {
|
3603
|
+
var type = handler.type;
|
3604
|
+
|
3605
|
+
this._modes[type] = {};
|
3606
|
+
|
3607
|
+
this._modes[type].handler = handler;
|
3608
|
+
|
3609
|
+
this._modes[type].button = this._createButton({
|
3610
|
+
type: type,
|
3611
|
+
title: buttonTitle,
|
3612
|
+
className: classNamePredix + '-' + type,
|
3613
|
+
container: container,
|
3614
|
+
callback: this._modes[type].handler.enable,
|
3615
|
+
context: this._modes[type].handler
|
3616
|
+
});
|
3617
|
+
|
3618
|
+
this._modes[type].buttonIndex = buttonIndex;
|
3619
|
+
|
3620
|
+
this._modes[type].handler
|
3621
|
+
.on('enabled', this._handlerActivated, this)
|
3622
|
+
.on('disabled', this._handlerDeactivated, this);
|
3623
|
+
},
|
3624
|
+
|
3625
|
+
/* Detect iOS based on browser User Agent, based on:
|
3626
|
+
* http://stackoverflow.com/a/9039885 */
|
3627
|
+
_detectIOS: function () {
|
3628
|
+
var iOS = (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream);
|
3629
|
+
return iOS;
|
3630
|
+
},
|
3631
|
+
|
3632
|
+
_createButton: function (options) {
|
3633
|
+
|
3634
|
+
var link = L.DomUtil.create('a', options.className || '', options.container);
|
3635
|
+
// Screen reader tag
|
3636
|
+
var sr = L.DomUtil.create('span', 'sr-only', options.container);
|
3637
|
+
|
3638
|
+
link.href = '#';
|
3639
|
+
link.appendChild(sr);
|
3640
|
+
|
3641
|
+
if (options.title) {
|
3642
|
+
link.title = options.title;
|
3643
|
+
sr.innerHTML = options.title;
|
3644
|
+
}
|
3645
|
+
|
3646
|
+
if (options.text) {
|
3647
|
+
link.innerHTML = options.text;
|
3648
|
+
sr.innerHTML = options.text;
|
3649
|
+
}
|
3650
|
+
|
3651
|
+
/* iOS does not use click events */
|
3652
|
+
var buttonEvent = this._detectIOS() ? 'touchstart' : 'click';
|
3653
|
+
|
3654
|
+
L.DomEvent
|
3655
|
+
.on(link, 'click', L.DomEvent.stopPropagation)
|
3656
|
+
.on(link, 'mousedown', L.DomEvent.stopPropagation)
|
3657
|
+
.on(link, 'dblclick', L.DomEvent.stopPropagation)
|
3658
|
+
.on(link, 'touchstart', L.DomEvent.stopPropagation)
|
3659
|
+
.on(link, 'click', L.DomEvent.preventDefault)
|
3660
|
+
.on(link, buttonEvent, options.callback, options.context);
|
3661
|
+
|
3662
|
+
return link;
|
3663
|
+
},
|
3664
|
+
|
3665
|
+
_disposeButton: function (button, callback) {
|
3666
|
+
/* iOS does not use click events */
|
3667
|
+
var buttonEvent = this._detectIOS() ? 'touchstart' : 'click';
|
3668
|
+
|
3669
|
+
L.DomEvent
|
3670
|
+
.off(button, 'click', L.DomEvent.stopPropagation)
|
3671
|
+
.off(button, 'mousedown', L.DomEvent.stopPropagation)
|
3672
|
+
.off(button, 'dblclick', L.DomEvent.stopPropagation)
|
3673
|
+
.off(button, 'touchstart', L.DomEvent.stopPropagation)
|
3674
|
+
.off(button, 'click', L.DomEvent.preventDefault)
|
3675
|
+
.off(button, buttonEvent, callback);
|
3676
|
+
},
|
3677
|
+
|
3678
|
+
_handlerActivated: function (e) {
|
3679
|
+
// Disable active mode (if present)
|
3680
|
+
this.disable();
|
3681
|
+
|
3682
|
+
// Cache new active feature
|
3683
|
+
this._activeMode = this._modes[e.handler];
|
3684
|
+
|
3685
|
+
L.DomUtil.addClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled');
|
3686
|
+
|
3687
|
+
this._showActionsToolbar();
|
3688
|
+
|
3689
|
+
this.fire('enable');
|
3690
|
+
},
|
3691
|
+
|
3692
|
+
_handlerDeactivated: function () {
|
3693
|
+
this._hideActionsToolbar();
|
3694
|
+
|
3695
|
+
L.DomUtil.removeClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled');
|
3696
|
+
|
3697
|
+
this._activeMode = null;
|
3698
|
+
|
3699
|
+
this.fire('disable');
|
3700
|
+
},
|
3701
|
+
|
3702
|
+
_createActions: function (handler) {
|
3703
|
+
var container = this._actionsContainer,
|
3704
|
+
buttons = this.getActions(handler),
|
3705
|
+
l = buttons.length,
|
3706
|
+
li, di, dl, button;
|
3707
|
+
|
3708
|
+
// Dispose the actions toolbar (todo: dispose only not used buttons)
|
3709
|
+
for (di = 0, dl = this._actionButtons.length; di < dl; di++) {
|
3710
|
+
this._disposeButton(this._actionButtons[di].button, this._actionButtons[di].callback);
|
3711
|
+
}
|
3712
|
+
this._actionButtons = [];
|
3713
|
+
|
3714
|
+
// Remove all old buttons
|
3715
|
+
while (container.firstChild) {
|
3716
|
+
container.removeChild(container.firstChild);
|
3717
|
+
}
|
3718
|
+
|
3719
|
+
for (var i = 0; i < l; i++) {
|
3720
|
+
if ('enabled' in buttons[i] && !buttons[i].enabled) {
|
3721
|
+
continue;
|
3722
|
+
}
|
3723
|
+
|
3724
|
+
li = L.DomUtil.create('li', '', container);
|
3725
|
+
|
3726
|
+
button = this._createButton({
|
3727
|
+
title: buttons[i].title,
|
3728
|
+
text: buttons[i].text,
|
3729
|
+
container: li,
|
3730
|
+
callback: buttons[i].callback,
|
3731
|
+
context: buttons[i].context
|
3732
|
+
});
|
3733
|
+
|
3734
|
+
this._actionButtons.push({
|
3735
|
+
button: button,
|
3736
|
+
callback: buttons[i].callback
|
3737
|
+
});
|
3738
|
+
}
|
3739
|
+
},
|
3740
|
+
|
3741
|
+
_showActionsToolbar: function () {
|
3742
|
+
var buttonIndex = this._activeMode.buttonIndex,
|
3743
|
+
lastButtonIndex = this._lastButtonIndex,
|
3744
|
+
toolbarPosition = this._activeMode.button.offsetTop - 1;
|
3745
|
+
|
3746
|
+
// Recreate action buttons on every click
|
3747
|
+
this._createActions(this._activeMode.handler);
|
3748
|
+
|
3749
|
+
// Correctly position the cancel button
|
3750
|
+
this._actionsContainer.style.top = toolbarPosition + 'px';
|
3751
|
+
|
3752
|
+
if (buttonIndex === 0) {
|
3753
|
+
L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop');
|
3754
|
+
L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-top');
|
3755
|
+
}
|
3756
|
+
|
3757
|
+
if (buttonIndex === lastButtonIndex) {
|
3758
|
+
L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom');
|
3759
|
+
L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-bottom');
|
3760
|
+
}
|
3761
|
+
|
3762
|
+
this._actionsContainer.style.display = 'block';
|
3763
|
+
},
|
3764
|
+
|
3765
|
+
_hideActionsToolbar: function () {
|
3766
|
+
this._actionsContainer.style.display = 'none';
|
3767
|
+
|
3768
|
+
L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop');
|
3769
|
+
L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom');
|
3770
|
+
L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-top');
|
3771
|
+
L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-bottom');
|
3772
|
+
}
|
3773
|
+
});
|
3774
|
+
|
3775
|
+
|
3776
|
+
|
3777
|
+
L.Draw = L.Draw || {};
|
3778
|
+
/**
|
3779
|
+
* @class L.Draw.Tooltip
|
3780
|
+
* @aka Tooltip
|
3781
|
+
*
|
3782
|
+
* The tooltip class — it is used to display the tooltip while drawing
|
3783
|
+
* This will be depreciated
|
3784
|
+
*
|
3785
|
+
* @example
|
3786
|
+
*
|
3787
|
+
* ```js
|
3788
|
+
* var tooltip = L.Draw.Tooltip();
|
3789
|
+
* ```
|
3790
|
+
*
|
3791
|
+
*/
|
3792
|
+
L.Draw.Tooltip = L.Class.extend({
|
3793
|
+
|
3794
|
+
// @section Methods for modifying draw state
|
3795
|
+
|
3796
|
+
// @method initialize(map): void
|
3797
|
+
// Tooltip constructor
|
3798
|
+
initialize: function (map) {
|
3799
|
+
this._map = map;
|
3800
|
+
this._popupPane = map._panes.popupPane;
|
3801
|
+
this._visible = false;
|
3802
|
+
|
3803
|
+
this._container = map.options.drawControlTooltips ?
|
3804
|
+
L.DomUtil.create('div', 'leaflet-draw-tooltip', this._popupPane) : null;
|
3805
|
+
this._singleLineLabel = false;
|
3806
|
+
|
3807
|
+
this._map.on('mouseout', this._onMouseOut, this);
|
3808
|
+
},
|
3809
|
+
|
3810
|
+
// @method dispose(): void
|
3811
|
+
// Remove Tooltip DOM and unbind events
|
3812
|
+
dispose: function () {
|
3813
|
+
this._map.off('mouseout', this._onMouseOut, this);
|
3814
|
+
|
3815
|
+
if (this._container) {
|
3816
|
+
this._popupPane.removeChild(this._container);
|
3817
|
+
this._container = null;
|
3818
|
+
}
|
3819
|
+
},
|
3820
|
+
|
3821
|
+
// @method updateContent(labelText): this
|
3822
|
+
// Changes the tooltip text to string in function call
|
3823
|
+
updateContent: function (labelText) {
|
3824
|
+
if (!this._container) {
|
3825
|
+
return this;
|
3826
|
+
}
|
3827
|
+
labelText.subtext = labelText.subtext || '';
|
3828
|
+
|
3829
|
+
// update the vertical position (only if changed)
|
3830
|
+
if (labelText.subtext.length === 0 && !this._singleLineLabel) {
|
3831
|
+
L.DomUtil.addClass(this._container, 'leaflet-draw-tooltip-single');
|
3832
|
+
this._singleLineLabel = true;
|
3833
|
+
}
|
3834
|
+
else if (labelText.subtext.length > 0 && this._singleLineLabel) {
|
3835
|
+
L.DomUtil.removeClass(this._container, 'leaflet-draw-tooltip-single');
|
3836
|
+
this._singleLineLabel = false;
|
3837
|
+
}
|
3838
|
+
|
3839
|
+
this._container.innerHTML =
|
3840
|
+
(labelText.subtext.length > 0 ?
|
3841
|
+
'<span class="leaflet-draw-tooltip-subtext">' + labelText.subtext + '</span>' + '<br />' : '') +
|
3842
|
+
'<span>' + labelText.text + '</span>';
|
3843
|
+
|
3844
|
+
if (!labelText.text && !labelText.subtext) {
|
3845
|
+
this._visible = false;
|
3846
|
+
this._container.style.visibility = 'hidden';
|
3847
|
+
} else {
|
3848
|
+
this._visible = true;
|
3849
|
+
this._container.style.visibility = 'inherit';
|
3850
|
+
}
|
3851
|
+
|
3852
|
+
return this;
|
3853
|
+
},
|
3854
|
+
|
3855
|
+
// @method updatePosition(latlng): this
|
3856
|
+
// Changes the location of the tooltip
|
3857
|
+
updatePosition: function (latlng) {
|
3858
|
+
var pos = this._map.latLngToLayerPoint(latlng),
|
3859
|
+
tooltipContainer = this._container;
|
3860
|
+
|
3861
|
+
if (this._container) {
|
3862
|
+
if (this._visible) {
|
3863
|
+
tooltipContainer.style.visibility = 'inherit';
|
3864
|
+
}
|
3865
|
+
L.DomUtil.setPosition(tooltipContainer, pos);
|
3866
|
+
}
|
3867
|
+
|
3868
|
+
return this;
|
3869
|
+
},
|
3870
|
+
|
3871
|
+
// @method showAsError(): this
|
3872
|
+
// Applies error class to tooltip
|
3873
|
+
showAsError: function () {
|
3874
|
+
if (this._container) {
|
3875
|
+
L.DomUtil.addClass(this._container, 'leaflet-error-draw-tooltip');
|
3876
|
+
}
|
3877
|
+
return this;
|
3878
|
+
},
|
3879
|
+
|
3880
|
+
// @method removeError(): this
|
3881
|
+
// Removes the error class from the tooltip
|
3882
|
+
removeError: function () {
|
3883
|
+
if (this._container) {
|
3884
|
+
L.DomUtil.removeClass(this._container, 'leaflet-error-draw-tooltip');
|
3885
|
+
}
|
3886
|
+
return this;
|
3887
|
+
},
|
3888
|
+
|
3889
|
+
_onMouseOut: function () {
|
3890
|
+
if (this._container) {
|
3891
|
+
this._container.style.visibility = 'hidden';
|
3892
|
+
}
|
3893
|
+
}
|
3894
|
+
});
|
3895
|
+
|
3896
|
+
|
3897
|
+
|
3898
|
+
/**
|
3899
|
+
* @class L.DrawToolbar
|
3900
|
+
* @aka Toolbar
|
3901
|
+
*/
|
3902
|
+
L.DrawToolbar = L.Toolbar.extend({
|
3903
|
+
|
3904
|
+
statics: {
|
3905
|
+
TYPE: 'draw'
|
3906
|
+
},
|
3907
|
+
|
3908
|
+
options: {
|
3909
|
+
polyline: {},
|
3910
|
+
polygon: {},
|
3911
|
+
rectangle: {},
|
3912
|
+
circle: {},
|
3913
|
+
marker: {},
|
3914
|
+
circlemarker: {}
|
3915
|
+
},
|
3916
|
+
|
3917
|
+
// @method initialize(): void
|
3918
|
+
initialize: function (options) {
|
3919
|
+
// Ensure that the options are merged correctly since L.extend is only shallow
|
3920
|
+
for (var type in this.options) {
|
3921
|
+
if (this.options.hasOwnProperty(type)) {
|
3922
|
+
if (options[type]) {
|
3923
|
+
options[type] = L.extend({}, this.options[type], options[type]);
|
3924
|
+
}
|
3925
|
+
}
|
3926
|
+
}
|
3927
|
+
|
3928
|
+
this._toolbarClass = 'leaflet-draw-draw';
|
3929
|
+
L.Toolbar.prototype.initialize.call(this, options);
|
3930
|
+
},
|
3931
|
+
|
3932
|
+
// @method getModeHandlers(): object
|
3933
|
+
// Get mode handlers information
|
3934
|
+
getModeHandlers: function (map) {
|
3935
|
+
return [
|
3936
|
+
{
|
3937
|
+
enabled: this.options.polyline,
|
3938
|
+
handler: new L.Draw.Polyline(map, this.options.polyline),
|
3939
|
+
title: L.drawLocal.draw.toolbar.buttons.polyline
|
3940
|
+
},
|
3941
|
+
{
|
3942
|
+
enabled: this.options.polygon,
|
3943
|
+
handler: new L.Draw.Polygon(map, this.options.polygon),
|
3944
|
+
title: L.drawLocal.draw.toolbar.buttons.polygon
|
3945
|
+
},
|
3946
|
+
{
|
3947
|
+
enabled: this.options.rectangle,
|
3948
|
+
handler: new L.Draw.Rectangle(map, this.options.rectangle),
|
3949
|
+
title: L.drawLocal.draw.toolbar.buttons.rectangle
|
3950
|
+
},
|
3951
|
+
{
|
3952
|
+
enabled: this.options.circle,
|
3953
|
+
handler: new L.Draw.Circle(map, this.options.circle),
|
3954
|
+
title: L.drawLocal.draw.toolbar.buttons.circle
|
3955
|
+
},
|
3956
|
+
{
|
3957
|
+
enabled: this.options.marker,
|
3958
|
+
handler: new L.Draw.Marker(map, this.options.marker),
|
3959
|
+
title: L.drawLocal.draw.toolbar.buttons.marker
|
3960
|
+
},
|
3961
|
+
{
|
3962
|
+
enabled: this.options.circlemarker,
|
3963
|
+
handler: new L.Draw.CircleMarker(map, this.options.circlemarker),
|
3964
|
+
title: L.drawLocal.draw.toolbar.buttons.circlemarker
|
3965
|
+
}
|
3966
|
+
];
|
3967
|
+
},
|
3968
|
+
|
3969
|
+
// @method getActions(): object
|
3970
|
+
// Get action information
|
3971
|
+
getActions: function (handler) {
|
3972
|
+
return [
|
3973
|
+
{
|
3974
|
+
enabled: handler.completeShape,
|
3975
|
+
title: L.drawLocal.draw.toolbar.finish.title,
|
3976
|
+
text: L.drawLocal.draw.toolbar.finish.text,
|
3977
|
+
callback: handler.completeShape,
|
3978
|
+
context: handler
|
3979
|
+
},
|
3980
|
+
{
|
3981
|
+
enabled: handler.deleteLastVertex,
|
3982
|
+
title: L.drawLocal.draw.toolbar.undo.title,
|
3983
|
+
text: L.drawLocal.draw.toolbar.undo.text,
|
3984
|
+
callback: handler.deleteLastVertex,
|
3985
|
+
context: handler
|
3986
|
+
},
|
3987
|
+
{
|
3988
|
+
title: L.drawLocal.draw.toolbar.actions.title,
|
3989
|
+
text: L.drawLocal.draw.toolbar.actions.text,
|
3990
|
+
callback: this.disable,
|
3991
|
+
context: this
|
3992
|
+
}
|
3993
|
+
];
|
3994
|
+
},
|
3995
|
+
|
3996
|
+
// @method setOptions(): void
|
3997
|
+
// Sets the options to the toolbar
|
3998
|
+
setOptions: function (options) {
|
3999
|
+
L.setOptions(this, options);
|
4000
|
+
|
4001
|
+
for (var type in this._modes) {
|
4002
|
+
if (this._modes.hasOwnProperty(type) && options.hasOwnProperty(type)) {
|
4003
|
+
this._modes[type].handler.setOptions(options[type]);
|
4004
|
+
}
|
4005
|
+
}
|
4006
|
+
}
|
4007
|
+
});
|
4008
|
+
|
4009
|
+
|
4010
|
+
|
4011
|
+
/*L.Map.mergeOptions({
|
4012
|
+
editControl: true
|
4013
|
+
});*/
|
4014
|
+
/**
|
4015
|
+
* @class L.EditToolbar
|
4016
|
+
* @aka EditToolbar
|
4017
|
+
*/
|
4018
|
+
L.EditToolbar = L.Toolbar.extend({
|
4019
|
+
statics: {
|
4020
|
+
TYPE: 'edit'
|
4021
|
+
},
|
4022
|
+
|
4023
|
+
options: {
|
4024
|
+
edit: {
|
4025
|
+
selectedPathOptions: {
|
4026
|
+
dashArray: '10, 10',
|
4027
|
+
|
4028
|
+
fill: true,
|
4029
|
+
fillColor: '#fe57a1',
|
4030
|
+
fillOpacity: 0.1,
|
4031
|
+
|
4032
|
+
// Whether to user the existing layers color
|
4033
|
+
maintainColor: false
|
4034
|
+
}
|
4035
|
+
},
|
4036
|
+
remove: {},
|
4037
|
+
poly: null,
|
4038
|
+
featureGroup: null /* REQUIRED! TODO: perhaps if not set then all layers on the map are selectable? */
|
4039
|
+
},
|
4040
|
+
|
4041
|
+
// @method intialize(): void
|
4042
|
+
initialize: function (options) {
|
4043
|
+
// Need to set this manually since null is an acceptable value here
|
4044
|
+
if (options.edit) {
|
4045
|
+
if (typeof options.edit.selectedPathOptions === 'undefined') {
|
4046
|
+
options.edit.selectedPathOptions = this.options.edit.selectedPathOptions;
|
4047
|
+
}
|
4048
|
+
options.edit.selectedPathOptions = L.extend({}, this.options.edit.selectedPathOptions, options.edit.selectedPathOptions);
|
4049
|
+
}
|
4050
|
+
|
4051
|
+
if (options.remove) {
|
4052
|
+
options.remove = L.extend({}, this.options.remove, options.remove);
|
4053
|
+
}
|
4054
|
+
|
4055
|
+
if (options.poly) {
|
4056
|
+
options.poly = L.extend({}, this.options.poly, options.poly);
|
4057
|
+
}
|
4058
|
+
|
4059
|
+
this._toolbarClass = 'leaflet-draw-edit';
|
4060
|
+
L.Toolbar.prototype.initialize.call(this, options);
|
4061
|
+
|
4062
|
+
this._selectedFeatureCount = 0;
|
4063
|
+
},
|
4064
|
+
|
4065
|
+
// @method getModeHandlers(): object
|
4066
|
+
// Get mode handlers information
|
4067
|
+
getModeHandlers: function (map) {
|
4068
|
+
var featureGroup = this.options.featureGroup;
|
4069
|
+
return [
|
4070
|
+
{
|
4071
|
+
enabled: this.options.edit,
|
4072
|
+
handler: new L.EditToolbar.Edit(map, {
|
4073
|
+
featureGroup: featureGroup,
|
4074
|
+
selectedPathOptions: this.options.edit.selectedPathOptions,
|
4075
|
+
poly: this.options.poly
|
4076
|
+
}),
|
4077
|
+
title: L.drawLocal.edit.toolbar.buttons.edit
|
4078
|
+
},
|
4079
|
+
{
|
4080
|
+
enabled: this.options.remove,
|
4081
|
+
handler: new L.EditToolbar.Delete(map, {
|
4082
|
+
featureGroup: featureGroup
|
4083
|
+
}),
|
4084
|
+
title: L.drawLocal.edit.toolbar.buttons.remove
|
4085
|
+
}
|
4086
|
+
];
|
4087
|
+
},
|
4088
|
+
|
4089
|
+
// @method getActions(): object
|
4090
|
+
// Get actions information
|
4091
|
+
getActions: function (handler) {
|
4092
|
+
var actions = [
|
4093
|
+
{
|
4094
|
+
title: L.drawLocal.edit.toolbar.actions.save.title,
|
4095
|
+
text: L.drawLocal.edit.toolbar.actions.save.text,
|
4096
|
+
callback: this._save,
|
4097
|
+
context: this
|
4098
|
+
},
|
4099
|
+
{
|
4100
|
+
title: L.drawLocal.edit.toolbar.actions.cancel.title,
|
4101
|
+
text: L.drawLocal.edit.toolbar.actions.cancel.text,
|
4102
|
+
callback: this.disable,
|
4103
|
+
context: this
|
4104
|
+
}
|
4105
|
+
];
|
4106
|
+
|
4107
|
+
if (handler.removeAllLayers) {
|
4108
|
+
actions.push({
|
4109
|
+
title: L.drawLocal.edit.toolbar.actions.clearAll.title,
|
4110
|
+
text: L.drawLocal.edit.toolbar.actions.clearAll.text,
|
4111
|
+
callback: this._clearAllLayers,
|
4112
|
+
context: this
|
4113
|
+
});
|
4114
|
+
}
|
4115
|
+
|
4116
|
+
return actions;
|
4117
|
+
},
|
4118
|
+
|
4119
|
+
// @method addToolbar(map): L.DomUtil
|
4120
|
+
// Adds the toolbar to the map
|
4121
|
+
addToolbar: function (map) {
|
4122
|
+
var container = L.Toolbar.prototype.addToolbar.call(this, map);
|
4123
|
+
|
4124
|
+
this._checkDisabled();
|
4125
|
+
|
4126
|
+
this.options.featureGroup.on('layeradd layerremove', this._checkDisabled, this);
|
4127
|
+
|
4128
|
+
return container;
|
4129
|
+
},
|
4130
|
+
|
4131
|
+
// @method removeToolbar(): void
|
4132
|
+
// Removes the toolbar from the map
|
4133
|
+
removeToolbar: function () {
|
4134
|
+
this.options.featureGroup.off('layeradd layerremove', this._checkDisabled, this);
|
4135
|
+
|
4136
|
+
L.Toolbar.prototype.removeToolbar.call(this);
|
4137
|
+
},
|
4138
|
+
|
4139
|
+
// @method disable(): void
|
4140
|
+
// Disables the toolbar
|
4141
|
+
disable: function () {
|
4142
|
+
if (!this.enabled()) {
|
4143
|
+
return;
|
4144
|
+
}
|
4145
|
+
|
4146
|
+
this._activeMode.handler.revertLayers();
|
4147
|
+
|
4148
|
+
L.Toolbar.prototype.disable.call(this);
|
4149
|
+
},
|
4150
|
+
|
4151
|
+
_save: function () {
|
4152
|
+
this._activeMode.handler.save();
|
4153
|
+
if (this._activeMode) {
|
4154
|
+
this._activeMode.handler.disable();
|
4155
|
+
}
|
4156
|
+
},
|
4157
|
+
|
4158
|
+
_clearAllLayers:function(){
|
4159
|
+
this._activeMode.handler.removeAllLayers();
|
4160
|
+
if (this._activeMode) {
|
4161
|
+
this._activeMode.handler.disable();
|
4162
|
+
}
|
4163
|
+
},
|
4164
|
+
|
4165
|
+
_checkDisabled: function () {
|
4166
|
+
var featureGroup = this.options.featureGroup,
|
4167
|
+
hasLayers = featureGroup.getLayers().length !== 0,
|
4168
|
+
button;
|
4169
|
+
|
4170
|
+
if (this.options.edit) {
|
4171
|
+
button = this._modes[L.EditToolbar.Edit.TYPE].button;
|
4172
|
+
|
4173
|
+
if (hasLayers) {
|
4174
|
+
L.DomUtil.removeClass(button, 'leaflet-disabled');
|
4175
|
+
} else {
|
4176
|
+
L.DomUtil.addClass(button, 'leaflet-disabled');
|
4177
|
+
}
|
4178
|
+
|
4179
|
+
button.setAttribute(
|
4180
|
+
'title',
|
4181
|
+
hasLayers ?
|
4182
|
+
L.drawLocal.edit.toolbar.buttons.edit
|
4183
|
+
: L.drawLocal.edit.toolbar.buttons.editDisabled
|
4184
|
+
);
|
4185
|
+
}
|
4186
|
+
|
4187
|
+
if (this.options.remove) {
|
4188
|
+
button = this._modes[L.EditToolbar.Delete.TYPE].button;
|
4189
|
+
|
4190
|
+
if (hasLayers) {
|
4191
|
+
L.DomUtil.removeClass(button, 'leaflet-disabled');
|
4192
|
+
} else {
|
4193
|
+
L.DomUtil.addClass(button, 'leaflet-disabled');
|
4194
|
+
}
|
4195
|
+
|
4196
|
+
button.setAttribute(
|
4197
|
+
'title',
|
4198
|
+
hasLayers ?
|
4199
|
+
L.drawLocal.edit.toolbar.buttons.remove
|
4200
|
+
: L.drawLocal.edit.toolbar.buttons.removeDisabled
|
4201
|
+
);
|
4202
|
+
}
|
4203
|
+
}
|
4204
|
+
});
|
4205
|
+
|
4206
|
+
|
4207
|
+
|
4208
|
+
/**
|
4209
|
+
* @class L.EditToolbar.Edit
|
4210
|
+
* @aka EditToolbar.Edit
|
4211
|
+
*/
|
4212
|
+
L.EditToolbar.Edit = L.Handler.extend({
|
4213
|
+
statics: {
|
4214
|
+
TYPE: 'edit'
|
4215
|
+
},
|
4216
|
+
|
4217
|
+
includes: L.Mixin.Events,
|
4218
|
+
|
4219
|
+
// @method intialize(): void
|
4220
|
+
initialize: function (map, options) {
|
4221
|
+
L.Handler.prototype.initialize.call(this, map);
|
4222
|
+
|
4223
|
+
L.setOptions(this, options);
|
4224
|
+
|
4225
|
+
// Store the selectable layer group for ease of access
|
4226
|
+
this._featureGroup = options.featureGroup;
|
4227
|
+
|
4228
|
+
if (!(this._featureGroup instanceof L.FeatureGroup)) {
|
4229
|
+
throw new Error('options.featureGroup must be a L.FeatureGroup');
|
4230
|
+
}
|
4231
|
+
|
4232
|
+
this._uneditedLayerProps = {};
|
4233
|
+
|
4234
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
4235
|
+
this.type = L.EditToolbar.Edit.TYPE;
|
4236
|
+
},
|
4237
|
+
|
4238
|
+
// @method enable(): void
|
4239
|
+
// Enable the edit toolbar
|
4240
|
+
enable: function () {
|
4241
|
+
if (this._enabled || !this._hasAvailableLayers()) {
|
4242
|
+
return;
|
4243
|
+
}
|
4244
|
+
this.fire('enabled', { handler: this.type });
|
4245
|
+
//this disable other handlers
|
4246
|
+
|
4247
|
+
this._map.fire(L.Draw.Event.EDITSTART, { handler: this.type });
|
4248
|
+
//allow drawLayer to be updated before beginning edition.
|
4249
|
+
|
4250
|
+
L.Handler.prototype.enable.call(this);
|
4251
|
+
this._featureGroup
|
4252
|
+
.on('layeradd', this._enableLayerEdit, this)
|
4253
|
+
.on('layerremove', this._disableLayerEdit, this);
|
4254
|
+
},
|
4255
|
+
|
4256
|
+
// @method disable(): void
|
4257
|
+
// Disable the edit toolbar
|
4258
|
+
disable: function () {
|
4259
|
+
if (!this._enabled) {
|
4260
|
+
return;
|
4261
|
+
}
|
4262
|
+
this._featureGroup
|
4263
|
+
.off('layeradd', this._enableLayerEdit, this)
|
4264
|
+
.off('layerremove', this._disableLayerEdit, this);
|
4265
|
+
L.Handler.prototype.disable.call(this);
|
4266
|
+
this._map.fire(L.Draw.Event.EDITSTOP, { handler: this.type });
|
4267
|
+
this.fire('disabled', { handler: this.type });
|
4268
|
+
},
|
4269
|
+
|
4270
|
+
// @method addHooks(): void
|
4271
|
+
// Add listener hooks for this handler
|
4272
|
+
addHooks: function () {
|
4273
|
+
var map = this._map;
|
4274
|
+
|
4275
|
+
if (map) {
|
4276
|
+
map.getContainer().focus();
|
4277
|
+
|
4278
|
+
this._featureGroup.eachLayer(this._enableLayerEdit, this);
|
4279
|
+
|
4280
|
+
this._tooltip = new L.Draw.Tooltip(this._map);
|
4281
|
+
this._tooltip.updateContent({
|
4282
|
+
text: L.drawLocal.edit.handlers.edit.tooltip.text,
|
4283
|
+
subtext: L.drawLocal.edit.handlers.edit.tooltip.subtext
|
4284
|
+
});
|
4285
|
+
|
4286
|
+
// Quickly access the tooltip to update for intersection checking
|
4287
|
+
map._editTooltip = this._tooltip;
|
4288
|
+
|
4289
|
+
this._updateTooltip();
|
4290
|
+
|
4291
|
+
this._map
|
4292
|
+
.on('mousemove', this._onMouseMove, this)
|
4293
|
+
.on('touchmove', this._onMouseMove, this)
|
4294
|
+
.on('MSPointerMove', this._onMouseMove, this)
|
4295
|
+
.on(L.Draw.Event.EDITVERTEX, this._updateTooltip, this);
|
4296
|
+
}
|
4297
|
+
},
|
4298
|
+
|
4299
|
+
// @method removeHooks(): void
|
4300
|
+
// Remove listener hooks for this handler
|
4301
|
+
removeHooks: function () {
|
4302
|
+
if (this._map) {
|
4303
|
+
// Clean up selected layers.
|
4304
|
+
this._featureGroup.eachLayer(this._disableLayerEdit, this);
|
4305
|
+
|
4306
|
+
// Clear the backups of the original layers
|
4307
|
+
this._uneditedLayerProps = {};
|
4308
|
+
|
4309
|
+
this._tooltip.dispose();
|
4310
|
+
this._tooltip = null;
|
4311
|
+
|
4312
|
+
this._map
|
4313
|
+
.off('mousemove', this._onMouseMove, this)
|
4314
|
+
.off('touchmove', this._onMouseMove, this)
|
4315
|
+
.off('MSPointerMove', this._onMouseMove, this)
|
4316
|
+
.off(L.Draw.Event.EDITVERTEX, this._updateTooltip, this);
|
4317
|
+
}
|
4318
|
+
},
|
4319
|
+
|
4320
|
+
// @method revertLayers(): void
|
4321
|
+
// Revert each layer's geometry changes
|
4322
|
+
revertLayers: function () {
|
4323
|
+
this._featureGroup.eachLayer(function (layer) {
|
4324
|
+
this._revertLayer(layer);
|
4325
|
+
}, this);
|
4326
|
+
},
|
4327
|
+
|
4328
|
+
// @method save(): void
|
4329
|
+
// Save the layer geometries
|
4330
|
+
save: function () {
|
4331
|
+
var editedLayers = new L.LayerGroup();
|
4332
|
+
this._featureGroup.eachLayer(function (layer) {
|
4333
|
+
if (layer.edited) {
|
4334
|
+
editedLayers.addLayer(layer);
|
4335
|
+
layer.edited = false;
|
4336
|
+
}
|
4337
|
+
});
|
4338
|
+
this._map.fire(L.Draw.Event.EDITED, { layers: editedLayers });
|
4339
|
+
},
|
4340
|
+
|
4341
|
+
_backupLayer: function (layer) {
|
4342
|
+
var id = L.Util.stamp(layer);
|
4343
|
+
|
4344
|
+
if (!this._uneditedLayerProps[id]) {
|
4345
|
+
// Polyline, Polygon or Rectangle
|
4346
|
+
if (layer instanceof L.Polyline || layer instanceof L.Polygon || layer instanceof L.Rectangle) {
|
4347
|
+
this._uneditedLayerProps[id] = {
|
4348
|
+
latlngs: L.LatLngUtil.cloneLatLngs(layer.getLatLngs())
|
4349
|
+
};
|
4350
|
+
} else if (layer instanceof L.Circle) {
|
4351
|
+
this._uneditedLayerProps[id] = {
|
4352
|
+
latlng: L.LatLngUtil.cloneLatLng(layer.getLatLng()),
|
4353
|
+
radius: layer.getRadius()
|
4354
|
+
};
|
4355
|
+
} else if (layer instanceof L.Marker || layer instanceof L.CircleMarker) { // Marker
|
4356
|
+
this._uneditedLayerProps[id] = {
|
4357
|
+
latlng: L.LatLngUtil.cloneLatLng(layer.getLatLng())
|
4358
|
+
};
|
4359
|
+
}
|
4360
|
+
}
|
4361
|
+
},
|
4362
|
+
|
4363
|
+
_getTooltipText: function () {
|
4364
|
+
return ({
|
4365
|
+
text: L.drawLocal.edit.handlers.edit.tooltip.text,
|
4366
|
+
subtext: L.drawLocal.edit.handlers.edit.tooltip.subtext
|
4367
|
+
});
|
4368
|
+
},
|
4369
|
+
|
4370
|
+
_updateTooltip: function () {
|
4371
|
+
this._tooltip.updateContent(this._getTooltipText());
|
4372
|
+
},
|
4373
|
+
|
4374
|
+
_revertLayer: function (layer) {
|
4375
|
+
var id = L.Util.stamp(layer);
|
4376
|
+
layer.edited = false;
|
4377
|
+
if (this._uneditedLayerProps.hasOwnProperty(id)) {
|
4378
|
+
// Polyline, Polygon or Rectangle
|
4379
|
+
if (layer instanceof L.Polyline || layer instanceof L.Polygon || layer instanceof L.Rectangle) {
|
4380
|
+
layer.setLatLngs(this._uneditedLayerProps[id].latlngs);
|
4381
|
+
} else if (layer instanceof L.Circle) {
|
4382
|
+
layer.setLatLng(this._uneditedLayerProps[id].latlng);
|
4383
|
+
layer.setRadius(this._uneditedLayerProps[id].radius);
|
4384
|
+
} else if (layer instanceof L.Marker || layer instanceof L.CircleMarker) { // Marker or CircleMarker
|
4385
|
+
layer.setLatLng(this._uneditedLayerProps[id].latlng);
|
4386
|
+
}
|
4387
|
+
|
4388
|
+
layer.fire('revert-edited', { layer: layer });
|
4389
|
+
}
|
4390
|
+
},
|
4391
|
+
|
4392
|
+
_enableLayerEdit: function (e) {
|
4393
|
+
var layer = e.layer || e.target || e,
|
4394
|
+
pathOptions, poly;
|
4395
|
+
|
4396
|
+
// Back up this layer (if haven't before)
|
4397
|
+
this._backupLayer(layer);
|
4398
|
+
|
4399
|
+
if (this.options.poly) {
|
4400
|
+
poly = L.Util.extend({}, this.options.poly);
|
4401
|
+
layer.options.poly = poly;
|
4402
|
+
}
|
4403
|
+
|
4404
|
+
// Set different style for editing mode
|
4405
|
+
if (this.options.selectedPathOptions) {
|
4406
|
+
pathOptions = L.Util.extend({}, this.options.selectedPathOptions);
|
4407
|
+
|
4408
|
+
// Use the existing color of the layer
|
4409
|
+
if (pathOptions.maintainColor) {
|
4410
|
+
pathOptions.color = layer.options.color;
|
4411
|
+
pathOptions.fillColor = layer.options.fillColor;
|
4412
|
+
}
|
4413
|
+
|
4414
|
+
layer.options.original = L.extend({}, layer.options);
|
4415
|
+
layer.options.editing = pathOptions;
|
4416
|
+
|
4417
|
+
}
|
4418
|
+
|
4419
|
+
if (layer instanceof L.Marker) {
|
4420
|
+
if (layer.editing) {
|
4421
|
+
layer.editing.enable();
|
4422
|
+
}
|
4423
|
+
layer.dragging.enable();
|
4424
|
+
layer
|
4425
|
+
.on('dragend', this._onMarkerDragEnd)
|
4426
|
+
// #TODO: remove when leaflet finally fixes their draggable so it's touch friendly again.
|
4427
|
+
.on('touchmove', this._onTouchMove, this)
|
4428
|
+
.on('MSPointerMove', this._onTouchMove, this)
|
4429
|
+
.on('touchend', this._onMarkerDragEnd, this)
|
4430
|
+
.on('MSPointerUp', this._onMarkerDragEnd, this);
|
4431
|
+
} else {
|
4432
|
+
layer.editing.enable();
|
4433
|
+
}
|
4434
|
+
},
|
4435
|
+
|
4436
|
+
_disableLayerEdit: function (e) {
|
4437
|
+
var layer = e.layer || e.target || e;
|
4438
|
+
|
4439
|
+
layer.edited = false;
|
4440
|
+
if (layer.editing) {
|
4441
|
+
layer.editing.disable();
|
4442
|
+
}
|
4443
|
+
|
4444
|
+
delete layer.options.editing;
|
4445
|
+
delete layer.options.original;
|
4446
|
+
// Reset layer styles to that of before select
|
4447
|
+
if (this._selectedPathOptions) {
|
4448
|
+
if (layer instanceof L.Marker) {
|
4449
|
+
this._toggleMarkerHighlight(layer);
|
4450
|
+
} else {
|
4451
|
+
// reset the layer style to what is was before being selected
|
4452
|
+
layer.setStyle(layer.options.previousOptions);
|
4453
|
+
// remove the cached options for the layer object
|
4454
|
+
delete layer.options.previousOptions;
|
4455
|
+
}
|
4456
|
+
}
|
4457
|
+
|
4458
|
+
if (layer instanceof L.Marker) {
|
4459
|
+
layer.dragging.disable();
|
4460
|
+
layer
|
4461
|
+
.off('dragend', this._onMarkerDragEnd, this)
|
4462
|
+
.off('touchmove', this._onTouchMove, this)
|
4463
|
+
.off('MSPointerMove', this._onTouchMove, this)
|
4464
|
+
.off('touchend', this._onMarkerDragEnd, this)
|
4465
|
+
.off('MSPointerUp', this._onMarkerDragEnd, this);
|
4466
|
+
} else {
|
4467
|
+
layer.editing.disable();
|
4468
|
+
}
|
4469
|
+
},
|
4470
|
+
|
4471
|
+
_onMouseMove: function (e) {
|
4472
|
+
this._tooltip.updatePosition(e.latlng);
|
4473
|
+
},
|
4474
|
+
|
4475
|
+
_onMarkerDragEnd: function (e) {
|
4476
|
+
var layer = e.target;
|
4477
|
+
layer.edited = true;
|
4478
|
+
this._map.fire(L.Draw.Event.EDITMOVE, { layer: layer });
|
4479
|
+
},
|
4480
|
+
|
4481
|
+
_onTouchMove: function (e) {
|
4482
|
+
var touchEvent = e.originalEvent.changedTouches[0],
|
4483
|
+
layerPoint = this._map.mouseEventToLayerPoint(touchEvent),
|
4484
|
+
latlng = this._map.layerPointToLatLng(layerPoint);
|
4485
|
+
e.target.setLatLng(latlng);
|
4486
|
+
},
|
4487
|
+
|
4488
|
+
_hasAvailableLayers: function () {
|
4489
|
+
return this._featureGroup.getLayers().length !== 0;
|
4490
|
+
}
|
4491
|
+
});
|
4492
|
+
|
4493
|
+
|
4494
|
+
|
4495
|
+
/**
|
4496
|
+
* @class L.EditToolbar.Delete
|
4497
|
+
* @aka EditToolbar.Delete
|
4498
|
+
*/
|
4499
|
+
L.EditToolbar.Delete = L.Handler.extend({
|
4500
|
+
statics: {
|
4501
|
+
TYPE: 'remove' // not delete as delete is reserved in js
|
4502
|
+
},
|
4503
|
+
|
4504
|
+
includes: L.Mixin.Events,
|
4505
|
+
|
4506
|
+
// @method intialize(): void
|
4507
|
+
initialize: function (map, options) {
|
4508
|
+
L.Handler.prototype.initialize.call(this, map);
|
4509
|
+
|
4510
|
+
L.Util.setOptions(this, options);
|
4511
|
+
|
4512
|
+
// Store the selectable layer group for ease of access
|
4513
|
+
this._deletableLayers = this.options.featureGroup;
|
4514
|
+
|
4515
|
+
if (!(this._deletableLayers instanceof L.FeatureGroup)) {
|
4516
|
+
throw new Error('options.featureGroup must be a L.FeatureGroup');
|
4517
|
+
}
|
4518
|
+
|
4519
|
+
// Save the type so super can fire, need to do this as cannot do this.TYPE :(
|
4520
|
+
this.type = L.EditToolbar.Delete.TYPE;
|
4521
|
+
},
|
4522
|
+
|
4523
|
+
// @method enable(): void
|
4524
|
+
// Enable the delete toolbar
|
4525
|
+
enable: function () {
|
4526
|
+
if (this._enabled || !this._hasAvailableLayers()) {
|
4527
|
+
return;
|
4528
|
+
}
|
4529
|
+
this.fire('enabled', { handler: this.type });
|
4530
|
+
|
4531
|
+
this._map.fire(L.Draw.Event.DELETESTART, { handler: this.type });
|
4532
|
+
|
4533
|
+
L.Handler.prototype.enable.call(this);
|
4534
|
+
|
4535
|
+
this._deletableLayers
|
4536
|
+
.on('layeradd', this._enableLayerDelete, this)
|
4537
|
+
.on('layerremove', this._disableLayerDelete, this);
|
4538
|
+
},
|
4539
|
+
|
4540
|
+
// @method disable(): void
|
4541
|
+
// Disable the delete toolbar
|
4542
|
+
disable: function () {
|
4543
|
+
if (!this._enabled) {
|
4544
|
+
return;
|
4545
|
+
}
|
4546
|
+
|
4547
|
+
this._deletableLayers
|
4548
|
+
.off('layeradd', this._enableLayerDelete, this)
|
4549
|
+
.off('layerremove', this._disableLayerDelete, this);
|
4550
|
+
|
4551
|
+
L.Handler.prototype.disable.call(this);
|
4552
|
+
|
4553
|
+
this._map.fire(L.Draw.Event.DELETESTOP, { handler: this.type });
|
4554
|
+
|
4555
|
+
this.fire('disabled', { handler: this.type });
|
4556
|
+
},
|
4557
|
+
|
4558
|
+
// @method addHooks(): void
|
4559
|
+
// Add listener hooks to this handler
|
4560
|
+
addHooks: function () {
|
4561
|
+
var map = this._map;
|
4562
|
+
|
4563
|
+
if (map) {
|
4564
|
+
map.getContainer().focus();
|
4565
|
+
|
4566
|
+
this._deletableLayers.eachLayer(this._enableLayerDelete, this);
|
4567
|
+
this._deletedLayers = new L.LayerGroup();
|
4568
|
+
|
4569
|
+
this._tooltip = new L.Draw.Tooltip(this._map);
|
4570
|
+
this._tooltip.updateContent({ text: L.drawLocal.edit.handlers.remove.tooltip.text });
|
4571
|
+
|
4572
|
+
this._map.on('mousemove', this._onMouseMove, this);
|
4573
|
+
}
|
4574
|
+
},
|
4575
|
+
|
4576
|
+
// @method removeHooks(): void
|
4577
|
+
// Remove listener hooks from this handler
|
4578
|
+
removeHooks: function () {
|
4579
|
+
if (this._map) {
|
4580
|
+
this._deletableLayers.eachLayer(this._disableLayerDelete, this);
|
4581
|
+
this._deletedLayers = null;
|
4582
|
+
|
4583
|
+
this._tooltip.dispose();
|
4584
|
+
this._tooltip = null;
|
4585
|
+
|
4586
|
+
this._map.off('mousemove', this._onMouseMove, this);
|
4587
|
+
}
|
4588
|
+
},
|
4589
|
+
|
4590
|
+
// @method revertLayers(): void
|
4591
|
+
// Revert the deleted layers back to their prior state.
|
4592
|
+
revertLayers: function () {
|
4593
|
+
// Iterate of the deleted layers and add them back into the featureGroup
|
4594
|
+
this._deletedLayers.eachLayer(function (layer) {
|
4595
|
+
this._deletableLayers.addLayer(layer);
|
4596
|
+
layer.fire('revert-deleted', { layer: layer });
|
4597
|
+
}, this);
|
4598
|
+
},
|
4599
|
+
|
4600
|
+
// @method save(): void
|
4601
|
+
// Save deleted layers
|
4602
|
+
save: function () {
|
4603
|
+
this._map.fire(L.Draw.Event.DELETED, { layers: this._deletedLayers });
|
4604
|
+
},
|
4605
|
+
|
4606
|
+
// @method removeAllLayers(): void
|
4607
|
+
// Remove all delateable layers
|
4608
|
+
removeAllLayers: function(){
|
4609
|
+
// Iterate of the delateable layers and add remove them
|
4610
|
+
this._deletableLayers.eachLayer(function (layer) {
|
4611
|
+
this._removeLayer({layer:layer});
|
4612
|
+
}, this);
|
4613
|
+
this.save();
|
4614
|
+
},
|
4615
|
+
|
4616
|
+
_enableLayerDelete: function (e) {
|
4617
|
+
var layer = e.layer || e.target || e;
|
4618
|
+
|
4619
|
+
layer.on('click', this._removeLayer, this);
|
4620
|
+
},
|
4621
|
+
|
4622
|
+
_disableLayerDelete: function (e) {
|
4623
|
+
var layer = e.layer || e.target || e;
|
4624
|
+
|
4625
|
+
layer.off('click', this._removeLayer, this);
|
4626
|
+
|
4627
|
+
// Remove from the deleted layers so we can't accidentally revert if the user presses cancel
|
4628
|
+
this._deletedLayers.removeLayer(layer);
|
4629
|
+
},
|
4630
|
+
|
4631
|
+
_removeLayer: function (e) {
|
4632
|
+
var layer = e.layer || e.target || e;
|
4633
|
+
|
4634
|
+
this._deletableLayers.removeLayer(layer);
|
4635
|
+
|
4636
|
+
this._deletedLayers.addLayer(layer);
|
4637
|
+
|
4638
|
+
layer.fire('deleted');
|
4639
|
+
},
|
4640
|
+
|
4641
|
+
_onMouseMove: function (e) {
|
4642
|
+
this._tooltip.updatePosition(e.latlng);
|
4643
|
+
},
|
4644
|
+
|
4645
|
+
_hasAvailableLayers: function () {
|
4646
|
+
return this._deletableLayers.getLayers().length !== 0;
|
4647
|
+
}
|
4648
|
+
});
|
4649
|
+
|
4650
|
+
|
4651
|
+
|
4652
|
+
}(window, document));
|
4653
|
+
//# sourceMappingURL=leaflet.draw-src.map
|