diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e95b0ea..ce256dab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ Leaflet Changelog * Map now preserves its center after resize. * When panning to another copy of the world (that's infinite horizontally), map overlays now jump to corresponding positions. [#273](https://github.com/CloudMade/Leaflet/issues/273) * Limited maximum zoom change on a single mouse wheel movement (so you won't zoom across the whole zoom range in one scroll). [#149](https://github.com/CloudMade/Leaflet/issues/149) + * Significantly improved line simplification performance (noticeable when rendering polylines/polygons with tens of thousands of points) * Improved circles performance by not drawing them if they're off the clip region. #### API improvements @@ -27,10 +28,13 @@ Leaflet Changelog * Improved `Map` `locate` method, added ability to watch location continuously and more options. [#212](https://github.com/CloudMade/Leaflet/issues/212) * Added second argument `inside` to `Map` `getBoundsZoom` method that allows you to get appropriate zoom for the view to fit *inside* the given bounds. * Added `hasLayer` method to `Map`. + * Added `Marker` `zIndexOffset` option to be able to set certain markers below/above others. [#65](https://github.com/CloudMade/Leaflet/issues/65) * Added `urlParams` third optional argument to `TileLayer` constructor for convenience: an object with properties that will be evaluated in the URL template. * Added `TileLayer` `continuousWorld` option to disable tile coordinates checking/wrapping. * Added `TileLayer` `tileunload` event fired when tile gets removed after panning (by [@CodeJosch](https://github.com/CodeJosch)). [#256](https://github.com/CloudMade/Leaflet/pull/256) * Added `TileLayer` `zoomOffset` option useful for non-256px tiles (by [@msaspence](https://github.com/msaspence)). + * Added `TileLayer` `zoomReverse` option to reverse zoom numbering (by [@Majiir](https://github.com/Majiir)). [#406](https://github.com/CloudMade/Leaflet/pull/406) + * Added `TileLayer.Canvas` `redraw` method (by [@mortenbekditlevsen](https://github.com/mortenbekditlevsen)). [#459](https://github.com/CloudMade/Leaflet/pull/459) * Added `Polyline` `closestLayerPoint` method that's can be useful for interaction features (by [@anru](https://github.com/anru)). [#186](https://github.com/CloudMade/Leaflet/pull/186) * Added `setLatLngs` method to `MultiPolyline` and `MultiPolygon` (by [@anru](https://github.com/anru)). [#194](https://github.com/CloudMade/Leaflet/pull/194) * Added `getBounds` method to `Polyline` and `Polygon` (by [@JasonSanford](https://github.com/JasonSanford)). [#253](https://github.com/CloudMade/Leaflet/pull/253) @@ -39,18 +43,27 @@ Leaflet Changelog * Added `ImageOverlay` `load` event. [#213](https://github.com/CloudMade/Leaflet/issues/213) * Added `minWidth` option to `Popup` (by [@marphi](https://github.com/marphi)). [#214](https://github.com/CloudMade/Leaflet/pull/214) * Improved `LatLng` constructor to be more tolerant (and throw descriptive error if latitude or longitude can't be interpreted as a number). [#136](https://github.com/CloudMade/Leaflet/issues/136) + * Added `LatLng` `distanceTo` method (great circle distance) (by [@mortenbekditlevsen](https://github.com/mortenbekditlevsen)). [#462](https://github.com/CloudMade/Leaflet/pull/462) * Added `LatLngBounds` `toBBoxString` method for convenience (by [@JasonSanford](https://github.com/JasonSanford)). [#263](https://github.com/CloudMade/Leaflet/pull/263) * Added `LatLngBounds` `intersects(otherBounds)` method (thanks to [@pagameba](https://github.com/pagameba)). [#350](https://github.com/CloudMade/Leaflet/pull/350) + * Added `Bounds` `intersects(otherBounds)` method. [#461](https://github.com/CloudMade/Leaflet/issues/461) * Added `L.Util.template` method for simple string template evaluation. * Added `DomUtil.removeClass` method (by [@anru](https://github.com/anru)). + * Added ability to pass empty imageUrl to icons for creating transparent clickable regions (by [@mortenbekditlevsen](https://github.com/mortenbekditlevsen)). [#460](https://github.com/CloudMade/Leaflet/pull/460) * Improved browser-specific code to rely more on feature detection rather than user agent string. * Improved superclass access mechanism to work with inheritance chains of 3 or more classes; now you should use `Klass.superclass` instead of `this.superclass` (by [@anru](https://github.com/anru)). [#179](https://github.com/CloudMade/Leaflet/pull/179) +#### Development workflow improvements + + * Build system completely overhauled to be based on Node.js, Jake, JSHint and UglifyJS. + * All code is now linted for errors and conformity with a strict code style (with JSHint), and wont build unless the check passes. + ### Bugfixes #### General bugfixes * Fixed a bug where `Circle` was rendered with incorrect radius (didn't take projection exagerration into account). [#331](https://github.com/CloudMade/Leaflet/issues/331) + * Fixed a bug where `Map` `getBounds` would work incorrectly on a date line cross. [#295](https://github.com/CloudMade/Leaflet/issues/295) * Fixed a bug where polygons and polylines sometimes rendered incorrectly on some zoom levels. [#381](https://github.com/CloudMade/Leaflet/issues/381) * Fixed a bug where fast mouse wheel zoom worked incorrectly when approaching min/max zoom values. * Fixed a bug where `GeoJSON` `pointToLayer` option wouldn't work in a `GeometryCollection`. [#391](https://github.com/CloudMade/Leaflet/issues/391) @@ -66,6 +79,7 @@ Leaflet Changelog * Fixed broken popup `closePopup` option (by [@jgerigmeyer](https://github.com/jgerigmeyer)). * Fixed a bug that caused en error when dragging marker with icon without shadow (by [@anru](https://github.com/anru)). [#178](https://github.com/CloudMade/Leaflet/issues/178) * Fixed a typo in `Bounds` `contains` method (by [@anru](https://github.com/anru)). [#180](https://github.com/CloudMade/Leaflet/pull/180) + * Fixed a bug where creating an empty `Polygon` with `new L.Polygon()` would raise an error. * Fixed a bug where drag event fired before the actual movement of layer (by [@anru](https://github.com/anru)). [#197](https://github.com/CloudMade/Leaflet/pull/197) * Fixed a bug where map click caused an error if dragging is initially disabled. [#196](https://github.com/CloudMade/Leaflet/issues/196) * Fixed a bug where map `movestart` event would fire after zoom animation. @@ -81,6 +95,7 @@ Leaflet Changelog #### Browser bugfixes * Fixed occasional crashes on Mac Safari (thanks to [@lapinos03](https://github.com/lapinos03)). [#191](https://github.com/CloudMade/Leaflet/issues/191) + * Fixed a bug where resizing the map would sometimes make it blurry on WebKit (by [@mortenbekditlevsen](https://github.com/mortenbekditlevsen)). [#453](https://github.com/CloudMade/Leaflet/pull/453) * Fixed a bug that raised error in IE6-8 when clicking on popup close button. [#235](https://github.com/CloudMade/Leaflet/issues/235) * Fixed a bug with Safari not redrawing UI immediately after closing a popup. [#296](https://github.com/CloudMade/Leaflet/issues/296) * Fixed a bug that caused performance drop and high CPU usage when calling `setView` or `panTo` to the current center. [#231](https://github.com/CloudMade/Leaflet/issues/231) @@ -91,6 +106,7 @@ Leaflet Changelog * Fixed a bug that caused an error when clicking vector layers under iOS. [#204](https://github.com/CloudMade/Leaflet/issues/204) * Fixed crash on Android 3+ when panning or zooming (by [@florian](https://github.com/florianf)). [#137](https://github.com/CloudMade/Leaflet/issues/137) + * Fixed a bug that caused the map to pan when touch-panning inside a popup. [#452](https://github.com/CloudMade/Leaflet/issues/452) ## 0.2.1 (2011-06-18) diff --git a/build/build.js b/build/build.js index a918d3bd..68cb44b1 100644 --- a/build/build.js +++ b/build/build.js @@ -47,7 +47,7 @@ exports.uglify = function (code) { ast = pro.ast_squeeze(ast, {keep_comps: false}); ast = pro.ast_squeeze_more(ast); - return pro.gen_code(ast); + return pro.gen_code(ast) + ';'; }; exports.combineFiles = function (files) { diff --git a/dist/leaflet-src.js b/dist/leaflet-src.js index 18606745..7bfb905c 100644 --- a/dist/leaflet-src.js +++ b/dist/leaflet-src.js @@ -451,7 +451,20 @@ L.Bounds = L.Class.extend({ (max.x <= this.max.x) && (min.y >= this.min.y) && (max.y <= this.max.y); + }, + + intersects: function (/*Bounds*/ bounds) { + var min = this.min, + max = this.max, + min2 = bounds.min, + max2 = bounds.max; + + var xIntersects = (max2.x >= min.x) && (min2.x <= max.x), + yIntersects = (max2.y >= min.y) && (min2.y <= max.y); + + return xIntersects && yIntersects; } + }); @@ -659,7 +672,7 @@ L.LatLng = function (/*Number*/ rawLat, /*Number*/ rawLng, /*Boolean*/ noWrap) { if (noWrap !== true) { lat = Math.max(Math.min(lat, 90), -90); // clamp latitude into -90..90 - lng = (lng + 180) % 360 + (lng < -180 ? 180 : -180); // wrap longtitude into -180..180 + lng = (lng + 180) % 360 + ((lng < -180 || lng === 180) ? 180 : -180); // wrap longtitude into -180..180 } //TODO change to lat() & lng() @@ -687,6 +700,22 @@ L.LatLng.prototype = { return 'LatLng(' + L.Util.formatNum(this.lat) + ', ' + L.Util.formatNum(this.lng) + ')'; + }, + + // Haversine distance formula, see http://en.wikipedia.org/wiki/Haversine_formula + distanceTo: function (/*LatLng*/ other)/*->Double*/ { + var R = 6378137, // earth radius in meters + d2r = L.LatLng.DEG_TO_RAD, + dLat = (other.lat - this.lat) * d2r, + dLon = (other.lng - this.lng) * d2r, + lat1 = this.lat * d2r, + lat2 = other.lat * d2r, + sin1 = Math.sin(dLat / 2), + sin2 = Math.sin(dLon / 2); + + var a = sin1 * sin1 + sin2 * sin2 * Math.cos(lat1) * Math.cos(lat2); + + return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); } }; @@ -709,8 +738,8 @@ L.LatLngBounds = L.Class.extend({ // extend the bounds to contain the given point extend: function (/*LatLng*/ latlng) { if (!this._southWest && !this._northEast) { - this._southWest = new L.LatLng(latlng.lat, latlng.lng); - this._northEast = new L.LatLng(latlng.lat, latlng.lng); + this._southWest = new L.LatLng(latlng.lat, latlng.lng, true); + this._northEast = new L.LatLng(latlng.lat, latlng.lng, true); } else { this._southWest.lat = Math.min(latlng.lat, this._southWest.lat); this._southWest.lng = Math.min(latlng.lng, this._southWest.lng); @@ -734,11 +763,11 @@ L.LatLngBounds = L.Class.extend({ }, getNorthWest: function () { - return new L.LatLng(this._northEast.lat, this._southWest.lng); + return new L.LatLng(this._northEast.lat, this._southWest.lng, true); }, getSouthEast: function () { - return new L.LatLng(this._southWest.lat, this._northEast.lng); + return new L.LatLng(this._southWest.lat, this._northEast.lng, true); }, contains: function (/*LatLngBounds or LatLng*/ obj) /*-> Boolean*/ { @@ -1125,7 +1154,7 @@ L.Map = L.Class.extend({ return this; } - this._rawPanBy(oldSize.subtract(this.getSize()).divideBy(2)); + this._rawPanBy(oldSize.subtract(this.getSize()).divideBy(2, true)); this.fire('move'); @@ -1152,8 +1181,8 @@ L.Map = L.Class.extend({ getBounds: function () { var bounds = this.getPixelBounds(), - sw = this.unproject(new L.Point(bounds.min.x, bounds.max.y)), - ne = this.unproject(new L.Point(bounds.max.x, bounds.min.y)); + sw = this.unproject(new L.Point(bounds.min.x, bounds.max.y), this._zoom, true), + ne = this.unproject(new L.Point(bounds.max.x, bounds.min.y), this._zoom, true); return new L.LatLngBounds(sw, ne); }, @@ -1200,7 +1229,7 @@ L.Map = L.Class.extend({ } } while (zoomNotFound && (zoom <= maxZoom)); - if (zoomNotFound) { + if (zoomNotFound && inside) { return null; } @@ -1382,7 +1411,7 @@ L.Map = L.Class.extend({ _initEvents: function () { L.DomEvent.addListener(this._container, 'click', this._onMouseClick, this); - var events = ['dblclick', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove']; + var events = ['dblclick', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'contextmenu']; var i, len; @@ -1420,6 +1449,10 @@ L.Map = L.Class.extend({ return; } + if (type === 'contextmenu') { + L.DomEvent.preventDefault(e); + } + this.fire(type, { latlng: this.mouseEventToLatLng(e), layerPoint: this.mouseEventToLayerPoint(e) @@ -1568,6 +1601,7 @@ L.TileLayer = L.Class.extend({ continuousWorld: false, noWrap: false, zoomOffset: 0, + zoomReverse: false, unloadInvisibleTiles: L.Browser.mobile, updateWhenIdle: L.Browser.mobile @@ -1676,6 +1710,10 @@ L.TileLayer = L.Class.extend({ } this._tiles = {}; + if (this.options.reuseTiles) { + this._unusedTiles = []; + } + if (clearOldContainer && this._container) { this._container.innerHTML = ""; } @@ -1696,7 +1734,8 @@ L.TileLayer = L.Class.extend({ this._addTilesFromCenterOut(tileBounds); - if (this.options.unloadInvisibleTiles) { + if (this.options.unloadInvisibleTiles || + this.options.reuseTiles) { this._removeOtherTiles(tileBounds); } }, @@ -1750,6 +1789,9 @@ L.TileLayer = L.Class.extend({ if (tile.parentNode === this._container) { this._container.removeChild(tile); } + if (this.options.reuseTiles) { + this._unusedTiles.push(this._tiles[key]); + } delete this._tiles[key]; } } @@ -1760,7 +1802,7 @@ L.TileLayer = L.Class.extend({ var tilePos = this._getTilePos(tilePoint), zoom = this._map.getZoom(), key = tilePoint.x + ':' + tilePoint.y, - tileLimit = Math.pow(2, (zoom + this.options.zoomOffset)); + tileLimit = Math.pow(2, this._getOffsetZoom(zoom)); // wrap tile coordinates if (!this.options.continuousWorld) { @@ -1777,8 +1819,8 @@ L.TileLayer = L.Class.extend({ } } - // create tile - var tile = this._createTile(); + // get unused tile - or create a new tile + var tile = this._getTile(); L.DomUtil.setPosition(tile, tilePos); this._tiles[key] = tile; @@ -1792,6 +1834,11 @@ L.TileLayer = L.Class.extend({ container.appendChild(tile); }, + _getOffsetZoom: function (zoom) { + zoom = this.options.zoomReverse ? this.options.maxZoom - zoom : zoom; + return zoom + this.options.zoomOffset; + }, + _getTilePos: function (tilePoint) { var origin = this._map.getPixelOrigin(), tileSize = this.options.tileSize; @@ -1807,7 +1854,7 @@ L.TileLayer = L.Class.extend({ return L.Util.template(this._url, L.Util.extend({ s: s, - z: zoom + this.options.zoomOffset, + z: this._getOffsetZoom(zoom), x: tilePoint.x, y: tilePoint.y }, this._urlParams)); @@ -1822,6 +1869,19 @@ L.TileLayer = L.Class.extend({ this._tileImg.style.height = tileSize + 'px'; }, + _getTile: function () { + if (this.options.reuseTiles && this._unusedTiles.length > 0) { + var tile = this._unusedTiles.pop(); + this._resetTile(tile); + return tile; + } + return this._createTile(); + }, + + _resetTile: function (tile) { + // Override if data stored on a tile needs to be cleaned up before reuse + }, + _createTile: function () { var tile = this._tileImg.cloneNode(false); tile.onselectstart = tile.onmousemove = L.Util.falseFn; @@ -1919,6 +1979,17 @@ L.TileLayer.Canvas = L.TileLayer.extend({ L.Util.setOptions(this, options); }, + redraw: function () { + for (var i in this._tiles) { + var tile = this._tiles[i]; + this._redrawTile(tile); + } + }, + + _redrawTile: function (tile) { + this.drawTile(tile, tile._tilePoint, tile._zoom); + }, + _createTileProto: function () { this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile'); @@ -1935,6 +2006,8 @@ L.TileLayer.Canvas = L.TileLayer.extend({ _loadTile: function (tile, tilePoint, zoom) { tile._layer = this; + tile._tilePoint = tilePoint; + tile._zoom = zoom; this.drawTile(tile, tilePoint, zoom); @@ -2039,13 +2112,19 @@ L.Icon = L.Class.extend({ _createIcon: function (name) { var size = this[name + 'Size'], - src = this[name + 'Url'], - img = this._createImg(src); - - if (!src) { + src = this[name + 'Url']; + if (!src && name === 'shadow') { return null; } + var img; + if (!src) { + img = this._createDiv(); + } + else { + img = this._createImg(src); + } + img.className = 'leaflet-marker-' + name; img.style.marginLeft = (-this.iconAnchor.x) + 'px'; @@ -2069,6 +2148,10 @@ L.Icon = L.Class.extend({ el.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + src + '")'; } return el; + }, + + _createDiv: function () { + return document.createElement('div'); } }); @@ -2085,7 +2168,8 @@ L.Marker = L.Class.extend({ icon: new L.Icon(), title: '', clickable: true, - draggable: false + draggable: false, + zIndexOffset: 0 }, initialize: function (latlng, options) { @@ -2179,8 +2263,7 @@ L.Marker = L.Class.extend({ L.DomUtil.setPosition(this._shadow, pos); } - this._icon.style.zIndex = pos.y; - // TODO zIndex offset + this._icon.style.zIndex = pos.y + this.options.zIndexOffset; }, _initInteraction: function () { @@ -2227,7 +2310,8 @@ L.Popup = L.Class.extend({ autoPan: true, closeButton: true, offset: new L.Point(0, 2), - autoPanPadding: new L.Point(5, 5) + autoPanPadding: new L.Point(5, 5), + className: '' }, initialize: function (options, source) { @@ -2294,7 +2378,7 @@ L.Popup = L.Class.extend({ }, _initLayout: function () { - this._container = L.DomUtil.create('div', 'leaflet-popup'); + this._container = L.DomUtil.create('div', 'leaflet-popup ' + this.options.className); if (this.options.closeButton) { this._closeButton = L.DomUtil.create('a', 'leaflet-popup-close-button', this._container); @@ -2404,7 +2488,9 @@ L.Popup = L.Class.extend({ L.Marker.include({ openPopup: function () { this._popup.setLatLng(this._latlng); - this._map.openPopup(this._popup); + if (this._map) { + this._map.openPopup(this._popup); + } return this; }, @@ -2816,7 +2902,7 @@ L.Map.include({ L.Path.include({ bindPopup: function (content, options) { if (!this._popup || this._popup.options !== options) { - this._popup = new L.Popup(options); + this._popup = new L.Popup(options, this); } this._popup.setContent(content); @@ -2945,72 +3031,80 @@ L.LineUtil = { return points.slice(); } + var sqTolerance = tolerance * tolerance; + // stage 1: vertex reduction - points = this.reducePoints(points, tolerance); + points = this._reducePoints(points, sqTolerance); // stage 2: Douglas-Peucker simplification - points = this.simplifyDP(points, tolerance); + points = this._simplifyDP(points, sqTolerance); return points; }, // distance from a point to a segment between two points pointToSegmentDistance: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { - return Math.sqrt(this._sqPointToSegmentDist(p, p1, p2)); + return Math.sqrt(this._sqClosestPointOnSegment(p, p1, p2, true)); }, closestPointOnSegment: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { - var point = this._sqClosestPointOnSegment(p, p1, p2); - point.distance = Math.sqrt(point._sqDist); - return point; + return this._sqClosestPointOnSegment(p, p1, p2); }, // Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm - simplifyDP: function (points, tol) { - var maxDist2 = 0, - index = 0, - t2 = tol * tol, - len = points.length, - i, dist2; + _simplifyDP: function (points, sqTolerance) { - if (len < 3) { - return points; - } + var len = points.length, + ArrayConstructor = typeof Uint8Array !== 'undefined' ? Uint8Array : Array, + markers = new ArrayConstructor(len); - for (i = 0; i < len - 1; i++) { - dist2 = this._sqPointToSegmentDist(points[i], points[0], points[len - 1]); - if (dist2 > maxDist2) { - index = i; - maxDist2 = dist2; + markers[0] = markers[len - 1] = 1; + + this._simplifyDPStep(points, markers, sqTolerance, 0, len - 1); + + var i, + newPoints = []; + + for (i = 0; i < len; i++) { + if (markers[i]) { + newPoints.push(points[i]); } } - var part1, part2; + return newPoints; + }, - if (maxDist2 >= t2) { - part1 = points.slice(0, index); - part2 = points.slice(index); + _simplifyDPStep: function (points, markers, sqTolerance, first, last) { - part1 = this.simplifyDP(part1, tol); - part2 = this.simplifyDP(part2, tol); + var maxSqDist = 0, + index, i, sqDist; - return part1.concat(part2); - } else { - return [points[0], points[len - 1]]; + for (i = first + 1; i <= last - 1; i++) { + sqDist = this._sqClosestPointOnSegment(points[i], points[first], points[last], true); + + if (sqDist > maxSqDist) { + index = i; + maxSqDist = sqDist; + } + } + + if (maxSqDist > sqTolerance) { + markers[index] = 1; + + this._simplifyDPStep(points, markers, sqTolerance, first, index); + this._simplifyDPStep(points, markers, sqTolerance, index, last); } }, // reduce points that are too close to each other to a single point - reducePoints: function (points, tol) { - var reducedPoints = [points[0]], - t2 = tol * tol; + _reducePoints: function (points, sqTolerance) { + var reducedPoints = [points[0]]; for (var i = 1, prev = 0, len = points.length; i < len; i++) { - if (this._sqDist(points[i], points[prev]) < t2) { - continue; + if (this._sqDist(points[i], points[prev]) > sqTolerance) { + reducedPoints.push(points[i]); + prev = i; } - reducedPoints.push(points[i]); - prev = i; } if (prev < len - 1) { reducedPoints.push(points[len - 1]); @@ -3100,28 +3194,31 @@ L.LineUtil = { return dx * dx + dy * dy; }, - // return closest point on segment with attribute _sqDist - square distance to segment - _sqClosestPointOnSegment: function (p, p1, p2) { - var x2 = p2.x - p1.x, - y2 = p2.y - p1.y, - apoint = p1; - if (x2 || y2) { - var dot = (p.x - p1.x) * x2 + (p.y - p1.y) * y2, - t = dot / this._sqDist(p1, p2); + // return closest point on segment or distance to that point + _sqClosestPointOnSegment: function (p, p1, p2, sqDist) { + var x = p1.x, + y = p1.y, + dx = p2.x - x, + dy = p2.y - y, + dot = dx * dx + dy * dy, + t; + + if (dot > 0) { + t = ((p.x - x) * dx + (p.y - y) * dy) / dot; if (t > 1) { - apoint = p2; + x = p2.x; + y = p2.y; } else if (t > 0) { - apoint = new L.Point(p1.x + x2 * t, p1.y + y2 * t); + x += dx * t; + y += dy * t; } } - apoint._sqDist = this._sqDist(p, apoint); - return apoint; - }, - // distance from a point to a segment between two points - _sqPointToSegmentDist: function (p, p1, p2) { - return this._sqClosestPointOnSegment(p, p1, p2)._sqDist; + dx = p.x - x; + dy = p.y - y; + + return sqDist ? dx * dx + dy * dy : new L.Point(x, y); } }; @@ -3347,7 +3444,7 @@ L.Polygon = L.Polyline.extend({ initialize: function (latlngs, options) { L.Polyline.prototype.initialize.call(this, latlngs, options); - if (latlngs[0] instanceof Array) { + if (latlngs && (latlngs[0] instanceof Array)) { this._latlngs = latlngs[0]; this._holes = latlngs.slice(1); } @@ -3987,7 +4084,7 @@ L.DomEvent = { }, disableClickPropagation: function (/*HTMLElement*/ el) { - L.DomEvent.addListener(el, 'mousedown', L.DomEvent.stopPropagation); + L.DomEvent.addListener(el, L.Draggable.START, L.DomEvent.stopPropagation); L.DomEvent.addListener(el, 'click', L.DomEvent.stopPropagation); L.DomEvent.addListener(el, 'dblclick', L.DomEvent.stopPropagation); }, @@ -4745,12 +4842,15 @@ L.Control.Zoom = L.Class.extend({ L.Control.Attribution = L.Class.extend({ + initialize: function (prefix) { + this._prefix = prefix || 'Powered by Leaflet'; + this._attributions = {}; + }, + onAdd: function (map) { this._container = L.DomUtil.create('div', 'leaflet-control-attribution'); L.DomEvent.disableClickPropagation(this._container); this._map = map; - this._prefix = 'Powered by Leaflet'; - this._attributions = {}; this._update(); }, @@ -5491,7 +5591,7 @@ L.Map.include({ options = L.Util.extend({ maxZoom: maxZoom || Infinity, setView: true - }); + }, options); return this.locate(options); }, diff --git a/dist/leaflet.js b/dist/leaflet.js index de25ba7e..d499ad60 100644 --- a/dist/leaflet.js +++ b/dist/leaflet.js @@ -3,4 +3,4 @@ Leaflet is a modern open-source JavaScript library for interactive maps. http://leaflet.cloudmade.com */ -(function(a){a.L={VERSION:"0.3",ROOT_URL:a.L_ROOT_URL||function(){var a=document.getElementsByTagName("script"),b=/\/?leaflet[\-\._]?([\w\-\._]*)\.js\??/,c,d,e,f;for(c=0,d=a.length;c0},removeEventListener:function(a,b,c){if(!this.hasEventListeners(a))return this;for(var d=0,e=this._leaflet_events,f=e[a].length;d=this.min.x&&c.x<=this.max.x&&b.y>=this.min.y&&c.y<=this.max.y}}),L.Transformation=L.Class.extend({initialize:function(a,b,c,d){this._a=a,this._b=b,this._c=c,this._d=d},transform:function(a,b){return this._transform(a.clone(),b)},_transform:function(a,b){return b=b||1,a.x=b*(this._a*a.x+this._b),a.y=b*(this._c*a.y+this._d),a},untransform:function(a,b){return b=b||1,new L.Point((a.x/b-this._b)/this._a,(a.y/b-this._d)/this._c)}}),L.DomUtil={get:function(a){return typeof a=="string"?document.getElementById(a):a},getStyle:function(a,b){var c=a.style[b];!c&&a.currentStyle&&(c=a.currentStyle[b]);if(!c||c==="auto"){var d=document.defaultView.getComputedStyle(a,null);c=d?d[b]:null}return c==="auto"?null:c},getViewportOffset:function(a){var b=0,c=0,d=a,e=document.body;do{b+=d.offsetTop||0,c+=d.offsetLeft||0;if(d.offsetParent===e&&L.DomUtil.getStyle(d,"position")==="absolute")break;d=d.offsetParent}while(d);d=a;do{if(d===e)break;b-=d.scrollTop||0,c-=d.scrollLeft||0,d=d.parentNode}while(d);return new L.Point(c,b)},create:function(a,b,c){var d=document.createElement(a);return d.className=b,c&&c.appendChild(d),d},disableTextSelection:function(){document.selection&&document.selection.empty&&document.selection.empty(),this._onselectstart||(this._onselectstart=document.onselectstart,document.onselectstart=L.Util.falseFn)},enableTextSelection:function(){document.onselectstart=this._onselectstart,this._onselectstart=null},hasClass:function(a,b){return a.className.length>0&&RegExp("(^|\\s)"+b+"(\\s|$)").test(a.className)},addClass:function(a,b){L.DomUtil.hasClass(a,b)||(a.className+=(a.className?" ":"")+b)},removeClass:function(a,b){a.className=a.className.replace(/(\S+)\s*/g,function(a,c){return c===b?"":a}).replace(/^\s+/,"")},setOpacity:function(a,b){L.Browser.ie?a.style.filter="alpha(opacity="+Math.round(b*100)+")":a.style.opacity=b},testProp:function(a){var b=document.documentElement.style;for(var c=0;c=b.lat&&e.lat<=c.lat&&d.lng>=b.lng&&e.lng<=c.lng},intersects:function(a){var b=this._southWest,c=this._northEast,d=a.getSouthWest(),e=a.getNorthEast(),f=e.lat>=b.lat&&d.lat<=c.lat,g=e.lng>=b.lng&&d.lng<=c.lng;return f&&g},toBBoxString:function(){var a=this._southWest,b=this._northEast;return[a.lng,a.lat,b.lng,b.lat].join(",")}}),L.Projection={},L.Projection.SphericalMercator={MAX_LATITUDE:85.0511287798,project:function(a){var b=L.LatLng.DEG_TO_RAD,c=this.MAX_LATITUDE,d=Math.max(Math.min(c,a.lat),-c),e=a.lng*b,f=d*b;return f=Math.log(Math.tan(Math.PI/4+f/2)),new L.Point(e,f)},unproject:function(a,b){var c=L.LatLng.RAD_TO_DEG,d=a.x*c,e=(2*Math.atan(Math.exp(a.y))-Math.PI/2)*c;return new L.LatLng(e,d,b)}},L.Projection.LonLat={project:function(a){return new L.Point(a.lng,a.lat)},unproject:function(a,b){return new L.LatLng(a.y,a.x,b)}},L.CRS={latLngToPoint:function(a,b){var c=this.projection.project(a);return this.transformation._transform(c,b)},pointToLatLng:function(a,b,c){var d=this.transformation.untransform(a,b);return this.projection.unproject(d,c)},project:function(a){return this.projection.project(a)}},L.CRS.EPSG3857=L.Util.extend({},L.CRS,{code:"EPSG:3857",projection:L.Projection.SphericalMercator,transformation:new L.Transformation(.5/Math.PI,.5,-0.5/Math.PI,.5),project:function(a){var b=this.projection.project(a),c=6378137;return b.multiplyBy(c)}}),L.CRS.EPSG900913=L.Util.extend({},L.CRS.EPSG3857,{code:"EPSG:900913"}),L.CRS.EPSG4326=L.Util.extend({},L.CRS,{code:"EPSG:4326",projection:L.Projection.LonLat,transformation:new L.Transformation(1/360,.5,-1/360,.5)}),L.Map=L.Class.extend({includes:L.Mixin.Events,options:{crs:L.CRS.EPSG3857||L.CRS.EPSG4326,scale:function(a){return 256*Math.pow(2,a)},center:null,zoom:null,layers:[],dragging:!0,touchZoom:L.Browser.touch&&!L.Browser.android,scrollWheelZoom:!L.Browser.touch,doubleClickZoom:!0,boxZoom:!0,zoomControl:!0,attributionControl:!0,fadeAnimation:L.DomUtil.TRANSITION&&!L.Browser.android,zoomAnimation:L.DomUtil.TRANSITION&&!L.Browser.android&&!L.Browser.mobileOpera,trackResize:!0,closePopupOnClick:!0,worldCopyJump:!0},initialize:function(a,b){L.Util.setOptions(this,b),this._container=L.DomUtil.get(a);if(this._container._leaflet)throw Error("Map container is already initialized.");this._container._leaflet=!0,this._initLayout(),L.DomEvent&&(this._initEvents(),L.Handler&&this._initInteraction(),L.Control&&this._initControls()),this.options.maxBounds&&this.setMaxBounds(this.options.maxBounds);var c=this.options.center,d=this.options.zoom;c!==null&&d!==null&&this.setView(c,d,!0);var e=this.options.layers;e=e instanceof Array?e:[e],this._tileLayersNum=0,this._initLayers(e)},setView:function(a,b){return this._resetView(a,this._limitZoom(b)),this},setZoom:function(a){return this.setView(this.getCenter(),a)},zoomIn:function(){return this.setZoom(this._zoom+1)},zoomOut:function(){return this.setZoom(this._zoom-1)},fitBounds:function(a){var b=this.getBoundsZoom(a);return this.setView(a.getCenter(),b)},fitWorld:function(){var a=new L.LatLng(-60,-170),b=new L.LatLng(85,179);return this.fitBounds(new L.LatLngBounds(a,b))},panTo:function(a){return this.setView(a,this._zoom)},panBy:function(a){return this.fire("movestart"),this._rawPanBy(a),this.fire("move"),this.fire("moveend"),this},setMaxBounds:function(a){this.options.maxBounds=a;if(!a)return this._boundsMinZoom=null,this;var b=this.getBoundsZoom(a,!0);return this._boundsMinZoom=b,this._loaded&&(this._zoomf.x&&(g=f.x-d.x),c.y>e.y&&(h=e.y-c.y),c.xl&&--m>0)o=h*Math.sin(j),n=Math.PI/2-2*Math.atan(i*Math.pow((1-o)/(1+o),.5*h))-j,j+=n;return new L.LatLng(j*c,f,b)}},L.CRS.EPSG3395=L.Util.extend({},L.CRS,{code:"EPSG:3395",projection:L.Projection.Mercator,transformation:function(){var a=L.Projection.Mercator,b=a.R_MAJOR,c=a.R_MINOR;return new L.Transformation(.5/(Math.PI*b),.5,-0.5/(Math.PI*c),.5)}()}),L.TileLayer=L.Class.extend({includes:L.Mixin.Events,options:{minZoom:0,maxZoom:18,tileSize:256,subdomains:"abc",errorTileUrl:"",attribution:"",opacity:1,scheme:"xyz",continuousWorld:!1,noWrap:!1,zoomOffset:0,unloadInvisibleTiles:L.Browser.mobile,updateWhenIdle:L.Browser.mobile},initialize:function(a,b,c){L.Util.setOptions(this,b),this._url=a,this._urlParams=c,typeof this.options.subdomains=="string"&&(this.options.subdomains=this.options.subdomains.split(""))},onAdd:function(a,b){this._map=a,this._insertAtTheBottom=b,this._initContainer(),this._createTileProto(),a.on("viewreset",this._resetCallback,this),this.options.updateWhenIdle?a.on("moveend",this._update,this):(this._limitedUpdate=L.Util.limitExecByInterval(this._update,150,this),a.on("move",this._limitedUpdate,this)),this._reset(),this._update()},onRemove:function(a){this._map.getPanes().tilePane.removeChild(this._container),this._container=null,this._map.off("viewreset",this._resetCallback,this),this.options.updateWhenIdle?this._map.off("moveend",this._update,this):this._map.off("move",this._limitedUpdate,this)},getAttribution:function(){return this.options.attribution},setOpacity:function(a){this.options.opacity=a,this._setOpacity(a);if(L.Browser.webkit)for(var b in this._tiles)this._tiles.hasOwnProperty(b)&&(this._tiles[b].style.webkitTransform+=" translate(0,0)")},_setOpacity:function(a){a<1&&L.DomUtil.setOpacity(this._container,a)},_initContainer:function(){var a=this._map.getPanes().tilePane,b=a.firstChild;if(!this._container||a.empty)this._container=L.DomUtil.create("div","leaflet-layer"),this._insertAtTheBottom&&b?a.insertBefore(this._container,b):a.appendChild(this._container),this._setOpacity(this.options.opacity)},_resetCallback:function(a){this._reset(a.hard)},_reset:function(a){var b;for(b in this._tiles)this._tiles.hasOwnProperty(b)&&this.fire("tileunload",{tile:this._tiles[b]});this._tiles={},a&&this._container&&(this._container.innerHTML=""),this._initContainer()},_update:function(){var a=this._map.getPixelBounds(),b=this.options.tileSize,c=new L.Point(Math.floor(a.min.x/b),Math.floor(a.min.y/b)),d=new L.Point(Math.floor(a.max.x/b),Math.floor(a.max.y/b)),e=new L.Bounds(c,d);this._addTilesFromCenterOut(e),this.options.unloadInvisibleTiles&&this._removeOtherTiles(e)},_addTilesFromCenterOut:function(a){var b=[],c=a.getCenter();for(var d=a.min.y;d<=a.max.y;d++)for(var e=a.min.x;e<=a.max.x;e++){if(e+":"+d in this._tiles)continue;b.push(new L.Point(e,d))}b.sort(function(a,b){return a.distanceTo(c)-b.distanceTo(c)});var f=document.createDocumentFragment();this._tilesToLoad=b.length;for(var g=0,h=this._tilesToLoad;ga.max.x||da.max.y)f=this._tiles[e],this.fire("tileunload",{tile:f,url:f.src}),f.parentNode===this._container&&this._container.removeChild(f),delete this._tiles[e]}},_addTile:function(a,b){var c=this._getTilePos(a),d=this._map.getZoom(),e=a.x+":"+a.y,f=Math.pow(2,d+this.options.zoomOffset);if(!this.options.continuousWorld){if(!this.options.noWrap)a.x=(a.x%f+f)%f;else if(a.x<0||a.x>=f){this._tilesToLoad--;return}if(a.y<0||a.y>=f){this._tilesToLoad--;return}}var g=this._createTile();L.DomUtil.setPosition(g,c),this._tiles[e]=g,this.options.scheme==="tms"&&(a.y=f-a.y-1),this._loadTile(g,a,d),b.appendChild(g)},_getTilePos:function(a){var b=this._map.getPixelOrigin(),c=this.options.tileSize;return a.multiplyBy(c).subtract(b)},getTileUrl:function(a,b){var c=this.options.subdomains,d=this.options.subdomains[(a.x+a.y)%c.length];return L.Util.template(this._url,L.Util.extend({s:d,z:b+this.options.zoomOffset,x:a.x,y:a.y},this._urlParams))},_createTileProto:function(){this._tileImg=L.DomUtil.create("img","leaflet-tile"),this._tileImg.galleryimg="no";var a=this.options.tileSize;this._tileImg.style.width=a+"px",this._tileImg.style.height=a+"px"},_createTile:function(){var a=this._tileImg.cloneNode(!1);return a.onselectstart=a.onmousemove=L.Util.falseFn,a},_loadTile:function(a,b,c){a._layer=this,a.onload=this._tileOnLoad,a.onerror=this._tileOnError,a.src=this.getTileUrl(b,c)},_tileOnLoad:function(a){var b=this._layer;this.className+=" leaflet-tile-loaded",b.fire("tileload",{tile:this,url:this.src}),b._tilesToLoad--,b._tilesToLoad||b.fire("load")},_tileOnError:function(a){var b=this._layer;b.fire("tileerror",{tile:this,url:this.src});var c=b.options.errorTileUrl;c&&(this.src=c)}}),L.TileLayer.WMS=L.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",version:"1.1.1",layers:"",styles:"",format:"image/jpeg",transparent:!1},initialize:function(a,b){this._url=a,this.wmsParams=L.Util.extend({},this.defaultWmsParams),this.wmsParams.width=this.wmsParams.height=this.options.tileSize;for(var c in b)this.options.hasOwnProperty(c)||(this.wmsParams[c]=b[c]);L.Util.setOptions(this,b)},onAdd:function(a){var b=parseFloat(this.wmsParams.version)<1.3?"srs":"crs";this.wmsParams[b]=a.options.crs.code,L.TileLayer.prototype.onAdd.call(this,a)},getTileUrl:function(a,b){var c=this.options.tileSize,d=a.multiplyBy(c),e=d.add(new L.Point(c,c)),f=this._map.unproject(d,this._zoom,!0),g=this._map.unproject(e,this._zoom,!0),h=this._map.options.crs.project(f),i=this._map.options.crs.project(g),j=[h.x,i.y,i.x,h.y].join(",");return this._url+L.Util.getParamString(this.wmsParams)+"&bbox="+j}}),L.TileLayer.Canvas=L.TileLayer.extend({options:{async:!1},initialize:function(a){L.Util.setOptions(this,a)},_createTileProto:function(){this._canvasProto=L.DomUtil.create("canvas","leaflet-tile");var a=this.options.tileSize;this._canvasProto.width=a,this._canvasProto.height=a},_createTile:function(){var a=this._canvasProto.cloneNode(!1);return a.onselectstart=a.onmousemove=L.Util.falseFn,a},_loadTile:function(a,b,c){a._layer=this,this.drawTile(a,b,c),this.options.async||this.tileDrawn(a)},drawTile:function(a,b,c){},tileDrawn:function(a){this._tileOnLoad.call(a)}}),L.ImageOverlay=L.Class.extend({includes:L.Mixin.Events,initialize:function(a,b){this._url=a,this._bounds=b},onAdd:function(a){this._map=a,this._image||this._initImage(),a.getPanes().overlayPane.appendChild(this._image),a.on("viewreset",this._reset,this),this._reset()},onRemove:function(a){a.getPanes().overlayPane.removeChild(this._image),a.off("viewreset",this._reset,this)},_initImage:function(){this._image=L.DomUtil.create("img","leaflet-image-layer"),this._image.style.visibility="hidden",L.Util.extend(this._image,{galleryimg:"no",onselectstart:L.Util.falseFn,onmousemove:L.Util.falseFn,onload:L.Util.bind(this._onImageLoad,this),src:this._url})},_reset:function(){var a=this._map.latLngToLayerPoint(this._bounds.getNorthWest()),b=this._map.latLngToLayerPoint(this._bounds.getSouthEast()),c=b.subtract(a);L.DomUtil.setPosition(this._image,a),this._image.style.width=c.x+"px",this._image.style.height=c.y+"px"},_onImageLoad:function(){this._image.style.visibility="",this.fire("load")}}),L.Icon=L.Class.extend({iconUrl:L.ROOT_URL+"images/marker.png",shadowUrl:L.ROOT_URL+"images/marker-shadow.png",iconSize:new L.Point(25,41),shadowSize:new L.Point(41,41),iconAnchor:new L.Point(13,41),popupAnchor:new L.Point(0,-33),initialize:function(a){a&&(this.iconUrl=a)},createIcon:function(){return this._createIcon("icon")},createShadow:function(){return this._createIcon("shadow")},_createIcon:function(a){var b=this[a+"Size"],c=this[a+"Url"],d=this._createImg(c);return c?(d.className="leaflet-marker-"+a,d.style.marginLeft=-this.iconAnchor.x+"px",d.style.marginTop=-this.iconAnchor.y+"px",b&&(d.style.width=b.x+"px",d.style.height=b.y+"px"),d):null},_createImg:function(a){var b;return L.Browser.ie6?(b=document.createElement("div"),b.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+a+'")'):(b=document.createElement("img"),b.src=a),b}}),L.Marker=L.Class.extend({includes:L.Mixin.Events,options:{icon:new L.Icon,title:"",clickable:!0,draggable:!1},initialize:function(a,b){L.Util.setOptions(this,b),this._latlng=a},onAdd:function(a){this._map=a,this._initIcon(),a.on("viewreset",this._reset,this),this._reset()},onRemove:function(a){this._removeIcon(),this.closePopup&&this.closePopup(),this._map=null,a.off("viewreset",this._reset,this)},getLatLng:function(){return this._latlng},setLatLng:function(a){this._latlng=a,this._icon&&(this._reset(),this._popup&&this._popup.setLatLng(this._latlng))},setIcon:function(a){this._map&&this._removeIcon(),this.options.icon=a,this._map&&(this._initIcon(),this._reset())},_initIcon:function(){this._icon||(this._icon=this.options.icon.createIcon(),this.options.title&&(this._icon.title=this.options.title),this._initInteraction()),this._shadow||(this._shadow=this.options.icon.createShadow()),this._map._panes.markerPane.appendChild(this._icon),this._shadow&&this._map._panes.shadowPane.appendChild(this._shadow)},_removeIcon:function(){this._map._panes.markerPane.removeChild(this._icon),this._shadow&&this._map._panes.shadowPane.removeChild(this._shadow),this._icon=this._shadow=null},_reset:function(){var a=this._map.latLngToLayerPoint(this._latlng).round();L.DomUtil.setPosition(this._icon,a),this._shadow&&L.DomUtil.setPosition(this._shadow,a),this._icon.style.zIndex=a.y},_initInteraction:function(){if(this.options.clickable){this._icon.className+=" leaflet-clickable",L.DomEvent.addListener(this._icon,"click",this._onMouseClick,this);var a=["dblclick","mousedown","mouseover","mouseout"];for(var b=0;bthis.options.maxWidth?this.options.maxWidth:af.x&&(d.x=c.x+this._containerWidth-f.x+e.x),c.y<0&&(d.y=c.y-e.y),c.y+a>f.y&&(d.y=c.y+a-f.y+e.y),(d.x||d.y)&&this._map.panBy(d)},_onCloseButtonClick:function(a){this._close(),L.DomEvent.stop(a)}}),L.Marker.include({openPopup:function(){return this._popup.setLatLng(this._latlng),this._map.openPopup(this._popup),this},closePopup:function(){return this._popup&&this._popup._close(),this},bindPopup:function(a,b){return b=L.Util.extend({offset:this.options.icon.popupAnchor},b),this._popup||this.on("click",this.openPopup,this),this._popup=new L.Popup(b,this),this._popup.setContent(a),this},unbindPopup:function(){return this._popup&&(this._popup=null,this.off("click",this.openPopup)),this}}),L.Map.include({openPopup:function(a){return this.closePopup(),this._popup=a,this.addLayer(a),this.fire("popupopen",{popup:this._popup}),this},closePopup:function(){return this._popup&&(this.removeLayer(this._popup),this.fire("popupclose",{popup:this._popup}),this._popup=null),this}}),L.LayerGroup=L.Class.extend({initialize:function(a){this._layers={};if(a)for(var b=0,c=a.length;b')}}catch(a){return function(a){return document.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}()},_initPath:function(){this._container=L.Path._createElement("shape"),this._container.className+=" leaflet-vml-shape"+(this.options.clickable?" leaflet-clickable":""),this._container.coordsize="1 1",this._path=L.Path._createElement("path"),this._container.appendChild(this._path),this._map._pathRoot.appendChild(this._container)},_initStyle:function(){this.options.stroke?(this._stroke=L.Path._createElement("stroke"),this._stroke.endcap="round",this._container.appendChild(this._stroke)):this._container.stroked=!1,this.options.fill?(this._container.filled=!0,this._fill=L.Path._createElement("fill"),this._container.appendChild(this._fill)):this._container.filled=!1,this._updateStyle()},_updateStyle:function(){this.options.stroke&&(this._stroke.weight=this.options.weight+"px",this._stroke.color=this.options.color,this._stroke.opacity=this.options.opacity),this.options.fill&&(this._fill.color=this.options.fillColor||this.options.color,this._fill.opacity=this.options.fillOpacity)},_updatePath:function(){this._container.style.display="none",this._path.v=this.getPathString()+" ",this._container.style.display=""}}),L.Map.include(L.Browser.svg||!L.Browser.vml?{}:{_initPathRoot:function(){this._pathRoot||(this._pathRoot=document.createElement("div"),this._pathRoot.className="leaflet-vml-container",this._panes.overlayPane.appendChild(this._pathRoot),this.on("moveend",this._updatePathViewport),this._updatePathViewport())}}),L.LineUtil={simplify:function(a,b){return!b||!a.length?a.slice():(a=this.reducePoints(a,b),a=this.simplifyDP(a,b),a)},pointToSegmentDistance:function(a,b,c){return Math.sqrt(this._sqPointToSegmentDist(a,b,c))},closestPointOnSegment:function(a,b,c){var d=this._sqClosestPointOnSegment(a,b,c);return d.distance=Math.sqrt(d._sqDist),d},simplifyDP:function(a,b){var c=0,d=0,e=b*b,f=a.length,g,h;if(f<3)return a;for(g=0;gc&&(d=g,c=h);var i,j;return cb.max.x&&(c|=2),a.yb.max.y&&(c|=8),c},_sqDist:function(a,b){var c=b.x-a.x,d=b.y-a.y;return c*c+d*d},_sqClosestPointOnSegment:function(a,b,c){var d=c.x-b.x,e=c.y-b.y,f=b;if(d||e){var g=(a.x-b.x)*d+(a.y-b.y)*e,h=g/this._sqDist(b,c);h>1?f=c:h>0&&(f=new L.Point(b.x+d*h,b.y+e*h))}return f._sqDist=this._sqDist(a,f),f},_sqPointToSegmentDist:function(a,b,c){return this._sqClosestPointOnSegment(a,b,c)._sqDist}},L.Polyline=L.Path.extend({initialize:function(a,b){L.Path.prototype.initialize.call(this,b),this._latlngs=a},options:{smoothFactor:1,noClip:!1,updateOnMoveEnd:!0},projectLatlngs:function(){this._originalPoints=[];for(var a=0,b=this._latlngs.length;aa.max.x||c.y-b>a.max.y||c.x+ba.y!=e.y>a.y&&a.x<(e.x-d.x)*(a.y-d.y)/(e.y-d.y)+d.x&&(b=!b)}return b}}:{}),L.Circle.include(L.Path.CANVAS?{_drawPath:function(){var a=this._point;this._ctx.beginPath(),this._ctx.arc(a.x,a.y,this._radius,0,Math.PI*2)},_containsPoint:function(a){var b=this._point,c=this.options.stroke?this.options.weight/2:0;return a.distanceTo(b)<=this._radius+c}}:{}),L.GeoJSON=L.FeatureGroup.extend({initialize:function(a,b){L.Util.setOptions(this,b),this._geojson=a,this._layers={},a&&this.addGeoJSON(a)},addGeoJSON:function(a){if(a.features){for(var b=0,c=a.features.length;b1)return;var b=a.touches&&a.touches.length===1?a.touches[0]:a,c=b.target;L.DomEvent.preventDefault(a),L.Browser.touch&&c.tagName.toLowerCase()==="a"&&(c.className+=" leaflet-active"),this._moved=!1;if(this._moving)return;L.Browser.touch||(L.DomUtil.disableTextSelection(),this._setMovingCursor()),this._startPos=this._newPos=L.DomUtil.getPosition(this._element),this._startPoint=new L.Point(b.clientX,b.clientY),L.DomEvent.addListener(document,L.Draggable.MOVE,this._onMove,this),L.DomEvent.addListener(document,L.Draggable.END,this._onUp,this)},_onMove:function(a){if(a.touches&&a.touches.length>1)return;L.DomEvent.preventDefault(a);var b=a.touches&&a.touches.length===1?a.touches[0]:a;this._moved||(this.fire("dragstart"),this._moved=!0),this._moving=!0;var c=new L.Point(b.clientX,b.clientY);this._newPos=this._startPos.add(c).subtract(this._startPoint),L.Util.requestAnimFrame(this._updatePosition,this,!0,this._dragStartTarget)},_updatePosition:function(){this.fire("predrag"),L.DomUtil.setPosition(this._element,this._newPos),this.fire("drag")},_onUp:function(a){if(a.changedTouches){var b=a.changedTouches[0],c=b.target,d=this._newPos&&this._newPos.distanceTo(this._startPos)||0;c.tagName.toLowerCase()==="a"&&(c.className=c.className.replace(" leaflet-active","")),d0&&c<=f,d=b}function l(a){e&&(g.type="dblclick",b(g),d=null)}var d,e=!1,f=250,g,h="_leaflet_",i="touchstart",j="touchend";a[h+i+c]=k,a[h+j+c]=l,a.addEventListener(i,k,!1),a.addEventListener(j,l,!1)},removeDoubleTapListener:function(a,b){var c="_leaflet_";a.removeEventListener(a,a[c+"touchstart"+b],!1),a.removeEventListener(a,a[c+"touchend"+b],!1)}}),L.Map.TouchZoom=L.Handler.extend({addHooks:function(){L.DomEvent.addListener(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){L.DomEvent.removeListener(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(a){if(!a.touches||a.touches.length!==2||this._map._animatingZoom)return;var b=this._map.mouseEventToLayerPoint(a.touches[0]),c=this._map.mouseEventToLayerPoint(a.touches[1]),d=this._map.containerPointToLayerPoint(this._map.getSize().divideBy(2));this._startCenter=b.add(c).divideBy(2,!0),this._startDist=b.distanceTo(c),this._moved=!1,this._zooming=!0,this._centerOffset=d.subtract(this._startCenter),L.DomEvent.addListener(document,"touchmove",this._onTouchMove,this),L.DomEvent.addListener(document,"touchend",this._onTouchEnd,this),L.DomEvent.preventDefault(a)},_onTouchMove:function(a){if(!a.touches||a.touches.length!==2)return;this._moved||(this._map._mapPane.className+=" leaflet-zoom-anim",this._map.fire("zoomstart").fire("movestart")._prepareTileBg(),this._moved=!0);var b=this._map.mouseEventToLayerPoint(a.touches[0]),c=this._map.mouseEventToLayerPoint(a.touches[1]);this._scale=b.distanceTo(c)/this._startDist,this._delta=b.add(c).divideBy(2,!0).subtract(this._startCenter),this._map._tileBg.style.webkitTransform=[L.DomUtil.getTranslateString(this._delta),L.DomUtil.getScaleString(this._scale,this._startCenter)].join(" "),L.DomEvent.preventDefault(a)},_onTouchEnd:function(a){if(!this._moved||!this._zooming)return;this._zooming=!1;var b=this._map.getZoom(),c=Math.log(this._scale)/Math.LN2,d=c>0?Math.ceil(c):Math.floor(c),e=this._map._limitZoom(b+d),f=e-b,g=this._centerOffset.subtract(this._delta).divideBy(this._scale),h=this._map.getPixelOrigin().add(this._startCenter).add(g),i=this._map.unproject(h);L.DomEvent.removeListener(document,"touchmove",this._onTouchMove),L.DomEvent.removeListener(document,"touchend",this._onTouchEnd);var j=Math.pow(2,f);this._map._runAnimation(i,e,j/this._scale,this._startCenter.add(g))}}),L.Map.BoxZoom=L.Handler.extend({initialize:function(a){this._map=a,this._container=a._container,this._pane=a._panes.overlayPane},addHooks:function(){L.DomEvent.addListener(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){L.DomEvent.removeListener(this._container,"mousedown",this._onMouseDown)},_onMouseDown:function(a){if(!a.shiftKey||a.which!==1&&a.button!==1)return!1;L.DomUtil.disableTextSelection(),this._startLayerPoint=this._map.mouseEventToLayerPoint(a),this._box=L.DomUtil.create("div","leaflet-zoom-box",this._pane),L.DomUtil.setPosition(this._box,this._startLayerPoint),this._container.style.cursor="crosshair",L.DomEvent.addListener(document,"mousemove",this._onMouseMove,this),L.DomEvent.addListener(document,"mouseup",this._onMouseUp,this),L.DomEvent.preventDefault(a)},_onMouseMove:function(a){var b=this._map.mouseEventToLayerPoint(a),c=b.x-this._startLayerPoint.x,d=b.y-this._startLayerPoint.y,e=Math.min(b.x,this._startLayerPoint.x),f=Math.min(b.y,this._startLayerPoint.y),g=new L.Point(e,f);L.DomUtil.setPosition(this._box,g),this._box.style.width=Math.abs(c)-4+"px",this._box.style.height=Math.abs(d)-4+"px"},_onMouseUp:function(a){this._pane.removeChild(this._box),this._container.style.cursor="",L.DomUtil.enableTextSelection(),L.DomEvent.removeListener(document,"mousemove",this._onMouseMove),L.DomEvent.removeListener(document,"mouseup",this._onMouseUp);var b=this._map.mouseEventToLayerPoint(a),c=new L.LatLngBounds(this._map.layerPointToLatLng(this._startLayerPoint),this._map.layerPointToLatLng(b));this._map.fitBounds(c)}}),L.Handler.MarkerDrag=L.Handler.extend({initialize:function(a){this._marker=a},addHooks:function(){var a=this._marker._icon;this._draggable||(this._draggable=new L.Draggable(a,a),this._draggable.on("dragstart",this._onDragStart,this).on("drag",this._onDrag,this).on("dragend",this._onDragEnd,this)),this._draggable.enable()},removeHooks:function(){this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},_onDragStart:function(a){this._marker.closePopup().fire("movestart").fire("dragstart")},_onDrag:function(a){var b=L.DomUtil.getPosition(this._marker._icon);this._marker._shadow&&L.DomUtil.setPosition(this._marker._shadow,b),this._marker._latlng=this._marker._map.layerPointToLatLng(b),this._marker.fire("move").fire("drag")},_onDragEnd:function(){this._marker.fire("moveend").fire("dragend")}}),L.Control={},L.Control.Position={TOP_LEFT:"topLeft",TOP_RIGHT:"topRight",BOTTOM_LEFT:"bottomLeft",BOTTOM_RIGHT:"bottomRight"},L.Map.include({addControl:function(a){a.onAdd(this);var b=a.getPosition(),c=this._controlCorners[b],d=a.getContainer();return L.DomUtil.addClass(d,"leaflet-control"),b.indexOf("bottom")!==-1?c.insertBefore(d,c.firstChild):c.appendChild(d),this},removeControl:function(a){var b=a.getPosition(),c=this._controlCorners[b],d=a.getContainer();return c.removeChild(d),a.onRemove&&a.onRemove(this),this},_initControlPos:function(){var a=this._controlCorners={},b="leaflet-",c=b+"top",d=b+"bottom",e=b+"left",f=b+"right",g=L.DomUtil.create("div",b+"control-container",this._container);L.Browser.touch&&(g.className+=" "+b+"big-buttons"),a.topLeft=L.DomUtil.create("div",c+" "+e,g),a.topRight=L.DomUtil.create("div",c+" "+f,g),a.bottomLeft=L.DomUtil.create("div",d+" "+e,g),a.bottomRight=L.DomUtil.create("div",d+" "+f,g)}}),L.Control.Zoom=L.Class.extend({onAdd:function(a){this._map=a,this._container=L.DomUtil.create("div","leaflet-control-zoom"),this._zoomInButton=this._createButton("Zoom in","leaflet-control-zoom-in",this._map.zoomIn,this._map),this._zoomOutButton=this._createButton("Zoom out","leaflet-control-zoom-out",this._map.zoomOut,this._map),this._container.appendChild(this._zoomInButton),this._container.appendChild(this._zoomOutButton)},getContainer:function(){return this._container},getPosition:function(){return L.Control.Position.TOP_LEFT},_createButton:function(a,b,c,d){var e=document.createElement("a");return e.href="#",e.title=a,e.className=b,L.DomEvent.disableClickPropagation(e),L.DomEvent.addListener(e,"click",L.DomEvent.preventDefault),L.DomEvent.addListener(e,"click",c,d),e}}),L.Control.Attribution=L.Class.extend({onAdd:function(a){this._container=L.DomUtil.create("div","leaflet-control-attribution"),L.DomEvent.disableClickPropagation(this._container),this._map=a,this._prefix='Powered by Leaflet',this._attributions={},this._update()},getPosition:function(){return L.Control.Position.BOTTOM_RIGHT},getContainer:function(){return this._container},setPrefix:function(a){this._prefix=a,this._update()},addAttribution:function(a){if(!a)return;this._attributions[a]=!0,this._update()},removeAttribution:function(a){if(!a)return;delete this._attributions[a],this._update()},_update:function(){if(!this._map)return;var a=[];for(var b in this._attributions)this._attributions.hasOwnProperty(b)&&a.push(b);var c=[];this._prefix&&c.push(this._prefix),a.length&&c.push(a.join(", ")),this._container.innerHTML=c.join(" — ")}}),L.Control.Layers=L.Class.extend({options:{collapsed:!L.Browser.touch},initialize:function(a,b,c){L.Util.setOptions(this,c),this._layers={};for(var d in a)a.hasOwnProperty(d)&&this._addLayer(a[d],d);for(d in b)b.hasOwnProperty(d)&&this._addLayer(b[d],d,!0)},onAdd:function(a){this._map=a,this._initLayout(),this._update()},getContainer:function(){return this._container},getPosition:function(){return L.Control.Position.TOP_RIGHT},addBaseLayer:function(a,b){return this._addLayer(a,b),this._update(),this},addOverlay:function(a,b){return this._addLayer(a,b,!0),this._update(),this},removeLayer:function(a){var b=L.Util.stamp(a);return delete this._layers[b],this._update(),this},_initLayout:function(){this._container=L.DomUtil.create("div","leaflet-control-layers"),L.DomEvent.disableClickPropagation(this._container),this._form=L.DomUtil.create("form","leaflet-control-layers-list");if(this.options.collapsed){L.DomEvent.addListener(this._container,"mouseover",this._expand,this),L.DomEvent.addListener(this._container,"mouseout",this._collapse,this);var a=this._layersLink=L.DomUtil.create("a","leaflet-control-layers-toggle");a.href="#",a.title="Layers",L.DomEvent.addListener(a,"focus",this._expand,this),L.DomEvent.addListener(this._map,L.Draggable.START,this._collapse,this),this._container.appendChild(a)}else this._expand();this._baseLayersList=L.DomUtil.create("div","leaflet-control-layers-base",this._form),this._separator=L.DomUtil.create("div","leaflet-control-layers-separator",this._form),this._overlaysList=L.DomUtil.create("div","leaflet-control-layers-overlays",this._form),this._container.appendChild(this._form)},_addLayer:function(a,b,c){var d=L.Util.stamp(a);this._layers[d]={layer:a,name:b,overlay:c}},_update:function(){if(!this._container)return;this._baseLayersList.innerHTML="",this._overlaysList.innerHTML="";var a=!1,b=!1;for(var c in this._layers)if(this._layers.hasOwnProperty(c)){var d=this._layers[c];this._addItem(d),b=b||d.overlay,a=a||!d.overlay}this._separator.style.display=b&&a?"":"none"},_addItem:function(a,b){var c=document.createElement("label"),d=document.createElement("input");a.overlay||(d.name="leaflet-base-layers"),d.type=a.overlay?"checkbox":"radio",d.checked=this._map.hasLayer(a.layer),d.layerId=L.Util.stamp(a.layer),L.DomEvent.addListener(d,"click",this._onInputClick,this);var e=document.createTextNode(" "+a.name);c.appendChild(d),c.appendChild(e);var f=a.overlay?this._overlaysList:this._baseLayersList;f.appendChild(c)},_onInputClick:function(){var a,b,c,d=this._form.getElementsByTagName("input"),e=d.length;for(a=0;a0},removeEventListener:function(a,b,c){if(!this.hasEventListeners(a))return this;for(var d=0,e=this._leaflet_events,f=e[a].length;d=this.min.x&&c.x<=this.max.x&&b.y>=this.min.y&&c.y<=this.max.y},intersects:function(a){var b=this.min,c=this.max,d=a.min,e=a.max,f=e.x>=b.x&&d.x<=c.x,g=e.y>=b.y&&d.y<=c.y;return f&&g}}),L.Transformation=L.Class.extend({initialize:function(a,b,c,d){this._a=a,this._b=b,this._c=c,this._d=d},transform:function(a,b){return this._transform(a.clone(),b)},_transform:function(a,b){return b=b||1,a.x=b*(this._a*a.x+this._b),a.y=b*(this._c*a.y+this._d),a},untransform:function(a,b){return b=b||1,new L.Point((a.x/b-this._b)/this._a,(a.y/b-this._d)/this._c)}}),L.DomUtil={get:function(a){return typeof a=="string"?document.getElementById(a):a},getStyle:function(a,b){var c=a.style[b];!c&&a.currentStyle&&(c=a.currentStyle[b]);if(!c||c==="auto"){var d=document.defaultView.getComputedStyle(a,null);c=d?d[b]:null}return c==="auto"?null:c},getViewportOffset:function(a){var b=0,c=0,d=a,e=document.body;do{b+=d.offsetTop||0,c+=d.offsetLeft||0;if(d.offsetParent===e&&L.DomUtil.getStyle(d,"position")==="absolute")break;d=d.offsetParent}while(d);d=a;do{if(d===e)break;b-=d.scrollTop||0,c-=d.scrollLeft||0,d=d.parentNode}while(d);return new L.Point(c,b)},create:function(a,b,c){var d=document.createElement(a);return d.className=b,c&&c.appendChild(d),d},disableTextSelection:function(){document.selection&&document.selection.empty&&document.selection.empty(),this._onselectstart||(this._onselectstart=document.onselectstart,document.onselectstart=L.Util.falseFn)},enableTextSelection:function(){document.onselectstart=this._onselectstart,this._onselectstart=null},hasClass:function(a,b){return a.className.length>0&&RegExp("(^|\\s)"+b+"(\\s|$)").test(a.className)},addClass:function(a,b){L.DomUtil.hasClass(a,b)||(a.className+=(a.className?" ":"")+b)},removeClass:function(a,b){a.className=a.className.replace(/(\S+)\s*/g,function(a,c){return c===b?"":a}).replace(/^\s+/,"")},setOpacity:function(a,b){L.Browser.ie?a.style.filter="alpha(opacity="+Math.round(b*100)+")":a.style.opacity=b},testProp:function(a){var b=document.documentElement.style;for(var c=0;c=b.lat&&e.lat<=c.lat&&d.lng>=b.lng&&e.lng<=c.lng},intersects:function(a){var b=this._southWest,c=this._northEast,d=a.getSouthWest(),e=a.getNorthEast(),f=e.lat>=b.lat&&d.lat<=c.lat,g=e.lng>=b.lng&&d.lng<=c.lng;return f&&g},toBBoxString:function(){var a=this._southWest,b=this._northEast;return[a.lng,a.lat,b.lng,b.lat].join(",")}}),L.Projection={},L.Projection.SphericalMercator={MAX_LATITUDE:85.0511287798,project:function(a){var b=L.LatLng.DEG_TO_RAD,c=this.MAX_LATITUDE,d=Math.max(Math.min(c,a.lat),-c),e=a.lng*b,f=d*b;return f=Math.log(Math.tan(Math.PI/4+f/2)),new L.Point(e,f)},unproject:function(a,b){var c=L.LatLng.RAD_TO_DEG,d=a.x*c,e=(2*Math.atan(Math.exp(a.y))-Math.PI/2)*c;return new L.LatLng(e,d,b)}},L.Projection.LonLat={project:function(a){return new L.Point(a.lng,a.lat)},unproject:function(a,b){return new L.LatLng(a.y,a.x,b)}},L.CRS={latLngToPoint:function(a,b){var c=this.projection.project(a);return this.transformation._transform(c,b)},pointToLatLng:function(a,b,c){var d=this.transformation.untransform(a,b);return this.projection.unproject(d,c)},project:function(a){return this.projection.project(a)}},L.CRS.EPSG3857=L.Util.extend({},L.CRS,{code:"EPSG:3857",projection:L.Projection.SphericalMercator,transformation:new L.Transformation(.5/Math.PI,.5,-0.5/Math.PI,.5),project:function(a){var b=this.projection.project(a),c=6378137;return b.multiplyBy(c)}}),L.CRS.EPSG900913=L.Util.extend({},L.CRS.EPSG3857,{code:"EPSG:900913"}),L.CRS.EPSG4326=L.Util.extend({},L.CRS,{code:"EPSG:4326",projection:L.Projection.LonLat,transformation:new L.Transformation(1/360,.5,-1/360,.5)}),L.Map=L.Class.extend({includes:L.Mixin.Events,options:{crs:L.CRS.EPSG3857||L.CRS.EPSG4326,scale:function(a){return 256*Math.pow(2,a)},center:null,zoom:null,layers:[],dragging:!0,touchZoom:L.Browser.touch&&!L.Browser.android,scrollWheelZoom:!L.Browser.touch,doubleClickZoom:!0,boxZoom:!0,zoomControl:!0,attributionControl:!0,fadeAnimation:L.DomUtil.TRANSITION&&!L.Browser.android,zoomAnimation:L.DomUtil.TRANSITION&&!L.Browser.android&&!L.Browser.mobileOpera,trackResize:!0,closePopupOnClick:!0,worldCopyJump:!0},initialize:function(a,b){L.Util.setOptions(this,b),this._container=L.DomUtil.get(a);if(this._container._leaflet)throw Error("Map container is already initialized.");this._container._leaflet=!0,this._initLayout(),L.DomEvent&&(this._initEvents(),L.Handler&&this._initInteraction(),L.Control&&this._initControls()),this.options.maxBounds&&this.setMaxBounds(this.options.maxBounds);var c=this.options.center,d=this.options.zoom;c!==null&&d!==null&&this.setView(c,d,!0);var e=this.options.layers;e=e instanceof Array?e:[e],this._tileLayersNum=0,this._initLayers(e)},setView:function(a,b){return this._resetView(a,this._limitZoom(b)),this},setZoom:function(a){return this.setView(this.getCenter(),a)},zoomIn:function(){return this.setZoom(this._zoom+1)},zoomOut:function(){return this.setZoom(this._zoom-1)},fitBounds:function(a){var b=this.getBoundsZoom(a);return this.setView(a.getCenter(),b)},fitWorld:function(){var a=new L.LatLng(-60,-170),b=new L.LatLng(85,179);return this.fitBounds(new L.LatLngBounds(a,b))},panTo:function(a){return this.setView(a,this._zoom)},panBy:function(a){return this.fire("movestart"),this._rawPanBy(a),this.fire("move"),this.fire("moveend"),this},setMaxBounds:function(a){this.options.maxBounds=a;if(!a)return this._boundsMinZoom=null,this;var b=this.getBoundsZoom(a,!0);return this._boundsMinZoom=b,this._loaded&&(this._zoomf.x&&(g=f.x-d.x),c.y>e.y&&(h=e.y-c.y),c.xl&&--m>0)o=h*Math.sin(j),n=Math.PI/2-2*Math.atan(i*Math.pow((1-o)/(1+o),.5*h))-j,j+=n;return new L.LatLng(j*c,f,b)}},L.CRS.EPSG3395=L.Util.extend({},L.CRS,{code:"EPSG:3395",projection:L.Projection.Mercator,transformation:function(){var a=L.Projection.Mercator,b=a.R_MAJOR,c=a.R_MINOR;return new L.Transformation(.5/(Math.PI*b),.5,-0.5/(Math.PI*c),.5)}()}),L.TileLayer=L.Class.extend({includes:L.Mixin.Events,options:{minZoom:0,maxZoom:18,tileSize:256,subdomains:"abc",errorTileUrl:"",attribution:"",opacity:1,scheme:"xyz",continuousWorld:!1,noWrap:!1,zoomOffset:0,zoomReverse:!1,unloadInvisibleTiles:L.Browser.mobile,updateWhenIdle:L.Browser.mobile},initialize:function(a,b,c){L.Util.setOptions(this,b),this._url=a,this._urlParams=c,typeof this.options.subdomains=="string"&&(this.options.subdomains=this.options.subdomains.split(""))},onAdd:function(a,b){this._map=a,this._insertAtTheBottom=b,this._initContainer(),this._createTileProto(),a.on("viewreset",this._resetCallback,this),this.options.updateWhenIdle?a.on("moveend",this._update,this):(this._limitedUpdate=L.Util.limitExecByInterval(this._update,150,this),a.on("move",this._limitedUpdate,this)),this._reset(),this._update()},onRemove:function(a){this._map.getPanes().tilePane.removeChild(this._container),this._container=null,this._map.off("viewreset",this._resetCallback,this),this.options.updateWhenIdle?this._map.off("moveend",this._update,this):this._map.off("move",this._limitedUpdate,this)},getAttribution:function(){return this.options.attribution},setOpacity:function(a){this.options.opacity=a,this._setOpacity(a);if(L.Browser.webkit)for(var b in this._tiles)this._tiles.hasOwnProperty(b)&&(this._tiles[b].style.webkitTransform+=" translate(0,0)")},_setOpacity:function(a){a<1&&L.DomUtil.setOpacity(this._container,a)},_initContainer:function(){var a=this._map.getPanes().tilePane,b=a.firstChild;if(!this._container||a.empty)this._container=L.DomUtil.create("div","leaflet-layer"),this._insertAtTheBottom&&b?a.insertBefore(this._container,b):a.appendChild(this._container),this._setOpacity(this.options.opacity)},_resetCallback:function(a){this._reset(a.hard)},_reset:function(a){var b;for(b in this._tiles)this._tiles.hasOwnProperty(b)&&this.fire("tileunload",{tile:this._tiles[b]});this._tiles={},this.options.reuseTiles&&(this._unusedTiles=[]),a&&this._container&&(this._container.innerHTML=""),this._initContainer()},_update:function(){var a=this._map.getPixelBounds(),b=this.options.tileSize,c=new L.Point(Math.floor(a.min.x/b),Math.floor(a.min.y/b)),d=new L.Point(Math.floor(a.max.x/b),Math.floor(a.max.y/b)),e=new L.Bounds(c,d);this._addTilesFromCenterOut(e),(this.options.unloadInvisibleTiles||this.options.reuseTiles)&&this._removeOtherTiles(e)},_addTilesFromCenterOut:function(a){var b=[],c=a.getCenter();for(var d=a.min.y;d<=a.max.y;d++)for(var e=a.min.x;e<=a.max.x;e++){if(e+":"+d in this._tiles)continue;b.push(new L.Point(e,d))}b.sort(function(a,b){return a.distanceTo(c)-b.distanceTo(c)});var f=document.createDocumentFragment();this._tilesToLoad=b.length;for(var g=0,h=this._tilesToLoad;ga.max.x||da.max.y)f=this._tiles[e],this.fire("tileunload",{tile:f,url:f.src}),f.parentNode===this._container&&this._container.removeChild(f),this.options.reuseTiles&&this._unusedTiles.push(this._tiles[e]),delete this._tiles[e]}},_addTile:function(a,b){var c=this._getTilePos(a),d=this._map.getZoom(),e=a.x+":"+a.y,f=Math.pow(2,this._getOffsetZoom(d));if(!this.options.continuousWorld){if(!this.options.noWrap)a.x=(a.x%f+f)%f;else if(a.x<0||a.x>=f){this._tilesToLoad--;return}if(a.y<0||a.y>=f){this._tilesToLoad--;return}}var g=this._getTile();L.DomUtil.setPosition(g,c),this._tiles[e]=g,this.options.scheme==="tms"&&(a.y=f-a.y-1),this._loadTile(g,a,d),b.appendChild(g)},_getOffsetZoom:function(a){return a=this.options.zoomReverse?this.options.maxZoom-a:a,a+this.options.zoomOffset},_getTilePos:function(a){var b=this._map.getPixelOrigin(),c=this.options.tileSize;return a.multiplyBy(c).subtract(b)},getTileUrl:function(a,b){var c=this.options.subdomains,d=this.options.subdomains[(a.x+a.y)%c.length];return L.Util.template(this._url,L.Util.extend({s:d,z:this._getOffsetZoom(b),x:a.x,y:a.y},this._urlParams))},_createTileProto:function(){this._tileImg=L.DomUtil.create("img","leaflet-tile"),this._tileImg.galleryimg="no";var a=this.options.tileSize;this._tileImg.style.width=a+"px",this._tileImg.style.height=a+"px"},_getTile:function(){if(this.options.reuseTiles&&this._unusedTiles.length>0){var a=this._unusedTiles.pop();return this._resetTile(a),a}return this._createTile()},_resetTile:function(a){},_createTile:function(){var a=this._tileImg.cloneNode(!1);return a.onselectstart=a.onmousemove=L.Util.falseFn,a},_loadTile:function(a,b,c){a._layer=this,a.onload=this._tileOnLoad,a.onerror=this._tileOnError,a.src=this.getTileUrl(b,c)},_tileOnLoad:function(a){var b=this._layer;this.className+=" leaflet-tile-loaded",b.fire("tileload",{tile:this,url:this.src}),b._tilesToLoad--,b._tilesToLoad||b.fire("load")},_tileOnError:function(a){var b=this._layer;b.fire("tileerror",{tile:this,url:this.src});var c=b.options.errorTileUrl;c&&(this.src=c)}}),L.TileLayer.WMS=L.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",version:"1.1.1",layers:"",styles:"",format:"image/jpeg",transparent:!1},initialize:function(a,b){this._url=a,this.wmsParams=L.Util.extend({},this.defaultWmsParams),this.wmsParams.width=this.wmsParams.height=this.options.tileSize;for(var c in b)this.options.hasOwnProperty(c)||(this.wmsParams[c]=b[c]);L.Util.setOptions(this,b)},onAdd:function(a){var b=parseFloat(this.wmsParams.version)<1.3?"srs":"crs";this.wmsParams[b]=a.options.crs.code,L.TileLayer.prototype.onAdd.call(this,a)},getTileUrl:function(a,b){var c=this.options.tileSize,d=a.multiplyBy(c),e=d.add(new L.Point(c,c)),f=this._map.unproject(d,this._zoom,!0),g=this._map.unproject(e,this._zoom,!0),h=this._map.options.crs.project(f),i=this._map.options.crs.project(g),j=[h.x,i.y,i.x,h.y].join(",");return this._url+L.Util.getParamString(this.wmsParams)+"&bbox="+j}}),L.TileLayer.Canvas=L.TileLayer.extend({options:{async:!1},initialize:function(a){L.Util.setOptions(this,a)},redraw:function(){for(var a in this._tiles){var b=this._tiles[a];this._redrawTile(b)}},_redrawTile:function(a){this.drawTile(a,a._tilePoint,a._zoom)},_createTileProto:function(){this._canvasProto=L.DomUtil.create("canvas","leaflet-tile");var a=this.options.tileSize;this._canvasProto.width=a,this._canvasProto.height=a},_createTile:function(){var a=this._canvasProto.cloneNode(!1);return a.onselectstart=a.onmousemove=L.Util.falseFn,a},_loadTile:function(a,b,c){a._layer=this,a._tilePoint=b,a._zoom=c,this.drawTile(a,b,c),this.options.async||this.tileDrawn(a)},drawTile:function(a,b,c){},tileDrawn:function(a){this._tileOnLoad.call(a)}}),L.ImageOverlay=L.Class.extend({includes:L.Mixin.Events,initialize:function(a,b){this._url=a,this._bounds=b},onAdd:function(a){this._map=a,this._image||this._initImage(),a.getPanes().overlayPane.appendChild(this._image),a.on("viewreset",this._reset,this),this._reset()},onRemove:function(a){a.getPanes().overlayPane.removeChild(this._image),a.off("viewreset",this._reset,this)},_initImage:function(){this._image=L.DomUtil.create("img","leaflet-image-layer"),this._image.style.visibility="hidden",L.Util.extend(this._image,{galleryimg:"no",onselectstart:L.Util.falseFn,onmousemove:L.Util.falseFn,onload:L.Util.bind(this._onImageLoad,this),src:this._url})},_reset:function(){var a=this._map.latLngToLayerPoint(this._bounds.getNorthWest()),b=this._map.latLngToLayerPoint(this._bounds.getSouthEast()),c=b.subtract(a);L.DomUtil.setPosition(this._image,a),this._image.style.width=c.x+"px",this._image.style.height=c.y+"px"},_onImageLoad:function(){this._image.style.visibility="",this.fire("load")}}),L.Icon=L.Class.extend({iconUrl:L.ROOT_URL+"images/marker.png",shadowUrl:L.ROOT_URL+"images/marker-shadow.png",iconSize:new L.Point(25,41),shadowSize:new L.Point(41,41),iconAnchor:new L.Point(13,41),popupAnchor:new L.Point(0,-33),initialize:function(a){a&&(this.iconUrl=a)},createIcon:function(){return this._createIcon("icon")},createShadow:function(){return this._createIcon("shadow")},_createIcon:function(a){var b=this[a+"Size"],c=this[a+"Url"];if(!c&&a==="shadow")return null;var d;return c?d=this._createImg(c):d=this._createDiv(),d.className="leaflet-marker-"+a,d.style.marginLeft=-this.iconAnchor.x+"px",d.style.marginTop=-this.iconAnchor.y+"px",b&&(d.style.width=b.x+"px",d.style.height=b.y+"px"),d},_createImg:function(a){var b;return L.Browser.ie6?(b=document.createElement("div"),b.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+a+'")'):(b=document.createElement("img"),b.src=a),b},_createDiv:function(){return document.createElement("div")}}),L.Marker=L.Class.extend({includes:L.Mixin.Events,options:{icon:new L.Icon,title:"",clickable:!0,draggable:!1,zIndexOffset:0},initialize:function(a,b){L.Util.setOptions(this,b),this._latlng=a},onAdd:function(a){this._map=a,this._initIcon(),a.on("viewreset",this._reset,this),this._reset()},onRemove:function(a){this._removeIcon(),this.closePopup&&this.closePopup(),this._map=null,a.off("viewreset",this._reset,this)},getLatLng:function(){return this._latlng},setLatLng:function(a){this._latlng=a,this._icon&&(this._reset(),this._popup&&this._popup.setLatLng(this._latlng))},setIcon:function(a){this._map&&this._removeIcon(),this.options.icon=a,this._map&&(this._initIcon(),this._reset())},_initIcon:function(){this._icon||(this._icon=this.options.icon.createIcon(),this.options.title&&(this._icon.title=this.options.title),this._initInteraction()),this._shadow||(this._shadow=this.options.icon.createShadow()),this._map._panes.markerPane.appendChild(this._icon),this._shadow&&this._map._panes.shadowPane.appendChild(this._shadow)},_removeIcon:function(){this._map._panes.markerPane.removeChild(this._icon),this._shadow&&this._map._panes.shadowPane.removeChild(this._shadow),this._icon=this._shadow=null},_reset:function(){var a=this._map.latLngToLayerPoint(this._latlng).round();L.DomUtil.setPosition(this._icon,a),this._shadow&&L.DomUtil.setPosition(this._shadow,a),this._icon.style.zIndex=a.y+this.options.zIndexOffset},_initInteraction:function(){if(this.options.clickable){this._icon.className+=" leaflet-clickable",L.DomEvent.addListener(this._icon,"click",this._onMouseClick,this);var a=["dblclick","mousedown","mouseover","mouseout"];for(var b=0;bthis.options.maxWidth?this.options.maxWidth:af.x&&(d.x=c.x+this._containerWidth-f.x+e.x),c.y<0&&(d.y=c.y-e.y),c.y+a>f.y&&(d.y=c.y+a-f.y+e.y),(d.x||d.y)&&this._map.panBy(d)},_onCloseButtonClick:function(a){this._close(),L.DomEvent.stop(a)}}),L.Marker.include({openPopup:function(){return this._popup.setLatLng(this._latlng),this._map&&this._map.openPopup(this._popup),this},closePopup:function(){return this._popup&&this._popup._close(),this},bindPopup:function(a,b){return b=L.Util.extend({offset:this.options.icon.popupAnchor},b),this._popup||this.on("click",this.openPopup,this),this._popup=new L.Popup(b,this),this._popup.setContent(a),this},unbindPopup:function(){return this._popup&&(this._popup=null,this.off("click",this.openPopup)),this}}),L.Map.include({openPopup:function(a){return this.closePopup(),this._popup=a,this.addLayer(a),this.fire("popupopen",{popup:this._popup}),this},closePopup:function(){return this._popup&&(this.removeLayer(this._popup),this.fire("popupclose",{popup:this._popup}),this._popup=null),this}}),L.LayerGroup=L.Class.extend({initialize:function(a){this._layers={};if(a)for(var b=0,c=a.length;b')}}catch(a){return function(a){return document.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}()},_initPath:function(){this._container=L.Path._createElement("shape"),this._container.className+=" leaflet-vml-shape"+(this.options.clickable?" leaflet-clickable":""),this._container.coordsize="1 1",this._path=L.Path._createElement("path"),this._container.appendChild(this._path),this._map._pathRoot.appendChild(this._container)},_initStyle:function(){this.options.stroke?(this._stroke=L.Path._createElement("stroke"),this._stroke.endcap="round",this._container.appendChild(this._stroke)):this._container.stroked=!1,this.options.fill?(this._container.filled=!0,this._fill=L.Path._createElement("fill"),this._container.appendChild(this._fill)):this._container.filled=!1,this._updateStyle()},_updateStyle:function(){this.options.stroke&&(this._stroke.weight=this.options.weight+"px",this._stroke.color=this.options.color,this._stroke.opacity=this.options.opacity),this.options.fill&&(this._fill.color=this.options.fillColor||this.options.color,this._fill.opacity=this.options.fillOpacity)},_updatePath:function(){this._container.style.display="none",this._path.v=this.getPathString()+" ",this._container.style.display=""}}),L.Map.include(L.Browser.svg||!L.Browser.vml?{}:{_initPathRoot:function(){this._pathRoot||(this._pathRoot=document.createElement("div"),this._pathRoot.className="leaflet-vml-container",this._panes.overlayPane.appendChild(this._pathRoot),this.on("moveend",this._updatePathViewport),this._updatePathViewport())}}),L.LineUtil={simplify:function(a,b){if(!b||!a.length)return a.slice();var c=b*b;return a=this._reducePoints(a,c),a=this._simplifyDP(a,c),a},pointToSegmentDistance:function(a,b,c){return Math.sqrt(this._sqClosestPointOnSegment(a,b,c,!0))},closestPointOnSegment:function(a,b,c){return this._sqClosestPointOnSegment(a,b,c)},_simplifyDP:function(a,b){var c=a.length,d=typeof Uint8Array!="undefined"?Uint8Array:Array,e=new d(c);e[0]=e[c-1]=1,this._simplifyDPStep(a,e,b,0,c-1);var f,g=[];for(f=0;ff&&(g=h,f=i);f>c&&(b[g]=1,this._simplifyDPStep(a,b,c,d,g),this._simplifyDPStep(a,b,c,g,e))},_reducePoints:function(a,b){var c=[a[0]];for(var d=1,e=0,f=a.length;db&&(c.push(a[d]),e=d);return eb.max.x&&(c|=2),a.yb.max.y&&(c|=8),c},_sqDist:function(a,b){var c=b.x-a.x,d=b.y-a.y;return c*c+d*d},_sqClosestPointOnSegment:function(a,b,c,d){var e=b.x,f=b.y,g=c.x-e,h=c.y-f,i=g*g+h*h,j;return i>0&&(j=((a.x-e)*g+(a.y-f)*h)/i,j>1?(e=c.x,f=c.y):j>0&&(e+=g*j,f+=h*j)),g=a.x-e,h=a.y-f,d?g*g+h*h:new L.Point(e,f)}},L.Polyline=L.Path.extend({initialize:function(a,b){L.Path.prototype.initialize.call(this,b),this._latlngs=a},options:{smoothFactor:1,noClip:!1,updateOnMoveEnd:!0},projectLatlngs:function(){this._originalPoints=[];for(var a=0,b=this._latlngs.length;aa.max.x||c.y-b>a.max.y||c.x+ba.y!=e.y>a.y&&a.x<(e.x-d.x)*(a.y-d.y)/(e.y-d.y)+d.x&&(b=!b)}return b}}:{}),L.Circle.include(L.Path.CANVAS?{_drawPath:function(){var a=this._point;this._ctx.beginPath(),this._ctx.arc(a.x,a.y,this._radius,0,Math.PI*2)},_containsPoint:function(a){var b=this._point,c=this.options.stroke?this.options.weight/2:0;return a.distanceTo(b)<=this._radius+c}}:{}),L.GeoJSON=L.FeatureGroup.extend({initialize:function(a,b){L.Util.setOptions(this,b),this._geojson=a,this._layers={},a&&this.addGeoJSON(a)},addGeoJSON:function(a){if(a.features){for(var b=0,c=a.features.length;b1)return;var b=a.touches&&a.touches.length===1?a.touches[0]:a,c=b.target;L.DomEvent.preventDefault(a),L.Browser.touch&&c.tagName.toLowerCase()==="a"&&(c.className+=" leaflet-active"),this._moved=!1;if(this._moving)return;L.Browser.touch||(L.DomUtil.disableTextSelection(),this._setMovingCursor()),this._startPos=this._newPos=L.DomUtil.getPosition(this._element),this._startPoint=new L.Point(b.clientX,b.clientY),L.DomEvent.addListener(document,L.Draggable.MOVE,this._onMove,this),L.DomEvent.addListener(document,L.Draggable.END,this._onUp,this)},_onMove:function(a){if(a.touches&&a.touches.length>1)return;L.DomEvent.preventDefault(a);var b=a.touches&&a.touches.length===1?a.touches[0]:a;this._moved||(this.fire("dragstart"),this._moved=!0),this._moving=!0;var c=new L.Point(b.clientX,b.clientY);this._newPos=this._startPos.add(c).subtract(this._startPoint),L.Util.requestAnimFrame(this._updatePosition,this,!0,this._dragStartTarget)},_updatePosition:function(){this.fire("predrag"),L.DomUtil.setPosition(this._element,this._newPos),this.fire("drag")},_onUp:function(a){if(a.changedTouches){var b=a.changedTouches[0],c=b.target,d=this._newPos&&this._newPos.distanceTo(this._startPos)||0;c.tagName.toLowerCase()==="a"&&(c.className=c.className.replace(" leaflet-active","")),d0&&c<=f,d=b}function l(a){e&&(g.type="dblclick",b(g),d=null)}var d,e=!1,f=250,g,h="_leaflet_",i="touchstart",j="touchend";a[h+i+c]=k,a[h+j+c]=l,a.addEventListener(i,k,!1),a.addEventListener(j,l,!1)},removeDoubleTapListener:function(a,b){var c="_leaflet_";a.removeEventListener(a,a[c+"touchstart"+b],!1),a.removeEventListener(a,a[c+"touchend"+b],!1)}}),L.Map.TouchZoom=L.Handler.extend({addHooks:function(){L.DomEvent.addListener(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){L.DomEvent.removeListener(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(a){if(!a.touches||a.touches.length!==2||this._map._animatingZoom)return;var b=this._map.mouseEventToLayerPoint(a.touches[0]),c=this._map.mouseEventToLayerPoint(a.touches[1]),d=this._map.containerPointToLayerPoint(this._map.getSize().divideBy(2));this._startCenter=b.add(c).divideBy(2,!0),this._startDist=b.distanceTo(c),this._moved=!1,this._zooming=!0,this._centerOffset=d.subtract(this._startCenter),L.DomEvent.addListener(document,"touchmove",this._onTouchMove,this),L.DomEvent.addListener(document,"touchend",this._onTouchEnd,this),L.DomEvent.preventDefault(a)},_onTouchMove:function(a){if(!a.touches||a.touches.length!==2)return;this._moved||(this._map._mapPane.className+=" leaflet-zoom-anim",this._map.fire("zoomstart").fire("movestart")._prepareTileBg(),this._moved=!0);var b=this._map.mouseEventToLayerPoint(a.touches[0]),c=this._map.mouseEventToLayerPoint(a.touches[1]);this._scale=b.distanceTo(c)/this._startDist,this._delta=b.add(c).divideBy(2,!0).subtract(this._startCenter),this._map._tileBg.style.webkitTransform=[L.DomUtil.getTranslateString(this._delta),L.DomUtil.getScaleString(this._scale,this._startCenter)].join(" "),L.DomEvent.preventDefault(a)},_onTouchEnd:function(a){if(!this._moved||!this._zooming)return;this._zooming=!1;var b=this._map.getZoom(),c=Math.log(this._scale)/Math.LN2,d=c>0?Math.ceil(c):Math.floor(c),e=this._map._limitZoom(b+d),f=e-b,g=this._centerOffset.subtract(this._delta).divideBy(this._scale),h=this._map.getPixelOrigin().add(this._startCenter).add(g),i=this._map.unproject(h);L.DomEvent.removeListener(document,"touchmove",this._onTouchMove),L.DomEvent.removeListener(document,"touchend",this._onTouchEnd);var j=Math.pow(2,f);this._map._runAnimation(i,e,j/this._scale,this._startCenter.add(g))}}),L.Map.BoxZoom=L.Handler.extend({initialize:function(a){this._map=a,this._container=a._container,this._pane=a._panes.overlayPane},addHooks:function(){L.DomEvent.addListener(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){L.DomEvent.removeListener(this._container,"mousedown",this._onMouseDown)},_onMouseDown:function(a){if(!a.shiftKey||a.which!==1&&a.button!==1)return!1;L.DomUtil.disableTextSelection(),this._startLayerPoint=this._map.mouseEventToLayerPoint(a),this._box=L.DomUtil.create("div","leaflet-zoom-box",this._pane),L.DomUtil.setPosition(this._box,this._startLayerPoint),this._container.style.cursor="crosshair",L.DomEvent.addListener(document,"mousemove",this._onMouseMove,this),L.DomEvent.addListener(document,"mouseup",this._onMouseUp,this),L.DomEvent.preventDefault(a)},_onMouseMove:function(a){var b=this._map.mouseEventToLayerPoint(a),c=b.x-this._startLayerPoint.x,d=b.y-this._startLayerPoint.y,e=Math.min(b.x,this._startLayerPoint.x),f=Math.min(b.y,this._startLayerPoint.y),g=new L.Point(e,f);L.DomUtil.setPosition(this._box,g),this._box.style.width=Math.abs(c)-4+"px",this._box.style.height=Math.abs(d)-4+"px"},_onMouseUp:function(a){this._pane.removeChild(this._box),this._container.style.cursor="",L.DomUtil.enableTextSelection(),L.DomEvent.removeListener(document,"mousemove",this._onMouseMove),L.DomEvent.removeListener(document,"mouseup",this._onMouseUp);var b=this._map.mouseEventToLayerPoint(a),c=new L.LatLngBounds(this._map.layerPointToLatLng(this._startLayerPoint),this._map.layerPointToLatLng(b));this._map.fitBounds(c)}}),L.Handler.MarkerDrag=L.Handler.extend({initialize:function(a){this._marker=a},addHooks:function(){var a=this._marker._icon;this._draggable||(this._draggable=new L.Draggable(a,a),this._draggable.on("dragstart",this._onDragStart,this).on("drag",this._onDrag,this).on("dragend",this._onDragEnd,this)),this._draggable.enable()},removeHooks:function(){this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},_onDragStart:function(a){this._marker.closePopup().fire("movestart").fire("dragstart")},_onDrag:function(a){var b=L.DomUtil.getPosition(this._marker._icon);this._marker._shadow&&L.DomUtil.setPosition(this._marker._shadow,b),this._marker._latlng=this._marker._map.layerPointToLatLng(b),this._marker.fire("move").fire("drag")},_onDragEnd:function(){this._marker.fire("moveend").fire("dragend")}}),L.Control={},L.Control.Position={TOP_LEFT:"topLeft",TOP_RIGHT:"topRight",BOTTOM_LEFT:"bottomLeft",BOTTOM_RIGHT:"bottomRight"},L.Map.include({addControl:function(a){a.onAdd(this);var b=a.getPosition(),c=this._controlCorners[b],d=a.getContainer();return L.DomUtil.addClass(d,"leaflet-control"),b.indexOf("bottom")!==-1?c.insertBefore(d,c.firstChild):c.appendChild(d),this},removeControl:function(a){var b=a.getPosition(),c=this._controlCorners[b],d=a.getContainer();return c.removeChild(d),a.onRemove&&a.onRemove(this),this},_initControlPos:function(){var a=this._controlCorners={},b="leaflet-",c=b+"top",d=b+"bottom",e=b+"left",f=b+"right",g=L.DomUtil.create("div",b+"control-container",this._container);L.Browser.touch&&(g.className+=" "+b+"big-buttons"),a.topLeft=L.DomUtil.create("div",c+" "+e,g),a.topRight=L.DomUtil.create("div",c+" "+f,g),a.bottomLeft=L.DomUtil.create("div",d+" "+e,g),a.bottomRight=L.DomUtil.create("div",d+" "+f,g)}}),L.Control.Zoom=L.Class.extend({onAdd:function(a){this._map=a,this._container=L.DomUtil.create("div","leaflet-control-zoom"),this._zoomInButton=this._createButton("Zoom in","leaflet-control-zoom-in",this._map.zoomIn,this._map),this._zoomOutButton=this._createButton("Zoom out","leaflet-control-zoom-out",this._map.zoomOut,this._map),this._container.appendChild(this._zoomInButton),this._container.appendChild(this._zoomOutButton)},getContainer:function(){return this._container},getPosition:function(){return L.Control.Position.TOP_LEFT},_createButton:function(a,b,c,d){var e=document.createElement("a");return e.href="#",e.title=a,e.className=b,L.DomEvent.disableClickPropagation(e),L.DomEvent.addListener(e,"click",L.DomEvent.preventDefault),L.DomEvent.addListener(e,"click",c,d),e}}),L.Control.Attribution=L.Class.extend({initialize:function(a){this._prefix=a||'Powered by Leaflet',this._attributions={}},onAdd:function(a){this._container=L.DomUtil.create("div","leaflet-control-attribution"),L.DomEvent.disableClickPropagation(this._container),this._map=a,this._update()},getPosition:function(){return L.Control.Position.BOTTOM_RIGHT},getContainer:function(){return this._container},setPrefix:function(a){this._prefix=a,this._update()},addAttribution:function(a){if(!a)return;this._attributions[a]=!0,this._update()},removeAttribution:function(a){if(!a)return;delete this._attributions[a],this._update()},_update:function(){if(!this._map)return;var a=[];for(var b in this._attributions)this._attributions.hasOwnProperty(b)&&a.push(b);var c=[];this._prefix&&c.push(this._prefix),a.length&&c.push(a.join(", ")),this._container.innerHTML=c.join(" — ")}}),L.Control.Layers=L.Class.extend({options:{collapsed:!L.Browser.touch},initialize:function(a,b,c){L.Util.setOptions(this,c),this._layers={};for(var d in a)a.hasOwnProperty(d)&&this._addLayer(a[d],d);for(d in b)b.hasOwnProperty(d)&&this._addLayer(b[d],d,!0)},onAdd:function(a){this._map=a,this._initLayout(),this._update()},getContainer:function(){return this._container},getPosition:function(){return L.Control.Position.TOP_RIGHT},addBaseLayer:function(a,b){return this._addLayer(a,b),this._update(),this},addOverlay:function(a,b){return this._addLayer(a,b,!0),this._update(),this},removeLayer:function(a){var b=L.Util.stamp(a);return delete this._layers[b],this._update(),this},_initLayout:function(){this._container=L.DomUtil.create("div","leaflet-control-layers"),L.DomEvent.disableClickPropagation(this._container),this._form=L.DomUtil.create("form","leaflet-control-layers-list");if(this.options.collapsed){L.DomEvent.addListener(this._container,"mouseover",this._expand,this),L.DomEvent.addListener(this._container,"mouseout",this._collapse,this);var a=this._layersLink=L.DomUtil.create("a","leaflet-control-layers-toggle");a.href="#",a.title="Layers",L.DomEvent.addListener(a,"focus",this._expand,this),L.DomEvent.addListener(this._map,L.Draggable.START,this._collapse,this),this._container.appendChild(a)}else this._expand();this._baseLayersList=L.DomUtil.create("div","leaflet-control-layers-base",this._form),this._separator=L.DomUtil.create("div","leaflet-control-layers-separator",this._form),this._overlaysList=L.DomUtil.create("div","leaflet-control-layers-overlays",this._form),this._container.appendChild(this._form)},_addLayer:function(a,b,c){var d=L.Util.stamp(a);this._layers[d]={layer:a,name:b,overlay:c}},_update:function(){if(!this._container)return;this._baseLayersList.innerHTML="",this._overlaysList.innerHTML="";var a=!1,b=!1;for(var c in this._layers)if(this._layers.hasOwnProperty(c)){var d=this._layers[c];this._addItem(d),b=b||d.overlay,a=a||!d.overlay}this._separator.style.display=b&&a?"":"none"},_addItem:function(a,b){var c=document.createElement("label"),d=document.createElement("input");a.overlay||(d.name="leaflet-base-layers"),d.type=a.overlay?"checkbox":"radio",d.checked=this._map.hasLayer(a.layer),d.layerId=L.Util.stamp(a.layer),L.DomEvent.addListener(d,"click",this._onInputClick,this);var e=document.createTextNode(" "+a.name);c.appendChild(d),c.appendChild(e);var f=a.overlay?this._overlaysList:this._baseLayersList;f.appendChild(c)},_onInputClick:function(){var a,b,c,d=this._form.getElementsByTagName("input"),e=d.length;for(a=0;aLeaflet'; + this._attributions = {}; + }, + onAdd: function (map) { this._container = L.DomUtil.create('div', 'leaflet-control-attribution'); L.DomEvent.disableClickPropagation(this._container); this._map = map; - this._prefix = 'Powered by Leaflet'; - this._attributions = {}; this._update(); }, diff --git a/src/dom/DomEvent.js b/src/dom/DomEvent.js index 785193d9..5ac4f070 100644 --- a/src/dom/DomEvent.js +++ b/src/dom/DomEvent.js @@ -112,7 +112,7 @@ L.DomEvent = { }, disableClickPropagation: function (/*HTMLElement*/ el) { - L.DomEvent.addListener(el, 'mousedown', L.DomEvent.stopPropagation); + L.DomEvent.addListener(el, L.Draggable.START, L.DomEvent.stopPropagation); L.DomEvent.addListener(el, 'click', L.DomEvent.stopPropagation); L.DomEvent.addListener(el, 'dblclick', L.DomEvent.stopPropagation); }, diff --git a/src/geo/LatLng.js b/src/geo/LatLng.js index 8db1b2d9..03897ac6 100644 --- a/src/geo/LatLng.js +++ b/src/geo/LatLng.js @@ -12,7 +12,7 @@ L.LatLng = function (/*Number*/ rawLat, /*Number*/ rawLng, /*Boolean*/ noWrap) { if (noWrap !== true) { lat = Math.max(Math.min(lat, 90), -90); // clamp latitude into -90..90 - lng = (lng + 180) % 360 + (lng < -180 ? 180 : -180); // wrap longtitude into -180..180 + lng = (lng + 180) % 360 + ((lng < -180 || lng === 180) ? 180 : -180); // wrap longtitude into -180..180 } //TODO change to lat() & lng() @@ -40,5 +40,21 @@ L.LatLng.prototype = { return 'LatLng(' + L.Util.formatNum(this.lat) + ', ' + L.Util.formatNum(this.lng) + ')'; + }, + + // Haversine distance formula, see http://en.wikipedia.org/wiki/Haversine_formula + distanceTo: function (/*LatLng*/ other)/*->Double*/ { + var R = 6378137, // earth radius in meters + d2r = L.LatLng.DEG_TO_RAD, + dLat = (other.lat - this.lat) * d2r, + dLon = (other.lng - this.lng) * d2r, + lat1 = this.lat * d2r, + lat2 = other.lat * d2r, + sin1 = Math.sin(dLat / 2), + sin2 = Math.sin(dLon / 2); + + var a = sin1 * sin1 + sin2 * sin2 * Math.cos(lat1) * Math.cos(lat2); + + return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); } }; diff --git a/src/geo/LatLngBounds.js b/src/geo/LatLngBounds.js index bdca2e92..7a87ea47 100644 --- a/src/geo/LatLngBounds.js +++ b/src/geo/LatLngBounds.js @@ -16,8 +16,8 @@ L.LatLngBounds = L.Class.extend({ // extend the bounds to contain the given point extend: function (/*LatLng*/ latlng) { if (!this._southWest && !this._northEast) { - this._southWest = new L.LatLng(latlng.lat, latlng.lng); - this._northEast = new L.LatLng(latlng.lat, latlng.lng); + this._southWest = new L.LatLng(latlng.lat, latlng.lng, true); + this._northEast = new L.LatLng(latlng.lat, latlng.lng, true); } else { this._southWest.lat = Math.min(latlng.lat, this._southWest.lat); this._southWest.lng = Math.min(latlng.lng, this._southWest.lng); @@ -41,11 +41,11 @@ L.LatLngBounds = L.Class.extend({ }, getNorthWest: function () { - return new L.LatLng(this._northEast.lat, this._southWest.lng); + return new L.LatLng(this._northEast.lat, this._southWest.lng, true); }, getSouthEast: function () { - return new L.LatLng(this._southWest.lat, this._northEast.lng); + return new L.LatLng(this._southWest.lat, this._northEast.lng, true); }, contains: function (/*LatLngBounds or LatLng*/ obj) /*-> Boolean*/ { diff --git a/src/geometry/Bounds.js b/src/geometry/Bounds.js index 162cc470..dd70edce 100644 --- a/src/geometry/Bounds.js +++ b/src/geometry/Bounds.js @@ -46,5 +46,18 @@ L.Bounds = L.Class.extend({ (max.x <= this.max.x) && (min.y >= this.min.y) && (max.y <= this.max.y); + }, + + intersects: function (/*Bounds*/ bounds) { + var min = this.min, + max = this.max, + min2 = bounds.min, + max2 = bounds.max; + + var xIntersects = (max2.x >= min.x) && (min2.x <= max.x), + yIntersects = (max2.y >= min.y) && (min2.y <= max.y); + + return xIntersects && yIntersects; } + }); diff --git a/src/geometry/LineUtil.js b/src/geometry/LineUtil.js index 21ccfd9e..ad0bded3 100644 --- a/src/geometry/LineUtil.js +++ b/src/geometry/LineUtil.js @@ -13,72 +13,80 @@ L.LineUtil = { return points.slice(); } + var sqTolerance = tolerance * tolerance; + // stage 1: vertex reduction - points = this.reducePoints(points, tolerance); + points = this._reducePoints(points, sqTolerance); // stage 2: Douglas-Peucker simplification - points = this.simplifyDP(points, tolerance); + points = this._simplifyDP(points, sqTolerance); return points; }, // distance from a point to a segment between two points pointToSegmentDistance: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { - return Math.sqrt(this._sqPointToSegmentDist(p, p1, p2)); + return Math.sqrt(this._sqClosestPointOnSegment(p, p1, p2, true)); }, closestPointOnSegment: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { - var point = this._sqClosestPointOnSegment(p, p1, p2); - point.distance = Math.sqrt(point._sqDist); - return point; + return this._sqClosestPointOnSegment(p, p1, p2); }, // Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm - simplifyDP: function (points, tol) { - var maxDist2 = 0, - index = 0, - t2 = tol * tol, - len = points.length, - i, dist2; + _simplifyDP: function (points, sqTolerance) { - if (len < 3) { - return points; - } + var len = points.length, + ArrayConstructor = typeof Uint8Array !== 'undefined' ? Uint8Array : Array, + markers = new ArrayConstructor(len); - for (i = 0; i < len - 1; i++) { - dist2 = this._sqPointToSegmentDist(points[i], points[0], points[len - 1]); - if (dist2 > maxDist2) { - index = i; - maxDist2 = dist2; + markers[0] = markers[len - 1] = 1; + + this._simplifyDPStep(points, markers, sqTolerance, 0, len - 1); + + var i, + newPoints = []; + + for (i = 0; i < len; i++) { + if (markers[i]) { + newPoints.push(points[i]); } } - var part1, part2; + return newPoints; + }, - if (maxDist2 >= t2) { - part1 = points.slice(0, index); - part2 = points.slice(index); + _simplifyDPStep: function (points, markers, sqTolerance, first, last) { - part1 = this.simplifyDP(part1, tol); - part2 = this.simplifyDP(part2, tol); + var maxSqDist = 0, + index, i, sqDist; - return part1.concat(part2); - } else { - return [points[0], points[len - 1]]; + for (i = first + 1; i <= last - 1; i++) { + sqDist = this._sqClosestPointOnSegment(points[i], points[first], points[last], true); + + if (sqDist > maxSqDist) { + index = i; + maxSqDist = sqDist; + } + } + + if (maxSqDist > sqTolerance) { + markers[index] = 1; + + this._simplifyDPStep(points, markers, sqTolerance, first, index); + this._simplifyDPStep(points, markers, sqTolerance, index, last); } }, // reduce points that are too close to each other to a single point - reducePoints: function (points, tol) { - var reducedPoints = [points[0]], - t2 = tol * tol; + _reducePoints: function (points, sqTolerance) { + var reducedPoints = [points[0]]; for (var i = 1, prev = 0, len = points.length; i < len; i++) { - if (this._sqDist(points[i], points[prev]) < t2) { - continue; + if (this._sqDist(points[i], points[prev]) > sqTolerance) { + reducedPoints.push(points[i]); + prev = i; } - reducedPoints.push(points[i]); - prev = i; } if (prev < len - 1) { reducedPoints.push(points[len - 1]); @@ -168,27 +176,30 @@ L.LineUtil = { return dx * dx + dy * dy; }, - // return closest point on segment with attribute _sqDist - square distance to segment - _sqClosestPointOnSegment: function (p, p1, p2) { - var x2 = p2.x - p1.x, - y2 = p2.y - p1.y, - apoint = p1; - if (x2 || y2) { - var dot = (p.x - p1.x) * x2 + (p.y - p1.y) * y2, - t = dot / this._sqDist(p1, p2); + // return closest point on segment or distance to that point + _sqClosestPointOnSegment: function (p, p1, p2, sqDist) { + var x = p1.x, + y = p1.y, + dx = p2.x - x, + dy = p2.y - y, + dot = dx * dx + dy * dy, + t; + + if (dot > 0) { + t = ((p.x - x) * dx + (p.y - y) * dy) / dot; if (t > 1) { - apoint = p2; + x = p2.x; + y = p2.y; } else if (t > 0) { - apoint = new L.Point(p1.x + x2 * t, p1.y + y2 * t); + x += dx * t; + y += dy * t; } } - apoint._sqDist = this._sqDist(p, apoint); - return apoint; - }, - // distance from a point to a segment between two points - _sqPointToSegmentDist: function (p, p1, p2) { - return this._sqClosestPointOnSegment(p, p1, p2)._sqDist; + dx = p.x - x; + dy = p.y - y; + + return sqDist ? dx * dx + dy * dy : new L.Point(x, y); } }; diff --git a/src/layer/Popup.js b/src/layer/Popup.js index 12a6611e..5b7e9fcc 100644 --- a/src/layer/Popup.js +++ b/src/layer/Popup.js @@ -8,7 +8,8 @@ L.Popup = L.Class.extend({ autoPan: true, closeButton: true, offset: new L.Point(0, 2), - autoPanPadding: new L.Point(5, 5) + autoPanPadding: new L.Point(5, 5), + className: '' }, initialize: function (options, source) { @@ -75,7 +76,7 @@ L.Popup = L.Class.extend({ }, _initLayout: function () { - this._container = L.DomUtil.create('div', 'leaflet-popup'); + this._container = L.DomUtil.create('div', 'leaflet-popup ' + this.options.className); if (this.options.closeButton) { this._closeButton = L.DomUtil.create('a', 'leaflet-popup-close-button', this._container); diff --git a/src/layer/marker/Icon.js b/src/layer/marker/Icon.js index 6e990a70..dc7502d8 100644 --- a/src/layer/marker/Icon.js +++ b/src/layer/marker/Icon.js @@ -24,13 +24,19 @@ L.Icon = L.Class.extend({ _createIcon: function (name) { var size = this[name + 'Size'], - src = this[name + 'Url'], - img = this._createImg(src); - - if (!src) { + src = this[name + 'Url']; + if (!src && name === 'shadow') { return null; } + var img; + if (!src) { + img = this._createDiv(); + } + else { + img = this._createImg(src); + } + img.className = 'leaflet-marker-' + name; img.style.marginLeft = (-this.iconAnchor.x) + 'px'; @@ -54,5 +60,9 @@ L.Icon = L.Class.extend({ el.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + src + '")'; } return el; + }, + + _createDiv: function () { + return document.createElement('div'); } }); diff --git a/src/layer/marker/Marker.Popup.js b/src/layer/marker/Marker.Popup.js index 9597c297..3d4768d4 100644 --- a/src/layer/marker/Marker.Popup.js +++ b/src/layer/marker/Marker.Popup.js @@ -5,7 +5,9 @@ L.Marker.include({ openPopup: function () { this._popup.setLatLng(this._latlng); - this._map.openPopup(this._popup); + if (this._map) { + this._map.openPopup(this._popup); + } return this; }, diff --git a/src/layer/marker/Marker.js b/src/layer/marker/Marker.js index 1f3c6b9c..6ce41b08 100644 --- a/src/layer/marker/Marker.js +++ b/src/layer/marker/Marker.js @@ -10,7 +10,8 @@ L.Marker = L.Class.extend({ icon: new L.Icon(), title: '', clickable: true, - draggable: false + draggable: false, + zIndexOffset: 0 }, initialize: function (latlng, options) { @@ -104,8 +105,7 @@ L.Marker = L.Class.extend({ L.DomUtil.setPosition(this._shadow, pos); } - this._icon.style.zIndex = pos.y; - // TODO zIndex offset + this._icon.style.zIndex = pos.y + this.options.zIndexOffset; }, _initInteraction: function () { diff --git a/src/layer/tile/TileLayer.Canvas.js b/src/layer/tile/TileLayer.Canvas.js index ff3be7ac..d1cc4c3f 100644 --- a/src/layer/tile/TileLayer.Canvas.js +++ b/src/layer/tile/TileLayer.Canvas.js @@ -7,6 +7,17 @@ L.TileLayer.Canvas = L.TileLayer.extend({ L.Util.setOptions(this, options); }, + redraw: function () { + for (var i in this._tiles) { + var tile = this._tiles[i]; + this._redrawTile(tile); + } + }, + + _redrawTile: function (tile) { + this.drawTile(tile, tile._tilePoint, tile._zoom); + }, + _createTileProto: function () { this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile'); @@ -23,6 +34,8 @@ L.TileLayer.Canvas = L.TileLayer.extend({ _loadTile: function (tile, tilePoint, zoom) { tile._layer = this; + tile._tilePoint = tilePoint; + tile._zoom = zoom; this.drawTile(tile, tilePoint, zoom); diff --git a/src/layer/tile/TileLayer.js b/src/layer/tile/TileLayer.js index 859c65ed..7f6e6d8d 100644 --- a/src/layer/tile/TileLayer.js +++ b/src/layer/tile/TileLayer.js @@ -17,9 +17,11 @@ L.TileLayer = L.Class.extend({ continuousWorld: false, noWrap: false, zoomOffset: 0, + zoomReverse: false, unloadInvisibleTiles: L.Browser.mobile, - updateWhenIdle: L.Browser.mobile + updateWhenIdle: L.Browser.mobile, + reuseTiles: false }, initialize: function (url, options, urlParams) { @@ -125,6 +127,10 @@ L.TileLayer = L.Class.extend({ } this._tiles = {}; + if (this.options.reuseTiles) { + this._unusedTiles = []; + } + if (clearOldContainer && this._container) { this._container.innerHTML = ""; } @@ -145,7 +151,7 @@ L.TileLayer = L.Class.extend({ this._addTilesFromCenterOut(tileBounds); - if (this.options.unloadInvisibleTiles) { + if (this.options.unloadInvisibleTiles || this.options.reuseTiles) { this._removeOtherTiles(tileBounds); } }, @@ -196,9 +202,14 @@ L.TileLayer = L.Class.extend({ // evil, don't do this! crashes Android 3, produces load errors, doesn't solve memory leaks // this._tiles[key].src = ''; + //tile.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; + if (tile.parentNode === this._container) { this._container.removeChild(tile); } + if (this.options.reuseTiles) { + this._unusedTiles.push(this._tiles[key]); + } delete this._tiles[key]; } } @@ -209,7 +220,7 @@ L.TileLayer = L.Class.extend({ var tilePos = this._getTilePos(tilePoint), zoom = this._map.getZoom(), key = tilePoint.x + ':' + tilePoint.y, - tileLimit = Math.pow(2, (zoom + this.options.zoomOffset)); + tileLimit = Math.pow(2, this._getOffsetZoom(zoom)); // wrap tile coordinates if (!this.options.continuousWorld) { @@ -226,8 +237,8 @@ L.TileLayer = L.Class.extend({ } } - // create tile - var tile = this._createTile(); + // get unused tile - or create a new tile + var tile = this._getTile(); L.DomUtil.setPosition(tile, tilePos); this._tiles[key] = tile; @@ -241,6 +252,11 @@ L.TileLayer = L.Class.extend({ container.appendChild(tile); }, + _getOffsetZoom: function (zoom) { + zoom = this.options.zoomReverse ? this.options.maxZoom - zoom : zoom; + return zoom + this.options.zoomOffset; + }, + _getTilePos: function (tilePoint) { var origin = this._map.getPixelOrigin(), tileSize = this.options.tileSize; @@ -256,7 +272,7 @@ L.TileLayer = L.Class.extend({ return L.Util.template(this._url, L.Util.extend({ s: s, - z: zoom + this.options.zoomOffset, + z: this._getOffsetZoom(zoom), x: tilePoint.x, y: tilePoint.y }, this._urlParams)); @@ -271,6 +287,19 @@ L.TileLayer = L.Class.extend({ this._tileImg.style.height = tileSize + 'px'; }, + _getTile: function () { + if (this.options.reuseTiles && this._unusedTiles.length > 0) { + var tile = this._unusedTiles.pop(); + this._resetTile(tile); + return tile; + } + return this._createTile(); + }, + + _resetTile: function (tile) { + // Override if data stored on a tile needs to be cleaned up before reuse + }, + _createTile: function () { var tile = this._tileImg.cloneNode(false); tile.onselectstart = tile.onmousemove = L.Util.falseFn; diff --git a/src/layer/vector/Path.Popup.js b/src/layer/vector/Path.Popup.js index 282abb11..337747b6 100644 --- a/src/layer/vector/Path.Popup.js +++ b/src/layer/vector/Path.Popup.js @@ -5,7 +5,7 @@ L.Path.include({ bindPopup: function (content, options) { if (!this._popup || this._popup.options !== options) { - this._popup = new L.Popup(options); + this._popup = new L.Popup(options, this); } this._popup.setContent(content); diff --git a/src/layer/vector/Polygon.js b/src/layer/vector/Polygon.js index 3631079c..c71fc361 100644 --- a/src/layer/vector/Polygon.js +++ b/src/layer/vector/Polygon.js @@ -10,7 +10,7 @@ L.Polygon = L.Polyline.extend({ initialize: function (latlngs, options) { L.Polyline.prototype.initialize.call(this, latlngs, options); - if (latlngs[0] instanceof Array) { + if (latlngs && (latlngs[0] instanceof Array)) { this._latlngs = latlngs[0]; this._holes = latlngs.slice(1); } diff --git a/src/map/Map.js b/src/map/Map.js index a4f32df6..3b0f25ee 100644 --- a/src/map/Map.js +++ b/src/map/Map.js @@ -253,7 +253,7 @@ L.Map = L.Class.extend({ return this; } - this._rawPanBy(oldSize.subtract(this.getSize()).divideBy(2)); + this._rawPanBy(oldSize.subtract(this.getSize()).divideBy(2, true)); this.fire('move'); @@ -280,8 +280,8 @@ L.Map = L.Class.extend({ getBounds: function () { var bounds = this.getPixelBounds(), - sw = this.unproject(new L.Point(bounds.min.x, bounds.max.y)), - ne = this.unproject(new L.Point(bounds.max.x, bounds.min.y)); + sw = this.unproject(new L.Point(bounds.min.x, bounds.max.y), this._zoom, true), + ne = this.unproject(new L.Point(bounds.max.x, bounds.min.y), this._zoom, true); return new L.LatLngBounds(sw, ne); }, @@ -328,7 +328,7 @@ L.Map = L.Class.extend({ } } while (zoomNotFound && (zoom <= maxZoom)); - if (zoomNotFound) { + if (zoomNotFound && inside) { return null; } @@ -510,7 +510,7 @@ L.Map = L.Class.extend({ _initEvents: function () { L.DomEvent.addListener(this._container, 'click', this._onMouseClick, this); - var events = ['dblclick', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove']; + var events = ['dblclick', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'contextmenu']; var i, len; @@ -548,6 +548,10 @@ L.Map = L.Class.extend({ return; } + if (type === 'contextmenu') { + L.DomEvent.preventDefault(e); + } + this.fire(type, { latlng: this.mouseEventToLatLng(e), layerPoint: this.mouseEventToLayerPoint(e) diff --git a/src/map/ext/Map.Geolocation.js b/src/map/ext/Map.Geolocation.js index c4d0ac09..567222c9 100644 --- a/src/map/ext/Map.Geolocation.js +++ b/src/map/ext/Map.Geolocation.js @@ -42,7 +42,7 @@ L.Map.include({ options = L.Util.extend({ maxZoom: maxZoom || Infinity, setView: true - }); + }, options); return this.locate(options); },