diff --git a/ajax/libs/leaflet.draw/0.2.3/images/spritesheet-2x.png b/ajax/libs/leaflet.draw/0.2.3/images/spritesheet-2x.png new file mode 100644 index 000000000..1525c9f69 Binary files /dev/null and b/ajax/libs/leaflet.draw/0.2.3/images/spritesheet-2x.png differ diff --git a/ajax/libs/leaflet.draw/0.2.3/images/spritesheet.png b/ajax/libs/leaflet.draw/0.2.3/images/spritesheet.png new file mode 100644 index 000000000..f7035a1cb Binary files /dev/null and b/ajax/libs/leaflet.draw/0.2.3/images/spritesheet.png differ diff --git a/ajax/libs/leaflet.draw/0.2.3/leaflet.draw-src.js b/ajax/libs/leaflet.draw/0.2.3/leaflet.draw-src.js new file mode 100644 index 000000000..c31c2b7cb --- /dev/null +++ b/ajax/libs/leaflet.draw/0.2.3/leaflet.draw-src.js @@ -0,0 +1,2870 @@ +/* + Leaflet.draw, a plugin that adds drawing and editing tools to Leaflet powered maps. + (c) 2012-2013, Jacob Toye, Smartrak + + https://github.com/Leaflet/Leaflet.draw + http://leafletjs.com + https://github.com/jacobtoye +*/ +(function (window, document, undefined) {/* + * Leaflet.draw assumes that you have already included the Leaflet library. + */ + +L.drawVersion = '0.2.3'; + +L.drawLocal = { + draw: { + toolbar: { + actions: { + title: 'Cancel drawing', + text: 'Cancel' + }, + undo: { + title: 'Delete last point drawn', + text: 'Delete last point' + }, + buttons: { + polyline: 'Draw a polyline', + polygon: 'Draw a polygon', + rectangle: 'Draw a rectangle', + circle: 'Draw a circle', + marker: 'Draw a marker' + } + }, + handlers: { + circle: { + tooltip: { + start: 'Click and drag to draw circle.' + } + }, + marker: { + tooltip: { + start: 'Click map to place marker.' + } + }, + polygon: { + tooltip: { + start: 'Click to start drawing shape.', + cont: 'Click to continue drawing shape.', + end: 'Click first point to close this shape.' + } + }, + polyline: { + error: 'Error: shape edges cannot cross!', + tooltip: { + start: 'Click to start drawing line.', + cont: 'Click to continue drawing line.', + end: 'Click last point to finish line.' + } + }, + rectangle: { + tooltip: { + start: 'Click and drag to draw rectangle.' + } + }, + simpleshape: { + tooltip: { + end: 'Release mouse to finish drawing.' + } + } + } + }, + edit: { + toolbar: { + actions: { + save: { + title: 'Save changes.', + text: 'Save' + }, + cancel: { + title: 'Cancel editing, discards all changes.', + text: 'Cancel' + } + }, + buttons: { + edit: 'Edit layers.', + editDisabled: 'No layers to edit.', + remove: 'Delete layers.', + removeDisabled: 'No layers to delete.' + } + }, + handlers: { + edit: { + tooltip: { + text: 'Drag handles, or marker to edit feature.', + subtext: 'Click cancel to undo changes.' + } + }, + remove: { + tooltip: { + text: 'Click on a feature to remove' + } + } + } + } +}; + + +L.Draw = {}; + +L.Draw.Feature = L.Handler.extend({ + includes: L.Mixin.Events, + + initialize: function (map, options) { + this._map = map; + this._container = map._container; + this._overlayPane = map._panes.overlayPane; + this._popupPane = map._panes.popupPane; + + // Merge default shapeOptions options with custom shapeOptions + if (options && options.shapeOptions) { + options.shapeOptions = L.Util.extend({}, this.options.shapeOptions, options.shapeOptions); + } + L.setOptions(this, options); + }, + + enable: function () { + if (this._enabled) { return; } + + this.fire('enabled', { handler: this.type }); + + this._map.fire('draw:drawstart', { layerType: this.type }); + + L.Handler.prototype.enable.call(this); + }, + + disable: function () { + if (!this._enabled) { return; } + + L.Handler.prototype.disable.call(this); + + this._map.fire('draw:drawstop', { layerType: this.type }); + + this.fire('disabled', { handler: this.type }); + }, + + addHooks: function () { + var map = this._map; + + if (map) { + L.DomUtil.disableTextSelection(); + + map.getContainer().focus(); + + this._tooltip = new L.Tooltip(this._map); + + L.DomEvent.on(this._container, 'keyup', this._cancelDrawing, this); + } + }, + + removeHooks: function () { + if (this._map) { + L.DomUtil.enableTextSelection(); + + this._tooltip.dispose(); + this._tooltip = null; + + L.DomEvent.off(this._container, 'keyup', this._cancelDrawing, this); + } + }, + + setOptions: function (options) { + L.setOptions(this, options); + }, + + _fireCreatedEvent: function (layer) { + this._map.fire('draw:created', { layer: layer, layerType: this.type }); + }, + + // Cancel drawing when the escape key is pressed + _cancelDrawing: function (e) { + if (e.keyCode === 27) { + this.disable(); + } + } +}); + +L.Draw.Polyline = L.Draw.Feature.extend({ + statics: { + TYPE: 'polyline' + }, + + Poly: L.Polyline, + + options: { + allowIntersection: true, + repeatMode: false, + drawError: { + color: '#b00b00', + timeout: 2500 + }, + icon: new L.DivIcon({ + iconSize: new L.Point(8, 8), + className: 'leaflet-div-icon leaflet-editing-icon' + }), + guidelineDistance: 20, + maxGuideLineLength: 4000, + shapeOptions: { + stroke: true, + color: '#f06eaa', + weight: 4, + opacity: 0.5, + fill: false, + clickable: true + }, + metric: true, // Whether to use the metric meaurement system or imperial + showLength: true, // Whether to display distance in the tooltip + zIndexOffset: 2000 // This should be > than the highest z-index any map layers + }, + + initialize: function (map, options) { + // Need to set this here to ensure the correct message is used. + this.options.drawError.message = L.drawLocal.draw.handlers.polyline.error; + + // Merge default drawError options with custom options + if (options && options.drawError) { + options.drawError = L.Util.extend({}, this.options.drawError, options.drawError); + } + + // Save the type so super can fire, need to do this as cannot do this.TYPE :( + this.type = L.Draw.Polyline.TYPE; + + L.Draw.Feature.prototype.initialize.call(this, map, options); + }, + + addHooks: function () { + L.Draw.Feature.prototype.addHooks.call(this); + if (this._map) { + this._markers = []; + + this._markerGroup = new L.LayerGroup(); + this._map.addLayer(this._markerGroup); + + this._poly = new L.Polyline([], this.options.shapeOptions); + + this._tooltip.updateContent(this._getTooltipText()); + + // Make a transparent marker that will used to catch click events. These click + // events will create the vertices. We need to do this so we can ensure that + // we can create vertices over other map layers (markers, vector layers). We + // also do not want to trigger any click handlers of objects we are clicking on + // while drawing. + if (!this._mouseMarker) { + this._mouseMarker = L.marker(this._map.getCenter(), { + icon: L.divIcon({ + className: 'leaflet-mouse-marker', + iconAnchor: [20, 20], + iconSize: [40, 40] + }), + opacity: 0, + zIndexOffset: this.options.zIndexOffset + }); + } + + this._mouseMarker + .on('mousedown', this._onMouseDown, this) + .addTo(this._map); + + this._map + .on('mousemove', this._onMouseMove, this) + .on('mouseup', this._onMouseUp, this) + .on('zoomend', this._onZoomEnd, this); + } + }, + + removeHooks: function () { + L.Draw.Feature.prototype.removeHooks.call(this); + + this._clearHideErrorTimeout(); + + this._cleanUpShape(); + + // remove markers from map + this._map.removeLayer(this._markerGroup); + delete this._markerGroup; + delete this._markers; + + this._map.removeLayer(this._poly); + delete this._poly; + + this._mouseMarker + .off('mousedown', this._onMouseDown, this) + .off('mouseup', this._onMouseUp, this); + this._map.removeLayer(this._mouseMarker); + delete this._mouseMarker; + + // clean up DOM + this._clearGuides(); + + this._map + .off('mousemove', this._onMouseMove, this) + .off('zoomend', this._onZoomEnd, this); + }, + + deleteLastVertex: function () { + if (this._markers.length <= 1) { + return; + } + + var lastMarker = this._markers.pop(), + poly = this._poly, + latlng = this._poly.spliceLatLngs(poly.getLatLngs().length - 1, 1)[0]; + + this._markerGroup.removeLayer(lastMarker); + + if (poly.getLatLngs().length < 2) { + this._map.removeLayer(poly); + } + + this._vertexChanged(latlng, false); + }, + + addVertex: function (latlng) { + var markersLength = this._markers.length; + + if (markersLength > 0 && !this.options.allowIntersection && this._poly.newLatLngIntersects(latlng)) { + this._showErrorTooltip(); + return; + } + else if (this._errorShown) { + this._hideErrorTooltip(); + } + + this._markers.push(this._createMarker(latlng)); + + this._poly.addLatLng(latlng); + + if (this._poly.getLatLngs().length === 2) { + this._map.addLayer(this._poly); + } + + this._vertexChanged(latlng, true); + }, + + _finishShape: function () { + var intersects = this._poly.newLatLngIntersects(this._poly.getLatLngs()[0], true); + + if ((!this.options.allowIntersection && intersects) || !this._shapeIsValid()) { + this._showErrorTooltip(); + return; + } + + this._fireCreatedEvent(); + this.disable(); + if (this.options.repeatMode) { + this.enable(); + } + }, + + //Called to verify the shape is valid when the user tries to finish it + //Return false if the shape is not valid + _shapeIsValid: function () { + return true; + }, + + _onZoomEnd: function () { + this._updateGuide(); + }, + + _onMouseMove: function (e) { + var newPos = e.layerPoint, + latlng = e.latlng; + + // Save latlng + // should this be moved to _updateGuide() ? + this._currentLatLng = latlng; + + this._updateTooltip(latlng); + + // Update the guide line + this._updateGuide(newPos); + + // Update the mouse marker position + this._mouseMarker.setLatLng(latlng); + + L.DomEvent.preventDefault(e.originalEvent); + }, + + _vertexChanged: function (latlng, added) { + this._updateFinishHandler(); + + this._updateRunningMeasure(latlng, added); + + this._clearGuides(); + + this._updateTooltip(); + }, + + _onMouseDown: function (e) { + var originalEvent = e.originalEvent; + this._mouseDownOrigin = L.point(originalEvent.clientX, originalEvent.clientY); + }, + + _onMouseUp: function (e) { + if (this._mouseDownOrigin) { + // We detect clicks within a certain tolerance, otherwise let it + // be interpreted as a drag by the map + var distance = L.point(e.originalEvent.clientX, e.originalEvent.clientY) + .distanceTo(this._mouseDownOrigin); + if (Math.abs(distance) < 9 * (window.devicePixelRatio || 1)) { + this.addVertex(e.latlng); + } + } + this._mouseDownOrigin = null; + }, + + _updateFinishHandler: function () { + var markerCount = this._markers.length; + // The last marker should have a click handler to close the polyline + if (markerCount > 1) { + this._markers[markerCount - 1].on('click', this._finishShape, this); + } + + // Remove the old marker click handler (as only the last point should close the polyline) + if (markerCount > 2) { + this._markers[markerCount - 2].off('click', this._finishShape, this); + } + }, + + _createMarker: function (latlng) { + var marker = new L.Marker(latlng, { + icon: this.options.icon, + zIndexOffset: this.options.zIndexOffset * 2 + }); + + this._markerGroup.addLayer(marker); + + return marker; + }, + + _updateGuide: function (newPos) { + var markerCount = this._markers.length; + + if (markerCount > 0) { + newPos = newPos || this._map.latLngToLayerPoint(this._currentLatLng); + + // draw the guide line + this._clearGuides(); + this._drawGuide( + this._map.latLngToLayerPoint(this._markers[markerCount - 1].getLatLng()), + newPos + ); + } + }, + + _updateTooltip: function (latLng) { + var text = this._getTooltipText(); + + if (latLng) { + this._tooltip.updatePosition(latLng); + } + + if (!this._errorShown) { + this._tooltip.updateContent(text); + } + }, + + _drawGuide: function (pointA, pointB) { + var length = Math.floor(Math.sqrt(Math.pow((pointB.x - pointA.x), 2) + Math.pow((pointB.y - pointA.y), 2))), + guidelineDistance = this.options.guidelineDistance, + maxGuideLineLength = this.options.maxGuideLineLength, + // Only draw a guideline with a max length + i = length > maxGuideLineLength ? length - maxGuideLineLength : guidelineDistance, + fraction, + dashPoint, + dash; + + //create the guides container if we haven't yet + if (!this._guidesContainer) { + this._guidesContainer = L.DomUtil.create('div', 'leaflet-draw-guides', this._overlayPane); + } + + //draw a dash every GuildeLineDistance + for (; i < length; i += this.options.guidelineDistance) { + //work out fraction along line we are + fraction = i / length; + + //calculate new x,y point + dashPoint = { + x: Math.floor((pointA.x * (1 - fraction)) + (fraction * pointB.x)), + y: Math.floor((pointA.y * (1 - fraction)) + (fraction * pointB.y)) + }; + + //add guide dash to guide container + dash = L.DomUtil.create('div', 'leaflet-draw-guide-dash', this._guidesContainer); + dash.style.backgroundColor = + !this._errorShown ? this.options.shapeOptions.color : this.options.drawError.color; + + L.DomUtil.setPosition(dash, dashPoint); + } + }, + + _updateGuideColor: function (color) { + if (this._guidesContainer) { + for (var i = 0, l = this._guidesContainer.childNodes.length; i < l; i++) { + this._guidesContainer.childNodes[i].style.backgroundColor = color; + } + } + }, + + // removes all child elements (guide dashes) from the guides container + _clearGuides: function () { + if (this._guidesContainer) { + while (this._guidesContainer.firstChild) { + this._guidesContainer.removeChild(this._guidesContainer.firstChild); + } + } + }, + + _getTooltipText: function () { + var showLength = this.options.showLength, + labelText, distanceStr; + + if (this._markers.length === 0) { + labelText = { + text: L.drawLocal.draw.handlers.polyline.tooltip.start + }; + } else { + distanceStr = showLength ? this._getMeasurementString() : ''; + + if (this._markers.length === 1) { + labelText = { + text: L.drawLocal.draw.handlers.polyline.tooltip.cont, + subtext: distanceStr + }; + } else { + labelText = { + text: L.drawLocal.draw.handlers.polyline.tooltip.end, + subtext: distanceStr + }; + } + } + return labelText; + }, + + _updateRunningMeasure: function (latlng, added) { + var markersLength = this._markers.length, + previousMarkerIndex, distance; + + if (this._markers.length === 1) { + this._measurementRunningTotal = 0; + } else { + previousMarkerIndex = markersLength - (added ? 2 : 1); + distance = latlng.distanceTo(this._markers[previousMarkerIndex].getLatLng()); + + this._measurementRunningTotal += distance * (added ? 1 : -1); + } + }, + + _getMeasurementString: function () { + var currentLatLng = this._currentLatLng, + previousLatLng = this._markers[this._markers.length - 1].getLatLng(), + distance; + + // calculate the distance from the last fixed point to the mouse position + distance = this._measurementRunningTotal + currentLatLng.distanceTo(previousLatLng); + + return L.GeometryUtil.readableDistance(distance, this.options.metric); + }, + + _showErrorTooltip: function () { + this._errorShown = true; + + // Update tooltip + this._tooltip + .showAsError() + .updateContent({ text: this.options.drawError.message }); + + // Update shape + this._updateGuideColor(this.options.drawError.color); + this._poly.setStyle({ color: this.options.drawError.color }); + + // Hide the error after 2 seconds + this._clearHideErrorTimeout(); + this._hideErrorTimeout = setTimeout(L.Util.bind(this._hideErrorTooltip, this), this.options.drawError.timeout); + }, + + _hideErrorTooltip: function () { + this._errorShown = false; + + this._clearHideErrorTimeout(); + + // Revert tooltip + this._tooltip + .removeError() + .updateContent(this._getTooltipText()); + + // Revert shape + this._updateGuideColor(this.options.shapeOptions.color); + this._poly.setStyle({ color: this.options.shapeOptions.color }); + }, + + _clearHideErrorTimeout: function () { + if (this._hideErrorTimeout) { + clearTimeout(this._hideErrorTimeout); + this._hideErrorTimeout = null; + } + }, + + _cleanUpShape: function () { + if (this._markers.length > 1) { + this._markers[this._markers.length - 1].off('click', this._finishShape, this); + } + }, + + _fireCreatedEvent: function () { + var poly = new this.Poly(this._poly.getLatLngs(), this.options.shapeOptions); + L.Draw.Feature.prototype._fireCreatedEvent.call(this, poly); + } +}); + + +L.Draw.Polygon = L.Draw.Polyline.extend({ + statics: { + TYPE: 'polygon' + }, + + Poly: L.Polygon, + + options: { + showArea: false, + shapeOptions: { + stroke: true, + color: '#f06eaa', + weight: 4, + opacity: 0.5, + fill: true, + fillColor: null, //same as color by default + fillOpacity: 0.2, + clickable: true + } + }, + + initialize: function (map, options) { + L.Draw.Polyline.prototype.initialize.call(this, map, options); + + // Save the type so super can fire, need to do this as cannot do this.TYPE :( + this.type = L.Draw.Polygon.TYPE; + }, + + _updateFinishHandler: function () { + var markerCount = this._markers.length; + + // The first marker should have a click handler to close the polygon + if (markerCount === 1) { + this._markers[0].on('click', this._finishShape, this); + } + + // Add and update the double click handler + if (markerCount > 2) { + this._markers[markerCount - 1].on('dblclick', this._finishShape, this); + // Only need to remove handler if has been added before + if (markerCount > 3) { + this._markers[markerCount - 2].off('dblclick', this._finishShape, this); + } + } + }, + + _getTooltipText: function () { + var text, subtext; + + if (this._markers.length === 0) { + text = L.drawLocal.draw.handlers.polygon.tooltip.start; + } else if (this._markers.length < 3) { + text = L.drawLocal.draw.handlers.polygon.tooltip.cont; + } else { + text = L.drawLocal.draw.handlers.polygon.tooltip.end; + subtext = this._getMeasurementString(); + } + + return { + text: text, + subtext: subtext + }; + }, + + _getMeasurementString: function () { + var area = this._area; + + if (!area) { + return null; + } + + return L.GeometryUtil.readableArea(area, this.options.metric); + }, + + _shapeIsValid: function () { + return this._markers.length >= 3; + }, + + _vertexAdded: function () { + // Check to see if we should show the area + if (this.options.allowIntersection || !this.options.showArea) { + return; + } + + var latLngs = this._poly.getLatLngs(); + + this._area = L.GeometryUtil.geodesicArea(latLngs); + }, + + _cleanUpShape: function () { + var markerCount = this._markers.length; + + if (markerCount > 0) { + this._markers[0].off('click', this._finishShape, this); + + if (markerCount > 2) { + this._markers[markerCount - 1].off('dblclick', this._finishShape, this); + } + } + } +}); + + +L.SimpleShape = {}; + +L.Draw.SimpleShape = L.Draw.Feature.extend({ + options: { + repeatMode: false + }, + + initialize: function (map, options) { + this._endLabelText = L.drawLocal.draw.handlers.simpleshape.tooltip.end; + + L.Draw.Feature.prototype.initialize.call(this, map, options); + }, + + addHooks: function () { + L.Draw.Feature.prototype.addHooks.call(this); + if (this._map) { + this._mapDraggable = this._map.dragging.enabled(); + + if (this._mapDraggable) { + this._map.dragging.disable(); + } + + //TODO refactor: move cursor to styles + this._container.style.cursor = 'crosshair'; + + this._tooltip.updateContent({ text: this._initialLabelText }); + + this._map + .on('mousedown', this._onMouseDown, this) + .on('mousemove', this._onMouseMove, this); + } + }, + + removeHooks: function () { + L.Draw.Feature.prototype.removeHooks.call(this); + if (this._map) { + if (this._mapDraggable) { + this._map.dragging.enable(); + } + + //TODO refactor: move cursor to styles + this._container.style.cursor = ''; + + this._map + .off('mousedown', this._onMouseDown, this) + .off('mousemove', this._onMouseMove, this); + + L.DomEvent.off(document, 'mouseup', this._onMouseUp, this); + + // If the box element doesn't exist they must not have moved the mouse, so don't need to destroy/return + if (this._shape) { + this._map.removeLayer(this._shape); + delete this._shape; + } + } + this._isDrawing = false; + }, + + _onMouseDown: function (e) { + this._isDrawing = true; + this._startLatLng = e.latlng; + + L.DomEvent + .on(document, 'mouseup', this._onMouseUp, this) + .preventDefault(e.originalEvent); + }, + + _onMouseMove: function (e) { + var latlng = e.latlng; + + this._tooltip.updatePosition(latlng); + if (this._isDrawing) { + this._tooltip.updateContent({ text: this._endLabelText }); + this._drawShape(latlng); + } + }, + + _onMouseUp: function () { + if (this._shape) { + this._fireCreatedEvent(); + } + + this.disable(); + if (this.options.repeatMode) { + this.enable(); + } + } +}); + +L.Draw.Rectangle = L.Draw.SimpleShape.extend({ + statics: { + TYPE: 'rectangle' + }, + + options: { + shapeOptions: { + stroke: true, + color: '#f06eaa', + weight: 4, + opacity: 0.5, + fill: true, + fillColor: null, //same as color by default + fillOpacity: 0.2, + clickable: true + } + }, + + initialize: function (map, options) { + // Save the type so super can fire, need to do this as cannot do this.TYPE :( + this.type = L.Draw.Rectangle.TYPE; + + this._initialLabelText = L.drawLocal.draw.handlers.rectangle.tooltip.start; + + L.Draw.SimpleShape.prototype.initialize.call(this, map, options); + }, + + _drawShape: function (latlng) { + if (!this._shape) { + this._shape = new L.Rectangle(new L.LatLngBounds(this._startLatLng, latlng), this.options.shapeOptions); + this._map.addLayer(this._shape); + } else { + this._shape.setBounds(new L.LatLngBounds(this._startLatLng, latlng)); + } + }, + + _fireCreatedEvent: function () { + var rectangle = new L.Rectangle(this._shape.getBounds(), this.options.shapeOptions); + L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this, rectangle); + } +}); + + +L.Draw.Circle = L.Draw.SimpleShape.extend({ + statics: { + TYPE: 'circle' + }, + + options: { + shapeOptions: { + stroke: true, + color: '#f06eaa', + weight: 4, + opacity: 0.5, + fill: true, + fillColor: null, //same as color by default + fillOpacity: 0.2, + clickable: true + }, + showRadius: true, + metric: true // Whether to use the metric meaurement system or imperial + }, + + initialize: function (map, options) { + // Save the type so super can fire, need to do this as cannot do this.TYPE :( + this.type = L.Draw.Circle.TYPE; + + this._initialLabelText = L.drawLocal.draw.handlers.circle.tooltip.start; + + L.Draw.SimpleShape.prototype.initialize.call(this, map, options); + }, + + _drawShape: function (latlng) { + if (!this._shape) { + this._shape = new L.Circle(this._startLatLng, this._startLatLng.distanceTo(latlng), this.options.shapeOptions); + this._map.addLayer(this._shape); + } else { + this._shape.setRadius(this._startLatLng.distanceTo(latlng)); + } + }, + + _fireCreatedEvent: function () { + var circle = new L.Circle(this._startLatLng, this._shape.getRadius(), this.options.shapeOptions); + L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this, circle); + }, + + _onMouseMove: function (e) { + var latlng = e.latlng, + showRadius = this.options.showRadius, + useMetric = this.options.metric, + radius; + + this._tooltip.updatePosition(latlng); + if (this._isDrawing) { + this._drawShape(latlng); + + // Get the new radius (rounded to 1 dp) + radius = this._shape.getRadius().toFixed(1); + + this._tooltip.updateContent({ + text: this._endLabelText, + subtext: showRadius ? 'Radius: ' + L.GeometryUtil.readableDistance(radius, useMetric) : '' + }); + } + } +}); + + +L.Draw.Marker = L.Draw.Feature.extend({ + statics: { + TYPE: 'marker' + }, + + options: { + icon: new L.Icon.Default(), + repeatMode: false, + zIndexOffset: 2000 // This should be > than the highest z-index any markers + }, + + initialize: function (map, options) { + // Save the type so super can fire, need to do this as cannot do this.TYPE :( + this.type = L.Draw.Marker.TYPE; + + L.Draw.Feature.prototype.initialize.call(this, map, options); + }, + + addHooks: function () { + L.Draw.Feature.prototype.addHooks.call(this); + + if (this._map) { + this._tooltip.updateContent({ text: L.drawLocal.draw.handlers.marker.tooltip.start }); + + // Same mouseMarker as in Draw.Polyline + if (!this._mouseMarker) { + this._mouseMarker = L.marker(this._map.getCenter(), { + icon: L.divIcon({ + className: 'leaflet-mouse-marker', + iconAnchor: [20, 20], + iconSize: [40, 40] + }), + opacity: 0, + zIndexOffset: this.options.zIndexOffset + }); + } + + this._mouseMarker + .on('click', this._onClick, this) + .addTo(this._map); + + this._map.on('mousemove', this._onMouseMove, this); + } + }, + + removeHooks: function () { + L.Draw.Feature.prototype.removeHooks.call(this); + + if (this._map) { + if (this._marker) { + this._marker.off('click', this._onClick, this); + this._map + .off('click', this._onClick, this) + .removeLayer(this._marker); + delete this._marker; + } + + this._mouseMarker.off('click', this._onClick, this); + this._map.removeLayer(this._mouseMarker); + delete this._mouseMarker; + + this._map.off('mousemove', this._onMouseMove, this); + } + }, + + _onMouseMove: function (e) { + var latlng = e.latlng; + + this._tooltip.updatePosition(latlng); + this._mouseMarker.setLatLng(latlng); + + if (!this._marker) { + this._marker = new L.Marker(latlng, { + icon: this.options.icon, + zIndexOffset: this.options.zIndexOffset + }); + // Bind to both marker and map to make sure we get the click event. + this._marker.on('click', this._onClick, this); + this._map + .on('click', this._onClick, this) + .addLayer(this._marker); + } + else { + latlng = this._mouseMarker.getLatLng(); + this._marker.setLatLng(latlng); + } + }, + + _onClick: function () { + this._fireCreatedEvent(); + + this.disable(); + if (this.options.repeatMode) { + this.enable(); + } + }, + + _fireCreatedEvent: function () { + var marker = new L.Marker(this._marker.getLatLng(), { icon: this.options.icon }); + L.Draw.Feature.prototype._fireCreatedEvent.call(this, marker); + } +}); + + +L.Edit = L.Edit || {}; + +/* + * L.Edit.Poly is an editing handler for polylines and polygons. + */ + +L.Edit.Poly = L.Handler.extend({ + options: { + icon: new L.DivIcon({ + iconSize: new L.Point(8, 8), + className: 'leaflet-div-icon leaflet-editing-icon' + }) + }, + + initialize: function (poly, options) { + this._poly = poly; + L.setOptions(this, options); + }, + + addHooks: function () { + if (this._poly._map) { + if (!this._markerGroup) { + this._initMarkers(); + } + this._poly._map.addLayer(this._markerGroup); + } + }, + + removeHooks: function () { + if (this._poly._map) { + this._poly._map.removeLayer(this._markerGroup); + delete this._markerGroup; + delete this._markers; + } + }, + + updateMarkers: function () { + this._markerGroup.clearLayers(); + this._initMarkers(); + }, + + _initMarkers: function () { + if (!this._markerGroup) { + this._markerGroup = new L.LayerGroup(); + } + this._markers = []; + + var latlngs = this._poly._latlngs, + i, j, len, marker; + + // TODO refactor holes implementation in Polygon to support it here + + for (i = 0, len = latlngs.length; i < len; i++) { + + marker = this._createMarker(latlngs[i], i); + marker.on('click', this._onMarkerClick, this); + this._markers.push(marker); + } + + var markerLeft, markerRight; + + for (i = 0, j = len - 1; i < len; j = i++) { + if (i === 0 && !(L.Polygon && (this._poly instanceof L.Polygon))) { + continue; + } + + markerLeft = this._markers[j]; + markerRight = this._markers[i]; + + this._createMiddleMarker(markerLeft, markerRight); + this._updatePrevNext(markerLeft, markerRight); + } + }, + + _createMarker: function (latlng, index) { + var marker = new L.Marker(latlng, { + draggable: true, + icon: this.options.icon + }); + + marker._origLatLng = latlng; + marker._index = index; + + marker.on('drag', this._onMarkerDrag, this); + marker.on('dragend', this._fireEdit, this); + + this._markerGroup.addLayer(marker); + + return marker; + }, + + _removeMarker: function (marker) { + var i = marker._index; + + this._markerGroup.removeLayer(marker); + this._markers.splice(i, 1); + this._poly.spliceLatLngs(i, 1); + this._updateIndexes(i, -1); + + marker + .off('drag', this._onMarkerDrag, this) + .off('dragend', this._fireEdit, this) + .off('click', this._onMarkerClick, this); + }, + + _fireEdit: function () { + this._poly.edited = true; + this._poly.fire('edit'); + }, + + _onMarkerDrag: function (e) { + var marker = e.target; + + L.extend(marker._origLatLng, marker._latlng); + + if (marker._middleLeft) { + marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker)); + } + if (marker._middleRight) { + marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next)); + } + + this._poly.redraw(); + }, + + _onMarkerClick: function (e) { + var minPoints = L.Polygon && (this._poly instanceof L.Polygon) ? 4 : 3, + marker = e.target; + + // If removing this point would create an invalid polyline/polygon don't remove + if (this._poly._latlngs.length < minPoints) { + return; + } + + // remove the marker + this._removeMarker(marker); + + // update prev/next links of adjacent markers + this._updatePrevNext(marker._prev, marker._next); + + // remove ghost markers near the removed marker + if (marker._middleLeft) { + this._markerGroup.removeLayer(marker._middleLeft); + } + if (marker._middleRight) { + this._markerGroup.removeLayer(marker._middleRight); + } + + // create a ghost marker in place of the removed one + if (marker._prev && marker._next) { + this._createMiddleMarker(marker._prev, marker._next); + + } else if (!marker._prev) { + marker._next._middleLeft = null; + + } else if (!marker._next) { + marker._prev._middleRight = null; + } + + this._fireEdit(); + }, + + _updateIndexes: function (index, delta) { + this._markerGroup.eachLayer(function (marker) { + if (marker._index > index) { + marker._index += delta; + } + }); + }, + + _createMiddleMarker: function (marker1, marker2) { + var latlng = this._getMiddleLatLng(marker1, marker2), + marker = this._createMarker(latlng), + onClick, + onDragStart, + onDragEnd; + + marker.setOpacity(0.6); + + marker1._middleRight = marker2._middleLeft = marker; + + onDragStart = function () { + var i = marker2._index; + + marker._index = i; + + marker + .off('click', onClick, this) + .on('click', this._onMarkerClick, this); + + latlng.lat = marker.getLatLng().lat; + latlng.lng = marker.getLatLng().lng; + this._poly.spliceLatLngs(i, 0, latlng); + this._markers.splice(i, 0, marker); + + marker.setOpacity(1); + + this._updateIndexes(i, 1); + marker2._index++; + this._updatePrevNext(marker1, marker); + this._updatePrevNext(marker, marker2); + + this._poly.fire('editstart'); + }; + + onDragEnd = function () { + marker.off('dragstart', onDragStart, this); + marker.off('dragend', onDragEnd, this); + + this._createMiddleMarker(marker1, marker); + this._createMiddleMarker(marker, marker2); + }; + + onClick = function () { + onDragStart.call(this); + onDragEnd.call(this); + this._fireEdit(); + }; + + marker + .on('click', onClick, this) + .on('dragstart', onDragStart, this) + .on('dragend', onDragEnd, this); + + this._markerGroup.addLayer(marker); + }, + + _updatePrevNext: function (marker1, marker2) { + if (marker1) { + marker1._next = marker2; + } + if (marker2) { + marker2._prev = marker1; + } + }, + + _getMiddleLatLng: function (marker1, marker2) { + var map = this._poly._map, + p1 = map.project(marker1.getLatLng()), + p2 = map.project(marker2.getLatLng()); + + return map.unproject(p1._add(p2)._divideBy(2)); + } +}); + +L.Polyline.addInitHook(function () { + + // Check to see if handler has already been initialized. This is to support versions of Leaflet that still have L.Handler.PolyEdit + if (this.editing) { + return; + } + + if (L.Edit.Poly) { + this.editing = new L.Edit.Poly(this); + + if (this.options.editable) { + this.editing.enable(); + } + } + + this.on('add', function () { + if (this.editing && this.editing.enabled()) { + this.editing.addHooks(); + } + }); + + this.on('remove', function () { + if (this.editing && this.editing.enabled()) { + this.editing.removeHooks(); + } + }); +}); + + +L.Edit = L.Edit || {}; + +L.Edit.SimpleShape = L.Handler.extend({ + options: { + moveIcon: new L.DivIcon({ + iconSize: new L.Point(8, 8), + className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-move' + }), + resizeIcon: new L.DivIcon({ + iconSize: new L.Point(8, 8), + className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-resize' + }) + }, + + initialize: function (shape, options) { + this._shape = shape; + L.Util.setOptions(this, options); + }, + + addHooks: function () { + if (this._shape._map) { + this._map = this._shape._map; + + if (!this._markerGroup) { + this._initMarkers(); + } + this._map.addLayer(this._markerGroup); + } + }, + + removeHooks: function () { + if (this._shape._map) { + this._unbindMarker(this._moveMarker); + + for (var i = 0, l = this._resizeMarkers.length; i < l; i++) { + this._unbindMarker(this._resizeMarkers[i]); + } + this._resizeMarkers = null; + + this._map.removeLayer(this._markerGroup); + delete this._markerGroup; + } + + this._map = null; + }, + + updateMarkers: function () { + this._markerGroup.clearLayers(); + this._initMarkers(); + }, + + _initMarkers: function () { + if (!this._markerGroup) { + this._markerGroup = new L.LayerGroup(); + } + + // Create center marker + this._createMoveMarker(); + + // Create edge marker + this._createResizeMarker(); + }, + + _createMoveMarker: function () { + // Children override + }, + + _createResizeMarker: function () { + // Children override + }, + + _createMarker: function (latlng, icon) { + var marker = new L.Marker(latlng, { + draggable: true, + icon: icon, + zIndexOffset: 10 + }); + + this._bindMarker(marker); + + this._markerGroup.addLayer(marker); + + return marker; + }, + + _bindMarker: function (marker) { + marker + .on('dragstart', this._onMarkerDragStart, this) + .on('drag', this._onMarkerDrag, this) + .on('dragend', this._onMarkerDragEnd, this); + }, + + _unbindMarker: function (marker) { + marker + .off('dragstart', this._onMarkerDragStart, this) + .off('drag', this._onMarkerDrag, this) + .off('dragend', this._onMarkerDragEnd, this); + }, + + _onMarkerDragStart: function (e) { + var marker = e.target; + marker.setOpacity(0); + + this._shape.fire('editstart'); + }, + + _fireEdit: function () { + this._shape.edited = true; + this._shape.fire('edit'); + }, + + _onMarkerDrag: function (e) { + var marker = e.target, + latlng = marker.getLatLng(); + + if (marker === this._moveMarker) { + this._move(latlng); + } else { + this._resize(latlng); + } + + this._shape.redraw(); + }, + + _onMarkerDragEnd: function (e) { + var marker = e.target; + marker.setOpacity(1); + + this._fireEdit(); + }, + + _move: function () { + // Children override + }, + + _resize: function () { + // Children override + } +}); + + +L.Edit = L.Edit || {}; + +L.Edit.Rectangle = L.Edit.SimpleShape.extend({ + _createMoveMarker: function () { + var bounds = this._shape.getBounds(), + center = bounds.getCenter(); + + this._moveMarker = this._createMarker(center, this.options.moveIcon); + }, + + _createResizeMarker: function () { + var corners = this._getCorners(); + + this._resizeMarkers = []; + + for (var i = 0, l = corners.length; i < l; i++) { + this._resizeMarkers.push(this._createMarker(corners[i], this.options.resizeIcon)); + // Monkey in the corner index as we will need to know this for dragging + this._resizeMarkers[i]._cornerIndex = i; + } + }, + + _onMarkerDragStart: function (e) { + L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this, e); + + // Save a reference to the opposite point + var corners = this._getCorners(), + marker = e.target, + currentCornerIndex = marker._cornerIndex; + + this._oppositeCorner = corners[(currentCornerIndex + 2) % 4]; + + this._toggleCornerMarkers(0, currentCornerIndex); + }, + + _onMarkerDragEnd: function (e) { + var marker = e.target, + bounds, center; + + // Reset move marker position to the center + if (marker === this._moveMarker) { + bounds = this._shape.getBounds(); + center = bounds.getCenter(); + + marker.setLatLng(center); + } + + this._toggleCornerMarkers(1); + + this._repositionCornerMarkers(); + + L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this, e); + }, + + _move: function (newCenter) { + var latlngs = this._shape.getLatLngs(), + bounds = this._shape.getBounds(), + center = bounds.getCenter(), + offset, newLatLngs = []; + + // Offset the latlngs to the new center + for (var i = 0, l = latlngs.length; i < l; i++) { + offset = [latlngs[i].lat - center.lat, latlngs[i].lng - center.lng]; + newLatLngs.push([newCenter.lat + offset[0], newCenter.lng + offset[1]]); + } + + this._shape.setLatLngs(newLatLngs); + + // Reposition the resize markers + this._repositionCornerMarkers(); + }, + + _resize: function (latlng) { + var bounds; + + // Update the shape based on the current position of this corner and the opposite point + this._shape.setBounds(L.latLngBounds(latlng, this._oppositeCorner)); + + // Reposition the move marker + bounds = this._shape.getBounds(); + this._moveMarker.setLatLng(bounds.getCenter()); + }, + + _getCorners: function () { + var bounds = this._shape.getBounds(), + nw = bounds.getNorthWest(), + ne = bounds.getNorthEast(), + se = bounds.getSouthEast(), + sw = bounds.getSouthWest(); + + return [nw, ne, se, sw]; + }, + + _toggleCornerMarkers: function (opacity) { + for (var i = 0, l = this._resizeMarkers.length; i < l; i++) { + this._resizeMarkers[i].setOpacity(opacity); + } + }, + + _repositionCornerMarkers: function () { + var corners = this._getCorners(); + + for (var i = 0, l = this._resizeMarkers.length; i < l; i++) { + this._resizeMarkers[i].setLatLng(corners[i]); + } + } +}); + +L.Rectangle.addInitHook(function () { + if (L.Edit.Rectangle) { + this.editing = new L.Edit.Rectangle(this); + + if (this.options.editable) { + this.editing.enable(); + } + } +}); + + +L.Edit = L.Edit || {}; + +L.Edit.Circle = L.Edit.SimpleShape.extend({ + _createMoveMarker: function () { + var center = this._shape.getLatLng(); + + this._moveMarker = this._createMarker(center, this.options.moveIcon); + }, + + _createResizeMarker: function () { + var center = this._shape.getLatLng(), + resizemarkerPoint = this._getResizeMarkerPoint(center); + + this._resizeMarkers = []; + this._resizeMarkers.push(this._createMarker(resizemarkerPoint, this.options.resizeIcon)); + }, + + _getResizeMarkerPoint: function (latlng) { + // From L.shape.getBounds() + var delta = this._shape._radius * Math.cos(Math.PI / 4), + point = this._map.project(latlng); + return this._map.unproject([point.x + delta, point.y - delta]); + }, + + _move: function (latlng) { + var resizemarkerPoint = this._getResizeMarkerPoint(latlng); + + // Move the resize marker + this._resizeMarkers[0].setLatLng(resizemarkerPoint); + + // Move the circle + this._shape.setLatLng(latlng); + }, + + _resize: function (latlng) { + var moveLatLng = this._moveMarker.getLatLng(), + radius = moveLatLng.distanceTo(latlng); + + this._shape.setRadius(radius); + } +}); + +L.Circle.addInitHook(function () { + if (L.Edit.Circle) { + this.editing = new L.Edit.Circle(this); + + if (this.options.editable) { + this.editing.enable(); + } + } + + this.on('add', function () { + if (this.editing && this.editing.enabled()) { + this.editing.addHooks(); + } + }); + + this.on('remove', function () { + if (this.editing && this.editing.enabled()) { + this.editing.removeHooks(); + } + }); +}); + +/* + * L.LatLngUtil contains different utility functions for LatLngs. + */ + +L.LatLngUtil = { + // Clones a LatLngs[], returns [][] + cloneLatLngs: function (latlngs) { + var clone = []; + for (var i = 0, l = latlngs.length; i < l; i++) { + clone.push(this.cloneLatLng(latlngs[i])); + } + return clone; + }, + + cloneLatLng: function (latlng) { + return L.latLng(latlng.lat, latlng.lng); + } +}; + +L.GeometryUtil = L.extend(L.GeometryUtil || {}, { + // Ported from the OpenLayers implementation. See https://github.com/openlayers/openlayers/blob/master/lib/OpenLayers/Geometry/LinearRing.js#L270 + geodesicArea: function (latLngs) { + var pointsCount = latLngs.length, + area = 0.0, + d2r = L.LatLng.DEG_TO_RAD, + p1, p2; + + if (pointsCount > 2) { + for (var i = 0; i < pointsCount; i++) { + p1 = latLngs[i]; + p2 = latLngs[(i + 1) % pointsCount]; + area += ((p2.lng - p1.lng) * d2r) * + (2 + Math.sin(p1.lat * d2r) + Math.sin(p2.lat * d2r)); + } + area = area * 6378137.0 * 6378137.0 / 2.0; + } + + return Math.abs(area); + }, + + readableArea: function (area, isMetric) { + var areaStr; + + if (isMetric) { + if (area >= 10000) { + areaStr = (area * 0.0001).toFixed(2) + ' ha'; + } else { + areaStr = area.toFixed(2) + ' m²'; + } + } else { + area *= 0.836127; // Square yards in 1 meter + + if (area >= 3097600) { //3097600 square yards in 1 square mile + areaStr = (area / 3097600).toFixed(2) + ' mi²'; + } else if (area >= 4840) {//48040 square yards in 1 acre + areaStr = (area / 4840).toFixed(2) + ' acres'; + } else { + areaStr = Math.ceil(area) + ' yd²'; + } + } + + return areaStr; + }, + + readableDistance: function (distance, isMetric) { + var distanceStr; + + if (isMetric) { + // show metres when distance is < 1km, then show km + if (distance > 1000) { + distanceStr = (distance / 1000).toFixed(2) + ' km'; + } else { + distanceStr = Math.ceil(distance) + ' m'; + } + } else { + distance *= 1.09361; + + if (distance > 1760) { + distanceStr = (distance / 1760).toFixed(2) + ' miles'; + } else { + distanceStr = Math.ceil(distance) + ' yd'; + } + } + + return distanceStr; + } +}); + +L.Util.extend(L.LineUtil, { + // Checks to see if two line segments intersect. Does not handle degenerate cases. + // http://compgeom.cs.uiuc.edu/~jeffe/teaching/373/notes/x06-sweepline.pdf + segmentsIntersect: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2, /*Point*/ p3) { + return this._checkCounterclockwise(p, p2, p3) !== + this._checkCounterclockwise(p1, p2, p3) && + this._checkCounterclockwise(p, p1, p2) !== + this._checkCounterclockwise(p, p1, p3); + }, + + // check to see if points are in counterclockwise order + _checkCounterclockwise: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { + return (p2.y - p.y) * (p1.x - p.x) > (p1.y - p.y) * (p2.x - p.x); + } +}); + +L.Polyline.include({ + // Check to see if this polyline has any linesegments that intersect. + // NOTE: does not support detecting intersection for degenerate cases. + intersects: function () { + var points = this._originalPoints, + len = points ? points.length : 0, + i, p, p1; + + if (this._tooFewPointsForIntersection()) { + return false; + } + + for (i = len - 1; i >= 3; i--) { + p = points[i - 1]; + p1 = points[i]; + + + if (this._lineSegmentsIntersectsRange(p, p1, i - 2)) { + return true; + } + } + + return false; + }, + + // Check for intersection if new latlng was added to this polyline. + // NOTE: does not support detecting intersection for degenerate cases. + newLatLngIntersects: function (latlng, skipFirst) { + // Cannot check a polyline for intersecting lats/lngs when not added to the map + if (!this._map) { + return false; + } + + return this.newPointIntersects(this._map.latLngToLayerPoint(latlng), skipFirst); + }, + + // Check for intersection if new point was added to this polyline. + // newPoint must be a layer point. + // NOTE: does not support detecting intersection for degenerate cases. + newPointIntersects: function (newPoint, skipFirst) { + var points = this._originalPoints, + len = points ? points.length : 0, + lastPoint = points ? points[len - 1] : null, + // The previous previous line segment. Previous line segment doesn't need testing. + maxIndex = len - 2; + + if (this._tooFewPointsForIntersection(1)) { + return false; + } + + return this._lineSegmentsIntersectsRange(lastPoint, newPoint, maxIndex, skipFirst ? 1 : 0); + }, + + // Polylines with 2 sides can only intersect in cases where points are collinear (we don't support detecting these). + // Cannot have intersection when < 3 line segments (< 4 points) + _tooFewPointsForIntersection: function (extraPoints) { + var points = this._originalPoints, + len = points ? points.length : 0; + // Increment length by extraPoints if present + len += extraPoints || 0; + + return !this._originalPoints || len <= 3; + }, + + // Checks a line segment intersections with any line segments before its predecessor. + // Don't need to check the predecessor as will never intersect. + _lineSegmentsIntersectsRange: function (p, p1, maxIndex, minIndex) { + var points = this._originalPoints, + p2, p3; + + minIndex = minIndex || 0; + + // Check all previous line segments (beside the immediately previous) for intersections + for (var j = maxIndex; j > minIndex; j--) { + p2 = points[j - 1]; + p3 = points[j]; + + if (L.LineUtil.segmentsIntersect(p, p1, p2, p3)) { + return true; + } + } + + return false; + } +}); + + +L.Polygon.include({ + // Checks a polygon for any intersecting line segments. Ignores holes. + intersects: function () { + var polylineIntersects, + points = this._originalPoints, + len, firstPoint, lastPoint, maxIndex; + + if (this._tooFewPointsForIntersection()) { + return false; + } + + polylineIntersects = L.Polyline.prototype.intersects.call(this); + + // If already found an intersection don't need to check for any more. + if (polylineIntersects) { + return true; + } + + len = points.length; + firstPoint = points[0]; + lastPoint = points[len - 1]; + maxIndex = len - 2; + + // Check the line segment between last and first point. Don't need to check the first line segment (minIndex = 1) + return this._lineSegmentsIntersectsRange(lastPoint, firstPoint, maxIndex, 1); + } +}); + +L.Control.Draw = L.Control.extend({ + + options: { + position: 'topleft', + draw: {}, + edit: false + }, + + initialize: function (options) { + if (L.version < '0.7') { + throw new Error('Leaflet.draw 0.2.3+ requires Leaflet 0.7.0+. Download latest from https://github.com/Leaflet/Leaflet/'); + } + + L.Control.prototype.initialize.call(this, options); + + var id, toolbar; + + this._toolbars = {}; + + // Initialize toolbars + if (L.DrawToolbar && this.options.draw) { + toolbar = new L.DrawToolbar(this.options.draw); + id = L.stamp(toolbar); + this._toolbars[id] = toolbar; + + // Listen for when toolbar is enabled + this._toolbars[id].on('enable', this._toolbarEnabled, this); + } + + if (L.EditToolbar && this.options.edit) { + toolbar = new L.EditToolbar(this.options.edit); + id = L.stamp(toolbar); + this._toolbars[id] = toolbar; + + // Listen for when toolbar is enabled + this._toolbars[id].on('enable', this._toolbarEnabled, this); + } + }, + + onAdd: function (map) { + var container = L.DomUtil.create('div', 'leaflet-draw'), + addedTopClass = false, + topClassName = 'leaflet-draw-toolbar-top', + toolbarContainer; + + for (var toolbarId in this._toolbars) { + if (this._toolbars.hasOwnProperty(toolbarId)) { + toolbarContainer = this._toolbars[toolbarId].addToolbar(map); + + if (toolbarContainer) { + // Add class to the first toolbar to remove the margin + if (!addedTopClass) { + if (!L.DomUtil.hasClass(toolbarContainer, topClassName)) { + L.DomUtil.addClass(toolbarContainer.childNodes[0], topClassName); + } + addedTopClass = true; + } + + container.appendChild(toolbarContainer); + } + } + } + + return container; + }, + + onRemove: function () { + for (var toolbarId in this._toolbars) { + if (this._toolbars.hasOwnProperty(toolbarId)) { + this._toolbars[toolbarId].removeToolbar(); + } + } + }, + + setDrawingOptions: function (options) { + for (var toolbarId in this._toolbars) { + if (this._toolbars[toolbarId] instanceof L.DrawToolbar) { + this._toolbars[toolbarId].setOptions(options); + } + } + }, + + _toolbarEnabled: function (e) { + var id = '' + L.stamp(e.target); + + for (var toolbarId in this._toolbars) { + if (this._toolbars.hasOwnProperty(toolbarId) && toolbarId !== id) { + this._toolbars[toolbarId].disable(); + } + } + } +}); + +L.Map.mergeOptions({ + drawControlTooltips: true, + drawControl: false +}); + +L.Map.addInitHook(function () { + if (this.options.drawControl) { + this.drawControl = new L.Control.Draw(); + this.addControl(this.drawControl); + } +}); + + +L.Toolbar = L.Class.extend({ + includes: [L.Mixin.Events], + + initialize: function (options) { + L.setOptions(this, options); + + this._modes = {}; + this._actionButtons = []; + this._activeMode = null; + }, + + enabled: function () { + return this._activeMode !== null; + }, + + disable: function () { + if (!this.enabled()) { return; } + + this._activeMode.handler.disable(); + }, + + addToolbar: function (map) { + var container = L.DomUtil.create('div', 'leaflet-draw-section'), + buttonIndex = 0, + buttonClassPrefix = this._toolbarClass || '', + modeHandlers = this.getModeHandlers(map), + i; + + this._toolbarContainer = L.DomUtil.create('div', 'leaflet-draw-toolbar leaflet-bar'); + this._map = map; + + for (i = 0; i < modeHandlers.length; i++) { + if (modeHandlers[i].enabled) { + this._initModeHandler( + modeHandlers[i].handler, + this._toolbarContainer, + buttonIndex++, + buttonClassPrefix, + modeHandlers[i].title + ); + } + } + + // if no buttons were added, do not add the toolbar + if (!buttonIndex) { + return; + } + + // Save button index of the last button, -1 as we would have ++ after the last button + this._lastButtonIndex = --buttonIndex; + + // Create empty actions part of the toolbar + this._actionsContainer = L.DomUtil.create('ul', 'leaflet-draw-actions'); + + // Add draw and cancel containers to the control container + container.appendChild(this._toolbarContainer); + container.appendChild(this._actionsContainer); + + return container; + }, + + removeToolbar: function () { + // Dispose each handler + for (var handlerId in this._modes) { + if (this._modes.hasOwnProperty(handlerId)) { + // Unbind handler button + this._disposeButton( + this._modes[handlerId].button, + this._modes[handlerId].handler.enable, + this._modes[handlerId].handler + ); + + // Make sure is disabled + this._modes[handlerId].handler.disable(); + + // Unbind handler + this._modes[handlerId].handler + .off('enabled', this._handlerActivated, this) + .off('disabled', this._handlerDeactivated, this); + } + } + this._modes = {}; + + // Dispose the actions toolbar + for (var i = 0, l = this._actionButtons.length; i < l; i++) { + this._disposeButton( + this._actionButtons[i].button, + this._actionButtons[i].callback, + this + ); + } + this._actionButtons = []; + this._actionsContainer = null; + }, + + _initModeHandler: function (handler, container, buttonIndex, classNamePredix, buttonTitle) { + var type = handler.type; + + this._modes[type] = {}; + + this._modes[type].handler = handler; + + this._modes[type].button = this._createButton({ + title: buttonTitle, + className: classNamePredix + '-' + type, + container: container, + callback: this._modes[type].handler.enable, + context: this._modes[type].handler + }); + + this._modes[type].buttonIndex = buttonIndex; + + this._modes[type].handler + .on('enabled', this._handlerActivated, this) + .on('disabled', this._handlerDeactivated, this); + }, + + _createButton: function (options) { + var link = L.DomUtil.create('a', options.className || '', options.container); + link.href = '#'; + + if (options.text) { + link.innerHTML = options.text; + } + + if (options.title) { + link.title = options.title; + } + + L.DomEvent + .on(link, 'click', L.DomEvent.stopPropagation) + .on(link, 'mousedown', L.DomEvent.stopPropagation) + .on(link, 'dblclick', L.DomEvent.stopPropagation) + .on(link, 'click', L.DomEvent.preventDefault) + .on(link, 'click', options.callback, options.context); + + return link; + }, + + _disposeButton: function (button, callback) { + L.DomEvent + .off(button, 'click', L.DomEvent.stopPropagation) + .off(button, 'mousedown', L.DomEvent.stopPropagation) + .off(button, 'dblclick', L.DomEvent.stopPropagation) + .off(button, 'click', L.DomEvent.preventDefault) + .off(button, 'click', callback); + }, + + _handlerActivated: function (e) { + // Disable active mode (if present) + this.disable(); + + // Cache new active feature + this._activeMode = this._modes[e.handler]; + + L.DomUtil.addClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled'); + + this._showActionsToolbar(); + + this.fire('enable'); + }, + + _handlerDeactivated: function () { + this._hideActionsToolbar(); + + L.DomUtil.removeClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled'); + + this._activeMode = null; + + this.fire('disable'); + }, + + _createActions: function (handler) { + var container = this._actionsContainer, + buttons = this.getActions(handler), + l = buttons.length, + li, di, dl, button; + + // Dispose the actions toolbar (todo: dispose only not used buttons) + for (di = 0, dl = this._actionButtons.length; di < dl; di++) { + this._disposeButton(this._actionButtons[di].button, this._actionButtons[di].callback); + } + this._actionButtons = []; + + // Remove all old buttons + while (container.firstChild) { + container.removeChild(container.firstChild); + } + + for (var i = 0; i < l; i++) { + if ('enabled' in buttons[i] && !buttons[i].enabled) { + continue; + } + + li = L.DomUtil.create('li', '', container); + + button = this._createButton({ + title: buttons[i].title, + text: buttons[i].text, + container: li, + callback: buttons[i].callback, + context: buttons[i].context + }); + + this._actionButtons.push({ + button: button, + callback: buttons[i].callback + }); + } + }, + + _showActionsToolbar: function () { + var buttonIndex = this._activeMode.buttonIndex, + lastButtonIndex = this._lastButtonIndex, + toolbarPosition = this._activeMode.button.offsetTop - 1; + + // Recreate action buttons on every click + this._createActions(this._activeMode.handler); + + // Correctly position the cancel button + this._actionsContainer.style.top = toolbarPosition + 'px'; + + if (buttonIndex === 0) { + L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop'); + L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-top'); + } + + if (buttonIndex === lastButtonIndex) { + L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom'); + L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-bottom'); + } + + this._actionsContainer.style.display = 'block'; + }, + + _hideActionsToolbar: function () { + this._actionsContainer.style.display = 'none'; + + L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop'); + L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom'); + L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-top'); + L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-bottom'); + } +}); + + +L.Tooltip = L.Class.extend({ + initialize: function (map) { + this._map = map; + this._popupPane = map._panes.popupPane; + + this._container = map.options.drawControlTooltips ? L.DomUtil.create('div', 'leaflet-draw-tooltip', this._popupPane) : null; + this._singleLineLabel = false; + }, + + dispose: function () { + if (this._container) { + this._popupPane.removeChild(this._container); + this._container = null; + } + }, + + updateContent: function (labelText) { + if (!this._container) { + return this; + } + labelText.subtext = labelText.subtext || ''; + + // update the vertical position (only if changed) + if (labelText.subtext.length === 0 && !this._singleLineLabel) { + L.DomUtil.addClass(this._container, 'leaflet-draw-tooltip-single'); + this._singleLineLabel = true; + } + else if (labelText.subtext.length > 0 && this._singleLineLabel) { + L.DomUtil.removeClass(this._container, 'leaflet-draw-tooltip-single'); + this._singleLineLabel = false; + } + + this._container.innerHTML = + (labelText.subtext.length > 0 ? '' + labelText.subtext + '' + '
' : '') + + '' + labelText.text + ''; + + return this; + }, + + updatePosition: function (latlng) { + var pos = this._map.latLngToLayerPoint(latlng), + tooltipContainer = this._container; + + if (this._container) { + tooltipContainer.style.visibility = 'inherit'; + L.DomUtil.setPosition(tooltipContainer, pos); + } + + return this; + }, + + showAsError: function () { + if (this._container) { + L.DomUtil.addClass(this._container, 'leaflet-error-draw-tooltip'); + } + return this; + }, + + removeError: function () { + if (this._container) { + L.DomUtil.removeClass(this._container, 'leaflet-error-draw-tooltip'); + } + return this; + } +}); + +L.DrawToolbar = L.Toolbar.extend({ + + options: { + polyline: {}, + polygon: {}, + rectangle: {}, + circle: {}, + marker: {} + }, + + initialize: function (options) { + // Ensure that the options are merged correctly since L.extend is only shallow + for (var type in this.options) { + if (this.options.hasOwnProperty(type)) { + if (options[type]) { + options[type] = L.extend({}, this.options[type], options[type]); + } + } + } + + this._toolbarClass = 'leaflet-draw-draw'; + L.Toolbar.prototype.initialize.call(this, options); + }, + + getModeHandlers: function (map) { + return [ + { + enabled: this.options.polyline, + handler: new L.Draw.Polyline(map, this.options.polyline), + title: L.drawLocal.draw.toolbar.buttons.polyline + }, + { + enabled: this.options.polygon, + handler: new L.Draw.Polygon(map, this.options.polygon), + title: L.drawLocal.draw.toolbar.buttons.polygon + }, + { + enabled: this.options.rectangle, + handler: new L.Draw.Rectangle(map, this.options.rectangle), + title: L.drawLocal.draw.toolbar.buttons.rectangle + }, + { + enabled: this.options.circle, + handler: new L.Draw.Circle(map, this.options.circle), + title: L.drawLocal.draw.toolbar.buttons.circle + }, + { + enabled: this.options.marker, + handler: new L.Draw.Marker(map, this.options.marker), + title: L.drawLocal.draw.toolbar.buttons.marker + } + ]; + }, + + // Get the actions part of the toolbar + getActions: function (handler) { + return [ + { + enabled: handler.deleteLastVertex, + title: L.drawLocal.draw.toolbar.undo.title, + text: L.drawLocal.draw.toolbar.undo.text, + callback: handler.deleteLastVertex, + context: handler + }, + { + title: L.drawLocal.draw.toolbar.actions.title, + text: L.drawLocal.draw.toolbar.actions.text, + callback: this.disable, + context: this + } + ]; + }, + + setOptions: function (options) { + L.setOptions(this, options); + + for (var type in this._modes) { + if (this._modes.hasOwnProperty(type) && options.hasOwnProperty(type)) { + this._modes[type].handler.setOptions(options[type]); + } + } + } +}); + + +/*L.Map.mergeOptions({ + editControl: true +});*/ + +L.EditToolbar = L.Toolbar.extend({ + options: { + edit: { + selectedPathOptions: { + color: '#fe57a1', /* Hot pink all the things! */ + opacity: 0.6, + dashArray: '10, 10', + + fill: true, + fillColor: '#fe57a1', + fillOpacity: 0.1 + } + }, + remove: {}, + featureGroup: null /* REQUIRED! TODO: perhaps if not set then all layers on the map are selectable? */ + }, + + initialize: function (options) { + // Need to set this manually since null is an acceptable value here + if (options.edit) { + if (typeof options.edit.selectedPathOptions === 'undefined') { + options.edit.selectedPathOptions = this.options.edit.selectedPathOptions; + } + options.edit = L.extend({}, this.options.edit, options.edit); + } + + if (options.remove) { + options.remove = L.extend({}, this.options.remove, options.remove); + } + + this._toolbarClass = 'leaflet-draw-edit'; + L.Toolbar.prototype.initialize.call(this, options); + + this._selectedFeatureCount = 0; + }, + + getModeHandlers: function (map) { + var featureGroup = this.options.featureGroup; + return [ + { + enabled: this.options.edit, + handler: new L.EditToolbar.Edit(map, { + featureGroup: featureGroup, + selectedPathOptions: this.options.edit.selectedPathOptions + }), + title: L.drawLocal.edit.toolbar.buttons.edit + }, + { + enabled: this.options.remove, + handler: new L.EditToolbar.Delete(map, { + featureGroup: featureGroup + }), + title: L.drawLocal.edit.toolbar.buttons.remove + } + ]; + }, + + getActions: function () { + return [ + { + title: L.drawLocal.edit.toolbar.actions.save.title, + text: L.drawLocal.edit.toolbar.actions.save.text, + callback: this._save, + context: this + }, + { + title: L.drawLocal.edit.toolbar.actions.cancel.title, + text: L.drawLocal.edit.toolbar.actions.cancel.text, + callback: this.disable, + context: this + } + ]; + }, + + addToolbar: function (map) { + var container = L.Toolbar.prototype.addToolbar.call(this, map); + + this._checkDisabled(); + + this.options.featureGroup.on('layeradd layerremove', this._checkDisabled, this); + + return container; + }, + + removeToolbar: function () { + this.options.featureGroup.off('layeradd layerremove', this._checkDisabled, this); + + L.Toolbar.prototype.removeToolbar.call(this); + }, + + disable: function () { + if (!this.enabled()) { return; } + + this._activeMode.handler.revertLayers(); + + L.Toolbar.prototype.disable.call(this); + }, + + _save: function () { + this._activeMode.handler.save(); + this._activeMode.handler.disable(); + }, + + _checkDisabled: function () { + var featureGroup = this.options.featureGroup, + hasLayers = featureGroup.getLayers().length !== 0, + button; + + if (this.options.edit) { + button = this._modes[L.EditToolbar.Edit.TYPE].button; + + if (hasLayers) { + L.DomUtil.removeClass(button, 'leaflet-disabled'); + } else { + L.DomUtil.addClass(button, 'leaflet-disabled'); + } + + button.setAttribute( + 'title', + hasLayers ? + L.drawLocal.edit.toolbar.buttons.edit + : L.drawLocal.edit.toolbar.buttons.editDisabled + ); + } + + if (this.options.remove) { + button = this._modes[L.EditToolbar.Delete.TYPE].button; + + if (hasLayers) { + L.DomUtil.removeClass(button, 'leaflet-disabled'); + } else { + L.DomUtil.addClass(button, 'leaflet-disabled'); + } + + button.setAttribute( + 'title', + hasLayers ? + L.drawLocal.edit.toolbar.buttons.remove + : L.drawLocal.edit.toolbar.buttons.removeDisabled + ); + } + } +}); + + +L.EditToolbar.Edit = L.Handler.extend({ + statics: { + TYPE: 'edit' + }, + + includes: L.Mixin.Events, + + initialize: function (map, options) { + L.Handler.prototype.initialize.call(this, map); + + // Set options to the default unless already set + this._selectedPathOptions = options.selectedPathOptions; + + // Store the selectable layer group for ease of access + this._featureGroup = options.featureGroup; + + if (!(this._featureGroup instanceof L.FeatureGroup)) { + throw new Error('options.featureGroup must be a L.FeatureGroup'); + } + + this._uneditedLayerProps = {}; + + // Save the type so super can fire, need to do this as cannot do this.TYPE :( + this.type = L.EditToolbar.Edit.TYPE; + }, + + enable: function () { + if (this._enabled || !this._hasAvailableLayers()) { + return; + } + this.fire('enabled', {handler: this.type}); + //this disable other handlers + + this._map.fire('draw:editstart', { handler: this.type }); + //allow drawLayer to be updated before beginning edition. + + L.Handler.prototype.enable.call(this); + this._featureGroup + .on('layeradd', this._enableLayerEdit, this) + .on('layerremove', this._disableLayerEdit, this); + }, + + disable: function () { + if (!this._enabled) { return; } + this._featureGroup + .off('layeradd', this._enableLayerEdit, this) + .off('layerremove', this._disableLayerEdit, this); + L.Handler.prototype.disable.call(this); + this._map.fire('draw:editstop', { handler: this.type }); + this.fire('disabled', {handler: this.type}); + }, + + addHooks: function () { + var map = this._map; + + if (map) { + map.getContainer().focus(); + + this._featureGroup.eachLayer(this._enableLayerEdit, this); + + this._tooltip = new L.Tooltip(this._map); + this._tooltip.updateContent({ + text: L.drawLocal.edit.handlers.edit.tooltip.text, + subtext: L.drawLocal.edit.handlers.edit.tooltip.subtext + }); + + this._map.on('mousemove', this._onMouseMove, this); + } + }, + + removeHooks: function () { + if (this._map) { + // Clean up selected layers. + this._featureGroup.eachLayer(this._disableLayerEdit, this); + + // Clear the backups of the original layers + this._uneditedLayerProps = {}; + + this._tooltip.dispose(); + this._tooltip = null; + + this._map.off('mousemove', this._onMouseMove, this); + } + }, + + revertLayers: function () { + this._featureGroup.eachLayer(function (layer) { + this._revertLayer(layer); + }, this); + }, + + save: function () { + var editedLayers = new L.LayerGroup(); + this._featureGroup.eachLayer(function (layer) { + if (layer.edited) { + editedLayers.addLayer(layer); + layer.edited = false; + } + }); + this._map.fire('draw:edited', {layers: editedLayers}); + }, + + _backupLayer: function (layer) { + var id = L.Util.stamp(layer); + + if (!this._uneditedLayerProps[id]) { + // Polyline, Polygon or Rectangle + if (layer instanceof L.Polyline || layer instanceof L.Polygon || layer instanceof L.Rectangle) { + this._uneditedLayerProps[id] = { + latlngs: L.LatLngUtil.cloneLatLngs(layer.getLatLngs()) + }; + } else if (layer instanceof L.Circle) { + this._uneditedLayerProps[id] = { + latlng: L.LatLngUtil.cloneLatLng(layer.getLatLng()), + radius: layer.getRadius() + }; + } else if (layer instanceof L.Marker) { // Marker + this._uneditedLayerProps[id] = { + latlng: L.LatLngUtil.cloneLatLng(layer.getLatLng()) + }; + } + } + }, + + _revertLayer: function (layer) { + var id = L.Util.stamp(layer); + layer.edited = false; + if (this._uneditedLayerProps.hasOwnProperty(id)) { + // Polyline, Polygon or Rectangle + if (layer instanceof L.Polyline || layer instanceof L.Polygon || layer instanceof L.Rectangle) { + layer.setLatLngs(this._uneditedLayerProps[id].latlngs); + } else if (layer instanceof L.Circle) { + layer.setLatLng(this._uneditedLayerProps[id].latlng); + layer.setRadius(this._uneditedLayerProps[id].radius); + } else if (layer instanceof L.Marker) { // Marker + layer.setLatLng(this._uneditedLayerProps[id].latlng); + } + } + }, + + _toggleMarkerHighlight: function (marker) { + if (!marker._icon) { + return; + } + // This is quite naughty, but I don't see another way of doing it. (short of setting a new icon) + var icon = marker._icon; + + icon.style.display = 'none'; + + if (L.DomUtil.hasClass(icon, 'leaflet-edit-marker-selected')) { + L.DomUtil.removeClass(icon, 'leaflet-edit-marker-selected'); + // Offset as the border will make the icon move. + this._offsetMarker(icon, -4); + + } else { + L.DomUtil.addClass(icon, 'leaflet-edit-marker-selected'); + // Offset as the border will make the icon move. + this._offsetMarker(icon, 4); + } + + icon.style.display = ''; + }, + + _offsetMarker: function (icon, offset) { + var iconMarginTop = parseInt(icon.style.marginTop, 10) - offset, + iconMarginLeft = parseInt(icon.style.marginLeft, 10) - offset; + + icon.style.marginTop = iconMarginTop + 'px'; + icon.style.marginLeft = iconMarginLeft + 'px'; + }, + + _enableLayerEdit: function (e) { + var layer = e.layer || e.target || e, + isMarker = layer instanceof L.Marker, + pathOptions; + + // Don't do anything if this layer is a marker but doesn't have an icon. Markers + // should usually have icons. If using Leaflet.draw with Leafler.markercluster there + // is a chance that a marker doesn't. + if (isMarker && !layer._icon) { + return; + } + + // Back up this layer (if haven't before) + this._backupLayer(layer); + + // Update layer style so appears editable + if (this._selectedPathOptions) { + pathOptions = L.Util.extend({}, this._selectedPathOptions); + + if (isMarker) { + this._toggleMarkerHighlight(layer); + } else { + layer.options.previousOptions = L.Util.extend({ dashArray: null }, layer.options); + + // Make sure that Polylines are not filled + if (!(layer instanceof L.Circle) && !(layer instanceof L.Polygon) && !(layer instanceof L.Rectangle)) { + pathOptions.fill = false; + } + + layer.setStyle(pathOptions); + } + } + + if (isMarker) { + layer.dragging.enable(); + layer.on('dragend', this._onMarkerDragEnd); + } else { + layer.editing.enable(); + } + }, + + _disableLayerEdit: function (e) { + var layer = e.layer || e.target || e; + layer.edited = false; + + // Reset layer styles to that of before select + if (this._selectedPathOptions) { + if (layer instanceof L.Marker) { + this._toggleMarkerHighlight(layer); + } else { + // reset the layer style to what is was before being selected + layer.setStyle(layer.options.previousOptions); + // remove the cached options for the layer object + delete layer.options.previousOptions; + } + } + + if (layer instanceof L.Marker) { + layer.dragging.disable(); + layer.off('dragend', this._onMarkerDragEnd, this); + } else { + layer.editing.disable(); + } + }, + + _onMarkerDragEnd: function (e) { + var layer = e.target; + layer.edited = true; + }, + + _onMouseMove: function (e) { + this._tooltip.updatePosition(e.latlng); + }, + + _hasAvailableLayers: function () { + return this._featureGroup.getLayers().length !== 0; + } +}); + + +L.EditToolbar.Delete = L.Handler.extend({ + statics: { + TYPE: 'remove' // not delete as delete is reserved in js + }, + + includes: L.Mixin.Events, + + initialize: function (map, options) { + L.Handler.prototype.initialize.call(this, map); + + L.Util.setOptions(this, options); + + // Store the selectable layer group for ease of access + this._deletableLayers = this.options.featureGroup; + + if (!(this._deletableLayers instanceof L.FeatureGroup)) { + throw new Error('options.featureGroup must be a L.FeatureGroup'); + } + + // Save the type so super can fire, need to do this as cannot do this.TYPE :( + this.type = L.EditToolbar.Delete.TYPE; + }, + + enable: function () { + if (this._enabled || !this._hasAvailableLayers()) { + return; + } + this.fire('enabled', { handler: this.type}); + + this._map.fire('draw:deletestart', { handler: this.type }); + + L.Handler.prototype.enable.call(this); + + this._deletableLayers + .on('layeradd', this._enableLayerDelete, this) + .on('layerremove', this._disableLayerDelete, this); + }, + + disable: function () { + if (!this._enabled) { return; } + + this._deletableLayers + .off('layeradd', this._enableLayerDelete, this) + .off('layerremove', this._disableLayerDelete, this); + + L.Handler.prototype.disable.call(this); + + this._map.fire('draw:deletestop', { handler: this.type }); + + this.fire('disabled', { handler: this.type}); + }, + + addHooks: function () { + var map = this._map; + + if (map) { + map.getContainer().focus(); + + this._deletableLayers.eachLayer(this._enableLayerDelete, this); + this._deletedLayers = new L.layerGroup(); + + this._tooltip = new L.Tooltip(this._map); + this._tooltip.updateContent({ text: L.drawLocal.edit.handlers.remove.tooltip.text }); + + this._map.on('mousemove', this._onMouseMove, this); + } + }, + + removeHooks: function () { + if (this._map) { + this._deletableLayers.eachLayer(this._disableLayerDelete, this); + this._deletedLayers = null; + + this._tooltip.dispose(); + this._tooltip = null; + + this._map.off('mousemove', this._onMouseMove, this); + } + }, + + revertLayers: function () { + // Iterate of the deleted layers and add them back into the featureGroup + this._deletedLayers.eachLayer(function (layer) { + this._deletableLayers.addLayer(layer); + }, this); + }, + + save: function () { + this._map.fire('draw:deleted', { layers: this._deletedLayers }); + }, + + _enableLayerDelete: function (e) { + var layer = e.layer || e.target || e; + + layer.on('click', this._removeLayer, this); + }, + + _disableLayerDelete: function (e) { + var layer = e.layer || e.target || e; + + layer.off('click', this._removeLayer, this); + + // Remove from the deleted layers so we can't accidently revert if the user presses cancel + this._deletedLayers.removeLayer(layer); + }, + + _removeLayer: function (e) { + var layer = e.layer || e.target || e; + + this._deletableLayers.removeLayer(layer); + + this._deletedLayers.addLayer(layer); + }, + + _onMouseMove: function (e) { + this._tooltip.updatePosition(e.latlng); + }, + + _hasAvailableLayers: function () { + return this._deletableLayers.getLayers().length !== 0; + } +}); + + +}(window, document)); \ No newline at end of file diff --git a/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.css b/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.css new file mode 100644 index 000000000..cb879cfa6 --- /dev/null +++ b/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.css @@ -0,0 +1,295 @@ +/* ================================================================== */ +/* Toolbars +/* ================================================================== */ + +.leaflet-draw-section { + position: relative; +} + +.leaflet-draw-toolbar { + margin-top: 12px; +} + +.leaflet-draw-toolbar-top { + margin-top: 0; +} + +.leaflet-draw-toolbar-notop a:first-child { + border-top-right-radius: 0; +} + +.leaflet-draw-toolbar-nobottom a:last-child { + border-bottom-right-radius: 0; +} + +.leaflet-draw-toolbar a { + background-image: url('images/spritesheet.png'); + background-repeat: no-repeat; +} + +.leaflet-retina .leaflet-draw-toolbar a { + background-image: url('images/spritesheet-2x.png'); + background-size: 270px 30px; +} + +.leaflet-draw a { + display: block; + text-align: center; + text-decoration: none; +} + +/* ================================================================== */ +/* Toolbar actions menu +/* ================================================================== */ + +.leaflet-draw-actions { + display: none; + list-style: none; + margin: 0; + padding: 0; + position: absolute; + left: 26px; /* leaflet-draw-toolbar.left + leaflet-draw-toolbar.width */ + top: 0; + white-space: nowrap; +} + +.leaflet-right .leaflet-draw-actions { + right:26px; + left:auto; +} + +.leaflet-draw-actions li { + display: inline-block; +} + +.leaflet-draw-actions li:first-child a { + border-left: none; +} + +.leaflet-draw-actions li:last-child a { + -webkit-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.leaflet-right .leaflet-draw-actions li:last-child a { + -webkit-border-radius: 0; + border-radius: 0; +} + +.leaflet-right .leaflet-draw-actions li:first-child a { + -webkit-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.leaflet-draw-actions a { + background-color: #919187; + border-left: 1px solid #AAA; + color: #FFF; + font: 11px/19px "Helvetica Neue", Arial, Helvetica, sans-serif; + line-height: 28px; + text-decoration: none; + padding-left: 10px; + padding-right: 10px; + height: 28px; +} + +.leaflet-draw-actions-bottom { + margin-top: 0; +} + +.leaflet-draw-actions-top { + margin-top: 1px; +} + +.leaflet-draw-actions-top a, +.leaflet-draw-actions-bottom a { + height: 27px; + line-height: 27px; +} + +.leaflet-draw-actions a:hover { + background-color: #A0A098; +} + +.leaflet-draw-actions-top.leaflet-draw-actions-bottom a { + height: 26px; + line-height: 26px; +} + +/* ================================================================== */ +/* Draw toolbar +/* ================================================================== */ + +.leaflet-draw-toolbar .leaflet-draw-draw-polyline { + background-position: -2px -2px; +} + +.leaflet-draw-toolbar .leaflet-draw-draw-polygon { + background-position: -31px -2px; +} + +.leaflet-draw-toolbar .leaflet-draw-draw-rectangle { + background-position: -62px -2px; +} + +.leaflet-draw-toolbar .leaflet-draw-draw-circle { + background-position: -92px -2px; +} + +.leaflet-draw-toolbar .leaflet-draw-draw-marker { + background-position: -122px -2px; +} + +/* ================================================================== */ +/* Edit toolbar +/* ================================================================== */ + +.leaflet-draw-toolbar .leaflet-draw-edit-edit { + background-position: -152px -2px; +} + +.leaflet-draw-toolbar .leaflet-draw-edit-remove { + background-position: -182px -2px; +} + +.leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled { + background-position: -212px -2px; +} + +.leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled { + background-position: -242px -2px; +} + +/* ================================================================== */ +/* Drawing styles +/* ================================================================== */ + +.leaflet-mouse-marker { + background-color: #fff; + cursor: crosshair; +} + +.leaflet-draw-tooltip { + background: rgb(54, 54, 54); + background: rgba(0, 0, 0, 0.5); + border: 1px solid transparent; + -webkit-border-radius: 4px; + border-radius: 4px; + color: #fff; + font: 12px/18px "Helvetica Neue", Arial, Helvetica, sans-serif; + margin-left: 20px; + margin-top: -21px; + padding: 4px 8px; + position: absolute; + visibility: hidden; + white-space: nowrap; + z-index: 6; +} + +.leaflet-draw-tooltip:before { + border-right: 6px solid black; + border-right-color: rgba(0, 0, 0, 0.5); + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + content: ""; + position: absolute; + top: 7px; + left: -7px; +} + +.leaflet-error-draw-tooltip { + background-color: #F2DEDE; + border: 1px solid #E6B6BD; + color: #B94A48; +} + +.leaflet-error-draw-tooltip:before { + border-right-color: #E6B6BD; +} + +.leaflet-draw-tooltip-single { + margin-top: -12px +} + +.leaflet-draw-tooltip-subtext { + color: #f8d5e4; +} + +.leaflet-draw-guide-dash { + font-size: 1%; + opacity: 0.6; + position: absolute; + width: 5px; + height: 5px; +} + +/* ================================================================== */ +/* Edit styles +/* ================================================================== */ + +.leaflet-edit-marker-selected { + background: rgba(254, 87, 161, 0.1); + border: 4px dashed rgba(254, 87, 161, 0.6); + -webkit-border-radius: 4px; + border-radius: 4px; +} + +.leaflet-edit-move { + cursor: move; +} + +.leaflet-edit-resize { + cursor: pointer; +} + +/* ================================================================== */ +/* Old IE styles +/* ================================================================== */ + +.leaflet-oldie .leaflet-draw-toolbar { + border: 3px solid #999; +} + +.leaflet-oldie .leaflet-draw-toolbar a { + background-color: #eee; +} + +.leaflet-oldie .leaflet-draw-toolbar a:hover { + background-color: #fff; +} + +.leaflet-oldie .leaflet-draw-actions { + left: 32px; + margin-top: 3px; +} + +.leaflet-oldie .leaflet-draw-actions li { + display: inline; + zoom: 1; +} + +.leaflet-oldie .leaflet-edit-marker-selected { + border: 4px dashed #fe93c2; +} + +.leaflet-oldie .leaflet-draw-actions a { + background-color: #999; +} + +.leaflet-oldie .leaflet-draw-actions a:hover { + background-color: #a5a5a5; +} + +.leaflet-oldie .leaflet-draw-actions-top a { + margin-top: 1px; +} + +.leaflet-oldie .leaflet-draw-actions-bottom a { + height: 28px; + line-height: 28px; +} + +.leaflet-oldie .leaflet-draw-actions-top.leaflet-draw-actions-bottom a { + height: 27px; + line-height: 27px; +} diff --git a/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.js b/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.js new file mode 100644 index 000000000..76bbf41cb --- /dev/null +++ b/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.js @@ -0,0 +1,10 @@ +/* + Leaflet.draw, a plugin that adds drawing and editing tools to Leaflet powered maps. + (c) 2012-2013, Jacob Toye, Smartrak + + https://github.com/Leaflet/Leaflet.draw + http://leafletjs.com + https://github.com/jacobtoye +*/ +!function(t,e){L.drawVersion="0.2.3",L.drawLocal={draw:{toolbar:{actions:{title:"Cancel drawing",text:"Cancel"},undo:{title:"Delete last point drawn",text:"Delete last point"},buttons:{polyline:"Draw a polyline",polygon:"Draw a polygon",rectangle:"Draw a rectangle",circle:"Draw a circle",marker:"Draw a marker"}},handlers:{circle:{tooltip:{start:"Click and drag to draw circle."}},marker:{tooltip:{start:"Click map to place marker."}},polygon:{tooltip:{start:"Click to start drawing shape.",cont:"Click to continue drawing shape.",end:"Click first point to close this shape."}},polyline:{error:"Error: shape edges cannot cross!",tooltip:{start:"Click to start drawing line.",cont:"Click to continue drawing line.",end:"Click last point to finish line."}},rectangle:{tooltip:{start:"Click and drag to draw rectangle."}},simpleshape:{tooltip:{end:"Release mouse to finish drawing."}}}},edit:{toolbar:{actions:{save:{title:"Save changes.",text:"Save"},cancel:{title:"Cancel editing, discards all changes.",text:"Cancel"}},buttons:{edit:"Edit layers.",editDisabled:"No layers to edit.",remove:"Delete layers.",removeDisabled:"No layers to delete."}},handlers:{edit:{tooltip:{text:"Drag handles, or marker to edit feature.",subtext:"Click cancel to undo changes."}},remove:{tooltip:{text:"Click on a feature to remove"}}}}},L.Draw={},L.Draw.Feature=L.Handler.extend({includes:L.Mixin.Events,initialize:function(t,e){this._map=t,this._container=t._container,this._overlayPane=t._panes.overlayPane,this._popupPane=t._panes.popupPane,e&&e.shapeOptions&&(e.shapeOptions=L.Util.extend({},this.options.shapeOptions,e.shapeOptions)),L.setOptions(this,e)},enable:function(){this._enabled||(this.fire("enabled",{handler:this.type}),this._map.fire("draw:drawstart",{layerType:this.type}),L.Handler.prototype.enable.call(this))},disable:function(){this._enabled&&(L.Handler.prototype.disable.call(this),this._map.fire("draw:drawstop",{layerType:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(L.DomUtil.disableTextSelection(),t.getContainer().focus(),this._tooltip=new L.Tooltip(this._map),L.DomEvent.on(this._container,"keyup",this._cancelDrawing,this))},removeHooks:function(){this._map&&(L.DomUtil.enableTextSelection(),this._tooltip.dispose(),this._tooltip=null,L.DomEvent.off(this._container,"keyup",this._cancelDrawing,this))},setOptions:function(t){L.setOptions(this,t)},_fireCreatedEvent:function(t){this._map.fire("draw:created",{layer:t,layerType:this.type})},_cancelDrawing:function(t){27===t.keyCode&&this.disable()}}),L.Draw.Polyline=L.Draw.Feature.extend({statics:{TYPE:"polyline"},Poly:L.Polyline,options:{allowIntersection:!0,repeatMode:!1,drawError:{color:"#b00b00",timeout:2500},icon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon"}),guidelineDistance:20,maxGuideLineLength:4e3,shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!1,clickable:!0},metric:!0,showLength:!0,zIndexOffset:2e3},initialize:function(t,e){this.options.drawError.message=L.drawLocal.draw.handlers.polyline.error,e&&e.drawError&&(e.drawError=L.Util.extend({},this.options.drawError,e.drawError)),this.type=L.Draw.Polyline.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._markers=[],this._markerGroup=new L.LayerGroup,this._map.addLayer(this._markerGroup),this._poly=new L.Polyline([],this.options.shapeOptions),this._tooltip.updateContent(this._getTooltipText()),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"leaflet-mouse-marker",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on("mousedown",this._onMouseDown,this).addTo(this._map),this._map.on("mousemove",this._onMouseMove,this).on("mouseup",this._onMouseUp,this).on("zoomend",this._onZoomEnd,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._clearHideErrorTimeout(),this._cleanUpShape(),this._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers,this._map.removeLayer(this._poly),delete this._poly,this._mouseMarker.off("mousedown",this._onMouseDown,this).off("mouseup",this._onMouseUp,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._clearGuides(),this._map.off("mousemove",this._onMouseMove,this).off("zoomend",this._onZoomEnd,this)},deleteLastVertex:function(){if(!(this._markers.length<=1)){var t=this._markers.pop(),e=this._poly,i=this._poly.spliceLatLngs(e.getLatLngs().length-1,1)[0];this._markerGroup.removeLayer(t),e.getLatLngs().length<2&&this._map.removeLayer(e),this._vertexChanged(i,!1)}},addVertex:function(t){var e=this._markers.length;return e>0&&!this.options.allowIntersection&&this._poly.newLatLngIntersects(t)?void this._showErrorTooltip():(this._errorShown&&this._hideErrorTooltip(),this._markers.push(this._createMarker(t)),this._poly.addLatLng(t),2===this._poly.getLatLngs().length&&this._map.addLayer(this._poly),void this._vertexChanged(t,!0))},_finishShape:function(){var t=this._poly.newLatLngIntersects(this._poly.getLatLngs()[0],!0);return!this.options.allowIntersection&&t||!this._shapeIsValid()?void this._showErrorTooltip():(this._fireCreatedEvent(),this.disable(),void(this.options.repeatMode&&this.enable()))},_shapeIsValid:function(){return!0},_onZoomEnd:function(){this._updateGuide()},_onMouseMove:function(t){var e=t.layerPoint,i=t.latlng;this._currentLatLng=i,this._updateTooltip(i),this._updateGuide(e),this._mouseMarker.setLatLng(i),L.DomEvent.preventDefault(t.originalEvent)},_vertexChanged:function(t,e){this._updateFinishHandler(),this._updateRunningMeasure(t,e),this._clearGuides(),this._updateTooltip()},_onMouseDown:function(t){var e=t.originalEvent;this._mouseDownOrigin=L.point(e.clientX,e.clientY)},_onMouseUp:function(e){if(this._mouseDownOrigin){var i=L.point(e.originalEvent.clientX,e.originalEvent.clientY).distanceTo(this._mouseDownOrigin);Math.abs(i)<9*(t.devicePixelRatio||1)&&this.addVertex(e.latlng)}this._mouseDownOrigin=null},_updateFinishHandler:function(){var t=this._markers.length;t>1&&this._markers[t-1].on("click",this._finishShape,this),t>2&&this._markers[t-2].off("click",this._finishShape,this)},_createMarker:function(t){var e=new L.Marker(t,{icon:this.options.icon,zIndexOffset:2*this.options.zIndexOffset});return this._markerGroup.addLayer(e),e},_updateGuide:function(t){var e=this._markers.length;e>0&&(t=t||this._map.latLngToLayerPoint(this._currentLatLng),this._clearGuides(),this._drawGuide(this._map.latLngToLayerPoint(this._markers[e-1].getLatLng()),t))},_updateTooltip:function(t){var e=this._getTooltipText();t&&this._tooltip.updatePosition(t),this._errorShown||this._tooltip.updateContent(e)},_drawGuide:function(t,e){var i,o,a,s=Math.floor(Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))),r=this.options.guidelineDistance,n=this.options.maxGuideLineLength,l=s>n?s-n:r;for(this._guidesContainer||(this._guidesContainer=L.DomUtil.create("div","leaflet-draw-guides",this._overlayPane));s>l;l+=this.options.guidelineDistance)i=l/s,o={x:Math.floor(t.x*(1-i)+i*e.x),y:Math.floor(t.y*(1-i)+i*e.y)},a=L.DomUtil.create("div","leaflet-draw-guide-dash",this._guidesContainer),a.style.backgroundColor=this._errorShown?this.options.drawError.color:this.options.shapeOptions.color,L.DomUtil.setPosition(a,o)},_updateGuideColor:function(t){if(this._guidesContainer)for(var e=0,i=this._guidesContainer.childNodes.length;i>e;e++)this._guidesContainer.childNodes[e].style.backgroundColor=t},_clearGuides:function(){if(this._guidesContainer)for(;this._guidesContainer.firstChild;)this._guidesContainer.removeChild(this._guidesContainer.firstChild)},_getTooltipText:function(){var t,e,i=this.options.showLength;return 0===this._markers.length?t={text:L.drawLocal.draw.handlers.polyline.tooltip.start}:(e=i?this._getMeasurementString():"",t=1===this._markers.length?{text:L.drawLocal.draw.handlers.polyline.tooltip.cont,subtext:e}:{text:L.drawLocal.draw.handlers.polyline.tooltip.end,subtext:e}),t},_updateRunningMeasure:function(t,e){var i,o,a=this._markers.length;1===this._markers.length?this._measurementRunningTotal=0:(i=a-(e?2:1),o=t.distanceTo(this._markers[i].getLatLng()),this._measurementRunningTotal+=o*(e?1:-1))},_getMeasurementString:function(){var t,e=this._currentLatLng,i=this._markers[this._markers.length-1].getLatLng();return t=this._measurementRunningTotal+e.distanceTo(i),L.GeometryUtil.readableDistance(t,this.options.metric)},_showErrorTooltip:function(){this._errorShown=!0,this._tooltip.showAsError().updateContent({text:this.options.drawError.message}),this._updateGuideColor(this.options.drawError.color),this._poly.setStyle({color:this.options.drawError.color}),this._clearHideErrorTimeout(),this._hideErrorTimeout=setTimeout(L.Util.bind(this._hideErrorTooltip,this),this.options.drawError.timeout)},_hideErrorTooltip:function(){this._errorShown=!1,this._clearHideErrorTimeout(),this._tooltip.removeError().updateContent(this._getTooltipText()),this._updateGuideColor(this.options.shapeOptions.color),this._poly.setStyle({color:this.options.shapeOptions.color})},_clearHideErrorTimeout:function(){this._hideErrorTimeout&&(clearTimeout(this._hideErrorTimeout),this._hideErrorTimeout=null)},_cleanUpShape:function(){this._markers.length>1&&this._markers[this._markers.length-1].off("click",this._finishShape,this)},_fireCreatedEvent:function(){var t=new this.Poly(this._poly.getLatLngs(),this.options.shapeOptions);L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Polygon=L.Draw.Polyline.extend({statics:{TYPE:"polygon"},Poly:L.Polygon,options:{showArea:!1,shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){L.Draw.Polyline.prototype.initialize.call(this,t,e),this.type=L.Draw.Polygon.TYPE},_updateFinishHandler:function(){var t=this._markers.length;1===t&&this._markers[0].on("click",this._finishShape,this),t>2&&(this._markers[t-1].on("dblclick",this._finishShape,this),t>3&&this._markers[t-2].off("dblclick",this._finishShape,this))},_getTooltipText:function(){var t,e;return 0===this._markers.length?t=L.drawLocal.draw.handlers.polygon.tooltip.start:this._markers.length<3?t=L.drawLocal.draw.handlers.polygon.tooltip.cont:(t=L.drawLocal.draw.handlers.polygon.tooltip.end,e=this._getMeasurementString()),{text:t,subtext:e}},_getMeasurementString:function(){var t=this._area;return t?L.GeometryUtil.readableArea(t,this.options.metric):null},_shapeIsValid:function(){return this._markers.length>=3},_vertexAdded:function(){if(!this.options.allowIntersection&&this.options.showArea){var t=this._poly.getLatLngs();this._area=L.GeometryUtil.geodesicArea(t)}},_cleanUpShape:function(){var t=this._markers.length;t>0&&(this._markers[0].off("click",this._finishShape,this),t>2&&this._markers[t-1].off("dblclick",this._finishShape,this))}}),L.SimpleShape={},L.Draw.SimpleShape=L.Draw.Feature.extend({options:{repeatMode:!1},initialize:function(t,e){this._endLabelText=L.drawLocal.draw.handlers.simpleshape.tooltip.end,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._mapDraggable=this._map.dragging.enabled(),this._mapDraggable&&this._map.dragging.disable(),this._container.style.cursor="crosshair",this._tooltip.updateContent({text:this._initialLabelText}),this._map.on("mousedown",this._onMouseDown,this).on("mousemove",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._mapDraggable&&this._map.dragging.enable(),this._container.style.cursor="",this._map.off("mousedown",this._onMouseDown,this).off("mousemove",this._onMouseMove,this),L.DomEvent.off(e,"mouseup",this._onMouseUp,this),this._shape&&(this._map.removeLayer(this._shape),delete this._shape)),this._isDrawing=!1},_onMouseDown:function(t){this._isDrawing=!0,this._startLatLng=t.latlng,L.DomEvent.on(e,"mouseup",this._onMouseUp,this).preventDefault(t.originalEvent)},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._isDrawing&&(this._tooltip.updateContent({text:this._endLabelText}),this._drawShape(e))},_onMouseUp:function(){this._shape&&this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()}}),L.Draw.Rectangle=L.Draw.SimpleShape.extend({statics:{TYPE:"rectangle"},options:{shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){this.type=L.Draw.Rectangle.TYPE,this._initialLabelText=L.drawLocal.draw.handlers.rectangle.tooltip.start,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_drawShape:function(t){this._shape?this._shape.setBounds(new L.LatLngBounds(this._startLatLng,t)):(this._shape=new L.Rectangle(new L.LatLngBounds(this._startLatLng,t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Rectangle(this._shape.getBounds(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Circle=L.Draw.SimpleShape.extend({statics:{TYPE:"circle"},options:{shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0},showRadius:!0,metric:!0},initialize:function(t,e){this.type=L.Draw.Circle.TYPE,this._initialLabelText=L.drawLocal.draw.handlers.circle.tooltip.start,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_drawShape:function(t){this._shape?this._shape.setRadius(this._startLatLng.distanceTo(t)):(this._shape=new L.Circle(this._startLatLng,this._startLatLng.distanceTo(t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Circle(this._startLatLng,this._shape.getRadius(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)},_onMouseMove:function(t){var e,i=t.latlng,o=this.options.showRadius,a=this.options.metric;this._tooltip.updatePosition(i),this._isDrawing&&(this._drawShape(i),e=this._shape.getRadius().toFixed(1),this._tooltip.updateContent({text:this._endLabelText,subtext:o?"Radius: "+L.GeometryUtil.readableDistance(e,a):""}))}}),L.Draw.Marker=L.Draw.Feature.extend({statics:{TYPE:"marker"},options:{icon:new L.Icon.Default,repeatMode:!1,zIndexOffset:2e3},initialize:function(t,e){this.type=L.Draw.Marker.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._tooltip.updateContent({text:L.drawLocal.draw.handlers.marker.tooltip.start}),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"leaflet-mouse-marker",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on("click",this._onClick,this).addTo(this._map),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._marker&&(this._marker.off("click",this._onClick,this),this._map.off("click",this._onClick,this).removeLayer(this._marker),delete this._marker),this._mouseMarker.off("click",this._onClick,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._map.off("mousemove",this._onMouseMove,this))},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._mouseMarker.setLatLng(e),this._marker?(e=this._mouseMarker.getLatLng(),this._marker.setLatLng(e)):(this._marker=new L.Marker(e,{icon:this.options.icon,zIndexOffset:this.options.zIndexOffset}),this._marker.on("click",this._onClick,this),this._map.on("click",this._onClick,this).addLayer(this._marker))},_onClick:function(){this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()},_fireCreatedEvent:function(){var t=new L.Marker(this._marker.getLatLng(),{icon:this.options.icon});L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Edit=L.Edit||{},L.Edit.Poly=L.Handler.extend({options:{icon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon"})},initialize:function(t,e){this._poly=t,L.setOptions(this,e)},addHooks:function(){this._poly._map&&(this._markerGroup||this._initMarkers(),this._poly._map.addLayer(this._markerGroup))},removeHooks:function(){this._poly._map&&(this._poly._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers)},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._markers=[];var t,e,i,o,a=this._poly._latlngs;for(t=0,i=a.length;i>t;t++)o=this._createMarker(a[t],t),o.on("click",this._onMarkerClick,this),this._markers.push(o);var s,r;for(t=0,e=i-1;i>t;e=t++)(0!==t||L.Polygon&&this._poly instanceof L.Polygon)&&(s=this._markers[e],r=this._markers[t],this._createMiddleMarker(s,r),this._updatePrevNext(s,r))},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:this.options.icon});return i._origLatLng=t,i._index=e,i.on("drag",this._onMarkerDrag,this),i.on("dragend",this._fireEdit,this),this._markerGroup.addLayer(i),i},_removeMarker:function(t){var e=t._index;this._markerGroup.removeLayer(t),this._markers.splice(e,1),this._poly.spliceLatLngs(e,1),this._updateIndexes(e,-1),t.off("drag",this._onMarkerDrag,this).off("dragend",this._fireEdit,this).off("click",this._onMarkerClick,this)},_fireEdit:function(){this._poly.edited=!0,this._poly.fire("edit")},_onMarkerDrag:function(t){var e=t.target;L.extend(e._origLatLng,e._latlng),e._middleLeft&&e._middleLeft.setLatLng(this._getMiddleLatLng(e._prev,e)),e._middleRight&&e._middleRight.setLatLng(this._getMiddleLatLng(e,e._next)),this._poly.redraw()},_onMarkerClick:function(t){var e=L.Polygon&&this._poly instanceof L.Polygon?4:3,i=t.target;this._poly._latlngs.lengtht&&(i._index+=e)})},_createMiddleMarker:function(t,e){var i,o,a,s=this._getMiddleLatLng(t,e),r=this._createMarker(s);r.setOpacity(.6),t._middleRight=e._middleLeft=r,o=function(){var o=e._index;r._index=o,r.off("click",i,this).on("click",this._onMarkerClick,this),s.lat=r.getLatLng().lat,s.lng=r.getLatLng().lng,this._poly.spliceLatLngs(o,0,s),this._markers.splice(o,0,r),r.setOpacity(1),this._updateIndexes(o,1),e._index++,this._updatePrevNext(t,r),this._updatePrevNext(r,e),this._poly.fire("editstart")},a=function(){r.off("dragstart",o,this),r.off("dragend",a,this),this._createMiddleMarker(t,r),this._createMiddleMarker(r,e)},i=function(){o.call(this),a.call(this),this._fireEdit()},r.on("click",i,this).on("dragstart",o,this).on("dragend",a,this),this._markerGroup.addLayer(r)},_updatePrevNext:function(t,e){t&&(t._next=e),e&&(e._prev=t)},_getMiddleLatLng:function(t,e){var i=this._poly._map,o=i.project(t.getLatLng()),a=i.project(e.getLatLng());return i.unproject(o._add(a)._divideBy(2))}}),L.Polyline.addInitHook(function(){this.editing||(L.Edit.Poly&&(this.editing=new L.Edit.Poly(this),this.options.editable&&this.editing.enable()),this.on("add",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on("remove",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()}))}),L.Edit=L.Edit||{},L.Edit.SimpleShape=L.Handler.extend({options:{moveIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-move"}),resizeIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-resize"})},initialize:function(t,e){this._shape=t,L.Util.setOptions(this,e)},addHooks:function(){this._shape._map&&(this._map=this._shape._map,this._markerGroup||this._initMarkers(),this._map.addLayer(this._markerGroup))},removeHooks:function(){if(this._shape._map){this._unbindMarker(this._moveMarker);for(var t=0,e=this._resizeMarkers.length;e>t;t++)this._unbindMarker(this._resizeMarkers[t]);this._resizeMarkers=null,this._map.removeLayer(this._markerGroup),delete this._markerGroup}this._map=null},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._createMoveMarker(),this._createResizeMarker()},_createMoveMarker:function(){},_createResizeMarker:function(){},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:e,zIndexOffset:10});return this._bindMarker(i),this._markerGroup.addLayer(i),i},_bindMarker:function(t){t.on("dragstart",this._onMarkerDragStart,this).on("drag",this._onMarkerDrag,this).on("dragend",this._onMarkerDragEnd,this)},_unbindMarker:function(t){t.off("dragstart",this._onMarkerDragStart,this).off("drag",this._onMarkerDrag,this).off("dragend",this._onMarkerDragEnd,this)},_onMarkerDragStart:function(t){var e=t.target;e.setOpacity(0),this._shape.fire("editstart")},_fireEdit:function(){this._shape.edited=!0,this._shape.fire("edit")},_onMarkerDrag:function(t){var e=t.target,i=e.getLatLng();e===this._moveMarker?this._move(i):this._resize(i),this._shape.redraw()},_onMarkerDragEnd:function(t){var e=t.target;e.setOpacity(1),this._fireEdit()},_move:function(){},_resize:function(){}}),L.Edit=L.Edit||{},L.Edit.Rectangle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getBounds(),e=t.getCenter();this._moveMarker=this._createMarker(e,this.options.moveIcon)},_createResizeMarker:function(){var t=this._getCorners();this._resizeMarkers=[];for(var e=0,i=t.length;i>e;e++)this._resizeMarkers.push(this._createMarker(t[e],this.options.resizeIcon)),this._resizeMarkers[e]._cornerIndex=e},_onMarkerDragStart:function(t){L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this,t);var e=this._getCorners(),i=t.target,o=i._cornerIndex;this._oppositeCorner=e[(o+2)%4],this._toggleCornerMarkers(0,o)},_onMarkerDragEnd:function(t){var e,i,o=t.target;o===this._moveMarker&&(e=this._shape.getBounds(),i=e.getCenter(),o.setLatLng(i)),this._toggleCornerMarkers(1),this._repositionCornerMarkers(),L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this,t)},_move:function(t){for(var e,i=this._shape.getLatLngs(),o=this._shape.getBounds(),a=o.getCenter(),s=[],r=0,n=i.length;n>r;r++)e=[i[r].lat-a.lat,i[r].lng-a.lng],s.push([t.lat+e[0],t.lng+e[1]]);this._shape.setLatLngs(s),this._repositionCornerMarkers()},_resize:function(t){var e;this._shape.setBounds(L.latLngBounds(t,this._oppositeCorner)),e=this._shape.getBounds(),this._moveMarker.setLatLng(e.getCenter())},_getCorners:function(){var t=this._shape.getBounds(),e=t.getNorthWest(),i=t.getNorthEast(),o=t.getSouthEast(),a=t.getSouthWest();return[e,i,o,a]},_toggleCornerMarkers:function(t){for(var e=0,i=this._resizeMarkers.length;i>e;e++)this._resizeMarkers[e].setOpacity(t)},_repositionCornerMarkers:function(){for(var t=this._getCorners(),e=0,i=this._resizeMarkers.length;i>e;e++)this._resizeMarkers[e].setLatLng(t[e])}}),L.Rectangle.addInitHook(function(){L.Edit.Rectangle&&(this.editing=new L.Edit.Rectangle(this),this.options.editable&&this.editing.enable())}),L.Edit=L.Edit||{},L.Edit.Circle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getLatLng();this._moveMarker=this._createMarker(t,this.options.moveIcon)},_createResizeMarker:function(){var t=this._shape.getLatLng(),e=this._getResizeMarkerPoint(t);this._resizeMarkers=[],this._resizeMarkers.push(this._createMarker(e,this.options.resizeIcon))},_getResizeMarkerPoint:function(t){var e=this._shape._radius*Math.cos(Math.PI/4),i=this._map.project(t);return this._map.unproject([i.x+e,i.y-e])},_move:function(t){var e=this._getResizeMarkerPoint(t);this._resizeMarkers[0].setLatLng(e),this._shape.setLatLng(t)},_resize:function(t){var e=this._moveMarker.getLatLng(),i=e.distanceTo(t);this._shape.setRadius(i)}}),L.Circle.addInitHook(function(){L.Edit.Circle&&(this.editing=new L.Edit.Circle(this),this.options.editable&&this.editing.enable()),this.on("add",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on("remove",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()})}),L.LatLngUtil={cloneLatLngs:function(t){for(var e=[],i=0,o=t.length;o>i;i++)e.push(this.cloneLatLng(t[i]));return e},cloneLatLng:function(t){return L.latLng(t.lat,t.lng)}},L.GeometryUtil=L.extend(L.GeometryUtil||{},{geodesicArea:function(t){var e,i,o=t.length,a=0,s=L.LatLng.DEG_TO_RAD;if(o>2){for(var r=0;o>r;r++)e=t[r],i=t[(r+1)%o],a+=(i.lng-e.lng)*s*(2+Math.sin(e.lat*s)+Math.sin(i.lat*s));a=6378137*a*6378137/2}return Math.abs(a)},readableArea:function(t,e){var i;return e?i=t>=1e4?(1e-4*t).toFixed(2)+" ha":t.toFixed(2)+" m²":(t*=.836127,i=t>=3097600?(t/3097600).toFixed(2)+" mi²":t>=4840?(t/4840).toFixed(2)+" acres":Math.ceil(t)+" yd²"),i},readableDistance:function(t,e){var i;return e?i=t>1e3?(t/1e3).toFixed(2)+" km":Math.ceil(t)+" m":(t*=1.09361,i=t>1760?(t/1760).toFixed(2)+" miles":Math.ceil(t)+" yd"),i}}),L.Util.extend(L.LineUtil,{segmentsIntersect:function(t,e,i,o){return this._checkCounterclockwise(t,i,o)!==this._checkCounterclockwise(e,i,o)&&this._checkCounterclockwise(t,e,i)!==this._checkCounterclockwise(t,e,o)},_checkCounterclockwise:function(t,e,i){return(i.y-t.y)*(e.x-t.x)>(e.y-t.y)*(i.x-t.x)}}),L.Polyline.include({intersects:function(){var t,e,i,o=this._originalPoints,a=o?o.length:0;if(this._tooFewPointsForIntersection())return!1;for(t=a-1;t>=3;t--)if(e=o[t-1],i=o[t],this._lineSegmentsIntersectsRange(e,i,t-2))return!0;return!1},newLatLngIntersects:function(t,e){return this._map?this.newPointIntersects(this._map.latLngToLayerPoint(t),e):!1},newPointIntersects:function(t,e){var i=this._originalPoints,o=i?i.length:0,a=i?i[o-1]:null,s=o-2;return this._tooFewPointsForIntersection(1)?!1:this._lineSegmentsIntersectsRange(a,t,s,e?1:0)},_tooFewPointsForIntersection:function(t){var e=this._originalPoints,i=e?e.length:0;return i+=t||0,!this._originalPoints||3>=i},_lineSegmentsIntersectsRange:function(t,e,i,o){var a,s,r=this._originalPoints;o=o||0;for(var n=i;n>o;n--)if(a=r[n-1],s=r[n],L.LineUtil.segmentsIntersect(t,e,a,s))return!0;return!1}}),L.Polygon.include({intersects:function(){var t,e,i,o,a,s=this._originalPoints;return this._tooFewPointsForIntersection()?!1:(t=L.Polyline.prototype.intersects.call(this))?!0:(e=s.length,i=s[0],o=s[e-1],a=e-2,this._lineSegmentsIntersectsRange(o,i,a,1))}}),L.Control.Draw=L.Control.extend({options:{position:"topleft",draw:{},edit:!1},initialize:function(t){if(L.version<"0.7")throw new Error("Leaflet.draw 0.2.3+ requires Leaflet 0.7.0+. Download latest from https://github.com/Leaflet/Leaflet/");L.Control.prototype.initialize.call(this,t);var e,i;this._toolbars={},L.DrawToolbar&&this.options.draw&&(i=new L.DrawToolbar(this.options.draw),e=L.stamp(i),this._toolbars[e]=i,this._toolbars[e].on("enable",this._toolbarEnabled,this)),L.EditToolbar&&this.options.edit&&(i=new L.EditToolbar(this.options.edit),e=L.stamp(i),this._toolbars[e]=i,this._toolbars[e].on("enable",this._toolbarEnabled,this))},onAdd:function(t){var e,i=L.DomUtil.create("div","leaflet-draw"),o=!1,a="leaflet-draw-toolbar-top";for(var s in this._toolbars)this._toolbars.hasOwnProperty(s)&&(e=this._toolbars[s].addToolbar(t),e&&(o||(L.DomUtil.hasClass(e,a)||L.DomUtil.addClass(e.childNodes[0],a),o=!0),i.appendChild(e)));return i},onRemove:function(){for(var t in this._toolbars)this._toolbars.hasOwnProperty(t)&&this._toolbars[t].removeToolbar()},setDrawingOptions:function(t){for(var e in this._toolbars)this._toolbars[e]instanceof L.DrawToolbar&&this._toolbars[e].setOptions(t)},_toolbarEnabled:function(t){var e=""+L.stamp(t.target);for(var i in this._toolbars)this._toolbars.hasOwnProperty(i)&&i!==e&&this._toolbars[i].disable()}}),L.Map.mergeOptions({drawControlTooltips:!0,drawControl:!1}),L.Map.addInitHook(function(){this.options.drawControl&&(this.drawControl=new L.Control.Draw,this.addControl(this.drawControl))}),L.Toolbar=L.Class.extend({includes:[L.Mixin.Events],initialize:function(t){L.setOptions(this,t),this._modes={},this._actionButtons=[],this._activeMode=null},enabled:function(){return null!==this._activeMode},disable:function(){this.enabled()&&this._activeMode.handler.disable()},addToolbar:function(t){var e,i=L.DomUtil.create("div","leaflet-draw-section"),o=0,a=this._toolbarClass||"",s=this.getModeHandlers(t);for(this._toolbarContainer=L.DomUtil.create("div","leaflet-draw-toolbar leaflet-bar"),this._map=t,e=0;ee;e++)this._disposeButton(this._actionButtons[e].button,this._actionButtons[e].callback,this);this._actionButtons=[],this._actionsContainer=null},_initModeHandler:function(t,e,i,o,a){var s=t.type;this._modes[s]={},this._modes[s].handler=t,this._modes[s].button=this._createButton({title:a,className:o+"-"+s,container:e,callback:this._modes[s].handler.enable,context:this._modes[s].handler}),this._modes[s].buttonIndex=i,this._modes[s].handler.on("enabled",this._handlerActivated,this).on("disabled",this._handlerDeactivated,this)},_createButton:function(t){var e=L.DomUtil.create("a",t.className||"",t.container);return e.href="#",t.text&&(e.innerHTML=t.text),t.title&&(e.title=t.title),L.DomEvent.on(e,"click",L.DomEvent.stopPropagation).on(e,"mousedown",L.DomEvent.stopPropagation).on(e,"dblclick",L.DomEvent.stopPropagation).on(e,"click",L.DomEvent.preventDefault).on(e,"click",t.callback,t.context),e},_disposeButton:function(t,e){L.DomEvent.off(t,"click",L.DomEvent.stopPropagation).off(t,"mousedown",L.DomEvent.stopPropagation).off(t,"dblclick",L.DomEvent.stopPropagation).off(t,"click",L.DomEvent.preventDefault).off(t,"click",e)},_handlerActivated:function(t){this.disable(),this._activeMode=this._modes[t.handler],L.DomUtil.addClass(this._activeMode.button,"leaflet-draw-toolbar-button-enabled"),this._showActionsToolbar(),this.fire("enable")},_handlerDeactivated:function(){this._hideActionsToolbar(),L.DomUtil.removeClass(this._activeMode.button,"leaflet-draw-toolbar-button-enabled"),this._activeMode=null,this.fire("disable")},_createActions:function(t){var e,i,o,a,s=this._actionsContainer,r=this.getActions(t),n=r.length;for(i=0,o=this._actionButtons.length;o>i;i++)this._disposeButton(this._actionButtons[i].button,this._actionButtons[i].callback);for(this._actionButtons=[];s.firstChild;)s.removeChild(s.firstChild);for(var l=0;n>l;l++)"enabled"in r[l]&&!r[l].enabled||(e=L.DomUtil.create("li","",s),a=this._createButton({title:r[l].title,text:r[l].text,container:e,callback:r[l].callback,context:r[l].context}),this._actionButtons.push({button:a,callback:r[l].callback}))},_showActionsToolbar:function(){var t=this._activeMode.buttonIndex,e=this._lastButtonIndex,i=this._activeMode.button.offsetTop-1;this._createActions(this._activeMode.handler),this._actionsContainer.style.top=i+"px",0===t&&(L.DomUtil.addClass(this._toolbarContainer,"leaflet-draw-toolbar-notop"),L.DomUtil.addClass(this._actionsContainer,"leaflet-draw-actions-top")),t===e&&(L.DomUtil.addClass(this._toolbarContainer,"leaflet-draw-toolbar-nobottom"),L.DomUtil.addClass(this._actionsContainer,"leaflet-draw-actions-bottom")),this._actionsContainer.style.display="block" +},_hideActionsToolbar:function(){this._actionsContainer.style.display="none",L.DomUtil.removeClass(this._toolbarContainer,"leaflet-draw-toolbar-notop"),L.DomUtil.removeClass(this._toolbarContainer,"leaflet-draw-toolbar-nobottom"),L.DomUtil.removeClass(this._actionsContainer,"leaflet-draw-actions-top"),L.DomUtil.removeClass(this._actionsContainer,"leaflet-draw-actions-bottom")}}),L.Tooltip=L.Class.extend({initialize:function(t){this._map=t,this._popupPane=t._panes.popupPane,this._container=t.options.drawControlTooltips?L.DomUtil.create("div","leaflet-draw-tooltip",this._popupPane):null,this._singleLineLabel=!1},dispose:function(){this._container&&(this._popupPane.removeChild(this._container),this._container=null)},updateContent:function(t){return this._container?(t.subtext=t.subtext||"",0!==t.subtext.length||this._singleLineLabel?t.subtext.length>0&&this._singleLineLabel&&(L.DomUtil.removeClass(this._container,"leaflet-draw-tooltip-single"),this._singleLineLabel=!1):(L.DomUtil.addClass(this._container,"leaflet-draw-tooltip-single"),this._singleLineLabel=!0),this._container.innerHTML=(t.subtext.length>0?''+t.subtext+"
":"")+""+t.text+"",this):this},updatePosition:function(t){var e=this._map.latLngToLayerPoint(t),i=this._container;return this._container&&(i.style.visibility="inherit",L.DomUtil.setPosition(i,e)),this},showAsError:function(){return this._container&&L.DomUtil.addClass(this._container,"leaflet-error-draw-tooltip"),this},removeError:function(){return this._container&&L.DomUtil.removeClass(this._container,"leaflet-error-draw-tooltip"),this}}),L.DrawToolbar=L.Toolbar.extend({options:{polyline:{},polygon:{},rectangle:{},circle:{},marker:{}},initialize:function(t){for(var e in this.options)this.options.hasOwnProperty(e)&&t[e]&&(t[e]=L.extend({},this.options[e],t[e]));this._toolbarClass="leaflet-draw-draw",L.Toolbar.prototype.initialize.call(this,t)},getModeHandlers:function(t){return[{enabled:this.options.polyline,handler:new L.Draw.Polyline(t,this.options.polyline),title:L.drawLocal.draw.toolbar.buttons.polyline},{enabled:this.options.polygon,handler:new L.Draw.Polygon(t,this.options.polygon),title:L.drawLocal.draw.toolbar.buttons.polygon},{enabled:this.options.rectangle,handler:new L.Draw.Rectangle(t,this.options.rectangle),title:L.drawLocal.draw.toolbar.buttons.rectangle},{enabled:this.options.circle,handler:new L.Draw.Circle(t,this.options.circle),title:L.drawLocal.draw.toolbar.buttons.circle},{enabled:this.options.marker,handler:new L.Draw.Marker(t,this.options.marker),title:L.drawLocal.draw.toolbar.buttons.marker}]},getActions:function(t){return[{enabled:t.deleteLastVertex,title:L.drawLocal.draw.toolbar.undo.title,text:L.drawLocal.draw.toolbar.undo.text,callback:t.deleteLastVertex,context:t},{title:L.drawLocal.draw.toolbar.actions.title,text:L.drawLocal.draw.toolbar.actions.text,callback:this.disable,context:this}]},setOptions:function(t){L.setOptions(this,t);for(var e in this._modes)this._modes.hasOwnProperty(e)&&t.hasOwnProperty(e)&&this._modes[e].handler.setOptions(t[e])}}),L.EditToolbar=L.Toolbar.extend({options:{edit:{selectedPathOptions:{color:"#fe57a1",opacity:.6,dashArray:"10, 10",fill:!0,fillColor:"#fe57a1",fillOpacity:.1}},remove:{},featureGroup:null},initialize:function(t){t.edit&&("undefined"==typeof t.edit.selectedPathOptions&&(t.edit.selectedPathOptions=this.options.edit.selectedPathOptions),t.edit=L.extend({},this.options.edit,t.edit)),t.remove&&(t.remove=L.extend({},this.options.remove,t.remove)),this._toolbarClass="leaflet-draw-edit",L.Toolbar.prototype.initialize.call(this,t),this._selectedFeatureCount=0},getModeHandlers:function(t){var e=this.options.featureGroup;return[{enabled:this.options.edit,handler:new L.EditToolbar.Edit(t,{featureGroup:e,selectedPathOptions:this.options.edit.selectedPathOptions}),title:L.drawLocal.edit.toolbar.buttons.edit},{enabled:this.options.remove,handler:new L.EditToolbar.Delete(t,{featureGroup:e}),title:L.drawLocal.edit.toolbar.buttons.remove}]},getActions:function(){return[{title:L.drawLocal.edit.toolbar.actions.save.title,text:L.drawLocal.edit.toolbar.actions.save.text,callback:this._save,context:this},{title:L.drawLocal.edit.toolbar.actions.cancel.title,text:L.drawLocal.edit.toolbar.actions.cancel.text,callback:this.disable,context:this}]},addToolbar:function(t){var e=L.Toolbar.prototype.addToolbar.call(this,t);return this._checkDisabled(),this.options.featureGroup.on("layeradd layerremove",this._checkDisabled,this),e},removeToolbar:function(){this.options.featureGroup.off("layeradd layerremove",this._checkDisabled,this),L.Toolbar.prototype.removeToolbar.call(this)},disable:function(){this.enabled()&&(this._activeMode.handler.revertLayers(),L.Toolbar.prototype.disable.call(this))},_save:function(){this._activeMode.handler.save(),this._activeMode.handler.disable()},_checkDisabled:function(){var t,e=this.options.featureGroup,i=0!==e.getLayers().length;this.options.edit&&(t=this._modes[L.EditToolbar.Edit.TYPE].button,i?L.DomUtil.removeClass(t,"leaflet-disabled"):L.DomUtil.addClass(t,"leaflet-disabled"),t.setAttribute("title",i?L.drawLocal.edit.toolbar.buttons.edit:L.drawLocal.edit.toolbar.buttons.editDisabled)),this.options.remove&&(t=this._modes[L.EditToolbar.Delete.TYPE].button,i?L.DomUtil.removeClass(t,"leaflet-disabled"):L.DomUtil.addClass(t,"leaflet-disabled"),t.setAttribute("title",i?L.drawLocal.edit.toolbar.buttons.remove:L.drawLocal.edit.toolbar.buttons.removeDisabled))}}),L.EditToolbar.Edit=L.Handler.extend({statics:{TYPE:"edit"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),this._selectedPathOptions=e.selectedPathOptions,this._featureGroup=e.featureGroup,!(this._featureGroup instanceof L.FeatureGroup))throw new Error("options.featureGroup must be a L.FeatureGroup");this._uneditedLayerProps={},this.type=L.EditToolbar.Edit.TYPE},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(this.fire("enabled",{handler:this.type}),this._map.fire("draw:editstart",{handler:this.type}),L.Handler.prototype.enable.call(this),this._featureGroup.on("layeradd",this._enableLayerEdit,this).on("layerremove",this._disableLayerEdit,this))},disable:function(){this._enabled&&(this._featureGroup.off("layeradd",this._enableLayerEdit,this).off("layerremove",this._disableLayerEdit,this),L.Handler.prototype.disable.call(this),this._map.fire("draw:editstop",{handler:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._featureGroup.eachLayer(this._enableLayerEdit,this),this._tooltip=new L.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.edit.tooltip.text,subtext:L.drawLocal.edit.handlers.edit.tooltip.subtext}),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._featureGroup.eachLayer(this._disableLayerEdit,this),this._uneditedLayerProps={},this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this))},revertLayers:function(){this._featureGroup.eachLayer(function(t){this._revertLayer(t)},this)},save:function(){var t=new L.LayerGroup;this._featureGroup.eachLayer(function(e){e.edited&&(t.addLayer(e),e.edited=!1)}),this._map.fire("draw:edited",{layers:t})},_backupLayer:function(t){var e=L.Util.stamp(t);this._uneditedLayerProps[e]||(t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?this._uneditedLayerProps[e]={latlngs:L.LatLngUtil.cloneLatLngs(t.getLatLngs())}:t instanceof L.Circle?this._uneditedLayerProps[e]={latlng:L.LatLngUtil.cloneLatLng(t.getLatLng()),radius:t.getRadius()}:t instanceof L.Marker&&(this._uneditedLayerProps[e]={latlng:L.LatLngUtil.cloneLatLng(t.getLatLng())}))},_revertLayer:function(t){var e=L.Util.stamp(t);t.edited=!1,this._uneditedLayerProps.hasOwnProperty(e)&&(t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?t.setLatLngs(this._uneditedLayerProps[e].latlngs):t instanceof L.Circle?(t.setLatLng(this._uneditedLayerProps[e].latlng),t.setRadius(this._uneditedLayerProps[e].radius)):t instanceof L.Marker&&t.setLatLng(this._uneditedLayerProps[e].latlng))},_toggleMarkerHighlight:function(t){if(t._icon){var e=t._icon;e.style.display="none",L.DomUtil.hasClass(e,"leaflet-edit-marker-selected")?(L.DomUtil.removeClass(e,"leaflet-edit-marker-selected"),this._offsetMarker(e,-4)):(L.DomUtil.addClass(e,"leaflet-edit-marker-selected"),this._offsetMarker(e,4)),e.style.display=""}},_offsetMarker:function(t,e){var i=parseInt(t.style.marginTop,10)-e,o=parseInt(t.style.marginLeft,10)-e;t.style.marginTop=i+"px",t.style.marginLeft=o+"px"},_enableLayerEdit:function(t){var e,i=t.layer||t.target||t,o=i instanceof L.Marker;(!o||i._icon)&&(this._backupLayer(i),this._selectedPathOptions&&(e=L.Util.extend({},this._selectedPathOptions),o?this._toggleMarkerHighlight(i):(i.options.previousOptions=L.Util.extend({dashArray:null},i.options),i instanceof L.Circle||i instanceof L.Polygon||i instanceof L.Rectangle||(e.fill=!1),i.setStyle(e))),o?(i.dragging.enable(),i.on("dragend",this._onMarkerDragEnd)):i.editing.enable())},_disableLayerEdit:function(t){var e=t.layer||t.target||t;e.edited=!1,this._selectedPathOptions&&(e instanceof L.Marker?this._toggleMarkerHighlight(e):(e.setStyle(e.options.previousOptions),delete e.options.previousOptions)),e instanceof L.Marker?(e.dragging.disable(),e.off("dragend",this._onMarkerDragEnd,this)):e.editing.disable()},_onMarkerDragEnd:function(t){var e=t.target;e.edited=!0},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_hasAvailableLayers:function(){return 0!==this._featureGroup.getLayers().length}}),L.EditToolbar.Delete=L.Handler.extend({statics:{TYPE:"remove"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),L.Util.setOptions(this,e),this._deletableLayers=this.options.featureGroup,!(this._deletableLayers instanceof L.FeatureGroup))throw new Error("options.featureGroup must be a L.FeatureGroup");this.type=L.EditToolbar.Delete.TYPE},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(this.fire("enabled",{handler:this.type}),this._map.fire("draw:deletestart",{handler:this.type}),L.Handler.prototype.enable.call(this),this._deletableLayers.on("layeradd",this._enableLayerDelete,this).on("layerremove",this._disableLayerDelete,this))},disable:function(){this._enabled&&(this._deletableLayers.off("layeradd",this._enableLayerDelete,this).off("layerremove",this._disableLayerDelete,this),L.Handler.prototype.disable.call(this),this._map.fire("draw:deletestop",{handler:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._deletableLayers.eachLayer(this._enableLayerDelete,this),this._deletedLayers=new L.layerGroup,this._tooltip=new L.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.remove.tooltip.text}),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._deletableLayers.eachLayer(this._disableLayerDelete,this),this._deletedLayers=null,this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this))},revertLayers:function(){this._deletedLayers.eachLayer(function(t){this._deletableLayers.addLayer(t)},this)},save:function(){this._map.fire("draw:deleted",{layers:this._deletedLayers})},_enableLayerDelete:function(t){var e=t.layer||t.target||t;e.on("click",this._removeLayer,this)},_disableLayerDelete:function(t){var e=t.layer||t.target||t;e.off("click",this._removeLayer,this),this._deletedLayers.removeLayer(e)},_removeLayer:function(t){var e=t.layer||t.target||t;this._deletableLayers.removeLayer(e),this._deletedLayers.addLayer(e)},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_hasAvailableLayers:function(){return 0!==this._deletableLayers.getLayers().length}})}(window,document); \ No newline at end of file diff --git a/ajax/libs/leaflet.draw/package.json b/ajax/libs/leaflet.draw/package.json index 497fd89f4..fd39cd479 100644 --- a/ajax/libs/leaflet.draw/package.json +++ b/ajax/libs/leaflet.draw/package.json @@ -1,7 +1,7 @@ { "name": "leaflet.draw", "filename": "leaflet.draw.js", - "version": "0.2.2", + "version": "0.2.3", "description": "Vector drawing plugin for Leaflet", "homepage": "https://github.com/Leaflet/Leaflet.draw", "keywords": [