├── .idea
├── .gitignore
├── geoserver_django_leaflet.iml
├── inspectionProfiles
│ └── profiles_settings.xml
├── misc.xml
└── modules.xml
├── README.md
├── db.sqlite3
├── geoserver_django_leaflet
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-37.pyc
│ ├── geoserver.cpython-37.pyc
│ ├── settings.cpython-37.pyc
│ ├── urls.cpython-37.pyc
│ └── wsgi.cpython-37.pyc
├── asgi.py
├── geoserver.py
├── settings.py
├── urls.py
└── wsgi.py
├── manage.py
├── static_files
├── draw_files
│ ├── Control.Draw.js
│ ├── Draw.Circle.js
│ ├── Draw.CircleMarker.js
│ ├── Draw.Feature.js
│ ├── Draw.Marker.js
│ ├── Draw.Polygon.js
│ ├── Draw.Polyline.js
│ ├── Draw.Rectangle.js
│ ├── Draw.SimpleShape.js
│ ├── DrawToolbar.js
│ ├── Edit.Circle.js
│ ├── Edit.CircleMarker.js
│ ├── Edit.Marker.js
│ ├── Edit.Poly.js
│ ├── Edit.Rectangle.js
│ ├── Edit.SimpleShape.js
│ ├── EditToolbar.Delete.js
│ ├── EditToolbar.Edit.js
│ ├── EditToolbar.js
│ ├── GeometryUtil.js
│ ├── LatLngUtil.js
│ ├── Leaflet.Draw.Event.js
│ ├── Leaflet.draw.js
│ ├── LineUtil.Intersect.js
│ ├── Polygon.Intersect.js
│ ├── Polyline.Intersect.js
│ ├── Toolbar.js
│ ├── Tooltip.js
│ ├── TouchEvents.js
│ ├── jquery-1.7.2.js
│ ├── jquery.cookie.js
│ ├── leaflet-src.js
│ ├── leaflet.css
│ ├── leaflet.draw.css
│ ├── spritesheet-2x.png
│ └── spritesheet.svg
├── jquery-1.7.2.js
├── leaflet-src.js
└── leaflet.css
└── templates
├── attr_feature.html
├── bbox_feature.html
├── draw.html
├── remove.html
└── tile_wmts.html
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/geoserver_django_leaflet.iml:
--------------------------------------------------------------------------------
1 |
2 |
' + L.GeometryUtil.readableArea(area, this.options.metric, this.options.precision);
96 | }
97 |
98 | return measurementString;
99 | },
100 |
101 | _shapeIsValid: function () {
102 | return this._markers.length >= 3;
103 | },
104 |
105 | _vertexChanged: function (latlng, added) {
106 | var latLngs;
107 |
108 | // Check to see if we should show the area
109 | if (!this.options.allowIntersection && this.options.showArea) {
110 | latLngs = this._poly.getLatLngs();
111 |
112 | this._area = L.GeometryUtil.geodesicArea(latLngs);
113 | }
114 |
115 | L.Draw.Polyline.prototype._vertexChanged.call(this, latlng, added);
116 | },
117 |
118 | _cleanUpShape: function () {
119 | var markerCount = this._markers.length;
120 |
121 | if (markerCount > 0) {
122 | this._markers[0].off('click', this._finishShape, this);
123 |
124 | if (markerCount > 2) {
125 | this._markers[markerCount - 1].off('dblclick', this._finishShape, this);
126 | }
127 | }
128 | }
129 | });
130 |
--------------------------------------------------------------------------------
/static_files/draw_files/Draw.Polyline.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @class L.Draw.Polyline
3 | * @aka Draw.Polyline
4 | * @inherits L.Draw.Feature
5 | */
6 | L.Draw.Polyline = L.Draw.Feature.extend({
7 | statics: {
8 | TYPE: 'polyline'
9 | },
10 |
11 | Poly: L.Polyline,
12 |
13 | options: {
14 | allowIntersection: true,
15 | repeatMode: false,
16 | drawError: {
17 | color: '#b00b00',
18 | timeout: 2500
19 | },
20 | icon: new L.DivIcon({
21 | iconSize: new L.Point(8, 8),
22 | className: 'leaflet-div-icon leaflet-editing-icon'
23 | }),
24 | touchIcon: new L.DivIcon({
25 | iconSize: new L.Point(20, 20),
26 | className: 'leaflet-div-icon leaflet-editing-icon leaflet-touch-icon'
27 | }),
28 | guidelineDistance: 20,
29 | maxGuideLineLength: 4000,
30 | shapeOptions: {
31 | stroke: true,
32 | color: '#3388ff',
33 | weight: 4,
34 | opacity: 0.5,
35 | fill: false,
36 | clickable: true
37 | },
38 | metric: true, // Whether to use the metric measurement system or imperial
39 | feet: true, // When not metric, to use feet instead of yards for display.
40 | nautic: false, // When not metric, not feet use nautic mile for display
41 | showLength: true, // Whether to display distance in the tooltip
42 | zIndexOffset: 2000, // This should be > than the highest z-index any map layers
43 | factor: 1, // To change distance calculation
44 | maxPoints: 0 // Once this number of points are placed, finish shape
45 | },
46 |
47 | // @method initialize(): void
48 | initialize: function (map, options) {
49 | // if touch, switch to touch icon
50 | if (L.Browser.touch) {
51 | this.options.icon = this.options.touchIcon;
52 | }
53 |
54 | // Need to set this here to ensure the correct message is used.
55 | this.options.drawError.message = L.drawLocal.draw.handlers.polyline.error;
56 |
57 | // Merge default drawError options with custom options
58 | if (options && options.drawError) {
59 | options.drawError = L.Util.extend({}, this.options.drawError, options.drawError);
60 | }
61 |
62 | // Save the type so super can fire, need to do this as cannot do this.TYPE :(
63 | this.type = L.Draw.Polyline.TYPE;
64 |
65 | L.Draw.Feature.prototype.initialize.call(this, map, options);
66 | },
67 |
68 | // @method addHooks(): void
69 | // Add listener hooks to this handler
70 | addHooks: function () {
71 | L.Draw.Feature.prototype.addHooks.call(this);
72 | if (this._map) {
73 | this._markers = [];
74 |
75 | this._markerGroup = new L.LayerGroup();
76 | this._map.addLayer(this._markerGroup);
77 |
78 | this._poly = new L.Polyline([], this.options.shapeOptions);
79 |
80 | this._tooltip.updateContent(this._getTooltipText());
81 |
82 | // Make a transparent marker that will used to catch click events. These click
83 | // events will create the vertices. We need to do this so we can ensure that
84 | // we can create vertices over other map layers (markers, vector layers). We
85 | // also do not want to trigger any click handlers of objects we are clicking on
86 | // while drawing.
87 | if (!this._mouseMarker) {
88 | this._mouseMarker = L.marker(this._map.getCenter(), {
89 | icon: L.divIcon({
90 | className: 'leaflet-mouse-marker',
91 | iconAnchor: [20, 20],
92 | iconSize: [40, 40]
93 | }),
94 | opacity: 0,
95 | zIndexOffset: this.options.zIndexOffset
96 | });
97 | }
98 |
99 | this._mouseMarker
100 | .on('mouseout', this._onMouseOut, this)
101 | .on('mousemove', this._onMouseMove, this) // Necessary to prevent 0.8 stutter
102 | .on('mousedown', this._onMouseDown, this)
103 | .on('mouseup', this._onMouseUp, this) // Necessary for 0.8 compatibility
104 | .addTo(this._map);
105 |
106 | this._map
107 | .on('mouseup', this._onMouseUp, this) // Necessary for 0.7 compatibility
108 | .on('mousemove', this._onMouseMove, this)
109 | .on('zoomlevelschange', this._onZoomEnd, this)
110 | .on('touchstart', this._onTouch, this)
111 | .on('zoomend', this._onZoomEnd, this);
112 |
113 | }
114 | },
115 |
116 | // @method removeHooks(): void
117 | // Remove listener hooks from this handler.
118 | removeHooks: function () {
119 | L.Draw.Feature.prototype.removeHooks.call(this);
120 |
121 | this._clearHideErrorTimeout();
122 |
123 | this._cleanUpShape();
124 |
125 | // remove markers from map
126 | this._map.removeLayer(this._markerGroup);
127 | delete this._markerGroup;
128 | delete this._markers;
129 |
130 | this._map.removeLayer(this._poly);
131 | delete this._poly;
132 |
133 | this._mouseMarker
134 | .off('mousedown', this._onMouseDown, this)
135 | .off('mouseout', this._onMouseOut, this)
136 | .off('mouseup', this._onMouseUp, this)
137 | .off('mousemove', this._onMouseMove, this);
138 | this._map.removeLayer(this._mouseMarker);
139 | delete this._mouseMarker;
140 |
141 | // clean up DOM
142 | this._clearGuides();
143 |
144 | this._map
145 | .off('mouseup', this._onMouseUp, this)
146 | .off('mousemove', this._onMouseMove, this)
147 | .off('zoomlevelschange', this._onZoomEnd, this)
148 | .off('zoomend', this._onZoomEnd, this)
149 | .off('touchstart', this._onTouch, this)
150 | .off('click', this._onTouch, this);
151 | },
152 |
153 | // @method deleteLastVertex(): void
154 | // Remove the last vertex from the polyline, removes polyline from map if only one point exists.
155 | deleteLastVertex: function () {
156 | if (this._markers.length <= 1) {
157 | return;
158 | }
159 |
160 | var lastMarker = this._markers.pop(),
161 | poly = this._poly,
162 | // Replaces .spliceLatLngs()
163 | latlngs = poly.getLatLngs(),
164 | latlng = latlngs.splice(-1, 1)[0];
165 | this._poly.setLatLngs(latlngs);
166 |
167 | this._markerGroup.removeLayer(lastMarker);
168 |
169 | if (poly.getLatLngs().length < 2) {
170 | this._map.removeLayer(poly);
171 | }
172 |
173 | this._vertexChanged(latlng, false);
174 | },
175 |
176 | // @method addVertex(): void
177 | // Add a vertex to the end of the polyline
178 | addVertex: function (latlng) {
179 | var markersLength = this._markers.length;
180 | // markersLength must be greater than or equal to 2 before intersections can occur
181 | if (markersLength >= 2 && !this.options.allowIntersection && this._poly.newLatLngIntersects(latlng)) {
182 | this._showErrorTooltip();
183 | return;
184 | }
185 | else if (this._errorShown) {
186 | this._hideErrorTooltip();
187 | }
188 |
189 | this._markers.push(this._createMarker(latlng));
190 |
191 | this._poly.addLatLng(latlng);
192 |
193 | if (this._poly.getLatLngs().length === 2) {
194 | this._map.addLayer(this._poly);
195 | }
196 |
197 | this._vertexChanged(latlng, true);
198 | },
199 |
200 | // @method completeShape(): void
201 | // Closes the polyline between the first and last points
202 | completeShape: function () {
203 | if (this._markers.length <= 1 || !this._shapeIsValid()) {
204 | return;
205 | }
206 |
207 | this._fireCreatedEvent();
208 | this.disable();
209 |
210 | if (this.options.repeatMode) {
211 | this.enable();
212 | }
213 | },
214 |
215 | _finishShape: function () {
216 | var latlngs = this._poly._defaultShape ? this._poly._defaultShape() : this._poly.getLatLngs();
217 | var intersects = this._poly.newLatLngIntersects(latlngs[latlngs.length - 1]);
218 |
219 | if ((!this.options.allowIntersection && intersects) || !this._shapeIsValid()) {
220 | this._showErrorTooltip();
221 | return;
222 | }
223 |
224 | this._fireCreatedEvent();
225 | this.disable();
226 | if (this.options.repeatMode) {
227 | this.enable();
228 | }
229 | },
230 |
231 | // Called to verify the shape is valid when the user tries to finish it
232 | // Return false if the shape is not valid
233 | _shapeIsValid: function () {
234 | return true;
235 | },
236 |
237 | _onZoomEnd: function () {
238 | if (this._markers !== null) {
239 | this._updateGuide();
240 | }
241 | },
242 |
243 | _onMouseMove: function (e) {
244 | var newPos = this._map.mouseEventToLayerPoint(e.originalEvent);
245 | var latlng = this._map.layerPointToLatLng(newPos);
246 |
247 | // Save latlng
248 | // should this be moved to _updateGuide() ?
249 | this._currentLatLng = latlng;
250 |
251 | this._updateTooltip(latlng);
252 |
253 | // Update the guide line
254 | this._updateGuide(newPos);
255 |
256 | // Update the mouse marker position
257 | this._mouseMarker.setLatLng(latlng);
258 |
259 | L.DomEvent.preventDefault(e.originalEvent);
260 | },
261 |
262 | _vertexChanged: function (latlng, added) {
263 | this._map.fire(L.Draw.Event.DRAWVERTEX, {layers: this._markerGroup});
264 | this._updateFinishHandler();
265 |
266 | this._updateRunningMeasure(latlng, added);
267 |
268 | this._clearGuides();
269 |
270 | this._updateTooltip();
271 | },
272 |
273 | _onMouseDown: function (e) {
274 | if (!this._clickHandled && !this._touchHandled && !this._disableMarkers) {
275 | this._onMouseMove(e);
276 | this._clickHandled = true;
277 | this._disableNewMarkers();
278 | var originalEvent = e.originalEvent;
279 | var clientX = originalEvent.clientX;
280 | var clientY = originalEvent.clientY;
281 | this._startPoint.call(this, clientX, clientY);
282 | }
283 | },
284 |
285 | _startPoint: function (clientX, clientY) {
286 | this._mouseDownOrigin = L.point(clientX, clientY);
287 | },
288 |
289 | _onMouseUp: function (e) {
290 | var originalEvent = e.originalEvent;
291 | var clientX = originalEvent.clientX;
292 | var clientY = originalEvent.clientY;
293 | this._endPoint.call(this, clientX, clientY, e);
294 | this._clickHandled = null;
295 | },
296 |
297 | _endPoint: function (clientX, clientY, e) {
298 | if (this._mouseDownOrigin) {
299 | var dragCheckDistance = L.point(clientX, clientY)
300 | .distanceTo(this._mouseDownOrigin);
301 | var lastPtDistance = this._calculateFinishDistance(e.latlng);
302 | if (this.options.maxPoints > 1 && this.options.maxPoints == this._markers.length + 1) {
303 | this.addVertex(e.latlng);
304 | this._finishShape();
305 | } else if (lastPtDistance < 10 && L.Browser.touch) {
306 | this._finishShape();
307 | } else if (Math.abs(dragCheckDistance) < 9 * (window.devicePixelRatio || 1)) {
308 | this.addVertex(e.latlng);
309 | }
310 | this._enableNewMarkers(); // after a short pause, enable new markers
311 | }
312 | this._mouseDownOrigin = null;
313 | },
314 |
315 | // ontouch prevented by clickHandled flag because some browsers fire both click/touch events,
316 | // causing unwanted behavior
317 | _onTouch: function (e) {
318 | var originalEvent = e.originalEvent;
319 | var clientX;
320 | var clientY;
321 | if (originalEvent.touches && originalEvent.touches[0] && !this._clickHandled && !this._touchHandled && !this._disableMarkers) {
322 | clientX = originalEvent.touches[0].clientX;
323 | clientY = originalEvent.touches[0].clientY;
324 | this._disableNewMarkers();
325 | this._touchHandled = true;
326 | this._startPoint.call(this, clientX, clientY);
327 | this._endPoint.call(this, clientX, clientY, e);
328 | this._touchHandled = null;
329 | }
330 | this._clickHandled = null;
331 | },
332 |
333 | _onMouseOut: function () {
334 | if (this._tooltip) {
335 | this._tooltip._onMouseOut.call(this._tooltip);
336 | }
337 | },
338 |
339 | // calculate if we are currently within close enough distance
340 | // of the closing point (first point for shapes, last point for lines)
341 | // this is semi-ugly code but the only reliable way i found to get the job done
342 | // note: calculating point.distanceTo between mouseDownOrigin and last marker did NOT work
343 | _calculateFinishDistance: function (potentialLatLng) {
344 | var lastPtDistance;
345 | if (this._markers.length > 0) {
346 | var finishMarker;
347 | if (this.type === L.Draw.Polyline.TYPE) {
348 | finishMarker = this._markers[this._markers.length - 1];
349 | } else if (this.type === L.Draw.Polygon.TYPE) {
350 | finishMarker = this._markers[0];
351 | } else {
352 | return Infinity;
353 | }
354 | var lastMarkerPoint = this._map.latLngToContainerPoint(finishMarker.getLatLng()),
355 | potentialMarker = new L.Marker(potentialLatLng, {
356 | icon: this.options.icon,
357 | zIndexOffset: this.options.zIndexOffset * 2
358 | });
359 | var potentialMarkerPint = this._map.latLngToContainerPoint(potentialMarker.getLatLng());
360 | lastPtDistance = lastMarkerPoint.distanceTo(potentialMarkerPint);
361 | } else {
362 | lastPtDistance = Infinity;
363 | }
364 | return lastPtDistance;
365 | },
366 |
367 | _updateFinishHandler: function () {
368 | var markerCount = this._markers.length;
369 | // The last marker should have a click handler to close the polyline
370 | if (markerCount > 1) {
371 | this._markers[markerCount - 1].on('click', this._finishShape, this);
372 | }
373 |
374 | // Remove the old marker click handler (as only the last point should close the polyline)
375 | if (markerCount > 2) {
376 | this._markers[markerCount - 2].off('click', this._finishShape, this);
377 | }
378 | },
379 |
380 | _createMarker: function (latlng) {
381 | var marker = new L.Marker(latlng, {
382 | icon: this.options.icon,
383 | zIndexOffset: this.options.zIndexOffset * 2
384 | });
385 |
386 | this._markerGroup.addLayer(marker);
387 |
388 | return marker;
389 | },
390 |
391 | _updateGuide: function (newPos) {
392 | var markerCount = this._markers ? this._markers.length : 0;
393 |
394 | if (markerCount > 0) {
395 | newPos = newPos || this._map.latLngToLayerPoint(this._currentLatLng);
396 |
397 | // draw the guide line
398 | this._clearGuides();
399 | this._drawGuide(
400 | this._map.latLngToLayerPoint(this._markers[markerCount - 1].getLatLng()),
401 | newPos
402 | );
403 | }
404 | },
405 |
406 | _updateTooltip: function (latLng) {
407 | var text = this._getTooltipText();
408 |
409 | if (latLng) {
410 | this._tooltip.updatePosition(latLng);
411 | }
412 |
413 | if (!this._errorShown) {
414 | this._tooltip.updateContent(text);
415 | }
416 | },
417 |
418 | _drawGuide: function (pointA, pointB) {
419 | var length = Math.floor(Math.sqrt(Math.pow((pointB.x - pointA.x), 2) + Math.pow((pointB.y - pointA.y), 2))),
420 | guidelineDistance = this.options.guidelineDistance,
421 | maxGuideLineLength = this.options.maxGuideLineLength,
422 | // Only draw a guideline with a max length
423 | i = length > maxGuideLineLength ? length - maxGuideLineLength : guidelineDistance,
424 | fraction,
425 | dashPoint,
426 | dash;
427 |
428 | //create the guides container if we haven't yet
429 | if (!this._guidesContainer) {
430 | this._guidesContainer = L.DomUtil.create('div', 'leaflet-draw-guides', this._overlayPane);
431 | }
432 |
433 | //draw a dash every GuildeLineDistance
434 | for (; i < length; i += this.options.guidelineDistance) {
435 | //work out fraction along line we are
436 | fraction = i / length;
437 |
438 | //calculate new x,y point
439 | dashPoint = {
440 | x: Math.floor((pointA.x * (1 - fraction)) + (fraction * pointB.x)),
441 | y: Math.floor((pointA.y * (1 - fraction)) + (fraction * pointB.y))
442 | };
443 |
444 | //add guide dash to guide container
445 | dash = L.DomUtil.create('div', 'leaflet-draw-guide-dash', this._guidesContainer);
446 | dash.style.backgroundColor =
447 | !this._errorShown ? this.options.shapeOptions.color : this.options.drawError.color;
448 |
449 | L.DomUtil.setPosition(dash, dashPoint);
450 | }
451 | },
452 |
453 | _updateGuideColor: function (color) {
454 | if (this._guidesContainer) {
455 | for (var i = 0, l = this._guidesContainer.childNodes.length; i < l; i++) {
456 | this._guidesContainer.childNodes[i].style.backgroundColor = color;
457 | }
458 | }
459 | },
460 |
461 | // removes all child elements (guide dashes) from the guides container
462 | _clearGuides: function () {
463 | if (this._guidesContainer) {
464 | while (this._guidesContainer.firstChild) {
465 | this._guidesContainer.removeChild(this._guidesContainer.firstChild);
466 | }
467 | }
468 | },
469 |
470 | _getTooltipText: function () {
471 | var showLength = this.options.showLength,
472 | labelText, distanceStr;
473 | if (this._markers.length === 0) {
474 | labelText = {
475 | text: L.drawLocal.draw.handlers.polyline.tooltip.start
476 | };
477 | } else {
478 | distanceStr = showLength ? this._getMeasurementString() : '';
479 |
480 | if (this._markers.length === 1) {
481 | labelText = {
482 | text: L.drawLocal.draw.handlers.polyline.tooltip.cont,
483 | subtext: distanceStr
484 | };
485 | } else {
486 | labelText = {
487 | text: L.drawLocal.draw.handlers.polyline.tooltip.end,
488 | subtext: distanceStr
489 | };
490 | }
491 | }
492 | return labelText;
493 | },
494 |
495 | _updateRunningMeasure: function (latlng, added) {
496 | var markersLength = this._markers.length,
497 | previousMarkerIndex, distance;
498 |
499 | if (this._markers.length === 1) {
500 | this._measurementRunningTotal = 0;
501 | } else {
502 | previousMarkerIndex = markersLength - (added ? 2 : 1);
503 |
504 | // Calculate the distance based on the version
505 | if (L.GeometryUtil.isVersion07x()) {
506 | distance = latlng.distanceTo(this._markers[previousMarkerIndex].getLatLng()) * (this.options.factor || 1);
507 | } else {
508 | distance = this._map.distance(latlng, this._markers[previousMarkerIndex].getLatLng()) * (this.options.factor || 1);
509 | }
510 |
511 | this._measurementRunningTotal += distance * (added ? 1 : -1);
512 | }
513 | },
514 |
515 | _getMeasurementString: function () {
516 | var currentLatLng = this._currentLatLng,
517 | previousLatLng = this._markers[this._markers.length - 1].getLatLng(),
518 | distance;
519 |
520 | // Calculate the distance from the last fixed point to the mouse position based on the version
521 | if (L.GeometryUtil.isVersion07x()) {
522 | distance = previousLatLng && currentLatLng && currentLatLng.distanceTo ? this._measurementRunningTotal + currentLatLng.distanceTo(previousLatLng) * (this.options.factor || 1) : this._measurementRunningTotal || 0;
523 | } else {
524 | distance = previousLatLng && currentLatLng ? this._measurementRunningTotal + this._map.distance(currentLatLng, previousLatLng) * (this.options.factor || 1) : this._measurementRunningTotal || 0;
525 | }
526 |
527 | return L.GeometryUtil.readableDistance(distance, this.options.metric, this.options.feet, this.options.nautic, this.options.precision);
528 | },
529 |
530 | _showErrorTooltip: function () {
531 | this._errorShown = true;
532 |
533 | // Update tooltip
534 | this._tooltip
535 | .showAsError()
536 | .updateContent({text: this.options.drawError.message});
537 |
538 | // Update shape
539 | this._updateGuideColor(this.options.drawError.color);
540 | this._poly.setStyle({color: this.options.drawError.color});
541 |
542 | // Hide the error after 2 seconds
543 | this._clearHideErrorTimeout();
544 | this._hideErrorTimeout = setTimeout(L.Util.bind(this._hideErrorTooltip, this), this.options.drawError.timeout);
545 | },
546 |
547 | _hideErrorTooltip: function () {
548 | this._errorShown = false;
549 |
550 | this._clearHideErrorTimeout();
551 |
552 | // Revert tooltip
553 | this._tooltip
554 | .removeError()
555 | .updateContent(this._getTooltipText());
556 |
557 | // Revert shape
558 | this._updateGuideColor(this.options.shapeOptions.color);
559 | this._poly.setStyle({color: this.options.shapeOptions.color});
560 | },
561 |
562 | _clearHideErrorTimeout: function () {
563 | if (this._hideErrorTimeout) {
564 | clearTimeout(this._hideErrorTimeout);
565 | this._hideErrorTimeout = null;
566 | }
567 | },
568 |
569 | // disable new markers temporarily;
570 | // this is to prevent duplicated touch/click events in some browsers
571 | _disableNewMarkers: function () {
572 | this._disableMarkers = true;
573 | },
574 |
575 | // see _disableNewMarkers
576 | _enableNewMarkers: function () {
577 | setTimeout(function () {
578 | this._disableMarkers = false;
579 | }.bind(this), 50);
580 | },
581 |
582 | _cleanUpShape: function () {
583 | if (this._markers.length > 1) {
584 | this._markers[this._markers.length - 1].off('click', this._finishShape, this);
585 | }
586 | },
587 |
588 | _fireCreatedEvent: function () {
589 | var poly = new this.Poly(this._poly.getLatLngs(), this.options.shapeOptions);
590 | L.Draw.Feature.prototype._fireCreatedEvent.call(this, poly);
591 | }
592 | });
593 |
--------------------------------------------------------------------------------
/static_files/draw_files/Draw.Rectangle.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @class L.Draw.Rectangle
3 | * @aka Draw.Rectangle
4 | * @inherits L.Draw.SimpleShape
5 | */
6 | L.Draw.Rectangle = L.Draw.SimpleShape.extend({
7 | statics: {
8 | TYPE: 'rectangle'
9 | },
10 |
11 | options: {
12 | shapeOptions: {
13 | stroke: true,
14 | color: '#3388ff',
15 | weight: 4,
16 | opacity: 0.5,
17 | fill: true,
18 | fillColor: null, //same as color by default
19 | fillOpacity: 0.2,
20 | showArea: true,
21 | clickable: true
22 | },
23 | metric: true // Whether to use the metric measurement system or imperial
24 | },
25 |
26 | // @method initialize(): void
27 | initialize: function (map, options) {
28 | // Save the type so super can fire, need to do this as cannot do this.TYPE :(
29 | this.type = L.Draw.Rectangle.TYPE;
30 |
31 | this._initialLabelText = L.drawLocal.draw.handlers.rectangle.tooltip.start;
32 |
33 | L.Draw.SimpleShape.prototype.initialize.call(this, map, options);
34 | },
35 |
36 | // @method disable(): void
37 | disable: function () {
38 | if (!this._enabled) {
39 | return;
40 | }
41 |
42 | this._isCurrentlyTwoClickDrawing = false;
43 | L.Draw.SimpleShape.prototype.disable.call(this);
44 | },
45 |
46 | _onMouseUp: function (e) {
47 | if (!this._shape && !this._isCurrentlyTwoClickDrawing) {
48 | this._isCurrentlyTwoClickDrawing = true;
49 | return;
50 | }
51 |
52 | // Make sure closing click is on map
53 | if (this._isCurrentlyTwoClickDrawing && !_hasAncestor(e.target, 'leaflet-pane')) {
54 | return;
55 | }
56 |
57 | L.Draw.SimpleShape.prototype._onMouseUp.call(this);
58 | },
59 |
60 | _drawShape: function (latlng) {
61 | if (!this._shape) {
62 | this._shape = new L.Rectangle(new L.LatLngBounds(this._startLatLng, latlng), this.options.shapeOptions);
63 | this._map.addLayer(this._shape);
64 | } else {
65 | this._shape.setBounds(new L.LatLngBounds(this._startLatLng, latlng));
66 | }
67 | },
68 |
69 | _fireCreatedEvent: function () {
70 | var rectangle = new L.Rectangle(this._shape.getBounds(), this.options.shapeOptions);
71 | L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this, rectangle);
72 | },
73 |
74 | _getTooltipText: function () {
75 | var tooltipText = L.Draw.SimpleShape.prototype._getTooltipText.call(this),
76 | shape = this._shape,
77 | showArea = this.options.showArea,
78 | latLngs, area, subtext;
79 |
80 | if (shape) {
81 | latLngs = this._shape._defaultShape ? this._shape._defaultShape() : this._shape.getLatLngs();
82 | area = L.GeometryUtil.geodesicArea(latLngs);
83 | subtext = showArea ? L.GeometryUtil.readableArea(area, this.options.metric) : '';
84 | }
85 |
86 | return {
87 | text: tooltipText.text,
88 | subtext: subtext
89 | };
90 | }
91 | });
92 |
93 | function _hasAncestor(el, cls) {
94 | while ((el = el.parentElement) && !el.classList.contains(cls)) {
95 | ;
96 | }
97 | return el;
98 | }
99 |
--------------------------------------------------------------------------------
/static_files/draw_files/Draw.SimpleShape.js:
--------------------------------------------------------------------------------
1 | L.SimpleShape = {};
2 | /**
3 | * @class L.Draw.SimpleShape
4 | * @aka Draw.SimpleShape
5 | * @inherits L.Draw.Feature
6 | */
7 | L.Draw.SimpleShape = L.Draw.Feature.extend({
8 | options: {
9 | repeatMode: false
10 | },
11 |
12 | // @method initialize(): void
13 | initialize: function (map, options) {
14 | this._endLabelText = L.drawLocal.draw.handlers.simpleshape.tooltip.end;
15 |
16 | L.Draw.Feature.prototype.initialize.call(this, map, options);
17 | },
18 |
19 | // @method addHooks(): void
20 | // Add listener hooks to this handler.
21 | addHooks: function () {
22 | L.Draw.Feature.prototype.addHooks.call(this);
23 | if (this._map) {
24 | this._mapDraggable = this._map.dragging.enabled();
25 |
26 | if (this._mapDraggable) {
27 | this._map.dragging.disable();
28 | }
29 |
30 | //TODO refactor: move cursor to styles
31 | this._container.style.cursor = 'crosshair';
32 |
33 | this._tooltip.updateContent({text: this._initialLabelText});
34 |
35 | this._map
36 | .on('mousedown', this._onMouseDown, this)
37 | .on('mousemove', this._onMouseMove, this)
38 | .on('touchstart', this._onMouseDown, this)
39 | .on('touchmove', this._onMouseMove, this);
40 |
41 | // we should prevent default, otherwise default behavior (scrolling) will fire,
42 | // and that will cause document.touchend to fire and will stop the drawing
43 | // (circle, rectangle) in touch mode.
44 | // (update): we have to send passive now to prevent scroll, because by default it is {passive: true} now, which means,
45 | // handler can't event.preventDefault
46 | // check the news https://developers.google.com/web/updates/2016/06/passive-event-listeners
47 | document.addEventListener('touchstart', L.DomEvent.preventDefault, {passive: false});
48 | }
49 | },
50 |
51 | // @method removeHooks(): void
52 | // Remove listener hooks from this handler.
53 | removeHooks: function () {
54 | L.Draw.Feature.prototype.removeHooks.call(this);
55 | if (this._map) {
56 | if (this._mapDraggable) {
57 | this._map.dragging.enable();
58 | }
59 |
60 | //TODO refactor: move cursor to styles
61 | this._container.style.cursor = '';
62 |
63 | this._map
64 | .off('mousedown', this._onMouseDown, this)
65 | .off('mousemove', this._onMouseMove, this)
66 | .off('touchstart', this._onMouseDown, this)
67 | .off('touchmove', this._onMouseMove, this);
68 |
69 | L.DomEvent.off(document, 'mouseup', this._onMouseUp, this);
70 | L.DomEvent.off(document, 'touchend', this._onMouseUp, this);
71 |
72 | document.removeEventListener('touchstart', L.DomEvent.preventDefault);
73 |
74 | // If the box element doesn't exist they must not have moved the mouse, so don't need to destroy/return
75 | if (this._shape) {
76 | this._map.removeLayer(this._shape);
77 | delete this._shape;
78 | }
79 | }
80 | this._isDrawing = false;
81 | },
82 |
83 | _getTooltipText: function () {
84 | return {
85 | text: this._endLabelText
86 | };
87 | },
88 |
89 | _onMouseDown: function (e) {
90 | this._isDrawing = true;
91 | this._startLatLng = e.latlng;
92 |
93 | L.DomEvent
94 | .on(document, 'mouseup', this._onMouseUp, this)
95 | .on(document, 'touchend', this._onMouseUp, this)
96 | .preventDefault(e.originalEvent);
97 | },
98 |
99 | _onMouseMove: function (e) {
100 | var latlng = e.latlng;
101 |
102 | this._tooltip.updatePosition(latlng);
103 | if (this._isDrawing) {
104 | this._tooltip.updateContent(this._getTooltipText());
105 | this._drawShape(latlng);
106 | }
107 | },
108 |
109 | _onMouseUp: function () {
110 | if (this._shape) {
111 | this._fireCreatedEvent();
112 | }
113 |
114 | this.disable();
115 | if (this.options.repeatMode) {
116 | this.enable();
117 | }
118 | }
119 | });
120 |
--------------------------------------------------------------------------------
/static_files/draw_files/DrawToolbar.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @class L.DrawToolbar
3 | * @aka Toolbar
4 | */
5 | L.DrawToolbar = L.Toolbar.extend({
6 |
7 | statics: {
8 | TYPE: 'draw'
9 | },
10 |
11 | options: {
12 | polyline: {},
13 | polygon: {},
14 | rectangle: {},
15 | circle: {},
16 | marker: {},
17 | circlemarker: {}
18 | },
19 |
20 | // @method initialize(): void
21 | initialize: function (options) {
22 | // Ensure that the options are merged correctly since L.extend is only shallow
23 | for (var type in this.options) {
24 | if (this.options.hasOwnProperty(type)) {
25 | if (options[type]) {
26 | options[type] = L.extend({}, this.options[type], options[type]);
27 | }
28 | }
29 | }
30 |
31 | this._toolbarClass = 'leaflet-draw-draw';
32 | L.Toolbar.prototype.initialize.call(this, options);
33 | },
34 |
35 | // @method getModeHandlers(): object
36 | // Get mode handlers information
37 | getModeHandlers: function (map) {
38 | return [
39 | {
40 | enabled: this.options.polyline,
41 | handler: new L.Draw.Polyline(map, this.options.polyline),
42 | title: L.drawLocal.draw.toolbar.buttons.polyline
43 | },
44 | {
45 | enabled: this.options.polygon,
46 | handler: new L.Draw.Polygon(map, this.options.polygon),
47 | title: L.drawLocal.draw.toolbar.buttons.polygon
48 | },
49 | {
50 | enabled: this.options.rectangle,
51 | handler: new L.Draw.Rectangle(map, this.options.rectangle),
52 | title: L.drawLocal.draw.toolbar.buttons.rectangle
53 | },
54 | {
55 | enabled: this.options.circle,
56 | handler: new L.Draw.Circle(map, this.options.circle),
57 | title: L.drawLocal.draw.toolbar.buttons.circle
58 | },
59 | {
60 | enabled: this.options.marker,
61 | handler: new L.Draw.Marker(map, this.options.marker),
62 | title: L.drawLocal.draw.toolbar.buttons.marker
63 | },
64 | {
65 | enabled: this.options.circlemarker,
66 | handler: new L.Draw.CircleMarker(map, this.options.circlemarker),
67 | title: L.drawLocal.draw.toolbar.buttons.circlemarker
68 | }
69 | ];
70 | },
71 |
72 | // @method getActions(): object
73 | // Get action information
74 | getActions: function (handler) {
75 | return [
76 | {
77 | enabled: handler.completeShape,
78 | title: L.drawLocal.draw.toolbar.finish.title,
79 | text: L.drawLocal.draw.toolbar.finish.text,
80 | callback: handler.completeShape,
81 | context: handler
82 | },
83 | {
84 | enabled: handler.deleteLastVertex,
85 | title: L.drawLocal.draw.toolbar.undo.title,
86 | text: L.drawLocal.draw.toolbar.undo.text,
87 | callback: handler.deleteLastVertex,
88 | context: handler
89 | },
90 | {
91 | title: L.drawLocal.draw.toolbar.actions.title,
92 | text: L.drawLocal.draw.toolbar.actions.text,
93 | callback: this.disable,
94 | context: this
95 | }
96 | ];
97 | },
98 |
99 | // @method setOptions(): void
100 | // Sets the options to the toolbar
101 | setOptions: function (options) {
102 | L.setOptions(this, options);
103 |
104 | for (var type in this._modes) {
105 | if (this._modes.hasOwnProperty(type) && options.hasOwnProperty(type)) {
106 | this._modes[type].handler.setOptions(options[type]);
107 | }
108 | }
109 | }
110 | });
111 |
--------------------------------------------------------------------------------
/static_files/draw_files/Edit.Circle.js:
--------------------------------------------------------------------------------
1 | L.Edit = L.Edit || {};
2 | /**
3 | * @class L.Edit.Circle
4 | * @aka Edit.Circle
5 | * @inherits L.Edit.CircleMarker
6 | */
7 | L.Edit.Circle = L.Edit.CircleMarker.extend({
8 |
9 | _createResizeMarker: function () {
10 | var center = this._shape.getLatLng(),
11 | resizemarkerPoint = this._getResizeMarkerPoint(center);
12 |
13 | this._resizeMarkers = [];
14 | this._resizeMarkers.push(this._createMarker(resizemarkerPoint, this.options.resizeIcon));
15 | },
16 |
17 | _getResizeMarkerPoint: function (latlng) {
18 | // From L.shape.getBounds()
19 | var delta = this._shape._radius * Math.cos(Math.PI / 4),
20 | point = this._map.project(latlng);
21 | return this._map.unproject([point.x + delta, point.y - delta]);
22 | },
23 |
24 | _resize: function (latlng) {
25 | var moveLatLng = this._moveMarker.getLatLng();
26 |
27 | // Calculate the radius based on the version
28 | if (L.GeometryUtil.isVersion07x()) {
29 | radius = moveLatLng.distanceTo(latlng);
30 | } else {
31 | radius = this._map.distance(moveLatLng, latlng);
32 | }
33 | this._shape.setRadius(radius);
34 |
35 | if (this._map.editTooltip) {
36 | this._map._editTooltip.updateContent({
37 | text: L.drawLocal.edit.handlers.edit.tooltip.subtext + '
' + L.drawLocal.edit.handlers.edit.tooltip.text,
38 | subtext: L.drawLocal.draw.handlers.circle.radius + ': ' +
39 | L.GeometryUtil.readableDistance(radius, true, this.options.feet, this.options.nautic)
40 | });
41 | }
42 |
43 | this._shape.setRadius(radius);
44 |
45 | this._map.fire(L.Draw.Event.EDITRESIZE, {layer: this._shape});
46 | }
47 | });
48 |
49 | L.Circle.addInitHook(function () {
50 | if (L.Edit.Circle) {
51 | this.editing = new L.Edit.Circle(this);
52 |
53 | if (this.options.editable) {
54 | this.editing.enable();
55 | }
56 | }
57 |
58 | this.on('add', function () {
59 | if (this.editing && this.editing.enabled()) {
60 | this.editing.addHooks();
61 | }
62 | });
63 |
64 | this.on('remove', function () {
65 | if (this.editing && this.editing.enabled()) {
66 | this.editing.removeHooks();
67 | }
68 | });
69 | });
70 |
--------------------------------------------------------------------------------
/static_files/draw_files/Edit.CircleMarker.js:
--------------------------------------------------------------------------------
1 | L.Edit = L.Edit || {};
2 | /**
3 | * @class L.Edit.CircleMarker
4 | * @aka Edit.Circle
5 | * @inherits L.Edit.SimpleShape
6 | */
7 | L.Edit.CircleMarker = L.Edit.SimpleShape.extend({
8 | _createMoveMarker: function () {
9 | var center = this._shape.getLatLng();
10 |
11 | this._moveMarker = this._createMarker(center, this.options.moveIcon);
12 | },
13 |
14 | _createResizeMarker: function () {
15 | // To avoid an undefined check in L.Edit.SimpleShape.removeHooks
16 | this._resizeMarkers = [];
17 | },
18 |
19 | _move: function (latlng) {
20 | if (this._resizeMarkers.length) {
21 | var resizemarkerPoint = this._getResizeMarkerPoint(latlng);
22 | // Move the resize marker
23 | this._resizeMarkers[0].setLatLng(resizemarkerPoint);
24 | }
25 |
26 | // Move the circle
27 | this._shape.setLatLng(latlng);
28 |
29 | this._map.fire(L.Draw.Event.EDITMOVE, {layer: this._shape});
30 | },
31 | });
32 |
33 | L.CircleMarker.addInitHook(function () {
34 | if (L.Edit.CircleMarker) {
35 | this.editing = new L.Edit.CircleMarker(this);
36 |
37 | if (this.options.editable) {
38 | this.editing.enable();
39 | }
40 | }
41 |
42 | this.on('add', function () {
43 | if (this.editing && this.editing.enabled()) {
44 | this.editing.addHooks();
45 | }
46 | });
47 |
48 | this.on('remove', function () {
49 | if (this.editing && this.editing.enabled()) {
50 | this.editing.removeHooks();
51 | }
52 | });
53 | });
54 |
--------------------------------------------------------------------------------
/static_files/draw_files/Edit.Marker.js:
--------------------------------------------------------------------------------
1 | L.Edit = L.Edit || {};
2 |
3 | /**
4 | * @class L.Edit.Marker
5 | * @aka Edit.Marker
6 | */
7 | L.Edit.Marker = L.Handler.extend({
8 | // @method initialize(): void
9 | initialize: function (marker, options) {
10 | this._marker = marker;
11 | L.setOptions(this, options);
12 | },
13 |
14 | // @method addHooks(): void
15 | // Add listener hooks to this handler
16 | addHooks: function () {
17 | var marker = this._marker;
18 |
19 | marker.dragging.enable();
20 | marker.on('dragend', this._onDragEnd, marker);
21 | this._toggleMarkerHighlight();
22 | },
23 |
24 | // @method removeHooks(): void
25 | // Remove listener hooks from this handler
26 | removeHooks: function () {
27 | var marker = this._marker;
28 |
29 | marker.dragging.disable();
30 | marker.off('dragend', this._onDragEnd, marker);
31 | this._toggleMarkerHighlight();
32 | },
33 |
34 | _onDragEnd: function (e) {
35 | var layer = e.target;
36 | layer.edited = true;
37 | this._map.fire(L.Draw.Event.EDITMOVE, {layer: layer});
38 | },
39 |
40 | _toggleMarkerHighlight: function () {
41 | var icon = this._marker._icon;
42 |
43 | // Don't do anything if this layer is a marker but doesn't have an icon. Markers
44 | // should usually have icons. If using Leaflet.draw with Leaflet.markercluster there
45 | // is a chance that a marker doesn't.
46 | if (!icon) {
47 | return;
48 | }
49 |
50 | // This is quite naughty, but I don't see another way of doing it. (short of setting a new icon)
51 | icon.style.display = 'none';
52 |
53 | if (L.DomUtil.hasClass(icon, 'leaflet-edit-marker-selected')) {
54 | L.DomUtil.removeClass(icon, 'leaflet-edit-marker-selected');
55 | // Offset as the border will make the icon move.
56 | this._offsetMarker(icon, -4);
57 |
58 | } else {
59 | L.DomUtil.addClass(icon, 'leaflet-edit-marker-selected');
60 | // Offset as the border will make the icon move.
61 | this._offsetMarker(icon, 4);
62 | }
63 |
64 | icon.style.display = '';
65 | },
66 |
67 | _offsetMarker: function (icon, offset) {
68 | var iconMarginTop = parseInt(icon.style.marginTop, 10) - offset,
69 | iconMarginLeft = parseInt(icon.style.marginLeft, 10) - offset;
70 |
71 | icon.style.marginTop = iconMarginTop + 'px';
72 | icon.style.marginLeft = iconMarginLeft + 'px';
73 | }
74 | });
75 |
76 | L.Marker.addInitHook(function () {
77 | if (L.Edit.Marker) {
78 | this.editing = new L.Edit.Marker(this);
79 |
80 | if (this.options.editable) {
81 | this.editing.enable();
82 | }
83 | }
84 | });
85 |
--------------------------------------------------------------------------------
/static_files/draw_files/Edit.Poly.js:
--------------------------------------------------------------------------------
1 | L.Edit = L.Edit || {};
2 |
3 | /**
4 | * @class L.Edit.Polyline
5 | * @aka L.Edit.Poly
6 | * @aka Edit.Poly
7 | */
8 | L.Edit.Poly = L.Handler.extend({
9 | // @method initialize(): void
10 | initialize: function (poly) {
11 |
12 | this.latlngs = [poly._latlngs];
13 | if (poly._holes) {
14 | this.latlngs = this.latlngs.concat(poly._holes);
15 | }
16 |
17 | this._poly = poly;
18 |
19 | this._poly.on('revert-edited', this._updateLatLngs, this);
20 | },
21 |
22 | // Compatibility method to normalize Poly* objects
23 | // between 0.7.x and 1.0+
24 | _defaultShape: function () {
25 | if (!L.Polyline._flat) {
26 | return this._poly._latlngs;
27 | }
28 | return L.Polyline._flat(this._poly._latlngs) ? this._poly._latlngs : this._poly._latlngs[0];
29 | },
30 |
31 | _eachVertexHandler: function (callback) {
32 | for (var i = 0; i < this._verticesHandlers.length; i++) {
33 | callback(this._verticesHandlers[i]);
34 | }
35 | },
36 |
37 | // @method addHooks(): void
38 | // Add listener hooks to this handler
39 | addHooks: function () {
40 | this._initHandlers();
41 | this._eachVertexHandler(function (handler) {
42 | handler.addHooks();
43 | });
44 | },
45 |
46 | // @method removeHooks(): void
47 | // Remove listener hooks from this handler
48 | removeHooks: function () {
49 | this._eachVertexHandler(function (handler) {
50 | handler.removeHooks();
51 | });
52 | },
53 |
54 | // @method updateMarkers(): void
55 | // Fire an update for each vertex handler
56 | updateMarkers: function () {
57 | this._eachVertexHandler(function (handler) {
58 | handler.updateMarkers();
59 | });
60 | },
61 |
62 | _initHandlers: function () {
63 | this._verticesHandlers = [];
64 | for (var i = 0; i < this.latlngs.length; i++) {
65 | this._verticesHandlers.push(new L.Edit.PolyVerticesEdit(this._poly, this.latlngs[i], this._poly.options.poly));
66 | }
67 | },
68 |
69 | _updateLatLngs: function (e) {
70 | this.latlngs = [e.layer._latlngs];
71 | if (e.layer._holes) {
72 | this.latlngs = this.latlngs.concat(e.layer._holes);
73 | }
74 | }
75 |
76 | });
77 |
78 | /**
79 | * @class L.Edit.PolyVerticesEdit
80 | * @aka Edit.PolyVerticesEdit
81 | */
82 | L.Edit.PolyVerticesEdit = L.Handler.extend({
83 | options: {
84 | icon: new L.DivIcon({
85 | iconSize: new L.Point(8, 8),
86 | className: 'leaflet-div-icon leaflet-editing-icon'
87 | }),
88 | touchIcon: new L.DivIcon({
89 | iconSize: new L.Point(20, 20),
90 | className: 'leaflet-div-icon leaflet-editing-icon leaflet-touch-icon'
91 | }),
92 | drawError: {
93 | color: '#b00b00',
94 | timeout: 1000
95 | }
96 |
97 |
98 | },
99 |
100 | // @method intialize(): void
101 | initialize: function (poly, latlngs, options) {
102 | // if touch, switch to touch icon
103 | if (L.Browser.touch) {
104 | this.options.icon = this.options.touchIcon;
105 | }
106 | this._poly = poly;
107 |
108 | if (options && options.drawError) {
109 | options.drawError = L.Util.extend({}, this.options.drawError, options.drawError);
110 | }
111 |
112 | this._latlngs = latlngs;
113 |
114 | L.setOptions(this, options);
115 | },
116 |
117 | // Compatibility method to normalize Poly* objects
118 | // between 0.7.x and 1.0+
119 | _defaultShape: function () {
120 | if (!L.Polyline._flat) {
121 | return this._latlngs;
122 | }
123 | return L.Polyline._flat(this._latlngs) ? this._latlngs : this._latlngs[0];
124 | },
125 |
126 | // @method addHooks(): void
127 | // Add listener hooks to this handler.
128 | addHooks: function () {
129 | var poly = this._poly;
130 | var path = poly._path;
131 |
132 | if (!(poly instanceof L.Polygon)) {
133 | poly.options.fill = false;
134 | if (poly.options.editing) {
135 | poly.options.editing.fill = false;
136 | }
137 | }
138 |
139 | if (path) {
140 | if (poly.options.editing && poly.options.editing.className) {
141 | if (poly.options.original.className) {
142 | poly.options.original.className.split(' ').forEach(function (className) {
143 | L.DomUtil.removeClass(path, className);
144 | });
145 | }
146 | poly.options.editing.className.split(' ').forEach(function (className) {
147 | L.DomUtil.addClass(path, className);
148 | });
149 | }
150 | }
151 |
152 | poly.setStyle(poly.options.editing);
153 |
154 | if (this._poly._map) {
155 |
156 | this._map = this._poly._map; // Set map
157 |
158 | if (!this._markerGroup) {
159 | this._initMarkers();
160 | }
161 | this._poly._map.addLayer(this._markerGroup);
162 | }
163 | },
164 |
165 | // @method removeHooks(): void
166 | // Remove listener hooks from this handler.
167 | removeHooks: function () {
168 | var poly = this._poly;
169 | var path = poly._path;
170 |
171 | if (path) {
172 | if (poly.options.editing && poly.options.editing.className) {
173 | poly.options.editing.className.split(' ').forEach(function (className) {
174 | L.DomUtil.removeClass(path, className);
175 | });
176 | if (poly.options.original.className) {
177 | poly.options.original.className.split(' ').forEach(function (className) {
178 | L.DomUtil.addClass(path, className);
179 | });
180 | }
181 | }
182 | }
183 |
184 | poly.setStyle(poly.options.original);
185 |
186 | if (poly._map) {
187 | poly._map.removeLayer(this._markerGroup);
188 | delete this._markerGroup;
189 | delete this._markers;
190 | }
191 | },
192 |
193 | // @method updateMarkers(): void
194 | // Clear markers and update their location
195 | updateMarkers: function () {
196 | this._markerGroup.clearLayers();
197 | this._initMarkers();
198 | },
199 |
200 | _initMarkers: function () {
201 | if (!this._markerGroup) {
202 | this._markerGroup = new L.LayerGroup();
203 | }
204 | this._markers = [];
205 |
206 | var latlngs = this._defaultShape(),
207 | i, j, len, marker;
208 |
209 | for (i = 0, len = latlngs.length; i < len; i++) {
210 |
211 | marker = this._createMarker(latlngs[i], i);
212 | marker.on('click', this._onMarkerClick, this);
213 | marker.on('contextmenu', this._onContextMenu, this);
214 | this._markers.push(marker);
215 | }
216 |
217 | var markerLeft, markerRight;
218 |
219 | for (i = 0, j = len - 1; i < len; j = i++) {
220 | if (i === 0 && !(L.Polygon && (this._poly instanceof L.Polygon))) {
221 | continue;
222 | }
223 |
224 | markerLeft = this._markers[j];
225 | markerRight = this._markers[i];
226 |
227 | this._createMiddleMarker(markerLeft, markerRight);
228 | this._updatePrevNext(markerLeft, markerRight);
229 | }
230 | },
231 |
232 | _createMarker: function (latlng, index) {
233 | // Extending L.Marker in TouchEvents.js to include touch.
234 | var marker = new L.Marker.Touch(latlng, {
235 | draggable: true,
236 | icon: this.options.icon,
237 | });
238 |
239 | marker._origLatLng = latlng;
240 | marker._index = index;
241 |
242 | marker
243 | .on('dragstart', this._onMarkerDragStart, this)
244 | .on('drag', this._onMarkerDrag, this)
245 | .on('dragend', this._fireEdit, this)
246 | .on('touchmove', this._onTouchMove, this)
247 | .on('touchend', this._fireEdit, this)
248 | .on('MSPointerMove', this._onTouchMove, this)
249 | .on('MSPointerUp', this._fireEdit, this);
250 |
251 | this._markerGroup.addLayer(marker);
252 |
253 | return marker;
254 | },
255 |
256 | _onMarkerDragStart: function () {
257 | this._poly.fire('editstart');
258 | },
259 |
260 | _spliceLatLngs: function () {
261 | var latlngs = this._defaultShape();
262 | var removed = [].splice.apply(latlngs, arguments);
263 | this._poly._convertLatLngs(latlngs, true);
264 | this._poly.redraw();
265 | return removed;
266 | },
267 |
268 | _removeMarker: function (marker) {
269 | var i = marker._index;
270 |
271 | this._markerGroup.removeLayer(marker);
272 | this._markers.splice(i, 1);
273 | this._spliceLatLngs(i, 1);
274 | this._updateIndexes(i, -1);
275 |
276 | marker
277 | .off('dragstart', this._onMarkerDragStart, this)
278 | .off('drag', this._onMarkerDrag, this)
279 | .off('dragend', this._fireEdit, this)
280 | .off('touchmove', this._onMarkerDrag, this)
281 | .off('touchend', this._fireEdit, this)
282 | .off('click', this._onMarkerClick, this)
283 | .off('MSPointerMove', this._onTouchMove, this)
284 | .off('MSPointerUp', this._fireEdit, this);
285 | },
286 |
287 | _fireEdit: function () {
288 | this._poly.edited = true;
289 | this._poly.fire('edit');
290 | this._poly._map.fire(L.Draw.Event.EDITVERTEX, {layers: this._markerGroup, poly: this._poly});
291 | },
292 |
293 | _onMarkerDrag: function (e) {
294 | var marker = e.target;
295 | var poly = this._poly;
296 |
297 | L.extend(marker._origLatLng, marker._latlng);
298 |
299 | if (marker._middleLeft) {
300 | marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
301 | }
302 | if (marker._middleRight) {
303 | marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
304 | }
305 |
306 | if (poly.options.poly) {
307 | var tooltip = poly._map._editTooltip; // Access the tooltip
308 |
309 | // If we don't allow intersections and the polygon intersects
310 | if (!poly.options.poly.allowIntersection && poly.intersects()) {
311 |
312 | var originalColor = poly.options.color;
313 | poly.setStyle({color: this.options.drawError.color});
314 |
315 | // Manually trigger 'dragend' behavior on marker we are about to remove
316 | // WORKAROUND: introduced in 1.0.0-rc2, may be related to #4484
317 | if (L.version.indexOf('0.7') !== 0) {
318 | marker.dragging._draggable._onUp(e);
319 | }
320 | this._onMarkerClick(e); // Remove violating marker
321 | // FIXME: Reset the marker to it's original position (instead of remove)
322 |
323 | if (tooltip) {
324 | tooltip.updateContent({
325 | text: L.drawLocal.draw.handlers.polyline.error
326 | });
327 | }
328 |
329 | // Reset everything back to normal after a second
330 | setTimeout(function () {
331 | poly.setStyle({color: originalColor});
332 | if (tooltip) {
333 | tooltip.updateContent({
334 | text: L.drawLocal.edit.handlers.edit.tooltip.text,
335 | subtext: L.drawLocal.edit.handlers.edit.tooltip.subtext
336 | });
337 | }
338 | }, 1000);
339 | }
340 | }
341 | //refresh the bounds when draging
342 | this._poly._bounds._southWest = L.latLng(Infinity, Infinity);
343 | this._poly._bounds._northEast = L.latLng(-Infinity, -Infinity);
344 | var latlngs = this._poly.getLatLngs();
345 | this._poly._convertLatLngs(latlngs, true);
346 | this._poly.redraw();
347 | this._poly.fire('editdrag');
348 | },
349 |
350 | _onMarkerClick: function (e) {
351 |
352 | var minPoints = L.Polygon && (this._poly instanceof L.Polygon) ? 4 : 3,
353 | marker = e.target;
354 |
355 | // If removing this point would create an invalid polyline/polygon don't remove
356 | if (this._defaultShape().length < minPoints) {
357 | return;
358 | }
359 |
360 | // remove the marker
361 | this._removeMarker(marker);
362 |
363 | // update prev/next links of adjacent markers
364 | this._updatePrevNext(marker._prev, marker._next);
365 |
366 | // remove ghost markers near the removed marker
367 | if (marker._middleLeft) {
368 | this._markerGroup.removeLayer(marker._middleLeft);
369 | }
370 | if (marker._middleRight) {
371 | this._markerGroup.removeLayer(marker._middleRight);
372 | }
373 |
374 | // create a ghost marker in place of the removed one
375 | if (marker._prev && marker._next) {
376 | this._createMiddleMarker(marker._prev, marker._next);
377 |
378 | } else if (!marker._prev) {
379 | marker._next._middleLeft = null;
380 |
381 | } else if (!marker._next) {
382 | marker._prev._middleRight = null;
383 | }
384 |
385 | this._fireEdit();
386 | },
387 |
388 | _onContextMenu: function (e) {
389 | var marker = e.target;
390 | var poly = this._poly;
391 | this._poly._map.fire(L.Draw.Event.MARKERCONTEXT, {marker: marker, layers: this._markerGroup, poly: this._poly});
392 | L.DomEvent.stopPropagation;
393 | },
394 |
395 | _onTouchMove: function (e) {
396 |
397 | var layerPoint = this._map.mouseEventToLayerPoint(e.originalEvent.touches[0]),
398 | latlng = this._map.layerPointToLatLng(layerPoint),
399 | marker = e.target;
400 |
401 | L.extend(marker._origLatLng, latlng);
402 |
403 | if (marker._middleLeft) {
404 | marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
405 | }
406 | if (marker._middleRight) {
407 | marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
408 | }
409 |
410 | this._poly.redraw();
411 | this.updateMarkers();
412 | },
413 |
414 | _updateIndexes: function (index, delta) {
415 | this._markerGroup.eachLayer(function (marker) {
416 | if (marker._index > index) {
417 | marker._index += delta;
418 | }
419 | });
420 | },
421 |
422 | _createMiddleMarker: function (marker1, marker2) {
423 | var latlng = this._getMiddleLatLng(marker1, marker2),
424 | marker = this._createMarker(latlng),
425 | onClick,
426 | onDragStart,
427 | onDragEnd;
428 |
429 | marker.setOpacity(0.6);
430 |
431 | marker1._middleRight = marker2._middleLeft = marker;
432 |
433 | onDragStart = function () {
434 | marker.off('touchmove', onDragStart, this);
435 | var i = marker2._index;
436 |
437 | marker._index = i;
438 |
439 | marker
440 | .off('click', onClick, this)
441 | .on('click', this._onMarkerClick, this);
442 |
443 | latlng.lat = marker.getLatLng().lat;
444 | latlng.lng = marker.getLatLng().lng;
445 | this._spliceLatLngs(i, 0, latlng);
446 | this._markers.splice(i, 0, marker);
447 |
448 | marker.setOpacity(1);
449 |
450 | this._updateIndexes(i, 1);
451 | marker2._index++;
452 | this._updatePrevNext(marker1, marker);
453 | this._updatePrevNext(marker, marker2);
454 |
455 | this._poly.fire('editstart');
456 | };
457 |
458 | onDragEnd = function () {
459 | marker.off('dragstart', onDragStart, this);
460 | marker.off('dragend', onDragEnd, this);
461 | marker.off('touchmove', onDragStart, this);
462 |
463 | this._createMiddleMarker(marker1, marker);
464 | this._createMiddleMarker(marker, marker2);
465 | };
466 |
467 | onClick = function () {
468 | onDragStart.call(this);
469 | onDragEnd.call(this);
470 | this._fireEdit();
471 | };
472 |
473 | marker
474 | .on('click', onClick, this)
475 | .on('dragstart', onDragStart, this)
476 | .on('dragend', onDragEnd, this)
477 | .on('touchmove', onDragStart, this);
478 |
479 | this._markerGroup.addLayer(marker);
480 | },
481 |
482 | _updatePrevNext: function (marker1, marker2) {
483 | if (marker1) {
484 | marker1._next = marker2;
485 | }
486 | if (marker2) {
487 | marker2._prev = marker1;
488 | }
489 | },
490 |
491 | _getMiddleLatLng: function (marker1, marker2) {
492 | var map = this._poly._map,
493 | p1 = map.project(marker1.getLatLng()),
494 | p2 = map.project(marker2.getLatLng());
495 |
496 | return map.unproject(p1._add(p2)._divideBy(2));
497 | }
498 | });
499 |
500 | L.Polyline.addInitHook(function () {
501 |
502 | // Check to see if handler has already been initialized. This is to support versions of Leaflet that still have L.Handler.PolyEdit
503 | if (this.editing) {
504 | return;
505 | }
506 |
507 | if (L.Edit.Poly) {
508 |
509 | this.editing = new L.Edit.Poly(this);
510 |
511 | if (this.options.editable) {
512 | this.editing.enable();
513 | }
514 | }
515 |
516 | this.on('add', function () {
517 | if (this.editing && this.editing.enabled()) {
518 | this.editing.addHooks();
519 | }
520 | });
521 |
522 | this.on('remove', function () {
523 | if (this.editing && this.editing.enabled()) {
524 | this.editing.removeHooks();
525 | }
526 | });
527 | });
528 |
--------------------------------------------------------------------------------
/static_files/draw_files/Edit.Rectangle.js:
--------------------------------------------------------------------------------
1 | L.Edit = L.Edit || {};
2 | /**
3 | * @class L.Edit.Rectangle
4 | * @aka Edit.Rectangle
5 | * @inherits L.Edit.SimpleShape
6 | */
7 | L.Edit.Rectangle = L.Edit.SimpleShape.extend({
8 | _createMoveMarker: function () {
9 | var bounds = this._shape.getBounds(),
10 | center = bounds.getCenter();
11 |
12 | this._moveMarker = this._createMarker(center, this.options.moveIcon);
13 | },
14 |
15 | _createResizeMarker: function () {
16 | var corners = this._getCorners();
17 |
18 | this._resizeMarkers = [];
19 |
20 | for (var i = 0, l = corners.length; i < l; i++) {
21 | this._resizeMarkers.push(this._createMarker(corners[i], this.options.resizeIcon));
22 | // Monkey in the corner index as we will need to know this for dragging
23 | this._resizeMarkers[i]._cornerIndex = i;
24 | }
25 | },
26 |
27 | _onMarkerDragStart: function (e) {
28 | L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this, e);
29 |
30 | // Save a reference to the opposite point
31 | var corners = this._getCorners(),
32 | marker = e.target,
33 | currentCornerIndex = marker._cornerIndex;
34 |
35 | this._oppositeCorner = corners[(currentCornerIndex + 2) % 4];
36 |
37 | this._toggleCornerMarkers(0, currentCornerIndex);
38 | },
39 |
40 | _onMarkerDragEnd: function (e) {
41 | var marker = e.target,
42 | bounds, center;
43 |
44 | // Reset move marker position to the center
45 | if (marker === this._moveMarker) {
46 | bounds = this._shape.getBounds();
47 | center = bounds.getCenter();
48 |
49 | marker.setLatLng(center);
50 | }
51 |
52 | this._toggleCornerMarkers(1);
53 |
54 | this._repositionCornerMarkers();
55 |
56 | L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this, e);
57 | },
58 |
59 | _move: function (newCenter) {
60 | var latlngs = this._shape._defaultShape ? this._shape._defaultShape() : this._shape.getLatLngs(),
61 | bounds = this._shape.getBounds(),
62 | center = bounds.getCenter(),
63 | offset, newLatLngs = [];
64 |
65 | // Offset the latlngs to the new center
66 | for (var i = 0, l = latlngs.length; i < l; i++) {
67 | offset = [latlngs[i].lat - center.lat, latlngs[i].lng - center.lng];
68 | newLatLngs.push([newCenter.lat + offset[0], newCenter.lng + offset[1]]);
69 | }
70 |
71 | this._shape.setLatLngs(newLatLngs);
72 |
73 | // Reposition the resize markers
74 | this._repositionCornerMarkers();
75 |
76 | this._map.fire(L.Draw.Event.EDITMOVE, {layer: this._shape});
77 | },
78 |
79 | _resize: function (latlng) {
80 | var bounds;
81 |
82 | // Update the shape based on the current position of this corner and the opposite point
83 | this._shape.setBounds(L.latLngBounds(latlng, this._oppositeCorner));
84 |
85 | // Reposition the move marker
86 | bounds = this._shape.getBounds();
87 | this._moveMarker.setLatLng(bounds.getCenter());
88 |
89 | this._map.fire(L.Draw.Event.EDITRESIZE, {layer: this._shape});
90 | },
91 |
92 | _getCorners: function () {
93 | var bounds = this._shape.getBounds(),
94 | nw = bounds.getNorthWest(),
95 | ne = bounds.getNorthEast(),
96 | se = bounds.getSouthEast(),
97 | sw = bounds.getSouthWest();
98 |
99 | return [nw, ne, se, sw];
100 | },
101 |
102 | _toggleCornerMarkers: function (opacity) {
103 | for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
104 | this._resizeMarkers[i].setOpacity(opacity);
105 | }
106 | },
107 |
108 | _repositionCornerMarkers: function () {
109 | var corners = this._getCorners();
110 |
111 | for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
112 | this._resizeMarkers[i].setLatLng(corners[i]);
113 | }
114 | }
115 | });
116 |
117 | L.Rectangle.addInitHook(function () {
118 | if (L.Edit.Rectangle) {
119 | this.editing = new L.Edit.Rectangle(this);
120 |
121 | if (this.options.editable) {
122 | this.editing.enable();
123 | }
124 | }
125 | });
126 |
--------------------------------------------------------------------------------
/static_files/draw_files/Edit.SimpleShape.js:
--------------------------------------------------------------------------------
1 | L.Edit = L.Edit || {};
2 | /**
3 | * @class L.Edit.SimpleShape
4 | * @aka Edit.SimpleShape
5 | */
6 | L.Edit.SimpleShape = L.Handler.extend({
7 | options: {
8 | moveIcon: new L.DivIcon({
9 | iconSize: new L.Point(8, 8),
10 | className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-move'
11 | }),
12 | resizeIcon: new L.DivIcon({
13 | iconSize: new L.Point(8, 8),
14 | className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-resize'
15 | }),
16 | touchMoveIcon: new L.DivIcon({
17 | iconSize: new L.Point(20, 20),
18 | className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-move leaflet-touch-icon'
19 | }),
20 | touchResizeIcon: new L.DivIcon({
21 | iconSize: new L.Point(20, 20),
22 | className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-resize leaflet-touch-icon'
23 | }),
24 | },
25 |
26 | // @method intialize(): void
27 | initialize: function (shape, options) {
28 | // if touch, switch to touch icon
29 | if (L.Browser.touch) {
30 | this.options.moveIcon = this.options.touchMoveIcon;
31 | this.options.resizeIcon = this.options.touchResizeIcon;
32 | }
33 |
34 | this._shape = shape;
35 | L.Util.setOptions(this, options);
36 | },
37 |
38 | // @method addHooks(): void
39 | // Add listener hooks to this handler
40 | addHooks: function () {
41 | var shape = this._shape;
42 | if (this._shape._map) {
43 | this._map = this._shape._map;
44 | shape.setStyle(shape.options.editing);
45 |
46 | if (shape._map) {
47 | this._map = shape._map;
48 | if (!this._markerGroup) {
49 | this._initMarkers();
50 | }
51 | this._map.addLayer(this._markerGroup);
52 | }
53 | }
54 | },
55 |
56 | // @method removeHooks(): void
57 | // Remove listener hooks from this handler
58 | removeHooks: function () {
59 | var shape = this._shape;
60 |
61 | shape.setStyle(shape.options.original);
62 |
63 | if (shape._map) {
64 | this._unbindMarker(this._moveMarker);
65 |
66 | for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
67 | this._unbindMarker(this._resizeMarkers[i]);
68 | }
69 | this._resizeMarkers = null;
70 |
71 | this._map.removeLayer(this._markerGroup);
72 | delete this._markerGroup;
73 | }
74 |
75 | this._map = null;
76 | },
77 |
78 | // @method updateMarkers(): void
79 | // Remove the edit markers from this layer
80 | updateMarkers: function () {
81 | this._markerGroup.clearLayers();
82 | this._initMarkers();
83 | },
84 |
85 | _initMarkers: function () {
86 | if (!this._markerGroup) {
87 | this._markerGroup = new L.LayerGroup();
88 | }
89 |
90 | // Create center marker
91 | this._createMoveMarker();
92 |
93 | // Create edge marker
94 | this._createResizeMarker();
95 | },
96 |
97 | _createMoveMarker: function () {
98 | // Children override
99 | },
100 |
101 | _createResizeMarker: function () {
102 | // Children override
103 | },
104 |
105 | _createMarker: function (latlng, icon) {
106 | // Extending L.Marker in TouchEvents.js to include touch.
107 | var marker = new L.Marker.Touch(latlng, {
108 | draggable: true,
109 | icon: icon,
110 | zIndexOffset: 10
111 | });
112 |
113 | this._bindMarker(marker);
114 |
115 | this._markerGroup.addLayer(marker);
116 |
117 | return marker;
118 | },
119 |
120 | _bindMarker: function (marker) {
121 | marker
122 | .on('dragstart', this._onMarkerDragStart, this)
123 | .on('drag', this._onMarkerDrag, this)
124 | .on('dragend', this._onMarkerDragEnd, this)
125 | .on('touchstart', this._onTouchStart, this)
126 | .on('touchmove', this._onTouchMove, this)
127 | .on('MSPointerMove', this._onTouchMove, this)
128 | .on('touchend', this._onTouchEnd, this)
129 | .on('MSPointerUp', this._onTouchEnd, this);
130 | },
131 |
132 | _unbindMarker: function (marker) {
133 | marker
134 | .off('dragstart', this._onMarkerDragStart, this)
135 | .off('drag', this._onMarkerDrag, this)
136 | .off('dragend', this._onMarkerDragEnd, this)
137 | .off('touchstart', this._onTouchStart, this)
138 | .off('touchmove', this._onTouchMove, this)
139 | .off('MSPointerMove', this._onTouchMove, this)
140 | .off('touchend', this._onTouchEnd, this)
141 | .off('MSPointerUp', this._onTouchEnd, this);
142 | },
143 |
144 | _onMarkerDragStart: function (e) {
145 | var marker = e.target;
146 | marker.setOpacity(0);
147 |
148 | this._shape.fire('editstart');
149 | },
150 |
151 | _fireEdit: function () {
152 | this._shape.edited = true;
153 | this._shape.fire('edit');
154 | },
155 |
156 | _onMarkerDrag: function (e) {
157 | var marker = e.target,
158 | latlng = marker.getLatLng();
159 |
160 | if (marker === this._moveMarker) {
161 | this._move(latlng);
162 | } else {
163 | this._resize(latlng);
164 | }
165 |
166 | this._shape.redraw();
167 | this._shape.fire('editdrag');
168 | },
169 |
170 | _onMarkerDragEnd: function (e) {
171 | var marker = e.target;
172 | marker.setOpacity(1);
173 |
174 | this._fireEdit();
175 | },
176 |
177 | _onTouchStart: function (e) {
178 | L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this, e);
179 |
180 | if (typeof(this._getCorners) === 'function') {
181 | // Save a reference to the opposite point
182 | var corners = this._getCorners(),
183 | marker = e.target,
184 | currentCornerIndex = marker._cornerIndex;
185 |
186 | marker.setOpacity(0);
187 |
188 | // Copyed from Edit.Rectangle.js line 23 _onMarkerDragStart()
189 | // Latlng is null otherwise.
190 | this._oppositeCorner = corners[(currentCornerIndex + 2) % 4];
191 | this._toggleCornerMarkers(0, currentCornerIndex);
192 | }
193 |
194 | this._shape.fire('editstart');
195 | },
196 |
197 | _onTouchMove: function (e) {
198 | var layerPoint = this._map.mouseEventToLayerPoint(e.originalEvent.touches[0]),
199 | latlng = this._map.layerPointToLatLng(layerPoint),
200 | marker = e.target;
201 |
202 | if (marker === this._moveMarker) {
203 | this._move(latlng);
204 | } else {
205 | this._resize(latlng);
206 | }
207 |
208 | this._shape.redraw();
209 |
210 | // prevent touchcancel in IOS
211 | // e.preventDefault();
212 | return false;
213 | },
214 |
215 | _onTouchEnd: function (e) {
216 | var marker = e.target;
217 | marker.setOpacity(1);
218 | this.updateMarkers();
219 | this._fireEdit();
220 | },
221 |
222 | _move: function () {
223 | // Children override
224 | },
225 |
226 | _resize: function () {
227 | // Children override
228 | }
229 | });
230 |
--------------------------------------------------------------------------------
/static_files/draw_files/EditToolbar.Delete.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @class L.EditToolbar.Delete
3 | * @aka EditToolbar.Delete
4 | */
5 | L.EditToolbar.Delete = L.Handler.extend({
6 | statics: {
7 | TYPE: 'remove' // not delete as delete is reserved in js
8 | },
9 |
10 | // @method intialize(): void
11 | initialize: function (map, options) {
12 | L.Handler.prototype.initialize.call(this, map);
13 |
14 | L.Util.setOptions(this, options);
15 |
16 | // Store the selectable layer group for ease of access
17 | this._deletableLayers = this.options.featureGroup;
18 |
19 | if (!(this._deletableLayers instanceof L.FeatureGroup)) {
20 | throw new Error('options.featureGroup must be a L.FeatureGroup');
21 | }
22 |
23 | // Save the type so super can fire, need to do this as cannot do this.TYPE :(
24 | this.type = L.EditToolbar.Delete.TYPE;
25 |
26 | var version = L.version.split('.');
27 | //If Version is >= 1.2.0
28 | if (parseInt(version[0], 10) === 1 && parseInt(version[1], 10) >= 2) {
29 | L.EditToolbar.Delete.include(L.Evented.prototype);
30 | } else {
31 | L.EditToolbar.Delete.include(L.Mixin.Events);
32 | }
33 |
34 | },
35 |
36 | // @method enable(): void
37 | // Enable the delete toolbar
38 | enable: function () {
39 | if (this._enabled || !this._hasAvailableLayers()) {
40 | return;
41 | }
42 | this.fire('enabled', {handler: this.type});
43 |
44 | this._map.fire(L.Draw.Event.DELETESTART, {handler: this.type});
45 |
46 | L.Handler.prototype.enable.call(this);
47 |
48 | this._deletableLayers
49 | .on('layeradd', this._enableLayerDelete, this)
50 | .on('layerremove', this._disableLayerDelete, this);
51 | },
52 |
53 | // @method disable(): void
54 | // Disable the delete toolbar
55 | disable: function () {
56 | if (!this._enabled) {
57 | return;
58 | }
59 |
60 | this._deletableLayers
61 | .off('layeradd', this._enableLayerDelete, this)
62 | .off('layerremove', this._disableLayerDelete, this);
63 |
64 | L.Handler.prototype.disable.call(this);
65 |
66 | this._map.fire(L.Draw.Event.DELETESTOP, {handler: this.type});
67 |
68 | this.fire('disabled', {handler: this.type});
69 | },
70 |
71 | // @method addHooks(): void
72 | // Add listener hooks to this handler
73 | addHooks: function () {
74 | var map = this._map;
75 |
76 | if (map) {
77 | map.getContainer().focus();
78 |
79 | this._deletableLayers.eachLayer(this._enableLayerDelete, this);
80 | this._deletedLayers = new L.LayerGroup();
81 |
82 | this._tooltip = new L.Draw.Tooltip(this._map);
83 | this._tooltip.updateContent({text: L.drawLocal.edit.handlers.remove.tooltip.text});
84 |
85 | this._map.on('mousemove', this._onMouseMove, this);
86 | }
87 | },
88 |
89 | // @method removeHooks(): void
90 | // Remove listener hooks from this handler
91 | removeHooks: function () {
92 | if (this._map) {
93 | this._deletableLayers.eachLayer(this._disableLayerDelete, this);
94 | this._deletedLayers = null;
95 |
96 | this._tooltip.dispose();
97 | this._tooltip = null;
98 |
99 | this._map.off('mousemove', this._onMouseMove, this);
100 | }
101 | },
102 |
103 | // @method revertLayers(): void
104 | // Revert the deleted layers back to their prior state.
105 | revertLayers: function () {
106 | // Iterate of the deleted layers and add them back into the featureGroup
107 | this._deletedLayers.eachLayer(function (layer) {
108 | this._deletableLayers.addLayer(layer);
109 | layer.fire('revert-deleted', {layer: layer});
110 | }, this);
111 | },
112 |
113 | // @method save(): void
114 | // Save deleted layers
115 | save: function () {
116 | this._map.fire(L.Draw.Event.DELETED, {layers: this._deletedLayers});
117 | },
118 |
119 | // @method removeAllLayers(): void
120 | // Remove all delateable layers
121 | removeAllLayers: function () {
122 | // Iterate of the delateable layers and add remove them
123 | this._deletableLayers.eachLayer(function (layer) {
124 | this._removeLayer({layer: layer});
125 | }, this);
126 | this.save();
127 | },
128 |
129 | _enableLayerDelete: function (e) {
130 | var layer = e.layer || e.target || e;
131 |
132 | layer.on('click', this._removeLayer, this);
133 | },
134 |
135 | _disableLayerDelete: function (e) {
136 | var layer = e.layer || e.target || e;
137 |
138 | layer.off('click', this._removeLayer, this);
139 |
140 | // Remove from the deleted layers so we can't accidentally revert if the user presses cancel
141 | this._deletedLayers.removeLayer(layer);
142 | },
143 |
144 | _removeLayer: function (e) {
145 | var layer = e.layer || e.target || e;
146 |
147 | this._deletableLayers.removeLayer(layer);
148 |
149 | this._deletedLayers.addLayer(layer);
150 |
151 | layer.fire('deleted');
152 | },
153 |
154 | _onMouseMove: function (e) {
155 | this._tooltip.updatePosition(e.latlng);
156 | },
157 |
158 | _hasAvailableLayers: function () {
159 | return this._deletableLayers.getLayers().length !== 0;
160 | }
161 | });
162 |
--------------------------------------------------------------------------------
/static_files/draw_files/EditToolbar.Edit.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @class L.EditToolbar.Edit
3 | * @aka EditToolbar.Edit
4 | */
5 | L.EditToolbar.Edit = L.Handler.extend({
6 | statics: {
7 | TYPE: 'edit'
8 | },
9 |
10 | // @method intialize(): void
11 | initialize: function (map, options) {
12 | L.Handler.prototype.initialize.call(this, map);
13 |
14 | L.setOptions(this, options);
15 |
16 | // Store the selectable layer group for ease of access
17 | this._featureGroup = options.featureGroup;
18 |
19 | if (!(this._featureGroup instanceof L.FeatureGroup)) {
20 | throw new Error('options.featureGroup must be a L.FeatureGroup');
21 | }
22 |
23 | this._uneditedLayerProps = {};
24 |
25 | // Save the type so super can fire, need to do this as cannot do this.TYPE :(
26 | this.type = L.EditToolbar.Edit.TYPE;
27 |
28 | var version = L.version.split('.');
29 | //If Version is >= 1.2.0
30 | if (parseInt(version[0], 10) === 1 && parseInt(version[1], 10) >= 2) {
31 | L.EditToolbar.Edit.include(L.Evented.prototype);
32 | } else {
33 | L.EditToolbar.Edit.include(L.Mixin.Events);
34 | }
35 | },
36 |
37 | // @method enable(): void
38 | // Enable the edit toolbar
39 | enable: function () {
40 | if (this._enabled || !this._hasAvailableLayers()) {
41 | return;
42 | }
43 | this.fire('enabled', {handler: this.type});
44 | //this disable other handlers
45 |
46 | this._map.fire(L.Draw.Event.EDITSTART, {handler: this.type});
47 | //allow drawLayer to be updated before beginning edition.
48 |
49 | L.Handler.prototype.enable.call(this);
50 | this._featureGroup
51 | .on('layeradd', this._enableLayerEdit, this)
52 | .on('layerremove', this._disableLayerEdit, this);
53 | },
54 |
55 | // @method disable(): void
56 | // Disable the edit toolbar
57 | disable: function () {
58 | if (!this._enabled) {
59 | return;
60 | }
61 | this._featureGroup
62 | .off('layeradd', this._enableLayerEdit, this)
63 | .off('layerremove', this._disableLayerEdit, this);
64 | L.Handler.prototype.disable.call(this);
65 | this._map.fire(L.Draw.Event.EDITSTOP, {handler: this.type});
66 | this.fire('disabled', {handler: this.type});
67 | },
68 |
69 | // @method addHooks(): void
70 | // Add listener hooks for this handler
71 | addHooks: function () {
72 | var map = this._map;
73 |
74 | if (map) {
75 | map.getContainer().focus();
76 |
77 | this._featureGroup.eachLayer(this._enableLayerEdit, this);
78 |
79 | this._tooltip = new L.Draw.Tooltip(this._map);
80 | this._tooltip.updateContent({
81 | text: L.drawLocal.edit.handlers.edit.tooltip.text,
82 | subtext: L.drawLocal.edit.handlers.edit.tooltip.subtext
83 | });
84 |
85 | // Quickly access the tooltip to update for intersection checking
86 | map._editTooltip = this._tooltip;
87 |
88 | this._updateTooltip();
89 |
90 | this._map
91 | .on('mousemove', this._onMouseMove, this)
92 | .on('touchmove', this._onMouseMove, this)
93 | .on('MSPointerMove', this._onMouseMove, this)
94 | .on(L.Draw.Event.EDITVERTEX, this._updateTooltip, this);
95 | }
96 | },
97 |
98 | // @method removeHooks(): void
99 | // Remove listener hooks for this handler
100 | removeHooks: function () {
101 | if (this._map) {
102 | // Clean up selected layers.
103 | this._featureGroup.eachLayer(this._disableLayerEdit, this);
104 |
105 | // Clear the backups of the original layers
106 | this._uneditedLayerProps = {};
107 |
108 | this._tooltip.dispose();
109 | this._tooltip = null;
110 |
111 | this._map
112 | .off('mousemove', this._onMouseMove, this)
113 | .off('touchmove', this._onMouseMove, this)
114 | .off('MSPointerMove', this._onMouseMove, this)
115 | .off(L.Draw.Event.EDITVERTEX, this._updateTooltip, this);
116 | }
117 | },
118 |
119 | // @method revertLayers(): void
120 | // Revert each layer's geometry changes
121 | revertLayers: function () {
122 | this._featureGroup.eachLayer(function (layer) {
123 | this._revertLayer(layer);
124 | }, this);
125 | },
126 |
127 | // @method save(): void
128 | // Save the layer geometries
129 | save: function () {
130 | var editedLayers = new L.LayerGroup();
131 | this._featureGroup.eachLayer(function (layer) {
132 | if (layer.edited) {
133 | editedLayers.addLayer(layer);
134 | layer.edited = false;
135 | }
136 | });
137 | this._map.fire(L.Draw.Event.EDITED, {layers: editedLayers});
138 | },
139 |
140 | _backupLayer: function (layer) {
141 | var id = L.Util.stamp(layer);
142 |
143 | if (!this._uneditedLayerProps[id]) {
144 | // Polyline, Polygon or Rectangle
145 | if (layer instanceof L.Polyline || layer instanceof L.Polygon || layer instanceof L.Rectangle) {
146 | this._uneditedLayerProps[id] = {
147 | latlngs: L.LatLngUtil.cloneLatLngs(layer.getLatLngs())
148 | };
149 | } else if (layer instanceof L.Circle) {
150 | this._uneditedLayerProps[id] = {
151 | latlng: L.LatLngUtil.cloneLatLng(layer.getLatLng()),
152 | radius: layer.getRadius()
153 | };
154 | } else if (layer instanceof L.Marker || layer instanceof L.CircleMarker) { // Marker
155 | this._uneditedLayerProps[id] = {
156 | latlng: L.LatLngUtil.cloneLatLng(layer.getLatLng())
157 | };
158 | }
159 | }
160 | },
161 |
162 | _getTooltipText: function () {
163 | return ({
164 | text: L.drawLocal.edit.handlers.edit.tooltip.text,
165 | subtext: L.drawLocal.edit.handlers.edit.tooltip.subtext
166 | });
167 | },
168 |
169 | _updateTooltip: function () {
170 | this._tooltip.updateContent(this._getTooltipText());
171 | },
172 |
173 | _revertLayer: function (layer) {
174 | var id = L.Util.stamp(layer);
175 | layer.edited = false;
176 | if (this._uneditedLayerProps.hasOwnProperty(id)) {
177 | // Polyline, Polygon or Rectangle
178 | if (layer instanceof L.Polyline || layer instanceof L.Polygon || layer instanceof L.Rectangle) {
179 | layer.setLatLngs(this._uneditedLayerProps[id].latlngs);
180 | } else if (layer instanceof L.Circle) {
181 | layer.setLatLng(this._uneditedLayerProps[id].latlng);
182 | layer.setRadius(this._uneditedLayerProps[id].radius);
183 | } else if (layer instanceof L.Marker || layer instanceof L.CircleMarker) { // Marker or CircleMarker
184 | layer.setLatLng(this._uneditedLayerProps[id].latlng);
185 | }
186 |
187 | layer.fire('revert-edited', {layer: layer});
188 | }
189 | },
190 |
191 | _enableLayerEdit: function (e) {
192 | var layer = e.layer || e.target || e,
193 | pathOptions, poly;
194 |
195 | // Back up this layer (if haven't before)
196 | this._backupLayer(layer);
197 |
198 | if (this.options.poly) {
199 | poly = L.Util.extend({}, this.options.poly);
200 | layer.options.poly = poly;
201 | }
202 |
203 | // Set different style for editing mode
204 | if (this.options.selectedPathOptions) {
205 | pathOptions = L.Util.extend({}, this.options.selectedPathOptions);
206 |
207 | // Use the existing color of the layer
208 | if (pathOptions.maintainColor) {
209 | pathOptions.color = layer.options.color;
210 | pathOptions.fillColor = layer.options.fillColor;
211 | }
212 |
213 | layer.options.original = L.extend({}, layer.options);
214 | layer.options.editing = pathOptions;
215 |
216 | }
217 |
218 | if (layer instanceof L.Marker) {
219 | if (layer.editing) {
220 | layer.editing.enable();
221 | }
222 | layer.dragging.enable();
223 | layer
224 | .on('dragend', this._onMarkerDragEnd)
225 | // #TODO: remove when leaflet finally fixes their draggable so it's touch friendly again.
226 | .on('touchmove', this._onTouchMove, this)
227 | .on('MSPointerMove', this._onTouchMove, this)
228 | .on('touchend', this._onMarkerDragEnd, this)
229 | .on('MSPointerUp', this._onMarkerDragEnd, this);
230 | } else {
231 | layer.editing.enable();
232 | }
233 | },
234 |
235 | _disableLayerEdit: function (e) {
236 | var layer = e.layer || e.target || e;
237 |
238 | layer.edited = false;
239 | if (layer.editing) {
240 | layer.editing.disable();
241 | }
242 |
243 | delete layer.options.editing;
244 | delete layer.options.original;
245 | // Reset layer styles to that of before select
246 | if (this._selectedPathOptions) {
247 | if (layer instanceof L.Marker) {
248 | this._toggleMarkerHighlight(layer);
249 | } else {
250 | // reset the layer style to what is was before being selected
251 | layer.setStyle(layer.options.previousOptions);
252 | // remove the cached options for the layer object
253 | delete layer.options.previousOptions;
254 | }
255 | }
256 |
257 | if (layer instanceof L.Marker) {
258 | layer.dragging.disable();
259 | layer
260 | .off('dragend', this._onMarkerDragEnd, this)
261 | .off('touchmove', this._onTouchMove, this)
262 | .off('MSPointerMove', this._onTouchMove, this)
263 | .off('touchend', this._onMarkerDragEnd, this)
264 | .off('MSPointerUp', this._onMarkerDragEnd, this);
265 | } else {
266 | layer.editing.disable();
267 | }
268 | },
269 |
270 | _onMouseMove: function (e) {
271 | this._tooltip.updatePosition(e.latlng);
272 | },
273 |
274 | _onMarkerDragEnd: function (e) {
275 | var layer = e.target;
276 | layer.edited = true;
277 | this._map.fire(L.Draw.Event.EDITMOVE, {layer: layer});
278 | },
279 |
280 | _onTouchMove: function (e) {
281 | var touchEvent = e.originalEvent.changedTouches[0],
282 | layerPoint = this._map.mouseEventToLayerPoint(touchEvent),
283 | latlng = this._map.layerPointToLatLng(layerPoint);
284 | e.target.setLatLng(latlng);
285 | },
286 |
287 | _hasAvailableLayers: function () {
288 | return this._featureGroup.getLayers().length !== 0;
289 | }
290 | });
291 |
--------------------------------------------------------------------------------
/static_files/draw_files/EditToolbar.js:
--------------------------------------------------------------------------------
1 | /*L.Map.mergeOptions({
2 | editControl: true
3 | });*/
4 | /**
5 | * @class L.EditToolbar
6 | * @aka EditToolbar
7 | */
8 | L.EditToolbar = L.Toolbar.extend({
9 | statics: {
10 | TYPE: 'edit'
11 | },
12 |
13 | options: {
14 | edit: {
15 | selectedPathOptions: {
16 | dashArray: '10, 10',
17 |
18 | fill: true,
19 | fillColor: '#fe57a1',
20 | fillOpacity: 0.1,
21 |
22 | // Whether to user the existing layers color
23 | maintainColor: false
24 | }
25 | },
26 | remove: {},
27 | poly: null,
28 | featureGroup: null /* REQUIRED! TODO: perhaps if not set then all layers on the map are selectable? */
29 | },
30 |
31 | // @method intialize(): void
32 | initialize: function (options) {
33 | // Need to set this manually since null is an acceptable value here
34 | if (options.edit) {
35 | if (typeof options.edit.selectedPathOptions === 'undefined') {
36 | options.edit.selectedPathOptions = this.options.edit.selectedPathOptions;
37 | }
38 | options.edit.selectedPathOptions = L.extend({}, this.options.edit.selectedPathOptions, options.edit.selectedPathOptions);
39 | }
40 |
41 | if (options.remove) {
42 | options.remove = L.extend({}, this.options.remove, options.remove);
43 | }
44 |
45 | if (options.poly) {
46 | options.poly = L.extend({}, this.options.poly, options.poly);
47 | }
48 |
49 | this._toolbarClass = 'leaflet-draw-edit';
50 | L.Toolbar.prototype.initialize.call(this, options);
51 |
52 | this._selectedFeatureCount = 0;
53 | },
54 |
55 | // @method getModeHandlers(): object
56 | // Get mode handlers information
57 | getModeHandlers: function (map) {
58 | var featureGroup = this.options.featureGroup;
59 | return [
60 | {
61 | enabled: this.options.edit,
62 | handler: new L.EditToolbar.Edit(map, {
63 | featureGroup: featureGroup,
64 | selectedPathOptions: this.options.edit.selectedPathOptions,
65 | poly: this.options.poly
66 | }),
67 | title: L.drawLocal.edit.toolbar.buttons.edit
68 | },
69 | {
70 | enabled: this.options.remove,
71 | handler: new L.EditToolbar.Delete(map, {
72 | featureGroup: featureGroup
73 | }),
74 | title: L.drawLocal.edit.toolbar.buttons.remove
75 | }
76 | ];
77 | },
78 |
79 | // @method getActions(): object
80 | // Get actions information
81 | getActions: function (handler) {
82 | var actions = [
83 | {
84 | title: L.drawLocal.edit.toolbar.actions.save.title,
85 | text: L.drawLocal.edit.toolbar.actions.save.text,
86 | callback: this._save,
87 | context: this
88 | },
89 | {
90 | title: L.drawLocal.edit.toolbar.actions.cancel.title,
91 | text: L.drawLocal.edit.toolbar.actions.cancel.text,
92 | callback: this.disable,
93 | context: this
94 | }
95 | ];
96 |
97 | if (handler.removeAllLayers) {
98 | actions.push({
99 | title: L.drawLocal.edit.toolbar.actions.clearAll.title,
100 | text: L.drawLocal.edit.toolbar.actions.clearAll.text,
101 | callback: this._clearAllLayers,
102 | context: this
103 | });
104 | }
105 |
106 | return actions;
107 | },
108 |
109 | // @method addToolbar(map): L.DomUtil
110 | // Adds the toolbar to the map
111 | addToolbar: function (map) {
112 | var container = L.Toolbar.prototype.addToolbar.call(this, map);
113 |
114 | this._checkDisabled();
115 |
116 | this.options.featureGroup.on('layeradd layerremove', this._checkDisabled, this);
117 |
118 | return container;
119 | },
120 |
121 | // @method removeToolbar(): void
122 | // Removes the toolbar from the map
123 | removeToolbar: function () {
124 | this.options.featureGroup.off('layeradd layerremove', this._checkDisabled, this);
125 |
126 | L.Toolbar.prototype.removeToolbar.call(this);
127 | },
128 |
129 | // @method disable(): void
130 | // Disables the toolbar
131 | disable: function () {
132 | if (!this.enabled()) {
133 | return;
134 | }
135 |
136 | this._activeMode.handler.revertLayers();
137 |
138 | L.Toolbar.prototype.disable.call(this);
139 | },
140 |
141 | _save: function () {
142 | this._activeMode.handler.save();
143 | if (this._activeMode) {
144 | this._activeMode.handler.disable();
145 | }
146 | },
147 |
148 | _clearAllLayers: function () {
149 | this._activeMode.handler.removeAllLayers();
150 | if (this._activeMode) {
151 | this._activeMode.handler.disable();
152 | }
153 | },
154 |
155 | _checkDisabled: function () {
156 | var featureGroup = this.options.featureGroup,
157 | hasLayers = featureGroup.getLayers().length !== 0,
158 | button;
159 |
160 | if (this.options.edit) {
161 | button = this._modes[L.EditToolbar.Edit.TYPE].button;
162 |
163 | if (hasLayers) {
164 | L.DomUtil.removeClass(button, 'leaflet-disabled');
165 | } else {
166 | L.DomUtil.addClass(button, 'leaflet-disabled');
167 | }
168 |
169 | button.setAttribute(
170 | 'title',
171 | hasLayers ?
172 | L.drawLocal.edit.toolbar.buttons.edit
173 | : L.drawLocal.edit.toolbar.buttons.editDisabled
174 | );
175 | }
176 |
177 | if (this.options.remove) {
178 | button = this._modes[L.EditToolbar.Delete.TYPE].button;
179 |
180 | if (hasLayers) {
181 | L.DomUtil.removeClass(button, 'leaflet-disabled');
182 | } else {
183 | L.DomUtil.addClass(button, 'leaflet-disabled');
184 | }
185 |
186 | button.setAttribute(
187 | 'title',
188 | hasLayers ?
189 | L.drawLocal.edit.toolbar.buttons.remove
190 | : L.drawLocal.edit.toolbar.buttons.removeDisabled
191 | );
192 | }
193 | }
194 | });
195 |
--------------------------------------------------------------------------------
/static_files/draw_files/GeometryUtil.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var defaultPrecision = {
4 | km: 2,
5 | ha: 2,
6 | m: 0,
7 | mi: 2,
8 | ac: 2,
9 | yd: 0,
10 | ft: 0,
11 | nm: 2
12 | };
13 |
14 |
15 | /**
16 | * @class L.GeometryUtil
17 | * @aka GeometryUtil
18 | */
19 | L.GeometryUtil = L.extend(L.GeometryUtil || {}, {
20 | // Ported from the OpenLayers implementation. See https://github.com/openlayers/openlayers/blob/master/lib/OpenLayers/Geometry/LinearRing.js#L270
21 |
22 | // @method geodesicArea(): number
23 | geodesicArea: function (latLngs) {
24 | var pointsCount = latLngs.length,
25 | area = 0.0,
26 | d2r = Math.PI / 180,
27 | p1, p2;
28 |
29 | if (pointsCount > 2) {
30 | for (var i = 0; i < pointsCount; i++) {
31 | p1 = latLngs[i];
32 | p2 = latLngs[(i + 1) % pointsCount];
33 | area += ((p2.lng - p1.lng) * d2r) *
34 | (2 + Math.sin(p1.lat * d2r) + Math.sin(p2.lat * d2r));
35 | }
36 | area = area * 6378137.0 * 6378137.0 / 2.0;
37 | }
38 |
39 | return Math.abs(area);
40 | },
41 |
42 | // @method formattedNumber(n, precision): string
43 | // Returns n in specified number format (if defined) and precision
44 | formattedNumber: function (n, precision) {
45 | var formatted = parseFloat(n).toFixed(precision),
46 | format = L.drawLocal.format && L.drawLocal.format.numeric,
47 | delimiters = format && format.delimiters,
48 | thousands = delimiters && delimiters.thousands,
49 | decimal = delimiters && delimiters.decimal;
50 |
51 | if (thousands || decimal) {
52 | var splitValue = formatted.split('.');
53 | formatted = thousands ? splitValue[0].replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + thousands) : splitValue[0];
54 | decimal = decimal || '.';
55 | if (splitValue.length > 1) {
56 | formatted = formatted + decimal + splitValue[1];
57 | }
58 | }
59 |
60 | return formatted;
61 | },
62 |
63 | // @method readableArea(area, isMetric, precision): string
64 | // Returns a readable area string in yards or metric.
65 | // The value will be rounded as defined by the precision option object.
66 | readableArea: function (area, isMetric, precision) {
67 | var areaStr,
68 | units,
69 | precision = L.Util.extend({}, defaultPrecision, precision);
70 |
71 | if (isMetric) {
72 | units = ['ha', 'm'];
73 | type = typeof isMetric;
74 | if (type === 'string') {
75 | units = [isMetric];
76 | } else if (type !== 'boolean') {
77 | units = isMetric;
78 | }
79 |
80 | if (area >= 1000000 && units.indexOf('km') !== -1) {
81 | areaStr = L.GeometryUtil.formattedNumber(area * 0.000001, precision['km']) + ' km²';
82 | } else if (area >= 10000 && units.indexOf('ha') !== -1) {
83 | areaStr = L.GeometryUtil.formattedNumber(area * 0.0001, precision['ha']) + ' ha';
84 | } else {
85 | areaStr = L.GeometryUtil.formattedNumber(area, precision['m']) + ' m²';
86 | }
87 | } else {
88 | area /= 0.836127; // Square yards in 1 meter
89 |
90 | if (area >= 3097600) { //3097600 square yards in 1 square mile
91 | areaStr = L.GeometryUtil.formattedNumber(area / 3097600, precision['mi']) + ' mi²';
92 | } else if (area >= 4840) { //4840 square yards in 1 acre
93 | areaStr = L.GeometryUtil.formattedNumber(area / 4840, precision['ac']) + ' acres';
94 | } else {
95 | areaStr = L.GeometryUtil.formattedNumber(area, precision['yd']) + ' yd²';
96 | }
97 | }
98 |
99 | return areaStr;
100 | },
101 |
102 | // @method readableDistance(distance, units): string
103 | // Converts a metric distance to one of [ feet, nauticalMile, metric or yards ] string
104 | //
105 | // @alternative
106 | // @method readableDistance(distance, isMetric, useFeet, isNauticalMile, precision): string
107 | // Converts metric distance to distance string.
108 | // The value will be rounded as defined by the precision option object.
109 | readableDistance: function (distance, isMetric, isFeet, isNauticalMile, precision) {
110 | var distanceStr,
111 | units,
112 | precision = L.Util.extend({}, defaultPrecision, precision);
113 |
114 | if (isMetric) {
115 | units = typeof isMetric == 'string' ? isMetric : 'metric';
116 | } else if (isFeet) {
117 | units = 'feet';
118 | } else if (isNauticalMile) {
119 | units = 'nauticalMile';
120 | } else {
121 | units = 'yards';
122 | }
123 |
124 | switch (units) {
125 | case 'metric':
126 | // show metres when distance is < 1km, then show km
127 | if (distance > 1000) {
128 | distanceStr = L.GeometryUtil.formattedNumber(distance / 1000, precision['km']) + ' km';
129 | } else {
130 | distanceStr = L.GeometryUtil.formattedNumber(distance, precision['m']) + ' m';
131 | }
132 | break;
133 | case 'feet':
134 | distance *= 1.09361 * 3;
135 | distanceStr = L.GeometryUtil.formattedNumber(distance, precision['ft']) + ' ft';
136 |
137 | break;
138 | case 'nauticalMile':
139 | distance *= 0.53996;
140 | distanceStr = L.GeometryUtil.formattedNumber(distance / 1000, precision['nm']) + ' nm';
141 | break;
142 | case 'yards':
143 | default:
144 | distance *= 1.09361;
145 |
146 | if (distance > 1760) {
147 | distanceStr = L.GeometryUtil.formattedNumber(distance / 1760, precision['mi']) + ' miles';
148 | } else {
149 | distanceStr = L.GeometryUtil.formattedNumber(distance, precision['yd']) + ' yd';
150 | }
151 | break;
152 | }
153 | return distanceStr;
154 | },
155 |
156 | // @method isVersion07x(): boolean
157 | // Returns true if the Leaflet version is 0.7.x, false otherwise.
158 | isVersion07x: function () {
159 | var version = L.version.split('.');
160 | //If Version is == 0.7.*
161 | return parseInt(version[0], 10) === 0 && parseInt(version[1], 10) === 7;
162 | },
163 | });
164 |
165 | })();
166 |
--------------------------------------------------------------------------------
/static_files/draw_files/LatLngUtil.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @class L.LatLngUtil
3 | * @aka LatLngUtil
4 | */
5 | L.LatLngUtil = {
6 | // Clones a LatLngs[], returns [][]
7 |
8 | // @method cloneLatLngs(LatLngs[]): L.LatLngs[]
9 | // Clone the latLng point or points or nested points and return an array with those points
10 | cloneLatLngs: function (latlngs) {
11 | var clone = [];
12 | for (var i = 0, l = latlngs.length; i < l; i++) {
13 | // Check for nested array (Polyline/Polygon)
14 | if (Array.isArray(latlngs[i])) {
15 | clone.push(L.LatLngUtil.cloneLatLngs(latlngs[i]));
16 | } else {
17 | clone.push(this.cloneLatLng(latlngs[i]));
18 | }
19 | }
20 | return clone;
21 | },
22 |
23 | // @method cloneLatLng(LatLng): L.LatLng
24 | // Clone the latLng and return a new LatLng object.
25 | cloneLatLng: function (latlng) {
26 | return L.latLng(latlng.lat, latlng.lng);
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/static_files/draw_files/Leaflet.Draw.Event.js:
--------------------------------------------------------------------------------
1 | /**
2 | * ### Events
3 | * Once you have successfully added the Leaflet.draw plugin to your map you will want to respond to the different
4 | * actions users can initiate. The following events will be triggered on the map:
5 | *
6 | * @class L.Draw.Event
7 | * @aka Draw.Event
8 | *
9 | * Use `L.Draw.Event.EVENTNAME` constants to ensure events are correct.
10 | *
11 | * @example
12 | * ```js
13 | * map.on(L.Draw.Event.CREATED; function (e) {
14 | * var type = e.layerType,
15 | * layer = e.layer;
16 | *
17 | * if (type === 'marker') {
18 | * // Do marker specific actions
19 | * }
20 | *
21 | * // Do whatever else you need to. (save to db; add to map etc)
22 | * map.addLayer(layer);
23 | *});
24 | * ```
25 | */
26 | L.Draw.Event = {};
27 | /**
28 | * @event draw:created: PolyLine; Polygon; Rectangle; Circle; Marker | String
29 | *
30 | * Layer that was just created.
31 | * The type of layer this is. One of: `polyline`; `polygon`; `rectangle`; `circle`; `marker`
32 | * Triggered when a new vector or marker has been created.
33 | *
34 | */
35 | L.Draw.Event.CREATED = 'draw:created';
36 |
37 | /**
38 | * @event draw:edited: LayerGroup
39 | *
40 | * List of all layers just edited on the map.
41 | *
42 | *
43 | * Triggered when layers in the FeatureGroup; initialised with the plugin; have been edited and saved.
44 | *
45 | * @example
46 | * ```js
47 | * map.on('draw:edited', function (e) {
48 | * var layers = e.layers;
49 | * layers.eachLayer(function (layer) {
50 | * //do whatever you want; most likely save back to db
51 | * });
52 | * });
53 | * ```
54 | */
55 | L.Draw.Event.EDITED = 'draw:edited';
56 |
57 | /**
58 | * @event draw:deleted: LayerGroup
59 | *
60 | * List of all layers just removed from the map.
61 | *
62 | * Triggered when layers have been removed (and saved) from the FeatureGroup.
63 | */
64 | L.Draw.Event.DELETED = 'draw:deleted';
65 |
66 | /**
67 | * @event draw:drawstart: String
68 | *
69 | * The type of layer this is. One of:`polyline`; `polygon`; `rectangle`; `circle`; `marker`
70 | *
71 | * Triggered when the user has chosen to draw a particular vector or marker.
72 | */
73 | L.Draw.Event.DRAWSTART = 'draw:drawstart';
74 |
75 | /**
76 | * @event draw:drawstop: String
77 | *
78 | * The type of layer this is. One of: `polyline`; `polygon`; `rectangle`; `circle`; `marker`
79 | *
80 | * Triggered when the user has finished a particular vector or marker.
81 | */
82 |
83 | L.Draw.Event.DRAWSTOP = 'draw:drawstop';
84 |
85 | /**
86 | * @event draw:drawvertex: LayerGroup
87 | *
88 | * List of all layers just being added from the map.
89 | *
90 | * Triggered when a vertex is created on a polyline or polygon.
91 | */
92 | L.Draw.Event.DRAWVERTEX = 'draw:drawvertex';
93 |
94 | /**
95 | * @event draw:editstart: String
96 | *
97 | * The type of edit this is. One of: `edit`
98 | *
99 | * Triggered when the user starts edit mode by clicking the edit tool button.
100 | */
101 |
102 | L.Draw.Event.EDITSTART = 'draw:editstart';
103 |
104 | /**
105 | * @event draw:editmove: ILayer
106 | *
107 | * Layer that was just moved.
108 | *
109 | * Triggered as the user moves a rectangle; circle or marker.
110 | */
111 | L.Draw.Event.EDITMOVE = 'draw:editmove';
112 |
113 | /**
114 | * @event draw:editresize: ILayer
115 | *
116 | * Layer that was just moved.
117 | *
118 | * Triggered as the user resizes a rectangle or circle.
119 | */
120 | L.Draw.Event.EDITRESIZE = 'draw:editresize';
121 |
122 | /**
123 | * @event draw:editvertex: LayerGroup
124 | *
125 | * List of all layers just being edited from the map.
126 | *
127 | * Triggered when a vertex is edited on a polyline or polygon.
128 | */
129 | L.Draw.Event.EDITVERTEX = 'draw:editvertex';
130 |
131 | /**
132 | * @event draw:editstop: String
133 | *
134 | * The type of edit this is. One of: `edit`
135 | *
136 | * Triggered when the user has finshed editing (edit mode) and saves edits.
137 | */
138 | L.Draw.Event.EDITSTOP = 'draw:editstop';
139 |
140 | /**
141 | * @event draw:deletestart: String
142 | *
143 | * The type of edit this is. One of: `remove`
144 | *
145 | * Triggered when the user starts remove mode by clicking the remove tool button.
146 | */
147 | L.Draw.Event.DELETESTART = 'draw:deletestart';
148 |
149 | /**
150 | * @event draw:deletestop: String
151 | *
152 | * The type of edit this is. One of: `remove`
153 | *
154 | * Triggered when the user has finished removing shapes (remove mode) and saves.
155 | */
156 | L.Draw.Event.DELETESTOP = 'draw:deletestop';
157 |
158 | /**
159 | * @event draw:toolbaropened: String
160 | *
161 | * Triggered when a toolbar is opened.
162 | */
163 | L.Draw.Event.TOOLBAROPENED = 'draw:toolbaropened';
164 |
165 | /**
166 | * @event draw:toolbarclosed: String
167 | *
168 | * Triggered when a toolbar is closed.
169 | */
170 | L.Draw.Event.TOOLBARCLOSED = 'draw:toolbarclosed';
171 |
172 | /**
173 | * @event draw:markercontext: String
174 | *
175 | * Triggered when a marker is right clicked.
176 | */
177 | L.Draw.Event.MARKERCONTEXT = 'draw:markercontext';
--------------------------------------------------------------------------------
/static_files/draw_files/Leaflet.draw.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Leaflet.draw assumes that you have already included the Leaflet library.
3 | */
4 | L.drawVersion = '0.4.2';
5 | /**
6 | * @class L.Draw
7 | * @aka Draw
8 | *
9 | *
10 | * To add the draw toolbar set the option drawControl: true in the map options.
11 | *
12 | * @example
13 | * ```js
14 | * var map = L.map('map', {drawControl: true}).setView([51.505, -0.09], 13);
15 | *
16 | * L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
17 | * attribution: '© OpenStreetMap contributors'
18 | * }).addTo(map);
19 | * ```
20 | *
21 | * ### Adding the edit toolbar
22 | * To use the edit toolbar you must initialise the Leaflet.draw control and manually add it to the map.
23 | *
24 | * ```js
25 | * var map = L.map('map').setView([51.505, -0.09], 13);
26 | *
27 | * L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
28 | * attribution: '© OpenStreetMap contributors'
29 | * }).addTo(map);
30 | *
31 | * // FeatureGroup is to store editable layers
32 | * var drawnItems = new L.FeatureGroup();
33 | * map.addLayer(drawnItems);
34 | *
35 | * var drawControl = new L.Control.Draw({
36 | * edit: {
37 | * featureGroup: drawnItems
38 | * }
39 | * });
40 | * map.addControl(drawControl);
41 | * ```
42 | *
43 | * The key here is the featureGroup option. This tells the plugin which FeatureGroup contains the layers that
44 | * should be editable. The featureGroup can contain 0 or more features with geometry types Point, LineString, and Polygon.
45 | * Leaflet.draw does not work with multigeometry features such as MultiPoint, MultiLineString, MultiPolygon,
46 | * or GeometryCollection. If you need to add multigeometry features to the draw plugin, convert them to a
47 | * FeatureCollection of non-multigeometries (Points, LineStrings, or Polygons).
48 | */
49 | L.Draw = {};
50 |
51 | /**
52 | * @class L.drawLocal
53 | * @aka L.drawLocal
54 | *
55 | * The core toolbar class of the API — it is used to create the toolbar ui
56 | *
57 | * @example
58 | * ```js
59 | * var modifiedDraw = L.drawLocal.extend({
60 | * draw: {
61 | * toolbar: {
62 | * buttons: {
63 | * polygon: 'Draw an awesome polygon'
64 | * }
65 | * }
66 | * }
67 | * });
68 | * ```
69 | *
70 | * The default state for the control is the draw toolbar just below the zoom control.
71 | * This will allow map users to draw vectors and markers.
72 | * **Please note the edit toolbar is not enabled by default.**
73 | */
74 | L.drawLocal = {
75 | // format: {
76 | // numeric: {
77 | // delimiters: {
78 | // thousands: ',',
79 | // decimal: '.'
80 | // }
81 | // }
82 | // },
83 | draw: {
84 | toolbar: {
85 | // #TODO: this should be reorganized where actions are nested in actions
86 | // ex: actions.undo or actions.cancel
87 | actions: {
88 | title: 'Cancel drawing',
89 | text: 'Cancel'
90 | },
91 | finish: {
92 | title: 'Finish drawing',
93 | text: 'Finish'
94 | },
95 | undo: {
96 | title: 'Delete last point drawn',
97 | text: 'Delete last point'
98 | },
99 | buttons: {
100 | polyline: 'Draw a polyline',
101 | polygon: 'Draw a polygon',
102 | rectangle: 'Draw a rectangle',
103 | circle: 'Draw a circle',
104 | marker: 'Draw a marker',
105 | circlemarker: 'Draw a circlemarker'
106 | }
107 | },
108 | handlers: {
109 | circle: {
110 | tooltip: {
111 | start: 'Click and drag to draw circle.'
112 | },
113 | radius: 'Radius'
114 | },
115 | circlemarker: {
116 | tooltip: {
117 | start: 'Click map to place circle marker.'
118 | }
119 | },
120 | marker: {
121 | tooltip: {
122 | start: 'Click map to place marker.'
123 | }
124 | },
125 | polygon: {
126 | tooltip: {
127 | start: 'Click to start drawing shape.',
128 | cont: 'Click to continue drawing shape.',
129 | end: 'Click first point to close this shape.'
130 | }
131 | },
132 | polyline: {
133 | error: 'Error: shape edges cannot cross!',
134 | tooltip: {
135 | start: 'Click to start drawing line.',
136 | cont: 'Click to continue drawing line.',
137 | end: 'Click last point to finish line.'
138 | }
139 | },
140 | rectangle: {
141 | tooltip: {
142 | start: 'Click and drag to draw rectangle.'
143 | }
144 | },
145 | simpleshape: {
146 | tooltip: {
147 | end: 'Release mouse to finish drawing.'
148 | }
149 | }
150 | }
151 | },
152 | edit: {
153 | toolbar: {
154 | actions: {
155 | save: {
156 | title: 'Save changes',
157 | text: 'Save'
158 | },
159 | cancel: {
160 | title: 'Cancel editing, discards all changes',
161 | text: 'Cancel'
162 | },
163 | clearAll: {
164 | title: 'Clear all layers',
165 | text: 'Clear All'
166 | }
167 | },
168 | buttons: {
169 | edit: 'Edit layers',
170 | editDisabled: 'No layers to edit',
171 | remove: 'Delete layers',
172 | removeDisabled: 'No layers to delete'
173 | }
174 | },
175 | handlers: {
176 | edit: {
177 | tooltip: {
178 | text: 'Drag handles or markers to edit features.',
179 | subtext: 'Click cancel to undo changes.'
180 | }
181 | },
182 | remove: {
183 | tooltip: {
184 | text: 'Click on a feature to remove.'
185 | }
186 | }
187 | }
188 | }
189 | };
190 |
--------------------------------------------------------------------------------
/static_files/draw_files/LineUtil.Intersect.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @class L.LineUtil
3 | * @aka Util
4 | * @aka L.Utils
5 | */
6 | L.Util.extend(L.LineUtil, {
7 |
8 | // @method segmentsIntersect(): boolean
9 | // Checks to see if two line segments intersect. Does not handle degenerate cases.
10 | // http://compgeom.cs.uiuc.edu/~jeffe/teaching/373/notes/x06-sweepline.pdf
11 | segmentsIntersect: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2, /*Point*/ p3) {
12 | return this._checkCounterclockwise(p, p2, p3) !==
13 | this._checkCounterclockwise(p1, p2, p3) &&
14 | this._checkCounterclockwise(p, p1, p2) !==
15 | this._checkCounterclockwise(p, p1, p3);
16 | },
17 |
18 | // check to see if points are in counterclockwise order
19 | _checkCounterclockwise: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) {
20 | return (p2.y - p.y) * (p1.x - p.x) > (p1.y - p.y) * (p2.x - p.x);
21 | }
22 | });
23 |
--------------------------------------------------------------------------------
/static_files/draw_files/Polygon.Intersect.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @class L.Polygon
3 | * @aka Polygon
4 | */
5 | L.Polygon.include({
6 |
7 | // @method intersects(): boolean
8 | // Checks a polygon for any intersecting line segments. Ignores holes.
9 | intersects: function () {
10 | var polylineIntersects,
11 | points = this._getProjectedPoints(),
12 | len, firstPoint, lastPoint, maxIndex;
13 |
14 | if (this._tooFewPointsForIntersection()) {
15 | return false;
16 | }
17 |
18 | polylineIntersects = L.Polyline.prototype.intersects.call(this);
19 |
20 | // If already found an intersection don't need to check for any more.
21 | if (polylineIntersects) {
22 | return true;
23 | }
24 |
25 | len = points.length;
26 | firstPoint = points[0];
27 | lastPoint = points[len - 1];
28 | maxIndex = len - 2;
29 |
30 | // Check the line segment between last and first point. Don't need to check the first line segment (minIndex = 1)
31 | return this._lineSegmentsIntersectsRange(lastPoint, firstPoint, maxIndex, 1);
32 | }
33 | });
34 |
--------------------------------------------------------------------------------
/static_files/draw_files/Polyline.Intersect.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @class L.Polyline
3 | * @aka Polyline
4 | */
5 | L.Polyline.include({
6 |
7 | // @method intersects(): boolean
8 | // Check to see if this polyline has any linesegments that intersect.
9 | // NOTE: does not support detecting intersection for degenerate cases.
10 | intersects: function () {
11 | var points = this._getProjectedPoints(),
12 | len = points ? points.length : 0,
13 | i, p, p1;
14 |
15 | if (this._tooFewPointsForIntersection()) {
16 | return false;
17 | }
18 |
19 | for (i = len - 1; i >= 3; i--) {
20 | p = points[i - 1];
21 | p1 = points[i];
22 |
23 |
24 | if (this._lineSegmentsIntersectsRange(p, p1, i - 2)) {
25 | return true;
26 | }
27 | }
28 |
29 | return false;
30 | },
31 |
32 | // @method newLatLngIntersects(): boolean
33 | // Check for intersection if new latlng was added to this polyline.
34 | // NOTE: does not support detecting intersection for degenerate cases.
35 | newLatLngIntersects: function (latlng, skipFirst) {
36 | // Cannot check a polyline for intersecting lats/lngs when not added to the map
37 | if (!this._map) {
38 | return false;
39 | }
40 |
41 | return this.newPointIntersects(this._map.latLngToLayerPoint(latlng), skipFirst);
42 | },
43 |
44 | // @method newPointIntersects(): boolean
45 | // Check for intersection if new point was added to this polyline.
46 | // newPoint must be a layer point.
47 | // NOTE: does not support detecting intersection for degenerate cases.
48 | newPointIntersects: function (newPoint, skipFirst) {
49 | var points = this._getProjectedPoints(),
50 | len = points ? points.length : 0,
51 | lastPoint = points ? points[len - 1] : null,
52 | // The previous previous line segment. Previous line segment doesn't need testing.
53 | maxIndex = len - 2;
54 |
55 | if (this._tooFewPointsForIntersection(1)) {
56 | return false;
57 | }
58 |
59 | return this._lineSegmentsIntersectsRange(lastPoint, newPoint, maxIndex, skipFirst ? 1 : 0);
60 | },
61 |
62 | // Polylines with 2 sides can only intersect in cases where points are collinear (we don't support detecting these).
63 | // Cannot have intersection when < 3 line segments (< 4 points)
64 | _tooFewPointsForIntersection: function (extraPoints) {
65 | var points = this._getProjectedPoints(),
66 | len = points ? points.length : 0;
67 | // Increment length by extraPoints if present
68 | len += extraPoints || 0;
69 |
70 | return !points || len <= 3;
71 | },
72 |
73 | // Checks a line segment intersections with any line segments before its predecessor.
74 | // Don't need to check the predecessor as will never intersect.
75 | _lineSegmentsIntersectsRange: function (p, p1, maxIndex, minIndex) {
76 | var points = this._getProjectedPoints(),
77 | p2, p3;
78 |
79 | minIndex = minIndex || 0;
80 |
81 | // Check all previous line segments (beside the immediately previous) for intersections
82 | for (var j = maxIndex; j > minIndex; j--) {
83 | p2 = points[j - 1];
84 | p3 = points[j];
85 |
86 | if (L.LineUtil.segmentsIntersect(p, p1, p2, p3)) {
87 | return true;
88 | }
89 | }
90 |
91 | return false;
92 | },
93 |
94 | _getProjectedPoints: function () {
95 | if (!this._defaultShape) {
96 | return this._originalPoints;
97 | }
98 | var points = [],
99 | _shape = this._defaultShape();
100 |
101 | for (var i = 0; i < _shape.length; i++) {
102 | points.push(this._map.latLngToLayerPoint(_shape[i]));
103 | }
104 | return points;
105 | }
106 | });
107 |
--------------------------------------------------------------------------------
/static_files/draw_files/Toolbar.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @class L.Draw.Toolbar
3 | * @aka Toolbar
4 | *
5 | * The toolbar class of the API — it is used to create the ui
6 | * This will be depreciated
7 | *
8 | * @example
9 | *
10 | * ```js
11 | * var toolbar = L.Toolbar();
12 | * toolbar.addToolbar(map);
13 | * ```
14 | *
15 | * ### Disabling a toolbar
16 | *
17 | * If you do not want a particular toolbar in your app you can turn it off by setting the toolbar to false.
18 | *
19 | * ```js
20 | * var drawControl = new L.Control.Draw({
21 | * draw: false,
22 | * edit: {
23 | * featureGroup: editableLayers
24 | * }
25 | * });
26 | * ```
27 | *
28 | * ### Disabling a toolbar item
29 | *
30 | * If you want to turn off a particular toolbar item, set it to false. The following disables drawing polygons and
31 | * markers. It also turns off the ability to edit layers.
32 | *
33 | * ```js
34 | * var drawControl = new L.Control.Draw({
35 | * draw: {
36 | * polygon: false,
37 | * marker: false
38 | * },
39 | * edit: {
40 | * featureGroup: editableLayers,
41 | * edit: false
42 | * }
43 | * });
44 | * ```
45 | */
46 | L.Toolbar = L.Class.extend({
47 | // @section Methods for modifying the toolbar
48 |
49 | // @method initialize(options): void
50 | // Toolbar constructor
51 | initialize: function (options) {
52 | L.setOptions(this, options);
53 |
54 | this._modes = {};
55 | this._actionButtons = [];
56 | this._activeMode = null;
57 |
58 | var version = L.version.split('.');
59 | //If Version is >= 1.2.0
60 | if (parseInt(version[0], 10) === 1 && parseInt(version[1], 10) >= 2) {
61 | L.Toolbar.include(L.Evented.prototype);
62 | } else {
63 | L.Toolbar.include(L.Mixin.Events);
64 | }
65 | },
66 |
67 | // @method enabled(): boolean
68 | // Gets a true/false of whether the toolbar is enabled
69 | enabled: function () {
70 | return this._activeMode !== null;
71 | },
72 |
73 | // @method disable(): void
74 | // Disables the toolbar
75 | disable: function () {
76 | if (!this.enabled()) {
77 | return;
78 | }
79 |
80 | this._activeMode.handler.disable();
81 | },
82 |
83 | // @method addToolbar(map): L.DomUtil
84 | // Adds the toolbar to the map and returns the toolbar dom element
85 | addToolbar: function (map) {
86 | var container = L.DomUtil.create('div', 'leaflet-draw-section'),
87 | buttonIndex = 0,
88 | buttonClassPrefix = this._toolbarClass || '',
89 | modeHandlers = this.getModeHandlers(map),
90 | i;
91 |
92 | this._toolbarContainer = L.DomUtil.create('div', 'leaflet-draw-toolbar leaflet-bar');
93 | this._map = map;
94 |
95 | for (i = 0; i < modeHandlers.length; i++) {
96 | if (modeHandlers[i].enabled) {
97 | this._initModeHandler(
98 | modeHandlers[i].handler,
99 | this._toolbarContainer,
100 | buttonIndex++,
101 | buttonClassPrefix,
102 | modeHandlers[i].title
103 | );
104 | }
105 | }
106 |
107 | // if no buttons were added, do not add the toolbar
108 | if (!buttonIndex) {
109 | return;
110 | }
111 |
112 | // Save button index of the last button, -1 as we would have ++ after the last button
113 | this._lastButtonIndex = --buttonIndex;
114 |
115 | // Create empty actions part of the toolbar
116 | this._actionsContainer = L.DomUtil.create('ul', 'leaflet-draw-actions');
117 |
118 | // Add draw and cancel containers to the control container
119 | container.appendChild(this._toolbarContainer);
120 | container.appendChild(this._actionsContainer);
121 |
122 | return container;
123 | },
124 |
125 | // @method removeToolbar(): void
126 | // Removes the toolbar and drops the handler event listeners
127 | removeToolbar: function () {
128 | // Dispose each handler
129 | for (var handlerId in this._modes) {
130 | if (this._modes.hasOwnProperty(handlerId)) {
131 | // Unbind handler button
132 | this._disposeButton(
133 | this._modes[handlerId].button,
134 | this._modes[handlerId].handler.enable,
135 | this._modes[handlerId].handler
136 | );
137 |
138 | // Make sure is disabled
139 | this._modes[handlerId].handler.disable();
140 |
141 | // Unbind handler
142 | this._modes[handlerId].handler
143 | .off('enabled', this._handlerActivated, this)
144 | .off('disabled', this._handlerDeactivated, this);
145 | }
146 | }
147 | this._modes = {};
148 |
149 | // Dispose the actions toolbar
150 | for (var i = 0, l = this._actionButtons.length; i < l; i++) {
151 | this._disposeButton(
152 | this._actionButtons[i].button,
153 | this._actionButtons[i].callback,
154 | this
155 | );
156 | }
157 | this._actionButtons = [];
158 | this._actionsContainer = null;
159 | },
160 |
161 | _initModeHandler: function (handler, container, buttonIndex, classNamePredix, buttonTitle) {
162 | var type = handler.type;
163 |
164 | this._modes[type] = {};
165 |
166 | this._modes[type].handler = handler;
167 |
168 | this._modes[type].button = this._createButton({
169 | type: type,
170 | title: buttonTitle,
171 | className: classNamePredix + '-' + type,
172 | container: container,
173 | callback: this._modes[type].handler.enable,
174 | context: this._modes[type].handler
175 | });
176 |
177 | this._modes[type].buttonIndex = buttonIndex;
178 |
179 | this._modes[type].handler
180 | .on('enabled', this._handlerActivated, this)
181 | .on('disabled', this._handlerDeactivated, this);
182 | },
183 |
184 | /* Detect iOS based on browser User Agent, based on:
185 | * http://stackoverflow.com/a/9039885 */
186 | _detectIOS: function () {
187 | var iOS = (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream);
188 | return iOS;
189 | },
190 |
191 | _createButton: function (options) {
192 |
193 | var link = L.DomUtil.create('a', options.className || '', options.container);
194 | // Screen reader tag
195 | var sr = L.DomUtil.create('span', 'sr-only', options.container);
196 |
197 | link.href = '#';
198 | link.appendChild(sr);
199 |
200 | if (options.title) {
201 | link.title = options.title;
202 | sr.innerHTML = options.title;
203 | }
204 |
205 | if (options.text) {
206 | link.innerHTML = options.text;
207 | sr.innerHTML = options.text;
208 | }
209 |
210 | /* iOS does not use click events */
211 | var buttonEvent = this._detectIOS() ? 'touchstart' : 'click';
212 |
213 | L.DomEvent
214 | .on(link, 'click', L.DomEvent.stopPropagation)
215 | .on(link, 'mousedown', L.DomEvent.stopPropagation)
216 | .on(link, 'dblclick', L.DomEvent.stopPropagation)
217 | .on(link, 'touchstart', L.DomEvent.stopPropagation)
218 | .on(link, 'click', L.DomEvent.preventDefault)
219 | .on(link, buttonEvent, options.callback, options.context);
220 |
221 | return link;
222 | },
223 |
224 | _disposeButton: function (button, callback) {
225 | /* iOS does not use click events */
226 | var buttonEvent = this._detectIOS() ? 'touchstart' : 'click';
227 |
228 | L.DomEvent
229 | .off(button, 'click', L.DomEvent.stopPropagation)
230 | .off(button, 'mousedown', L.DomEvent.stopPropagation)
231 | .off(button, 'dblclick', L.DomEvent.stopPropagation)
232 | .off(button, 'touchstart', L.DomEvent.stopPropagation)
233 | .off(button, 'click', L.DomEvent.preventDefault)
234 | .off(button, buttonEvent, callback);
235 | },
236 |
237 | _handlerActivated: function (e) {
238 | // Disable active mode (if present)
239 | this.disable();
240 |
241 | // Cache new active feature
242 | this._activeMode = this._modes[e.handler];
243 |
244 | L.DomUtil.addClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled');
245 |
246 | this._showActionsToolbar();
247 |
248 | this.fire('enable');
249 | },
250 |
251 | _handlerDeactivated: function () {
252 | this._hideActionsToolbar();
253 |
254 | L.DomUtil.removeClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled');
255 |
256 | this._activeMode = null;
257 |
258 | this.fire('disable');
259 | },
260 |
261 | _createActions: function (handler) {
262 | var container = this._actionsContainer,
263 | buttons = this.getActions(handler),
264 | l = buttons.length,
265 | li, di, dl, button;
266 |
267 | // Dispose the actions toolbar (todo: dispose only not used buttons)
268 | for (di = 0, dl = this._actionButtons.length; di < dl; di++) {
269 | this._disposeButton(this._actionButtons[di].button, this._actionButtons[di].callback);
270 | }
271 | this._actionButtons = [];
272 |
273 | // Remove all old buttons
274 | while (container.firstChild) {
275 | container.removeChild(container.firstChild);
276 | }
277 |
278 | for (var i = 0; i < l; i++) {
279 | if ('enabled' in buttons[i] && !buttons[i].enabled) {
280 | continue;
281 | }
282 |
283 | li = L.DomUtil.create('li', '', container);
284 |
285 | button = this._createButton({
286 | title: buttons[i].title,
287 | text: buttons[i].text,
288 | container: li,
289 | callback: buttons[i].callback,
290 | context: buttons[i].context
291 | });
292 |
293 | this._actionButtons.push({
294 | button: button,
295 | callback: buttons[i].callback
296 | });
297 | }
298 | },
299 |
300 | _showActionsToolbar: function () {
301 | var buttonIndex = this._activeMode.buttonIndex,
302 | lastButtonIndex = this._lastButtonIndex,
303 | toolbarPosition = this._activeMode.button.offsetTop - 1;
304 |
305 | // Recreate action buttons on every click
306 | this._createActions(this._activeMode.handler);
307 |
308 | // Correctly position the cancel button
309 | this._actionsContainer.style.top = toolbarPosition + 'px';
310 |
311 | if (buttonIndex === 0) {
312 | L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop');
313 | L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-top');
314 | }
315 |
316 | if (buttonIndex === lastButtonIndex) {
317 | L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom');
318 | L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-bottom');
319 | }
320 |
321 | this._actionsContainer.style.display = 'block';
322 | this._map.fire(L.Draw.Event.TOOLBAROPENED);
323 | },
324 |
325 | _hideActionsToolbar: function () {
326 | this._actionsContainer.style.display = 'none';
327 |
328 | L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop');
329 | L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom');
330 | L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-top');
331 | L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-bottom');
332 | this._map.fire(L.Draw.Event.TOOLBARCLOSED);
333 | }
334 | });
335 |
--------------------------------------------------------------------------------
/static_files/draw_files/Tooltip.js:
--------------------------------------------------------------------------------
1 | L.Draw = L.Draw || {};
2 | /**
3 | * @class L.Draw.Tooltip
4 | * @aka Tooltip
5 | *
6 | * The tooltip class — it is used to display the tooltip while drawing
7 | * This will be depreciated
8 | *
9 | * @example
10 | *
11 | * ```js
12 | * var tooltip = L.Draw.Tooltip();
13 | * ```
14 | *
15 | */
16 | L.Draw.Tooltip = L.Class.extend({
17 |
18 | // @section Methods for modifying draw state
19 |
20 | // @method initialize(map): void
21 | // Tooltip constructor
22 | initialize: function (map) {
23 | this._map = map;
24 | this._popupPane = map._panes.popupPane;
25 | this._visible = false;
26 |
27 | this._container = map.options.drawControlTooltips ?
28 | L.DomUtil.create('div', 'leaflet-draw-tooltip', this._popupPane) : null;
29 | this._singleLineLabel = false;
30 |
31 | this._map.on('mouseout', this._onMouseOut, this);
32 | },
33 |
34 | // @method dispose(): void
35 | // Remove Tooltip DOM and unbind events
36 | dispose: function () {
37 | this._map.off('mouseout', this._onMouseOut, this);
38 |
39 | if (this._container) {
40 | this._popupPane.removeChild(this._container);
41 | this._container = null;
42 | }
43 | },
44 |
45 | // @method updateContent(labelText): this
46 | // Changes the tooltip text to string in function call
47 | updateContent: function (labelText) {
48 | if (!this._container) {
49 | return this;
50 | }
51 | labelText.subtext = labelText.subtext || '';
52 |
53 | // update the vertical position (only if changed)
54 | if (labelText.subtext.length === 0 && !this._singleLineLabel) {
55 | L.DomUtil.addClass(this._container, 'leaflet-draw-tooltip-single');
56 | this._singleLineLabel = true;
57 | }
58 | else if (labelText.subtext.length > 0 && this._singleLineLabel) {
59 | L.DomUtil.removeClass(this._container, 'leaflet-draw-tooltip-single');
60 | this._singleLineLabel = false;
61 | }
62 |
63 | this._container.innerHTML =
64 | (labelText.subtext.length > 0 ?
65 | '' + labelText.subtext + '' + '
' : '') +
66 | '' + labelText.text + '';
67 |
68 | if (!labelText.text && !labelText.subtext) {
69 | this._visible = false;
70 | this._container.style.visibility = 'hidden';
71 | } else {
72 | this._visible = true;
73 | this._container.style.visibility = 'inherit';
74 | }
75 |
76 | return this;
77 | },
78 |
79 | // @method updatePosition(latlng): this
80 | // Changes the location of the tooltip
81 | updatePosition: function (latlng) {
82 | var pos = this._map.latLngToLayerPoint(latlng),
83 | tooltipContainer = this._container;
84 |
85 | if (this._container) {
86 | if (this._visible) {
87 | tooltipContainer.style.visibility = 'inherit';
88 | }
89 | L.DomUtil.setPosition(tooltipContainer, pos);
90 | }
91 |
92 | return this;
93 | },
94 |
95 | // @method showAsError(): this
96 | // Applies error class to tooltip
97 | showAsError: function () {
98 | if (this._container) {
99 | L.DomUtil.addClass(this._container, 'leaflet-error-draw-tooltip');
100 | }
101 | return this;
102 | },
103 |
104 | // @method removeError(): this
105 | // Removes the error class from the tooltip
106 | removeError: function () {
107 | if (this._container) {
108 | L.DomUtil.removeClass(this._container, 'leaflet-error-draw-tooltip');
109 | }
110 | return this;
111 | },
112 |
113 | _onMouseOut: function () {
114 | if (this._container) {
115 | this._container.style.visibility = 'hidden';
116 | }
117 | }
118 | });
119 |
--------------------------------------------------------------------------------
/static_files/draw_files/TouchEvents.js:
--------------------------------------------------------------------------------
1 | L.Map.mergeOptions({
2 | touchExtend: true
3 | });
4 |
5 | /**
6 | * @class L.Map.TouchExtend
7 | * @aka TouchExtend
8 | */
9 | L.Map.TouchExtend = L.Handler.extend({
10 |
11 | // @method initialize(): void
12 | // Sets TouchExtend private accessor variables
13 | initialize: function (map) {
14 | this._map = map;
15 | this._container = map._container;
16 | this._pane = map._panes.overlayPane;
17 | },
18 |
19 | // @method addHooks(): void
20 | // Adds dom listener events to the map container
21 | addHooks: function () {
22 | L.DomEvent.on(this._container, 'touchstart', this._onTouchStart, this);
23 | L.DomEvent.on(this._container, 'touchend', this._onTouchEnd, this);
24 | L.DomEvent.on(this._container, 'touchmove', this._onTouchMove, this);
25 | if (this._detectIE()) {
26 | L.DomEvent.on(this._container, 'MSPointerDown', this._onTouchStart, this);
27 | L.DomEvent.on(this._container, 'MSPointerUp', this._onTouchEnd, this);
28 | L.DomEvent.on(this._container, 'MSPointerMove', this._onTouchMove, this);
29 | L.DomEvent.on(this._container, 'MSPointerCancel', this._onTouchCancel, this);
30 |
31 | } else {
32 | L.DomEvent.on(this._container, 'touchcancel', this._onTouchCancel, this);
33 | L.DomEvent.on(this._container, 'touchleave', this._onTouchLeave, this);
34 | }
35 | },
36 |
37 | // @method removeHooks(): void
38 | // Removes dom listener events from the map container
39 | removeHooks: function () {
40 | L.DomEvent.off(this._container, 'touchstart', this._onTouchStart);
41 | L.DomEvent.off(this._container, 'touchend', this._onTouchEnd);
42 | L.DomEvent.off(this._container, 'touchmove', this._onTouchMove);
43 | if (this._detectIE()) {
44 | L.DomEvent.off(this._container, 'MSPointerDowm', this._onTouchStart);
45 | L.DomEvent.off(this._container, 'MSPointerUp', this._onTouchEnd);
46 | L.DomEvent.off(this._container, 'MSPointerMove', this._onTouchMove);
47 | L.DomEvent.off(this._container, 'MSPointerCancel', this._onTouchCancel);
48 | } else {
49 | L.DomEvent.off(this._container, 'touchcancel', this._onTouchCancel);
50 | L.DomEvent.off(this._container, 'touchleave', this._onTouchLeave);
51 | }
52 | },
53 |
54 | _touchEvent: function (e, type) {
55 | // #TODO: fix the pageX error that is do a bug in Android where a single touch triggers two click events
56 | // _filterClick is what leaflet uses as a workaround.
57 | // This is a problem with more things than just android. Another problem is touchEnd has no touches in
58 | // its touch list.
59 | var touchEvent = {};
60 | if (typeof e.touches !== 'undefined') {
61 | if (!e.touches.length) {
62 | return;
63 | }
64 | touchEvent = e.touches[0];
65 | } else if (e.pointerType === 'touch') {
66 | touchEvent = e;
67 | if (!this._filterClick(e)) {
68 | return;
69 | }
70 | } else {
71 | return;
72 | }
73 |
74 | var containerPoint = this._map.mouseEventToContainerPoint(touchEvent),
75 | layerPoint = this._map.mouseEventToLayerPoint(touchEvent),
76 | latlng = this._map.layerPointToLatLng(layerPoint);
77 |
78 | this._map.fire(type, {
79 | latlng: latlng,
80 | layerPoint: layerPoint,
81 | containerPoint: containerPoint,
82 | pageX: touchEvent.pageX,
83 | pageY: touchEvent.pageY,
84 | originalEvent: e
85 | });
86 | },
87 |
88 | /** Borrowed from Leaflet and modified for bool ops **/
89 | _filterClick: function (e) {
90 | var timeStamp = (e.timeStamp || e.originalEvent.timeStamp),
91 | elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick);
92 |
93 | // are they closer together than 500ms yet more than 100ms?
94 | // Android typically triggers them ~300ms apart while multiple listeners
95 | // on the same event should be triggered far faster;
96 | // or check if click is simulated on the element, and if it is, reject any non-simulated events
97 | if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) {
98 | L.DomEvent.stop(e);
99 | return false;
100 | }
101 | L.DomEvent._lastClick = timeStamp;
102 | return true;
103 | },
104 |
105 | _onTouchStart: function (e) {
106 | if (!this._map._loaded) {
107 | return;
108 | }
109 |
110 | var type = 'touchstart';
111 | this._touchEvent(e, type);
112 |
113 | },
114 |
115 | _onTouchEnd: function (e) {
116 | if (!this._map._loaded) {
117 | return;
118 | }
119 |
120 | var type = 'touchend';
121 | this._touchEvent(e, type);
122 | },
123 |
124 | _onTouchCancel: function (e) {
125 | if (!this._map._loaded) {
126 | return;
127 | }
128 |
129 | var type = 'touchcancel';
130 | if (this._detectIE()) {
131 | type = 'pointercancel';
132 | }
133 | this._touchEvent(e, type);
134 | },
135 |
136 | _onTouchLeave: function (e) {
137 | if (!this._map._loaded) {
138 | return;
139 | }
140 |
141 | var type = 'touchleave';
142 | this._touchEvent(e, type);
143 | },
144 |
145 | _onTouchMove: function (e) {
146 | if (!this._map._loaded) {
147 | return;
148 | }
149 |
150 | var type = 'touchmove';
151 | this._touchEvent(e, type);
152 | },
153 |
154 | _detectIE: function () {
155 | var ua = window.navigator.userAgent;
156 |
157 | var msie = ua.indexOf('MSIE ');
158 | if (msie > 0) {
159 | // IE 10 or older => return version number
160 | return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
161 | }
162 |
163 | var trident = ua.indexOf('Trident/');
164 | if (trident > 0) {
165 | // IE 11 => return version number
166 | var rv = ua.indexOf('rv:');
167 | return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
168 | }
169 |
170 | var edge = ua.indexOf('Edge/');
171 | if (edge > 0) {
172 | // IE 12 => return version number
173 | return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
174 | }
175 |
176 | // other browser
177 | return false;
178 | }
179 | });
180 |
181 | L.Map.addInitHook('addHandler', 'touchExtend', L.Map.TouchExtend);
182 |
183 |
184 | /**
185 | * @class L.Marker.Touch
186 | * @aka Marker.Touch
187 | *
188 | * This isn't full Touch support. This is just to get markers to also support dom touch events after creation
189 | * #TODO: find a better way of getting markers to support touch.
190 | */
191 | L.Marker.Touch = L.Marker.extend({
192 |
193 | _initInteraction: function () {
194 | if (!this.addInteractiveTarget) {
195 | // 0.7.x support
196 | return this._initInteractionLegacy();
197 | }
198 | // TODO this may need be updated to re-add touch events for 1.0+
199 | return L.Marker.prototype._initInteraction.apply(this);
200 | },
201 |
202 | // This is an exact copy of https://github.com/Leaflet/Leaflet/blob/v0.7/src/layer/marker/Marker.js
203 | // with the addition of the touch events
204 | _initInteractionLegacy: function () {
205 |
206 | if (!this.options.clickable) {
207 | return;
208 | }
209 |
210 | // TODO refactor into something shared with Map/Path/etc. to DRY it up
211 |
212 | var icon = this._icon,
213 | events = ['dblclick',
214 | 'mousedown',
215 | 'mouseover',
216 | 'mouseout',
217 | 'contextmenu',
218 | 'touchstart',
219 | 'touchend',
220 | 'touchmove'];
221 | if (this._detectIE) {
222 | events.concat(['MSPointerDown',
223 | 'MSPointerUp',
224 | 'MSPointerMove',
225 | 'MSPointerCancel']);
226 | } else {
227 | events.concat(['touchcancel']);
228 | }
229 |
230 | L.DomUtil.addClass(icon, 'leaflet-clickable');
231 | L.DomEvent.on(icon, 'click', this._onMouseClick, this);
232 | L.DomEvent.on(icon, 'keypress', this._onKeyPress, this);
233 |
234 | for (var i = 0; i < events.length; i++) {
235 | L.DomEvent.on(icon, events[i], this._fireMouseEvent, this);
236 | }
237 |
238 | if (L.Handler.MarkerDrag) {
239 | this.dragging = new L.Handler.MarkerDrag(this);
240 |
241 | if (this.options.draggable) {
242 | this.dragging.enable();
243 | }
244 | }
245 | },
246 |
247 | _detectIE: function () {
248 | var ua = window.navigator.userAgent;
249 |
250 | var msie = ua.indexOf('MSIE ');
251 | if (msie > 0) {
252 | // IE 10 or older => return version number
253 | return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
254 | }
255 |
256 | var trident = ua.indexOf('Trident/');
257 | if (trident > 0) {
258 | // IE 11 => return version number
259 | var rv = ua.indexOf('rv:');
260 | return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
261 | }
262 |
263 | var edge = ua.indexOf('Edge/');
264 | if (edge > 0) {
265 | // IE 12 => return version number
266 | return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
267 | }
268 |
269 | // other browser
270 | return false;
271 | }
272 | });
273 |
--------------------------------------------------------------------------------
/static_files/draw_files/jquery.cookie.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery Cookie Plugin v1.4.0
3 | * https://github.com/carhartl/jquery-cookie
4 | *
5 | * Copyright 2013 Klaus Hartl
6 | * Released under the MIT license
7 | */
8 | (function (factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as anonymous module.
11 | define(['jquery'], factory);
12 | } else {
13 | // Browser globals.
14 | factory(jQuery);
15 | }
16 | }(function ($) {
17 |
18 | var pluses = /\+/g;
19 |
20 | function encode(s) {
21 | return config.raw ? s : encodeURIComponent(s);
22 | }
23 |
24 | function decode(s) {
25 | return config.raw ? s : decodeURIComponent(s);
26 | }
27 |
28 | function stringifyCookieValue(value) {
29 | return encode(config.json ? JSON.stringify(value) : String(value));
30 | }
31 |
32 | function parseCookieValue(s) {
33 | if (s.indexOf('"') === 0) {
34 | // This is a quoted cookie as according to RFC2068, unescape...
35 | s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
36 | }
37 |
38 | try {
39 | // Replace server-side written pluses with spaces.
40 | // If we can't decode the cookie, ignore it, it's unusable.
41 | s = decodeURIComponent(s.replace(pluses, ' '));
42 | } catch(e) {
43 | return;
44 | }
45 |
46 | try {
47 | // If we can't parse the cookie, ignore it, it's unusable.
48 | return config.json ? JSON.parse(s) : s;
49 | } catch(e) {}
50 | }
51 |
52 | function read(s, converter) {
53 | var value = config.raw ? s : parseCookieValue(s);
54 | return $.isFunction(converter) ? converter(value) : value;
55 | }
56 |
57 | var config = $.cookie = function (key, value, options) {
58 |
59 | // Write
60 | if (value !== undefined && !$.isFunction(value)) {
61 | options = $.extend({}, config.defaults, options);
62 |
63 | if (typeof options.expires === 'number') {
64 | var days = options.expires, t = options.expires = new Date();
65 | t.setDate(t.getDate() + days);
66 | }
67 |
68 | return (document.cookie = [
69 | encode(key), '=', stringifyCookieValue(value),
70 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
71 | options.path ? '; path=' + options.path : '',
72 | options.domain ? '; domain=' + options.domain : '',
73 | options.secure ? '; secure' : ''
74 | ].join(''));
75 | }
76 |
77 | // Read
78 |
79 | var result = key ? undefined : {};
80 |
81 | // To prevent the for loop in the first place assign an empty array
82 | // in case there are no cookies at all. Also prevents odd result when
83 | // calling $.cookie().
84 | var cookies = document.cookie ? document.cookie.split('; ') : [];
85 |
86 | for (var i = 0, l = cookies.length; i < l; i++) {
87 | var parts = cookies[i].split('=');
88 | var name = decode(parts.shift());
89 | var cookie = parts.join('=');
90 |
91 | if (key && key === name) {
92 | // If second argument (value) is a function it's a converter...
93 | result = read(cookie, value);
94 | break;
95 | }
96 |
97 | // Prevent storing a cookie that we couldn't decode.
98 | if (!key && (cookie = read(cookie)) !== undefined) {
99 | result[name] = cookie;
100 | }
101 | }
102 |
103 | return result;
104 | };
105 |
106 | config.defaults = {};
107 |
108 | $.removeCookie = function (key, options) {
109 | if ($.cookie(key) !== undefined) {
110 | // Must not alter options, thus extending a fresh object...
111 | $.cookie(key, '', $.extend({}, options, { expires: -1 }));
112 | return true;
113 | }
114 | return false;
115 | };
116 |
117 | }));
118 |
--------------------------------------------------------------------------------
/static_files/draw_files/leaflet.css:
--------------------------------------------------------------------------------
1 | /* required styles */
2 |
3 | .leaflet-pane,
4 | .leaflet-tile,
5 | .leaflet-marker-icon,
6 | .leaflet-marker-shadow,
7 | .leaflet-tile-container,
8 | .leaflet-pane > svg,
9 | .leaflet-pane > canvas,
10 | .leaflet-zoom-box,
11 | .leaflet-image-layer,
12 | .leaflet-layer {
13 | position: absolute;
14 | left: 0;
15 | top: 0;
16 | }
17 | .leaflet-container {
18 | overflow: hidden;
19 | }
20 | .leaflet-tile,
21 | .leaflet-marker-icon,
22 | .leaflet-marker-shadow {
23 | -webkit-user-select: none;
24 | -moz-user-select: none;
25 | user-select: none;
26 | -webkit-user-drag: none;
27 | }
28 | /* Safari renders non-retina tile on retina better with this, but Chrome is worse */
29 | .leaflet-safari .leaflet-tile {
30 | image-rendering: -webkit-optimize-contrast;
31 | }
32 | /* hack that prevents hw layers "stretching" when loading new tiles */
33 | .leaflet-safari .leaflet-tile-container {
34 | width: 1600px;
35 | height: 1600px;
36 | -webkit-transform-origin: 0 0;
37 | }
38 | .leaflet-marker-icon,
39 | .leaflet-marker-shadow {
40 | display: block;
41 | }
42 | /* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
43 | /* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
44 | .leaflet-container .leaflet-overlay-pane svg,
45 | .leaflet-container .leaflet-marker-pane img,
46 | .leaflet-container .leaflet-shadow-pane img,
47 | .leaflet-container .leaflet-tile-pane img,
48 | .leaflet-container img.leaflet-image-layer {
49 | max-width: none !important;
50 | max-height: none !important;
51 | }
52 |
53 | .leaflet-container.leaflet-touch-zoom {
54 | -ms-touch-action: pan-x pan-y;
55 | touch-action: pan-x pan-y;
56 | }
57 | .leaflet-container.leaflet-touch-drag {
58 | -ms-touch-action: pinch-zoom;
59 | /* Fallback for FF which doesn't support pinch-zoom */
60 | touch-action: none;
61 | touch-action: pinch-zoom;
62 | }
63 | .leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
64 | -ms-touch-action: none;
65 | touch-action: none;
66 | }
67 | .leaflet-container {
68 | -webkit-tap-highlight-color: transparent;
69 | }
70 | .leaflet-container a {
71 | -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
72 | }
73 | .leaflet-tile {
74 | filter: inherit;
75 | visibility: hidden;
76 | }
77 | .leaflet-tile-loaded {
78 | visibility: inherit;
79 | }
80 | .leaflet-zoom-box {
81 | width: 0;
82 | height: 0;
83 | -moz-box-sizing: border-box;
84 | box-sizing: border-box;
85 | z-index: 800;
86 | }
87 | /* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
88 | .leaflet-overlay-pane svg {
89 | -moz-user-select: none;
90 | }
91 |
92 | .leaflet-pane { z-index: 400; }
93 |
94 | .leaflet-tile-pane { z-index: 200; }
95 | .leaflet-overlay-pane { z-index: 400; }
96 | .leaflet-shadow-pane { z-index: 500; }
97 | .leaflet-marker-pane { z-index: 600; }
98 | .leaflet-tooltip-pane { z-index: 650; }
99 | .leaflet-popup-pane { z-index: 700; }
100 |
101 | .leaflet-map-pane canvas { z-index: 100; }
102 | .leaflet-map-pane svg { z-index: 200; }
103 |
104 | .leaflet-vml-shape {
105 | width: 1px;
106 | height: 1px;
107 | }
108 | .lvml {
109 | behavior: url(#default#VML);
110 | display: inline-block;
111 | position: absolute;
112 | }
113 |
114 |
115 | /* control positioning */
116 |
117 | .leaflet-control {
118 | position: relative;
119 | z-index: 800;
120 | pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
121 | pointer-events: auto;
122 | }
123 | .leaflet-top,
124 | .leaflet-bottom {
125 | position: absolute;
126 | z-index: 1000;
127 | pointer-events: none;
128 | }
129 | .leaflet-top {
130 | top: 0;
131 | }
132 | .leaflet-right {
133 | right: 0;
134 | }
135 | .leaflet-bottom {
136 | bottom: 0;
137 | }
138 | .leaflet-left {
139 | left: 0;
140 | }
141 | .leaflet-control {
142 | float: left;
143 | clear: both;
144 | }
145 | .leaflet-right .leaflet-control {
146 | float: right;
147 | }
148 | .leaflet-top .leaflet-control {
149 | margin-top: 10px;
150 | }
151 | .leaflet-bottom .leaflet-control {
152 | margin-bottom: 10px;
153 | }
154 | .leaflet-left .leaflet-control {
155 | margin-left: 10px;
156 | }
157 | .leaflet-right .leaflet-control {
158 | margin-right: 10px;
159 | }
160 |
161 |
162 | /* zoom and fade animations */
163 |
164 | .leaflet-fade-anim .leaflet-tile {
165 | will-change: opacity;
166 | }
167 | .leaflet-fade-anim .leaflet-popup {
168 | opacity: 0;
169 | -webkit-transition: opacity 0.2s linear;
170 | -moz-transition: opacity 0.2s linear;
171 | -o-transition: opacity 0.2s linear;
172 | transition: opacity 0.2s linear;
173 | }
174 | .leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
175 | opacity: 1;
176 | }
177 | .leaflet-zoom-animated {
178 | -webkit-transform-origin: 0 0;
179 | -ms-transform-origin: 0 0;
180 | transform-origin: 0 0;
181 | }
182 | .leaflet-zoom-anim .leaflet-zoom-animated {
183 | will-change: transform;
184 | }
185 | .leaflet-zoom-anim .leaflet-zoom-animated {
186 | -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
187 | -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
188 | -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
189 | transition: transform 0.25s cubic-bezier(0,0,0.25,1);
190 | }
191 | .leaflet-zoom-anim .leaflet-tile,
192 | .leaflet-pan-anim .leaflet-tile {
193 | -webkit-transition: none;
194 | -moz-transition: none;
195 | -o-transition: none;
196 | transition: none;
197 | }
198 |
199 | .leaflet-zoom-anim .leaflet-zoom-hide {
200 | visibility: hidden;
201 | }
202 |
203 |
204 | /* cursors */
205 |
206 | .leaflet-interactive {
207 | cursor: pointer;
208 | }
209 | .leaflet-grab {
210 | cursor: -webkit-grab;
211 | cursor: -moz-grab;
212 | }
213 | .leaflet-crosshair,
214 | .leaflet-crosshair .leaflet-interactive {
215 | cursor: crosshair;
216 | }
217 | .leaflet-popup-pane,
218 | .leaflet-control {
219 | cursor: auto;
220 | }
221 | .leaflet-dragging .leaflet-grab,
222 | .leaflet-dragging .leaflet-grab .leaflet-interactive,
223 | .leaflet-dragging .leaflet-marker-draggable {
224 | cursor: move;
225 | cursor: -webkit-grabbing;
226 | cursor: -moz-grabbing;
227 | }
228 |
229 | /* marker & overlays interactivity */
230 | .leaflet-marker-icon,
231 | .leaflet-marker-shadow,
232 | .leaflet-image-layer,
233 | .leaflet-pane > svg path,
234 | .leaflet-tile-container {
235 | pointer-events: none;
236 | }
237 |
238 | .leaflet-marker-icon.leaflet-interactive,
239 | .leaflet-image-layer.leaflet-interactive,
240 | .leaflet-pane > svg path.leaflet-interactive {
241 | pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
242 | pointer-events: auto;
243 | }
244 |
245 | /* visual tweaks */
246 |
247 | .leaflet-container {
248 | background: #ddd;
249 | outline: 0;
250 | }
251 | .leaflet-container a {
252 | color: #0078A8;
253 | }
254 | .leaflet-container a.leaflet-active {
255 | outline: 2px solid orange;
256 | }
257 | .leaflet-zoom-box {
258 | border: 2px dotted #38f;
259 | background: rgba(255,255,255,0.5);
260 | }
261 |
262 |
263 | /* general typography */
264 | .leaflet-container {
265 | font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
266 | }
267 |
268 |
269 | /* general toolbar styles */
270 |
271 | .leaflet-bar {
272 | box-shadow: 0 1px 5px rgba(0,0,0,0.65);
273 | border-radius: 4px;
274 | }
275 | .leaflet-bar a,
276 | .leaflet-bar a:hover {
277 | background-color: #fff;
278 | border-bottom: 1px solid #ccc;
279 | width: 26px;
280 | height: 26px;
281 | line-height: 26px;
282 | display: block;
283 | text-align: center;
284 | text-decoration: none;
285 | color: black;
286 | }
287 | .leaflet-bar a,
288 | .leaflet-control-layers-toggle {
289 | background-position: 50% 50%;
290 | background-repeat: no-repeat;
291 | display: block;
292 | }
293 | .leaflet-bar a:hover {
294 | background-color: #f4f4f4;
295 | }
296 | .leaflet-bar a:first-child {
297 | border-top-left-radius: 4px;
298 | border-top-right-radius: 4px;
299 | }
300 | .leaflet-bar a:last-child {
301 | border-bottom-left-radius: 4px;
302 | border-bottom-right-radius: 4px;
303 | border-bottom: none;
304 | }
305 | .leaflet-bar a.leaflet-disabled {
306 | cursor: default;
307 | background-color: #f4f4f4;
308 | color: #bbb;
309 | }
310 |
311 | .leaflet-touch .leaflet-bar a {
312 | width: 30px;
313 | height: 30px;
314 | line-height: 30px;
315 | }
316 | .leaflet-touch .leaflet-bar a:first-child {
317 | border-top-left-radius: 2px;
318 | border-top-right-radius: 2px;
319 | }
320 | .leaflet-touch .leaflet-bar a:last-child {
321 | border-bottom-left-radius: 2px;
322 | border-bottom-right-radius: 2px;
323 | }
324 |
325 | /* zoom control */
326 |
327 | .leaflet-control-zoom-in,
328 | .leaflet-control-zoom-out {
329 | font: bold 18px 'Lucida Console', Monaco, monospace;
330 | text-indent: 1px;
331 | }
332 |
333 | .leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
334 | font-size: 22px;
335 | }
336 |
337 |
338 | /* layers control */
339 |
340 | .leaflet-control-layers {
341 | box-shadow: 0 1px 5px rgba(0,0,0,0.4);
342 | background: #fff;
343 | border-radius: 5px;
344 | }
345 | .leaflet-control-layers-toggle {
346 | background-image: url(images/layers.png);
347 | width: 36px;
348 | height: 36px;
349 | }
350 | .leaflet-retina .leaflet-control-layers-toggle {
351 | background-image: url(images/layers-2x.png);
352 | background-size: 26px 26px;
353 | }
354 | .leaflet-touch .leaflet-control-layers-toggle {
355 | width: 44px;
356 | height: 44px;
357 | }
358 | .leaflet-control-layers .leaflet-control-layers-list,
359 | .leaflet-control-layers-expanded .leaflet-control-layers-toggle {
360 | display: none;
361 | }
362 | .leaflet-control-layers-expanded .leaflet-control-layers-list {
363 | display: block;
364 | position: relative;
365 | }
366 | .leaflet-control-layers-expanded {
367 | padding: 6px 10px 6px 6px;
368 | color: #333;
369 | background: #fff;
370 | }
371 | .leaflet-control-layers-scrollbar {
372 | overflow-y: scroll;
373 | overflow-x: hidden;
374 | padding-right: 5px;
375 | }
376 | .leaflet-control-layers-selector {
377 | margin-top: 2px;
378 | position: relative;
379 | top: 1px;
380 | }
381 | .leaflet-control-layers label {
382 | display: block;
383 | }
384 | .leaflet-control-layers-separator {
385 | height: 0;
386 | border-top: 1px solid #ddd;
387 | margin: 5px -10px 5px -6px;
388 | }
389 |
390 | /* Default icon URLs */
391 | .leaflet-default-icon-path {
392 | background-image: url(images/marker-icon.png);
393 | }
394 |
395 |
396 | /* attribution and scale controls */
397 |
398 | .leaflet-container .leaflet-control-attribution {
399 | background: #fff;
400 | background: rgba(255, 255, 255, 0.7);
401 | margin: 0;
402 | }
403 | .leaflet-control-attribution,
404 | .leaflet-control-scale-line {
405 | padding: 0 5px;
406 | color: #333;
407 | }
408 | .leaflet-control-attribution a {
409 | text-decoration: none;
410 | }
411 | .leaflet-control-attribution a:hover {
412 | text-decoration: underline;
413 | }
414 | .leaflet-container .leaflet-control-attribution,
415 | .leaflet-container .leaflet-control-scale {
416 | font-size: 11px;
417 | }
418 | .leaflet-left .leaflet-control-scale {
419 | margin-left: 5px;
420 | }
421 | .leaflet-bottom .leaflet-control-scale {
422 | margin-bottom: 5px;
423 | }
424 | .leaflet-control-scale-line {
425 | border: 2px solid #777;
426 | border-top: none;
427 | line-height: 1.1;
428 | padding: 2px 5px 1px;
429 | font-size: 11px;
430 | white-space: nowrap;
431 | overflow: hidden;
432 | -moz-box-sizing: border-box;
433 | box-sizing: border-box;
434 |
435 | background: #fff;
436 | background: rgba(255, 255, 255, 0.5);
437 | }
438 | .leaflet-control-scale-line:not(:first-child) {
439 | border-top: 2px solid #777;
440 | border-bottom: none;
441 | margin-top: -2px;
442 | }
443 | .leaflet-control-scale-line:not(:first-child):not(:last-child) {
444 | border-bottom: 2px solid #777;
445 | }
446 |
447 | .leaflet-touch .leaflet-control-attribution,
448 | .leaflet-touch .leaflet-control-layers,
449 | .leaflet-touch .leaflet-bar {
450 | box-shadow: none;
451 | }
452 | .leaflet-touch .leaflet-control-layers,
453 | .leaflet-touch .leaflet-bar {
454 | border: 2px solid rgba(0,0,0,0.2);
455 | background-clip: padding-box;
456 | }
457 |
458 |
459 | /* popup */
460 |
461 | .leaflet-popup {
462 | position: absolute;
463 | text-align: center;
464 | margin-bottom: 20px;
465 | }
466 | .leaflet-popup-content-wrapper {
467 | padding: 1px;
468 | text-align: left;
469 | border-radius: 12px;
470 | }
471 | .leaflet-popup-content {
472 | margin: 13px 19px;
473 | line-height: 1.4;
474 | }
475 | .leaflet-popup-content p {
476 | margin: 18px 0;
477 | }
478 | .leaflet-popup-tip-container {
479 | width: 40px;
480 | height: 20px;
481 | position: absolute;
482 | left: 50%;
483 | margin-left: -20px;
484 | overflow: hidden;
485 | pointer-events: none;
486 | }
487 | .leaflet-popup-tip {
488 | width: 17px;
489 | height: 17px;
490 | padding: 1px;
491 |
492 | margin: -10px auto 0;
493 |
494 | -webkit-transform: rotate(45deg);
495 | -moz-transform: rotate(45deg);
496 | -ms-transform: rotate(45deg);
497 | -o-transform: rotate(45deg);
498 | transform: rotate(45deg);
499 | }
500 | .leaflet-popup-content-wrapper,
501 | .leaflet-popup-tip {
502 | background: white;
503 | color: #333;
504 | box-shadow: 0 3px 14px rgba(0,0,0,0.4);
505 | }
506 | .leaflet-container a.leaflet-popup-close-button {
507 | position: absolute;
508 | top: 0;
509 | right: 0;
510 | padding: 4px 4px 0 0;
511 | border: none;
512 | text-align: center;
513 | width: 18px;
514 | height: 14px;
515 | font: 16px/14px Tahoma, Verdana, sans-serif;
516 | color: #c3c3c3;
517 | text-decoration: none;
518 | font-weight: bold;
519 | background: transparent;
520 | }
521 | .leaflet-container a.leaflet-popup-close-button:hover {
522 | color: #999;
523 | }
524 | .leaflet-popup-scrolled {
525 | overflow: auto;
526 | border-bottom: 1px solid #ddd;
527 | border-top: 1px solid #ddd;
528 | }
529 |
530 | .leaflet-oldie .leaflet-popup-content-wrapper {
531 | zoom: 1;
532 | }
533 | .leaflet-oldie .leaflet-popup-tip {
534 | width: 24px;
535 | margin: 0 auto;
536 |
537 | -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
538 | filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
539 | }
540 | .leaflet-oldie .leaflet-popup-tip-container {
541 | margin-top: -1px;
542 | }
543 |
544 | .leaflet-oldie .leaflet-control-zoom,
545 | .leaflet-oldie .leaflet-control-layers,
546 | .leaflet-oldie .leaflet-popup-content-wrapper,
547 | .leaflet-oldie .leaflet-popup-tip {
548 | border: 1px solid #999;
549 | }
550 |
551 |
552 | /* div icon */
553 |
554 | .leaflet-div-icon {
555 | background: #fff;
556 | border: 1px solid #666;
557 | }
558 |
559 |
560 | /* Tooltip */
561 | /* Base styles for the element that has a tooltip */
562 | .leaflet-tooltip {
563 | position: absolute;
564 | padding: 6px;
565 | background-color: #fff;
566 | border: 1px solid #fff;
567 | border-radius: 3px;
568 | color: #222;
569 | white-space: nowrap;
570 | -webkit-user-select: none;
571 | -moz-user-select: none;
572 | -ms-user-select: none;
573 | user-select: none;
574 | pointer-events: none;
575 | box-shadow: 0 1px 3px rgba(0,0,0,0.4);
576 | }
577 | .leaflet-tooltip.leaflet-clickable {
578 | cursor: pointer;
579 | pointer-events: auto;
580 | }
581 | .leaflet-tooltip-top:before,
582 | .leaflet-tooltip-bottom:before,
583 | .leaflet-tooltip-left:before,
584 | .leaflet-tooltip-right:before {
585 | position: absolute;
586 | pointer-events: none;
587 | border: 6px solid transparent;
588 | background: transparent;
589 | content: "";
590 | }
591 |
592 | /* Directions */
593 |
594 | .leaflet-tooltip-bottom {
595 | margin-top: 6px;
596 | }
597 | .leaflet-tooltip-top {
598 | margin-top: -6px;
599 | }
600 | .leaflet-tooltip-bottom:before,
601 | .leaflet-tooltip-top:before {
602 | left: 50%;
603 | margin-left: -6px;
604 | }
605 | .leaflet-tooltip-top:before {
606 | bottom: 0;
607 | margin-bottom: -12px;
608 | border-top-color: #fff;
609 | }
610 | .leaflet-tooltip-bottom:before {
611 | top: 0;
612 | margin-top: -12px;
613 | margin-left: -6px;
614 | border-bottom-color: #fff;
615 | }
616 | .leaflet-tooltip-left {
617 | margin-left: -6px;
618 | }
619 | .leaflet-tooltip-right {
620 | margin-left: 6px;
621 | }
622 | .leaflet-tooltip-left:before,
623 | .leaflet-tooltip-right:before {
624 | top: 50%;
625 | margin-top: -6px;
626 | }
627 | .leaflet-tooltip-left:before {
628 | right: 0;
629 | margin-right: -12px;
630 | border-left-color: #fff;
631 | }
632 | .leaflet-tooltip-right:before {
633 | left: 0;
634 | margin-left: -12px;
635 | border-right-color: #fff;
636 | }
637 |
--------------------------------------------------------------------------------
/static_files/draw_files/leaflet.draw.css:
--------------------------------------------------------------------------------
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('./spritesheet.png');
27 | background-image: linear-gradient(transparent, transparent), url('./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('./spritesheet-2x.png');
35 | background-image: linear-gradient(transparent, transparent), url('./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 | /* Edit toolbar
202 | /* ================================================================== */
203 |
204 | .leaflet-draw-toolbar .leaflet-draw-edit-edit {
205 | background-position: -152px -2px;
206 | }
207 |
208 | .leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-edit {
209 | background-position: -150px -1px;
210 | }
211 |
212 | .leaflet-draw-toolbar .leaflet-draw-edit-remove {
213 | background-position: -182px -2px;
214 | }
215 |
216 | .leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-remove {
217 | background-position: -180px -1px;
218 | }
219 |
220 | .leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled {
221 | background-position: -212px -2px;
222 | }
223 |
224 | .leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled {
225 | background-position: -210px -1px;
226 | }
227 |
228 | .leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled {
229 | background-position: -242px -2px;
230 | }
231 |
232 | .leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled {
233 | background-position: -240px -2px;
234 | }
235 |
236 | /* ================================================================== */
237 | /* Drawing styles
238 | /* ================================================================== */
239 |
240 | .leaflet-mouse-marker {
241 | background-color: #fff;
242 | cursor: crosshair;
243 | }
244 |
245 | .leaflet-draw-tooltip {
246 | background: rgb(54, 54, 54);
247 | background: rgba(0, 0, 0, 0.5);
248 | border: 1px solid transparent;
249 | -webkit-border-radius: 4px;
250 | border-radius: 4px;
251 | color: #fff;
252 | font: 12px/18px "Helvetica Neue", Arial, Helvetica, sans-serif;
253 | margin-left: 20px;
254 | margin-top: -21px;
255 | padding: 4px 8px;
256 | position: absolute;
257 | visibility: hidden;
258 | white-space: nowrap;
259 | z-index: 6;
260 | }
261 |
262 | .leaflet-draw-tooltip:before {
263 | border-right: 6px solid black;
264 | border-right-color: rgba(0, 0, 0, 0.5);
265 | border-top: 6px solid transparent;
266 | border-bottom: 6px solid transparent;
267 | content: "";
268 | position: absolute;
269 | top: 7px;
270 | left: -7px;
271 | }
272 |
273 | .leaflet-error-draw-tooltip {
274 | background-color: #F2DEDE;
275 | border: 1px solid #E6B6BD;
276 | color: #B94A48;
277 | }
278 |
279 | .leaflet-error-draw-tooltip:before {
280 | border-right-color: #E6B6BD;
281 | }
282 |
283 | .leaflet-draw-tooltip-single {
284 | margin-top: -12px
285 | }
286 |
287 | .leaflet-draw-tooltip-subtext {
288 | color: #f8d5e4;
289 | }
290 |
291 | .leaflet-draw-guide-dash {
292 | font-size: 1%;
293 | opacity: 0.6;
294 | position: absolute;
295 | width: 5px;
296 | height: 5px;
297 | }
298 |
299 | /* ================================================================== */
300 | /* Edit styles
301 | /* ================================================================== */
302 |
303 | .leaflet-edit-marker-selected {
304 | background-color: rgba(254, 87, 161, 0.1);
305 | border: 4px dashed rgba(254, 87, 161, 0.6);
306 | -webkit-border-radius: 4px;
307 | border-radius: 4px;
308 | box-sizing: content-box;
309 | }
310 |
311 | .leaflet-edit-move {
312 | cursor: move;
313 | }
314 |
315 | .leaflet-edit-resize {
316 | cursor: pointer;
317 | }
318 |
319 | /* ================================================================== */
320 | /* Old IE styles
321 | /* ================================================================== */
322 |
323 | .leaflet-oldie .leaflet-draw-toolbar {
324 | border: 1px solid #999;
325 | }
326 |
--------------------------------------------------------------------------------
/static_files/draw_files/spritesheet-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yimengyao13/geoserver_django_leaflet/2efa16ab245481391434ffa644658ced04ce07ba/static_files/draw_files/spritesheet-2x.png
--------------------------------------------------------------------------------
/static_files/draw_files/spritesheet.svg:
--------------------------------------------------------------------------------
1 |
2 |
156 |
--------------------------------------------------------------------------------
/static_files/leaflet.css:
--------------------------------------------------------------------------------
1 | /* required styles
2 | 所需风格*/
3 |
4 | .leaflet-pane,
5 | .leaflet-tile,
6 | .leaflet-marker-icon,
7 | .leaflet-marker-shadow,
8 | .leaflet-tile-container,
9 | .leaflet-pane > svg,
10 | .leaflet-pane > canvas,
11 | .leaflet-zoom-box,
12 | .leaflet-image-layer,
13 | .leaflet-layer {
14 | position: absolute;
15 | left: 0;
16 | top: 0;
17 | }
18 | .leaflet-container {
19 | overflow: hidden;
20 | }
21 | .leaflet-tile,
22 | .leaflet-marker-icon,
23 | .leaflet-marker-shadow {
24 | -webkit-user-select: none;
25 | -moz-user-select: none;
26 | user-select: none;
27 | -webkit-user-drag: none;
28 | }
29 | /* Prevents IE11 from highlighting tiles in blue
30 | 防止IE11用蓝色高亮显示tile */
31 | .leaflet-tile::selection {
32 | background: transparent;
33 | }
34 | /* Safari renders non-retina tile on retina better with this, but Chrome is worse
35 | Safari用这个在视网膜上显示非视网膜贴图效果更好,但Chrome就更差了 */
36 | .leaflet-safari .leaflet-tile {
37 | image-rendering: -webkit-optimize-contrast;
38 | }
39 | /* hack that prevents hw layers "stretching" when loading new tiles
40 | hack防止hw层“拉伸”时加载新瓷砖 */
41 | .leaflet-safari .leaflet-tile-container {
42 | width: 1600px;
43 | height: 1600px;
44 | -webkit-transform-origin: 0 0;
45 | }
46 | .leaflet-marker-icon,
47 | .leaflet-marker-shadow {
48 | display: block;
49 | }
50 | /* .leaflet-container svg:
51 | reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x
52 | 在Joomla中运行的时候,重置svg的max-width*/
53 | /* .leaflet-container img:
54 | map is broken in FF if you have max-width: 100% on tiles
55 | 如果在瓦片中使用max-width=100%,地图就会在FF中中断*/
56 | .leaflet-container .leaflet-overlay-pane svg,
57 | .leaflet-container .leaflet-marker-pane img,
58 | .leaflet-container .leaflet-shadow-pane img,
59 | .leaflet-container .leaflet-tile-pane img,
60 | .leaflet-container img.leaflet-image-layer,
61 | .leaflet-container .leaflet-tile {
62 | max-width: none !important;
63 | max-height: none !important;
64 | }
65 |
66 | .leaflet-container.leaflet-touch-zoom {
67 | -ms-touch-action: pan-x pan-y;
68 | touch-action: pan-x pan-y;
69 | }
70 | .leaflet-container.leaflet-touch-drag {
71 | -ms-touch-action: pinch-zoom;
72 | /* Fallback for FF which doesn't support pinch-zoom
73 | FF的Fallback不支持缩放 */
74 | touch-action: none;
75 | touch-action: pinch-zoom;
76 | }
77 | .leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
78 | -ms-touch-action: none;
79 | touch-action: none;
80 | }
81 | .leaflet-container {
82 | -webkit-tap-highlight-color: transparent;
83 | }
84 | .leaflet-container a {
85 | -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
86 | }
87 | .leaflet-tile {
88 | filter: inherit;
89 | visibility: hidden;
90 | }
91 | .leaflet-tile-loaded {
92 | visibility: inherit;
93 | }
94 | .leaflet-zoom-box {
95 | width: 0;
96 | height: 0;
97 | -moz-box-sizing: border-box;
98 | box-sizing: border-box;
99 | z-index: 800;
100 | }
101 | /* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319
102 | 解决方案见网址 */
103 | .leaflet-overlay-pane svg {
104 | -moz-user-select: none;
105 | }
106 |
107 | .leaflet-pane { z-index: 400; }
108 |
109 | .leaflet-tile-pane { z-index: 200; }
110 | .leaflet-overlay-pane { z-index: 400; }
111 | .leaflet-shadow-pane { z-index: 500; }
112 | .leaflet-marker-pane { z-index: 600; }
113 | .leaflet-tooltip-pane { z-index: 650; }
114 | .leaflet-popup-pane { z-index: 700; }
115 |
116 | .leaflet-map-pane canvas { z-index: 100; }
117 | .leaflet-map-pane svg { z-index: 200; }
118 |
119 | .leaflet-vml-shape {
120 | width: 1px;
121 | height: 1px;
122 | }
123 | .lvml {
124 | behavior: url(#default#VML);
125 | display: inline-block;
126 | position: absolute;
127 | }
128 |
129 |
130 | /* control positioning
131 | 控制控件位置*/
132 |
133 | .leaflet-control {
134 | position: relative;
135 | z-index: 800;
136 | pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
137 | pointer-events: auto;
138 | }
139 | .leaflet-top,
140 | .leaflet-bottom {
141 | position: absolute;
142 | z-index: 1000;
143 | pointer-events: none;
144 | }
145 | .leaflet-top {
146 | top: 0;
147 | }
148 | .leaflet-right {
149 | right: 0;
150 | }
151 | .leaflet-bottom {
152 | bottom: 0;
153 | }
154 | .leaflet-left {
155 | left: 0;
156 | }
157 | .leaflet-control {
158 | float: left;
159 | clear: both;
160 | }
161 | .leaflet-right .leaflet-control {
162 | float: right;
163 | }
164 | .leaflet-top .leaflet-control {
165 | margin-top: 10px;
166 | }
167 | .leaflet-bottom .leaflet-control {
168 | margin-bottom: 10px;
169 | }
170 | .leaflet-left .leaflet-control {
171 | margin-left: 10px;
172 | }
173 | .leaflet-right .leaflet-control {
174 | margin-right: 10px;
175 | }
176 |
177 |
178 | /* zoom and fade animations
179 | 缩放和淡出 */
180 |
181 | .leaflet-fade-anim .leaflet-tile {
182 | will-change: opacity;
183 | }
184 | .leaflet-fade-anim .leaflet-popup {
185 | opacity: 0;
186 | -webkit-transition: opacity 0.2s linear;
187 | -moz-transition: opacity 0.2s linear;
188 | transition: opacity 0.2s linear;
189 | }
190 | .leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
191 | opacity: 1;
192 | }
193 | .leaflet-zoom-animated {
194 | -webkit-transform-origin: 0 0;
195 | -ms-transform-origin: 0 0;
196 | transform-origin: 0 0;
197 | }
198 | .leaflet-zoom-anim .leaflet-zoom-animated {
199 | will-change: transform;
200 | }
201 | .leaflet-zoom-anim .leaflet-zoom-animated {
202 | -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
203 | -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
204 | transition: transform 0.25s cubic-bezier(0,0,0.25,1);
205 | }
206 | .leaflet-zoom-anim .leaflet-tile,
207 | .leaflet-pan-anim .leaflet-tile {
208 | -webkit-transition: none;
209 | -moz-transition: none;
210 | transition: none;
211 | }
212 |
213 | .leaflet-zoom-anim .leaflet-zoom-hide {
214 | visibility: hidden;
215 | }
216 |
217 |
218 | /* cursors游标 */
219 |
220 | .leaflet-interactive {
221 | cursor: pointer;
222 | }
223 | .leaflet-grab {
224 | cursor: -webkit-grab;
225 | cursor: -moz-grab;
226 | cursor: grab;
227 | }
228 | .leaflet-crosshair,
229 | .leaflet-crosshair .leaflet-interactive {
230 | cursor: crosshair;
231 | }
232 | .leaflet-popup-pane,
233 | .leaflet-control {
234 | cursor: auto;
235 | }
236 | .leaflet-dragging .leaflet-grab,
237 | .leaflet-dragging .leaflet-grab .leaflet-interactive,
238 | .leaflet-dragging .leaflet-marker-draggable {
239 | cursor: move;
240 | cursor: -webkit-grabbing;
241 | cursor: -moz-grabbing;
242 | cursor: grabbing;
243 | }
244 |
245 | /* marker & overlays interactivity
246 | 标记&覆盖的交互性*/
247 | .leaflet-marker-icon,
248 | .leaflet-marker-shadow,
249 | .leaflet-image-layer,
250 | .leaflet-pane > svg path,
251 | .leaflet-tile-container {
252 | pointer-events: none;
253 | }
254 |
255 | .leaflet-marker-icon.leaflet-interactive,
256 | .leaflet-image-layer.leaflet-interactive,
257 | .leaflet-pane > svg path.leaflet-interactive,
258 | svg.leaflet-image-layer.leaflet-interactive path {
259 | pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
260 | pointer-events: auto;
261 | }
262 |
263 | /* visual tweaks视觉调整 */
264 |
265 | .leaflet-container {
266 | background: #ddd;
267 | outline: 0;
268 | }
269 | .leaflet-container a {
270 | color: #0078A8;
271 | }
272 | .leaflet-container a.leaflet-active {
273 | outline: 2px solid orange;
274 | }
275 | .leaflet-zoom-box {
276 | border: 2px dotted #38f;
277 | background: rgba(255,255,255,0.5);
278 | }
279 |
280 |
281 | /* general typography 一般的排版*/
282 | .leaflet-container {
283 | font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
284 | }
285 |
286 |
287 | /* general toolbar styles 一般的工具条样式 */
288 |
289 | .leaflet-bar {
290 | box-shadow: 0 1px 5px rgba(0,0,0,0.65);
291 | border-radius: 4px;
292 | }
293 | .leaflet-bar a,
294 | .leaflet-bar a:hover {
295 | background-color: #fff;
296 | border-bottom: 1px solid #ccc;
297 | width: 26px;
298 | height: 26px;
299 | line-height: 26px;
300 | display: block;
301 | text-align: center;
302 | text-decoration: none;
303 | color: black;
304 | }
305 | .leaflet-bar a,
306 | .leaflet-control-layers-toggle {
307 | background-position: 50% 50%;
308 | background-repeat: no-repeat;
309 | display: block;
310 | }
311 | .leaflet-bar a:hover {
312 | background-color: #f4f4f4;
313 | }
314 | .leaflet-bar a:first-child {
315 | border-top-left-radius: 4px;
316 | border-top-right-radius: 4px;
317 | }
318 | .leaflet-bar a:last-child {
319 | border-bottom-left-radius: 4px;
320 | border-bottom-right-radius: 4px;
321 | border-bottom: none;
322 | }
323 | .leaflet-bar a.leaflet-disabled {
324 | cursor: default;
325 | background-color: #f4f4f4;
326 | color: #bbb;
327 | }
328 |
329 | .leaflet-touch .leaflet-bar a {
330 | width: 30px;
331 | height: 30px;
332 | line-height: 30px;
333 | }
334 | .leaflet-touch .leaflet-bar a:first-child {
335 | border-top-left-radius: 2px;
336 | border-top-right-radius: 2px;
337 | }
338 | .leaflet-touch .leaflet-bar a:last-child {
339 | border-bottom-left-radius: 2px;
340 | border-bottom-right-radius: 2px;
341 | }
342 |
343 | /* zoom control 缩放控件*/
344 |
345 | .leaflet-control-zoom-in,
346 | .leaflet-control-zoom-out {
347 | font: bold 18px 'Lucida Console', Monaco, monospace;
348 | text-indent: 1px;
349 | }
350 |
351 | .leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
352 | font-size: 22px;
353 | }
354 |
355 |
356 | /* layers control 图层控件*/
357 |
358 | .leaflet-control-layers {
359 | box-shadow: 0 1px 5px rgba(0,0,0,0.4);
360 | background: #fff;
361 | border-radius: 5px;
362 | }
363 | .leaflet-control-layers-toggle {
364 | background-image: url(images/layers.png);
365 | width: 36px;
366 | height: 36px;
367 | }
368 | .leaflet-retina .leaflet-control-layers-toggle {
369 | background-image: url(images/layers-2x.png);
370 | background-size: 26px 26px;
371 | }
372 | .leaflet-touch .leaflet-control-layers-toggle {
373 | width: 44px;
374 | height: 44px;
375 | }
376 | .leaflet-control-layers .leaflet-control-layers-list,
377 | .leaflet-control-layers-expanded .leaflet-control-layers-toggle {
378 | display: none;
379 | }
380 | .leaflet-control-layers-expanded .leaflet-control-layers-list {
381 | display: block;
382 | position: relative;
383 | }
384 | .leaflet-control-layers-expanded {
385 | padding: 6px 10px 6px 6px;
386 | color: #333;
387 | background: #fff;
388 | }
389 | .leaflet-control-layers-scrollbar {
390 | overflow-y: scroll;
391 | overflow-x: hidden;
392 | padding-right: 5px;
393 | }
394 | .leaflet-control-layers-selector {
395 | margin-top: 2px;
396 | position: relative;
397 | top: 1px;
398 | }
399 | .leaflet-control-layers label {
400 | display: block;
401 | }
402 | .leaflet-control-layers-separator {
403 | height: 0;
404 | border-top: 1px solid #ddd;
405 | margin: 5px -10px 5px -6px;
406 | }
407 |
408 | /* Default icon URLs 默认的icon url */
409 | .leaflet-default-icon-path {
410 | background-image: url(images/marker-icon.png);
411 | }
412 |
413 |
414 | /* attribution and scale controls 归因和比例尺控件*/
415 |
416 | .leaflet-container .leaflet-control-attribution {
417 | background: #fff;
418 | background: rgba(255, 255, 255, 0.7);
419 | margin: 0;
420 | }
421 | .leaflet-control-attribution,
422 | .leaflet-control-scale-line {
423 | padding: 0 5px;
424 | color: #333;
425 | }
426 | .leaflet-control-attribution a {
427 | text-decoration: none;
428 | }
429 | .leaflet-control-attribution a:hover {
430 | text-decoration: underline;
431 | }
432 | .leaflet-container .leaflet-control-attribution,
433 | .leaflet-container .leaflet-control-scale {
434 | font-size: 11px;
435 | }
436 | .leaflet-left .leaflet-control-scale {
437 | margin-left: 5px;
438 | }
439 | .leaflet-bottom .leaflet-control-scale {
440 | margin-bottom: 5px;
441 | }
442 | .leaflet-control-scale-line {
443 | border: 2px solid #777;
444 | border-top: none;
445 | line-height: 1.1;
446 | padding: 2px 5px 1px;
447 | font-size: 11px;
448 | white-space: nowrap;
449 | overflow: hidden;
450 | -moz-box-sizing: border-box;
451 | box-sizing: border-box;
452 |
453 | background: #fff;
454 | background: rgba(255, 255, 255, 0.5);
455 | }
456 | .leaflet-control-scale-line:not(:first-child) {
457 | border-top: 2px solid #777;
458 | border-bottom: none;
459 | margin-top: -2px;
460 | }
461 | .leaflet-control-scale-line:not(:first-child):not(:last-child) {
462 | border-bottom: 2px solid #777;
463 | }
464 |
465 | .leaflet-touch .leaflet-control-attribution,
466 | .leaflet-touch .leaflet-control-layers,
467 | .leaflet-touch .leaflet-bar {
468 | box-shadow: none;
469 | }
470 | .leaflet-touch .leaflet-control-layers,
471 | .leaflet-touch .leaflet-bar {
472 | border: 2px solid rgba(0,0,0,0.2);
473 | background-clip: padding-box;
474 | }
475 |
476 |
477 | /* popup 弹窗 */
478 |
479 | .leaflet-popup {
480 | position: absolute;
481 | text-align: center;
482 | margin-bottom: 20px;
483 | }
484 | .leaflet-popup-content-wrapper {
485 | padding: 1px;
486 | text-align: left;
487 | border-radius: 12px;
488 | }
489 | .leaflet-popup-content {
490 | margin: 13px 19px;
491 | line-height: 1.4;
492 | }
493 | .leaflet-popup-content p {
494 | margin: 18px 0;
495 | }
496 | .leaflet-popup-tip-container {
497 | width: 40px;
498 | height: 20px;
499 | position: absolute;
500 | left: 50%;
501 | margin-left: -20px;
502 | overflow: hidden;
503 | pointer-events: none;
504 | }
505 | .leaflet-popup-tip {
506 | width: 17px;
507 | height: 17px;
508 | padding: 1px;
509 |
510 | margin: -10px auto 0;
511 |
512 | -webkit-transform: rotate(45deg);
513 | -moz-transform: rotate(45deg);
514 | -ms-transform: rotate(45deg);
515 | transform: rotate(45deg);
516 | }
517 | .leaflet-popup-content-wrapper,
518 | .leaflet-popup-tip {
519 | background: white;
520 | color: #333;
521 | box-shadow: 0 3px 14px rgba(0,0,0,0.4);
522 | }
523 | .leaflet-container a.leaflet-popup-close-button {
524 | position: absolute;
525 | top: 0;
526 | right: 0;
527 | padding: 4px 4px 0 0;
528 | border: none;
529 | text-align: center;
530 | width: 18px;
531 | height: 14px;
532 | font: 16px/14px Tahoma, Verdana, sans-serif;
533 | color: #c3c3c3;
534 | text-decoration: none;
535 | font-weight: bold;
536 | background: transparent;
537 | }
538 | .leaflet-container a.leaflet-popup-close-button:hover {
539 | color: #999;
540 | }
541 | .leaflet-popup-scrolled {
542 | overflow: auto;
543 | border-bottom: 1px solid #ddd;
544 | border-top: 1px solid #ddd;
545 | }
546 |
547 | .leaflet-oldie .leaflet-popup-content-wrapper {
548 | -ms-zoom: 1;
549 | }
550 | .leaflet-oldie .leaflet-popup-tip {
551 | width: 24px;
552 | margin: 0 auto;
553 |
554 | -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
555 | filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
556 | }
557 | .leaflet-oldie .leaflet-popup-tip-container {
558 | margin-top: -1px;
559 | }
560 |
561 | .leaflet-oldie .leaflet-control-zoom,
562 | .leaflet-oldie .leaflet-control-layers,
563 | .leaflet-oldie .leaflet-popup-content-wrapper,
564 | .leaflet-oldie .leaflet-popup-tip {
565 | border: 1px solid #999;
566 | }
567 |
568 |
569 | /* div icon div icon*/
570 |
571 | .leaflet-div-icon {
572 | background: #fff;
573 | border: 1px solid #666;
574 | }
575 |
576 |
577 | /* Tooltip */
578 | /* Base styles for the element that has a tooltip 具有工具提示的元素的基本样式 */
579 | .leaflet-tooltip {
580 | position: absolute;
581 | padding: 6px;
582 | background-color: #fff;
583 | border: 1px solid #fff;
584 | border-radius: 3px;
585 | color: #222;
586 | white-space: nowrap;
587 | -webkit-user-select: none;
588 | -moz-user-select: none;
589 | -ms-user-select: none;
590 | user-select: none;
591 | pointer-events: none;
592 | box-shadow: 0 1px 3px rgba(0,0,0,0.4);
593 | }
594 | .leaflet-tooltip.leaflet-clickable {
595 | cursor: pointer;
596 | pointer-events: auto;
597 | }
598 | .leaflet-tooltip-top:before,
599 | .leaflet-tooltip-bottom:before,
600 | .leaflet-tooltip-left:before,
601 | .leaflet-tooltip-right:before {
602 | position: absolute;
603 | pointer-events: none;
604 | border: 6px solid transparent;
605 | background: transparent;
606 | content: "";
607 | }
608 |
609 | /* Directions 方向*/
610 |
611 | .leaflet-tooltip-bottom {
612 | margin-top: 6px;
613 | }
614 | .leaflet-tooltip-top {
615 | margin-top: -6px;
616 | }
617 | .leaflet-tooltip-bottom:before,
618 | .leaflet-tooltip-top:before {
619 | left: 50%;
620 | margin-left: -6px;
621 | }
622 | .leaflet-tooltip-top:before {
623 | bottom: 0;
624 | margin-bottom: -12px;
625 | border-top-color: #fff;
626 | }
627 | .leaflet-tooltip-bottom:before {
628 | top: 0;
629 | margin-top: -12px;
630 | margin-left: -6px;
631 | border-bottom-color: #fff;
632 | }
633 | .leaflet-tooltip-left {
634 | margin-left: -6px;
635 | }
636 | .leaflet-tooltip-right {
637 | margin-left: 6px;
638 | }
639 | .leaflet-tooltip-left:before,
640 | .leaflet-tooltip-right:before {
641 | top: 50%;
642 | margin-top: -6px;
643 | }
644 | .leaflet-tooltip-left:before {
645 | right: 0;
646 | margin-right: -12px;
647 | border-left-color: #fff;
648 | }
649 | .leaflet-tooltip-right:before {
650 | left: 0;
651 | margin-left: -12px;
652 | border-right-color: #fff;
653 | }
654 |
--------------------------------------------------------------------------------
/templates/attr_feature.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |