leaflet-rails 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ee7c67fd6f07cb0b7b467e04d22667781a33cc36
4
- data.tar.gz: 483f1222824f6bb72f31095f5bdaa8e02b282668
2
+ SHA256:
3
+ metadata.gz: 78b6afc48a50ce5cf8e2f439b037a0c2607fa2a2b431acedb796e1f7adead522
4
+ data.tar.gz: d5a68b45e906359fa77a4b8a356766fc1d65cb292820bcf3851ca54af2c3133a
5
5
  SHA512:
6
- metadata.gz: fa9a8cfab3f44a62950d1001fb24b7ec663b24759b8f389dcea4451ab5076072b6c7ce0ba1282573a2c65d8631ee71c6e76ca7830b820c9c0f479b713b1bbdc4
7
- data.tar.gz: b703bf4f556ee14297fa2329ee6848933740eeb55c968eafff2b446127b269e0827f5538ef809818a0c251ea98c08ba3e223aca0ba54595d0dbcfcf0a663a917
6
+ metadata.gz: e664e5bf49d2fc99f22493f5cba226d420dfd89541550aa525ce2cc45877a687ea3788c2285c48eac71f8aba681d1a87574137029b62be2ef51bb568804f61c2
7
+ data.tar.gz: ec58a9ac0d61c758f14c47d89502f2d4b392bb9974df66ebd0c36efd7ce5b665e9a3ba11cf66f25791edb6f905db54da2f0773dcd91ab8921aa1d8dde97de911
@@ -1,5 +1,5 @@
1
1
  module Leaflet
2
2
  module Rails
3
- VERSION = "1.2.0"
3
+ VERSION = "1.3.0"
4
4
  end
5
5
  end
File without changes
File without changes
File without changes
File without changes
@@ -1,14 +1,15 @@
1
1
  /* @preserve
2
- * Leaflet 1.2.0, a JS library for interactive maps. http://leafletjs.com
2
+ * Leaflet 1.3.0+Detached: 1a38558f7b22f5ffacda5f6a1b8e60d54c361873.1a38558, a JS library for interactive maps. http://leafletjs.com
3
3
  * (c) 2010-2017 Vladimir Agafonkin, (c) 2010-2011 CloudMade
4
4
  */
5
+
5
6
  (function (global, factory) {
6
7
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
7
8
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
8
9
  (factory((global.L = {})));
9
10
  }(this, (function (exports) { 'use strict';
10
11
 
11
- var version = "1.2.0";
12
+ var version = "1.3.0+HEAD.1a38558";
12
13
 
13
14
  /*
14
15
  * @namespace Util
@@ -65,12 +66,12 @@ function bind(fn, obj) {
65
66
  var lastId = 0;
66
67
 
67
68
  // @function stamp(obj: Object): Number
68
- // Returns the unique ID of an object, assiging it one if it doesn't have it.
69
+ // Returns the unique ID of an object, assigning it one if it doesn't have it.
69
70
  function stamp(obj) {
70
71
  /*eslint-disable */
71
72
  obj._leaflet_id = obj._leaflet_id || ++lastId;
72
73
  return obj._leaflet_id;
73
- /*eslint-enable */
74
+ /* eslint-enable */
74
75
  }
75
76
 
76
77
  // @function throttle(fn: Function, time: Number, context: Object): Function
@@ -124,9 +125,9 @@ function wrapNum(x, range, includeMax) {
124
125
  function falseFn() { return false; }
125
126
 
126
127
  // @function formatNum(num: Number, digits?: Number): Number
127
- // Returns the number `num` rounded to `digits` decimals, or to 5 decimals by default.
128
+ // Returns the number `num` rounded to `digits` decimals, or to 6 decimals by default.
128
129
  function formatNum(num, digits) {
129
- var pow = Math.pow(10, digits || 5);
130
+ var pow = Math.pow(10, (digits === undefined ? 6 : digits));
130
131
  return Math.round(num * pow) / pow;
131
132
  }
132
133
 
@@ -167,7 +168,7 @@ function getParamString(obj, existingUrl, uppercase) {
167
168
  return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
168
169
  }
169
170
 
170
- var templateRe = /\{ *([\w_\-]+) *\}/g;
171
+ var templateRe = /\{ *([\w_-]+) *\}/g;
171
172
 
172
173
  // @function template(str: String, data: Object): String
173
174
  // Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`
@@ -390,7 +391,7 @@ Class.addInitHook = function (fn) { // (Function) || (String, args...)
390
391
  };
391
392
 
392
393
  function checkDeprecatedMixinEvents(includes) {
393
- if (!L || !L.Mixin) { return; }
394
+ if (typeof L === 'undefined' || !L || !L.Mixin) { return; }
394
395
 
395
396
  includes = isArray(includes) ? includes : [includes];
396
397
 
@@ -576,7 +577,11 @@ var Events = {
576
577
  fire: function (type, data, propagate) {
577
578
  if (!this.listens(type, propagate)) { return this; }
578
579
 
579
- var event = extend({}, data, {type: type, target: this});
580
+ var event = extend({}, data, {
581
+ type: type,
582
+ target: this,
583
+ sourceTarget: data && data.sourceTarget || this
584
+ });
580
585
 
581
586
  if (this._events) {
582
587
  var listeners = this._events[type];
@@ -657,7 +662,10 @@ var Events = {
657
662
 
658
663
  _propagateEvent: function (e) {
659
664
  for (var id in this._eventParents) {
660
- this._eventParents[id].fire(e.type, extend({layer: e.target}, e), true);
665
+ this._eventParents[id].fire(e.type, extend({
666
+ layer: e.target,
667
+ propagatedFrom: e.target
668
+ }, e), true);
661
669
  }
662
670
  }
663
671
  };
@@ -707,6 +715,10 @@ var Evented = Class.extend(Events);
707
715
  * map.panBy([200, 300]);
708
716
  * map.panBy(L.point(200, 300));
709
717
  * ```
718
+ *
719
+ * Note that `Point` does not inherit from Leafet's `Class` object,
720
+ * which means new classes can't inherit from it, and new methods
721
+ * can't be added to it with the `include` function.
710
722
  */
711
723
 
712
724
  function Point(x, y, round) {
@@ -716,6 +728,10 @@ function Point(x, y, round) {
716
728
  this.y = (round ? Math.round(y) : y);
717
729
  }
718
730
 
731
+ var trunc = Math.trunc || function (v) {
732
+ return v > 0 ? Math.floor(v) : Math.ceil(v);
733
+ };
734
+
719
735
  Point.prototype = {
720
736
 
721
737
  // @method clone(): Point
@@ -826,6 +842,18 @@ Point.prototype = {
826
842
  return this;
827
843
  },
828
844
 
845
+ // @method trunc(): Point
846
+ // Returns a copy of the current point with truncated coordinates (rounded towards zero).
847
+ trunc: function () {
848
+ return this.clone()._trunc();
849
+ },
850
+
851
+ _trunc: function () {
852
+ this.x = trunc(this.x);
853
+ this.y = trunc(this.y);
854
+ return this;
855
+ },
856
+
829
857
  // @method distanceTo(otherPoint: Point): Number
830
858
  // Returns the cartesian distance between the current and the given points.
831
859
  distanceTo: function (point) {
@@ -909,6 +937,10 @@ function toPoint(x, y, round) {
909
937
  * ```js
910
938
  * otherBounds.intersects([[10, 10], [40, 60]]);
911
939
  * ```
940
+ *
941
+ * Note that `Bounds` does not inherit from Leafet's `Class` object,
942
+ * which means new classes can't inherit from it, and new methods
943
+ * can't be added to it with the `include` function.
912
944
  */
913
945
 
914
946
  function Bounds(a, b) {
@@ -1082,6 +1114,10 @@ function toBounds(a, b) {
1082
1114
  * ```
1083
1115
  *
1084
1116
  * Caution: if the area crosses the antimeridian (often confused with the International Date Line), you must specify corners _outside_ the [-180, 180] degrees longitude range.
1117
+ *
1118
+ * Note that `LatLngBounds` does not inherit from Leafet's `Class` object,
1119
+ * which means new classes can't inherit from it, and new methods
1120
+ * can't be added to it with the `include` function.
1085
1121
  */
1086
1122
 
1087
1123
  function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[])
@@ -1135,7 +1171,9 @@ LatLngBounds.prototype = {
1135
1171
  },
1136
1172
 
1137
1173
  // @method pad(bufferRatio: Number): LatLngBounds
1138
- // Returns bigger bounds created by extending the current bounds by a given percentage in each direction.
1174
+ // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
1175
+ // For example, a ratio of 0.5 extends the bounds by 50% in each direction.
1176
+ // Negative values will retract the bounds.
1139
1177
  pad: function (bufferRatio) {
1140
1178
  var sw = this._southWest,
1141
1179
  ne = this._northEast,
@@ -1270,7 +1308,7 @@ LatLngBounds.prototype = {
1270
1308
  },
1271
1309
 
1272
1310
  // @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean
1273
- // Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds. The margin of error can be overriden by setting `maxMargin` to a small number.
1311
+ // Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds. The margin of error can be overridden by setting `maxMargin` to a small number.
1274
1312
  equals: function (bounds, maxMargin) {
1275
1313
  if (!bounds) { return false; }
1276
1314
 
@@ -1321,6 +1359,10 @@ function toLatLngBounds(a, b) {
1321
1359
  * map.panTo({lat: 50, lng: 30});
1322
1360
  * map.panTo(L.latLng(50, 30));
1323
1361
  * ```
1362
+ *
1363
+ * Note that `LatLng` does not inherit from Leafet's `Class` object,
1364
+ * which means new classes can't inherit from it, and new methods
1365
+ * can't be added to it with the `include` function.
1324
1366
  */
1325
1367
 
1326
1368
  function LatLng(lat, lng, alt) {
@@ -1345,7 +1387,7 @@ function LatLng(lat, lng, alt) {
1345
1387
 
1346
1388
  LatLng.prototype = {
1347
1389
  // @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean
1348
- // Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overriden by setting `maxMargin` to a small number.
1390
+ // Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overridden by setting `maxMargin` to a small number.
1349
1391
  equals: function (obj, maxMargin) {
1350
1392
  if (!obj) { return false; }
1351
1393
 
@@ -1367,7 +1409,7 @@ LatLng.prototype = {
1367
1409
  },
1368
1410
 
1369
1411
  // @method distanceTo(otherLatLng: LatLng): Number
1370
- // Returns the distance (in meters) to the given `LatLng` calculated using the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula).
1412
+ // Returns the distance (in meters) to the given `LatLng` calculated using the [Spherical Law of Cosines](https://en.wikipedia.org/wiki/Spherical_law_of_cosines).
1371
1413
  distanceTo: function (other) {
1372
1414
  return Earth.distance(this, toLatLng(other));
1373
1415
  },
@@ -1443,6 +1485,10 @@ function toLatLng(a, b, c) {
1443
1485
  * Leaflet defines the most usual CRSs by default. If you want to use a
1444
1486
  * CRS not defined by default, take a look at the
1445
1487
  * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin.
1488
+ *
1489
+ * Note that the CRS instances do not inherit from Leafet's `Class` object,
1490
+ * and can't be instantiated. Also, new classes can't inherit from them,
1491
+ * and methods can't be added to them with the `include` function.
1446
1492
  */
1447
1493
 
1448
1494
  var CRS = {
@@ -1585,10 +1631,11 @@ var Earth = extend({}, CRS, {
1585
1631
  var rad = Math.PI / 180,
1586
1632
  lat1 = latlng1.lat * rad,
1587
1633
  lat2 = latlng2.lat * rad,
1588
- a = Math.sin(lat1) * Math.sin(lat2) +
1589
- Math.cos(lat1) * Math.cos(lat2) * Math.cos((latlng2.lng - latlng1.lng) * rad);
1590
-
1591
- return this.R * Math.acos(Math.min(a, 1));
1634
+ sinDLat = Math.sin((latlng2.lat - latlng1.lat) * rad / 2),
1635
+ sinDLon = Math.sin((latlng2.lng - latlng1.lng) * rad / 2),
1636
+ a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon,
1637
+ c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
1638
+ return this.R * c;
1592
1639
  }
1593
1640
  });
1594
1641
 
@@ -1613,8 +1660,8 @@ var SphericalMercator = {
1613
1660
  sin = Math.sin(lat * d);
1614
1661
 
1615
1662
  return new Point(
1616
- this.R * latlng.lng * d,
1617
- this.R * Math.log((1 + sin) / (1 - sin)) / 2);
1663
+ this.R * latlng.lng * d,
1664
+ this.R * Math.log((1 + sin) / (1 - sin)) / 2);
1618
1665
  },
1619
1666
 
1620
1667
  unproject: function (point) {
@@ -1701,7 +1748,7 @@ Transformation.prototype = {
1701
1748
 
1702
1749
  // @alternative
1703
1750
  // @factory L.transformation(coefficients: Array): Transformation
1704
- // Expects an coeficients array of the form
1751
+ // Expects an coefficients array of the form
1705
1752
  // `[a: Number, b: Number, c: Number, d: Number]`.
1706
1753
 
1707
1754
  function toTransformation(a, b, c, d) {
@@ -1802,6 +1849,11 @@ var android = userAgentContains('android');
1802
1849
  // @property android23: Boolean; `true` for browsers running on Android 2 or Android 3.
1803
1850
  var android23 = userAgentContains('android 2') || userAgentContains('android 3');
1804
1851
 
1852
+ /* See https://stackoverflow.com/a/17961266 for details on detecting stock Android */
1853
+ var webkitVer = parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10); // also matches AppleWebKit
1854
+ // @property androidStock: Boolean; `true` for the Android stock browser (i.e. not Chrome)
1855
+ var androidStock = android && userAgentContains('Google') && webkitVer < 537 && !('AudioNode' in window);
1856
+
1805
1857
  // @property opera: Boolean; `true` for the Opera browser
1806
1858
  var opera = !!window.opera;
1807
1859
 
@@ -1914,6 +1966,7 @@ var Browser = (Object.freeze || Object)({
1914
1966
  webkit: webkit,
1915
1967
  android: android,
1916
1968
  android23: android23,
1969
+ androidStock: androidStock,
1917
1970
  opera: opera,
1918
1971
  chrome: chrome,
1919
1972
  gecko: gecko,
@@ -1949,6 +2002,7 @@ var POINTER_MOVE = msPointer ? 'MSPointerMove' : 'pointermove';
1949
2002
  var POINTER_UP = msPointer ? 'MSPointerUp' : 'pointerup';
1950
2003
  var POINTER_CANCEL = msPointer ? 'MSPointerCancel' : 'pointercancel';
1951
2004
  var TAG_WHITE_LIST = ['INPUT', 'SELECT', 'OPTION'];
2005
+
1952
2006
  var _pointers = {};
1953
2007
  var _pointerDocListener = false;
1954
2008
 
@@ -1991,7 +2045,7 @@ function removePointerListener(obj, type, id) {
1991
2045
 
1992
2046
  function _addPointerStart(obj, handler, id) {
1993
2047
  var onDown = bind(function (e) {
1994
- if (e.pointerType !== 'mouse' && e.pointerType !== e.MSPOINTER_TYPE_MOUSE && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) {
2048
+ if (e.pointerType !== 'mouse' && e.MSPOINTER_TYPE_MOUSE && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) {
1995
2049
  // In IE11, some touch events needs to fire for form controls, or
1996
2050
  // the controls will stop working. We keep a whitelist of tag names that
1997
2051
  // need these events. For other target tags, we prevent default on the event.
@@ -2072,8 +2126,8 @@ function _addPointerEnd(obj, handler, id) {
2072
2126
  * Extends the event handling code with double tap support for mobile browsers.
2073
2127
  */
2074
2128
 
2075
- var _touchstart = msPointer ? 'MSPointerDown' : pointer ? 'pointerdown' : 'touchstart';
2076
- var _touchend = msPointer ? 'MSPointerUp' : pointer ? 'pointerup' : 'touchend';
2129
+ var _touchstart = msPointer ? 'MSPointerDown' : pointer ? 'pointerdown' : 'touchstart';
2130
+ var _touchend = msPointer ? 'MSPointerUp' : pointer ? 'pointerup' : 'touchend';
2077
2131
  var _pre = '_leaflet_';
2078
2132
 
2079
2133
  // inspired by Zepto touch code by Thomas Fuchs
@@ -2188,18 +2242,13 @@ function on(obj, types, fn, context) {
2188
2242
  var eventsKey = '_leaflet_events';
2189
2243
 
2190
2244
  // @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this
2191
- // Removes a previously added listener function. If no function is specified,
2192
- // it will remove all the listeners of that particular DOM event from the element.
2245
+ // Removes a previously added listener function.
2193
2246
  // Note that if you passed a custom context to on, you must pass the same
2194
2247
  // context to `off` in order to remove the listener.
2195
2248
 
2196
2249
  // @alternative
2197
2250
  // @function off(el: HTMLElement, eventMap: Object, context?: Object): this
2198
2251
  // Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
2199
-
2200
- // @alternative
2201
- // @function off(el: HTMLElement): this
2202
- // Removes all known event listeners
2203
2252
  function off(obj, types, fn, context) {
2204
2253
 
2205
2254
  if (typeof types === 'object') {
@@ -2284,7 +2333,8 @@ function removeOne(obj, type, fn, context) {
2284
2333
  if (pointer && type.indexOf('touch') === 0) {
2285
2334
  removePointerListener(obj, type, id);
2286
2335
 
2287
- } else if (touch && (type === 'dblclick') && removeDoubleTapListener) {
2336
+ } else if (touch && (type === 'dblclick') && removeDoubleTapListener &&
2337
+ !(pointer && chrome)) {
2288
2338
  removeDoubleTapListener(obj, id);
2289
2339
 
2290
2340
  } else if ('removeEventListener' in obj) {
@@ -2356,7 +2406,7 @@ function preventDefault(e) {
2356
2406
  return this;
2357
2407
  }
2358
2408
 
2359
- // @function stop(ev): this
2409
+ // @function stop(ev: DOMEvent): this
2360
2410
  // Does `stopPropagation` and `preventDefault` at the same time.
2361
2411
  function stop(e) {
2362
2412
  preventDefault(e);
@@ -2374,9 +2424,11 @@ function getMousePosition(e, container) {
2374
2424
 
2375
2425
  var rect = container.getBoundingClientRect();
2376
2426
 
2427
+ var scaleX = rect.width / container.offsetWidth || 1;
2428
+ var scaleY = rect.height / container.offsetHeight || 1;
2377
2429
  return new Point(
2378
- e.clientX - rect.left - container.clientLeft,
2379
- e.clientY - rect.top - container.clientTop);
2430
+ e.clientX / scaleX - rect.left - container.clientLeft,
2431
+ e.clientY / scaleY - rect.top - container.clientTop);
2380
2432
  }
2381
2433
 
2382
2434
  // Chrome on Win scrolls double the pixels as in other platforms (see #4538),
@@ -2694,7 +2746,7 @@ function setPosition(el, point) {
2694
2746
 
2695
2747
  /*eslint-disable */
2696
2748
  el._leaflet_pos = point;
2697
- /*eslint-enable */
2749
+ /* eslint-enable */
2698
2750
 
2699
2751
  if (any3d) {
2700
2752
  setTransform(el, point);
@@ -3333,7 +3385,7 @@ var Map = Evented.extend({
3333
3385
  }
3334
3386
  }
3335
3387
 
3336
- this._moveStart(true);
3388
+ this._moveStart(true, options.noMoveStart);
3337
3389
 
3338
3390
  frame.call(this);
3339
3391
  return this;
@@ -3371,10 +3423,15 @@ var Map = Evented.extend({
3371
3423
  // @method setMinZoom(zoom: Number): this
3372
3424
  // Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option).
3373
3425
  setMinZoom: function (zoom) {
3426
+ var oldZoom = this.options.minZoom;
3374
3427
  this.options.minZoom = zoom;
3375
3428
 
3376
- if (this._loaded && this.getZoom() < this.options.minZoom) {
3377
- return this.setZoom(zoom);
3429
+ if (this._loaded && oldZoom !== zoom) {
3430
+ this.fire('zoomlevelschange');
3431
+
3432
+ if (this.getZoom() < this.options.minZoom) {
3433
+ return this.setZoom(zoom);
3434
+ }
3378
3435
  }
3379
3436
 
3380
3437
  return this;
@@ -3383,10 +3440,15 @@ var Map = Evented.extend({
3383
3440
  // @method setMaxZoom(zoom: Number): this
3384
3441
  // Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option).
3385
3442
  setMaxZoom: function (zoom) {
3443
+ var oldZoom = this.options.maxZoom;
3386
3444
  this.options.maxZoom = zoom;
3387
3445
 
3388
- if (this._loaded && (this.getZoom() > this.options.maxZoom)) {
3389
- return this.setZoom(zoom);
3446
+ if (this._loaded && oldZoom !== zoom) {
3447
+ this.fire('zoomlevelschange');
3448
+
3449
+ if (this.getZoom() > this.options.maxZoom) {
3450
+ return this.setZoom(zoom);
3451
+ }
3390
3452
  }
3391
3453
 
3392
3454
  return this;
@@ -3407,7 +3469,7 @@ var Map = Evented.extend({
3407
3469
  return this;
3408
3470
  },
3409
3471
 
3410
- // @method invalidateSize(options: Zoom/Pan options): this
3472
+ // @method invalidateSize(options: Zoom/pan options): this
3411
3473
  // Checks if the map container size changed and updates the map if so —
3412
3474
  // call it after you've changed the map size dynamically, also animating
3413
3475
  // pan by default. If `options.pan` is `false`, panning will not occur.
@@ -3580,8 +3642,7 @@ var Map = Evented.extend({
3580
3642
  this.fire('locationfound', data);
3581
3643
  },
3582
3644
 
3583
- // TODO handler.addTo
3584
- // TODO Appropiate docs section?
3645
+ // TODO Appropriate docs section?
3585
3646
  // @section Other Methods
3586
3647
  // @method addHandler(name: String, HandlerClass: Function): this
3587
3648
  // Adds a new `Handler` to the map, given its name and constructor function.
@@ -3616,10 +3677,16 @@ var Map = Evented.extend({
3616
3677
  } catch (e) {
3617
3678
  /*eslint-disable */
3618
3679
  this._container._leaflet_id = undefined;
3619
- /*eslint-enable */
3680
+ /* eslint-enable */
3620
3681
  this._containerId = undefined;
3621
3682
  }
3622
3683
 
3684
+ if (this._locationWatchId !== undefined) {
3685
+ this.stopLocate();
3686
+ }
3687
+
3688
+ this._stop();
3689
+
3623
3690
  remove(this._mapPane);
3624
3691
 
3625
3692
  if (this._clearControlPos) {
@@ -3998,7 +4065,7 @@ var Map = Evented.extend({
3998
4065
  // Pane for `GridLayer`s and `TileLayer`s
3999
4066
  this.createPane('tilePane');
4000
4067
  // @pane overlayPane: HTMLElement = 400
4001
- // Pane for vector overlays (`Path`s), like `Polyline`s and `Polygon`s
4068
+ // Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s and `VideoOverlay`s
4002
4069
  this.createPane('shadowPane');
4003
4070
  // @pane shadowPane: HTMLElement = 500
4004
4071
  // Pane for overlay shadows (e.g. `Marker` shadows)
@@ -4007,7 +4074,7 @@ var Map = Evented.extend({
4007
4074
  // Pane for `Icon`s of `Marker`s
4008
4075
  this.createPane('markerPane');
4009
4076
  // @pane tooltipPane: HTMLElement = 650
4010
- // Pane for tooltip.
4077
+ // Pane for `Tooltip`s.
4011
4078
  this.createPane('tooltipPane');
4012
4079
  // @pane popupPane: HTMLElement = 700
4013
4080
  // Pane for `Popup`s.
@@ -4034,7 +4101,7 @@ var Map = Evented.extend({
4034
4101
 
4035
4102
  var zoomChanged = this._zoom !== zoom;
4036
4103
  this
4037
- ._moveStart(zoomChanged)
4104
+ ._moveStart(zoomChanged, false)
4038
4105
  ._move(center, zoom)
4039
4106
  ._moveEnd(zoomChanged);
4040
4107
 
@@ -4051,7 +4118,7 @@ var Map = Evented.extend({
4051
4118
  }
4052
4119
  },
4053
4120
 
4054
- _moveStart: function (zoomChanged) {
4121
+ _moveStart: function (zoomChanged, noMoveStart) {
4055
4122
  // @event zoomstart: Event
4056
4123
  // Fired when the map zoom is about to change (e.g. before zoom animation).
4057
4124
  // @event movestart: Event
@@ -4059,7 +4126,10 @@ var Map = Evented.extend({
4059
4126
  if (zoomChanged) {
4060
4127
  this.fire('zoomstart');
4061
4128
  }
4062
- return this.fire('movestart');
4129
+ if (!noMoveStart) {
4130
+ this.fire('movestart');
4131
+ }
4132
+ return this;
4063
4133
  },
4064
4134
 
4065
4135
  _move: function (center, zoom, data) {
@@ -4261,9 +4331,9 @@ var Map = Evented.extend({
4261
4331
  };
4262
4332
 
4263
4333
  if (e.type !== 'keypress') {
4264
- var isMarker = (target.options && 'icon' in target.options);
4334
+ var isMarker = target.getLatLng && (!target._radius || target._radius <= 10);
4265
4335
  data.containerPoint = isMarker ?
4266
- this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
4336
+ this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
4267
4337
  data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);
4268
4338
  data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);
4269
4339
  }
@@ -4422,7 +4492,7 @@ var Map = Evented.extend({
4422
4492
 
4423
4493
  _tryAnimatedPan: function (center, options) {
4424
4494
  // difference between the new and current centers in pixels
4425
- var offset = this._getCenterOffset(center)._floor();
4495
+ var offset = this._getCenterOffset(center)._trunc();
4426
4496
 
4427
4497
  // don't animate too far unless animate: true specified in options
4428
4498
  if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }
@@ -4492,7 +4562,7 @@ var Map = Evented.extend({
4492
4562
 
4493
4563
  requestAnimFrame(function () {
4494
4564
  this
4495
- ._moveStart(true)
4565
+ ._moveStart(true, false)
4496
4566
  ._animateZoom(center, zoom, true);
4497
4567
  }, this);
4498
4568
 
@@ -4500,6 +4570,8 @@ var Map = Evented.extend({
4500
4570
  },
4501
4571
 
4502
4572
  _animateZoom: function (center, zoom, startAnim, noUpdate) {
4573
+ if (!this._mapPane) { return; }
4574
+
4503
4575
  if (startAnim) {
4504
4576
  this._animatingZoom = true;
4505
4577
 
@@ -4525,7 +4597,9 @@ var Map = Evented.extend({
4525
4597
  _onZoomTransitionEnd: function () {
4526
4598
  if (!this._animatingZoom) { return; }
4527
4599
 
4528
- removeClass(this._mapPane, 'leaflet-zoom-anim');
4600
+ if (this._mapPane) {
4601
+ removeClass(this._mapPane, 'leaflet-zoom-anim');
4602
+ }
4529
4603
 
4530
4604
  this._animatingZoom = false;
4531
4605
 
@@ -5343,8 +5417,8 @@ var Scale = Control.extend({
5343
5417
  y = map.getSize().y / 2;
5344
5418
 
5345
5419
  var maxMeters = map.distance(
5346
- map.containerPointToLatLng([0, y]),
5347
- map.containerPointToLatLng([this.options.maxWidth, y]));
5420
+ map.containerPointToLatLng([0, y]),
5421
+ map.containerPointToLatLng([this.options.maxWidth, y]));
5348
5422
 
5349
5423
  this._updateScales(maxMeters);
5350
5424
  },
@@ -5586,6 +5660,14 @@ var Handler = Class.extend({
5586
5660
  // Called when the handler is disabled, should remove the event hooks added previously.
5587
5661
  });
5588
5662
 
5663
+ // @section There is static function which can be called without instantiating L.Handler:
5664
+ // @function addTo(map: Map, name: String): this
5665
+ // Adds a new Handler to the given map with the given name.
5666
+ Handler.addTo = function (map, name) {
5667
+ map.addHandler(name, this);
5668
+ return this;
5669
+ };
5670
+
5589
5671
  var Mixin = {Events: Events};
5590
5672
 
5591
5673
  /*
@@ -5812,7 +5894,7 @@ var Draggable = Evented.extend({
5812
5894
  /*
5813
5895
  * @namespace LineUtil
5814
5896
  *
5815
- * Various utility functions for polyine points processing, used by Leaflet internally to make polylines lightning-fast.
5897
+ * Various utility functions for polyline points processing, used by Leaflet internally to make polylines lightning-fast.
5816
5898
  */
5817
5899
 
5818
5900
  // Simplify polyline with vertex reduction and Douglas-Peucker simplification.
@@ -6067,10 +6149,10 @@ var LineUtil = (Object.freeze || Object)({
6067
6149
  */
6068
6150
 
6069
6151
  /* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]
6070
- * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgeman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).
6152
+ * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).
6071
6153
  * Used by Leaflet to only show polygon points that are on the screen or near, increasing
6072
6154
  * performance. Note that polygon points needs different algorithm for clipping
6073
- * than polyline, so there's a seperate method for it.
6155
+ * than polyline, so there's a separate method for it.
6074
6156
  */
6075
6157
  function clipPolygon(points, bounds, round) {
6076
6158
  var clippedPoints,
@@ -6208,6 +6290,10 @@ var Mercator = {
6208
6290
  * The inverse of `project`. Projects a 2D point into a geographical location.
6209
6291
  * Only accepts actual `L.Point` instances, not arrays.
6210
6292
 
6293
+ * Note that the projection instances do not inherit from Leafet's `Class` object,
6294
+ * and can't be instantiated. Also, new classes can't inherit from them,
6295
+ * and methods can't be added to them with the `include` function.
6296
+
6211
6297
  */
6212
6298
 
6213
6299
 
@@ -6589,7 +6675,9 @@ Map.include({
6589
6675
 
6590
6676
  var LayerGroup = Layer.extend({
6591
6677
 
6592
- initialize: function (layers) {
6678
+ initialize: function (layers, options) {
6679
+ setOptions(this, options);
6680
+
6593
6681
  this._layers = {};
6594
6682
 
6595
6683
  var i, len;
@@ -6644,10 +6732,7 @@ var LayerGroup = Layer.extend({
6644
6732
  // @method clearLayers(): this
6645
6733
  // Removes all the layers from the group.
6646
6734
  clearLayers: function () {
6647
- for (var i in this._layers) {
6648
- this.removeLayer(this._layers[i]);
6649
- }
6650
- return this;
6735
+ return this.eachLayer(this.removeLayer, this);
6651
6736
  },
6652
6737
 
6653
6738
  // @method invoke(methodName: String, …): this
@@ -6670,15 +6755,11 @@ var LayerGroup = Layer.extend({
6670
6755
  },
6671
6756
 
6672
6757
  onAdd: function (map) {
6673
- for (var i in this._layers) {
6674
- map.addLayer(this._layers[i]);
6675
- }
6758
+ this.eachLayer(map.addLayer, map);
6676
6759
  },
6677
6760
 
6678
6761
  onRemove: function (map) {
6679
- for (var i in this._layers) {
6680
- map.removeLayer(this._layers[i]);
6681
- }
6762
+ this.eachLayer(map.removeLayer, map);
6682
6763
  },
6683
6764
 
6684
6765
  // @method eachLayer(fn: Function, context?: Object): this
@@ -6705,10 +6786,7 @@ var LayerGroup = Layer.extend({
6705
6786
  // Returns an array of all the layers added to the group.
6706
6787
  getLayers: function () {
6707
6788
  var layers = [];
6708
-
6709
- for (var i in this._layers) {
6710
- layers.push(this._layers[i]);
6711
- }
6789
+ this.eachLayer(layers.push, layers);
6712
6790
  return layers;
6713
6791
  },
6714
6792
 
@@ -6726,10 +6804,10 @@ var LayerGroup = Layer.extend({
6726
6804
  });
6727
6805
 
6728
6806
 
6729
- // @factory L.layerGroup(layers?: Layer[])
6730
- // Create a layer group, optionally given an initial set of layers.
6731
- var layerGroup = function (layers) {
6732
- return new LayerGroup(layers);
6807
+ // @factory L.layerGroup(layers?: Layer[], options?: Object)
6808
+ // Create a layer group, optionally given an initial set of layers and an `options` object.
6809
+ var layerGroup = function (layers, options) {
6810
+ return new LayerGroup(layers, options);
6733
6811
  };
6734
6812
 
6735
6813
  /*
@@ -6800,7 +6878,7 @@ var FeatureGroup = LayerGroup.extend({
6800
6878
  },
6801
6879
 
6802
6880
  // @method bringToBack(): this
6803
- // Brings the layer group to the top of all other layers
6881
+ // Brings the layer group to the back of all other layers
6804
6882
  bringToBack: function () {
6805
6883
  return this.invoke('bringToBack');
6806
6884
  },
@@ -6872,9 +6950,12 @@ var Icon = Class.extend({
6872
6950
  * will be aligned so that this point is at the marker's geographical location. Centered
6873
6951
  * by default if size is specified, also can be set in CSS with negative margins.
6874
6952
  *
6875
- * @option popupAnchor: Point = null
6953
+ * @option popupAnchor: Point = [0, 0]
6876
6954
  * The coordinates of the point from which popups will "open", relative to the icon anchor.
6877
6955
  *
6956
+ * @option tooltipAnchor: Point = [0, 0]
6957
+ * The coordinates of the point from which tooltips will "open", relative to the icon anchor.
6958
+ *
6878
6959
  * @option shadowUrl: String = null
6879
6960
  * The URL to the icon shadow image. If not specified, no shadow image will be created.
6880
6961
  *
@@ -6891,6 +6972,11 @@ var Icon = Class.extend({
6891
6972
  * A custom class name to assign to both icon and shadow images. Empty by default.
6892
6973
  */
6893
6974
 
6975
+ options: {
6976
+ popupAnchor: [0, 0],
6977
+ tooltipAnchor: [0, 0],
6978
+ },
6979
+
6894
6980
  initialize: function (options) {
6895
6981
  setOptions(this, options);
6896
6982
  },
@@ -7002,9 +7088,9 @@ var IconDefault = Icon.extend({
7002
7088
  }
7003
7089
 
7004
7090
  // @option imagePath: String
7005
- // `Icon.Default` will try to auto-detect the absolute location of the
7091
+ // `Icon.Default` will try to auto-detect the location of the
7006
7092
  // blue icon images. If you are placing these images in a non-standard
7007
- // way, set this option to point to the right absolute path.
7093
+ // way, set this option to point to the right path.
7008
7094
  return (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name);
7009
7095
  },
7010
7096
 
@@ -7018,7 +7104,7 @@ var IconDefault = Icon.extend({
7018
7104
  if (path === null || path.indexOf('url') !== 0) {
7019
7105
  path = '';
7020
7106
  } else {
7021
- path = path.replace(/^url\([\"\']?/, '').replace(/marker-icon\.png[\"\']?\)$/, '');
7107
+ path = path.replace(/^url\(["']?/, '').replace(/marker-icon\.png["']?\)$/, '');
7022
7108
  }
7023
7109
 
7024
7110
  return path;
@@ -7057,6 +7143,7 @@ var MarkerDrag = Handler.extend({
7057
7143
 
7058
7144
  this._draggable.on({
7059
7145
  dragstart: this._onDragStart,
7146
+ predrag: this._onPreDrag,
7060
7147
  drag: this._onDrag,
7061
7148
  dragend: this._onDragEnd
7062
7149
  }, this).enable();
@@ -7067,6 +7154,7 @@ var MarkerDrag = Handler.extend({
7067
7154
  removeHooks: function () {
7068
7155
  this._draggable.off({
7069
7156
  dragstart: this._onDragStart,
7157
+ predrag: this._onPreDrag,
7070
7158
  drag: this._onDrag,
7071
7159
  dragend: this._onDragEnd
7072
7160
  }, this).disable();
@@ -7080,6 +7168,42 @@ var MarkerDrag = Handler.extend({
7080
7168
  return this._draggable && this._draggable._moved;
7081
7169
  },
7082
7170
 
7171
+ _adjustPan: function (e) {
7172
+ var marker = this._marker,
7173
+ map = marker._map,
7174
+ speed = this._marker.options.autoPanSpeed,
7175
+ padding = this._marker.options.autoPanPadding,
7176
+ iconPos = L.DomUtil.getPosition(marker._icon),
7177
+ bounds = map.getPixelBounds(),
7178
+ origin = map.getPixelOrigin();
7179
+
7180
+ var panBounds = toBounds(
7181
+ bounds.min._subtract(origin).add(padding),
7182
+ bounds.max._subtract(origin).subtract(padding)
7183
+ );
7184
+
7185
+ if (!panBounds.contains(iconPos)) {
7186
+ // Compute incremental movement
7187
+ var movement = toPoint(
7188
+ (Math.max(panBounds.max.x, iconPos.x) - panBounds.max.x) / (bounds.max.x - panBounds.max.x) -
7189
+ (Math.min(panBounds.min.x, iconPos.x) - panBounds.min.x) / (bounds.min.x - panBounds.min.x),
7190
+
7191
+ (Math.max(panBounds.max.y, iconPos.y) - panBounds.max.y) / (bounds.max.y - panBounds.max.y) -
7192
+ (Math.min(panBounds.min.y, iconPos.y) - panBounds.min.y) / (bounds.min.y - panBounds.min.y)
7193
+ ).multiplyBy(speed);
7194
+
7195
+ map.panBy(movement, {animate: false});
7196
+
7197
+ this._draggable._newPos._add(movement);
7198
+ this._draggable._startPos._add(movement);
7199
+
7200
+ L.DomUtil.setPosition(marker._icon, this._draggable._newPos);
7201
+ this._onDrag(e);
7202
+
7203
+ this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
7204
+ }
7205
+ },
7206
+
7083
7207
  _onDragStart: function () {
7084
7208
  // @section Dragging events
7085
7209
  // @event dragstart: Event
@@ -7095,6 +7219,13 @@ var MarkerDrag = Handler.extend({
7095
7219
  .fire('dragstart');
7096
7220
  },
7097
7221
 
7222
+ _onPreDrag: function (e) {
7223
+ if (this._marker.options.autoPan) {
7224
+ cancelAnimFrame(this._panRequest);
7225
+ this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
7226
+ }
7227
+ },
7228
+
7098
7229
  _onDrag: function (e) {
7099
7230
  var marker = this._marker,
7100
7231
  shadow = marker._shadow,
@@ -7121,6 +7252,8 @@ var MarkerDrag = Handler.extend({
7121
7252
  // @event dragend: DragEndEvent
7122
7253
  // Fired when the user stops dragging the marker.
7123
7254
 
7255
+ cancelAnimFrame(this._panRequest);
7256
+
7124
7257
  // @event moveend: Event
7125
7258
  // Fired when the marker stops moving (because of dragging).
7126
7259
  delete this._oldLatLng;
@@ -7161,6 +7294,18 @@ var Marker = Layer.extend({
7161
7294
  // Whether the marker is draggable with mouse/touch or not.
7162
7295
  draggable: false,
7163
7296
 
7297
+ // @option autoPan: Boolean = false
7298
+ // Set it to `true` if you want the map to do panning animation when marker hits the edges.
7299
+ autoPan: false,
7300
+
7301
+ // @option autoPanPadding: Point = Point(50, 50)
7302
+ // Equivalent of setting both top left and bottom right autopan padding to the same value.
7303
+ autoPanPadding: [50, 50],
7304
+
7305
+ // @option autoPanSpeed: Number = 10
7306
+ // Number of pixels the map should move by.
7307
+ autoPanSpeed: 10,
7308
+
7164
7309
  // @option keyboard: Boolean = true
7165
7310
  // Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.
7166
7311
  keyboard: true,
@@ -7291,7 +7436,7 @@ var Marker = Layer.extend({
7291
7436
 
7292
7437
  update: function () {
7293
7438
 
7294
- if (this._icon) {
7439
+ if (this._icon && this._map) {
7295
7440
  var pos = this._map.latLngToLayerPoint(this._latlng).round();
7296
7441
  this._setPos(pos);
7297
7442
  }
@@ -7316,8 +7461,9 @@ var Marker = Layer.extend({
7316
7461
  if (options.title) {
7317
7462
  icon.title = options.title;
7318
7463
  }
7319
- if (options.alt) {
7320
- icon.alt = options.alt;
7464
+
7465
+ if (icon.tagName === 'IMG') {
7466
+ icon.alt = options.alt || '';
7321
7467
  }
7322
7468
  }
7323
7469
 
@@ -7461,11 +7607,11 @@ var Marker = Layer.extend({
7461
7607
  },
7462
7608
 
7463
7609
  _getPopupAnchor: function () {
7464
- return this.options.icon.options.popupAnchor || [0, 0];
7610
+ return this.options.icon.options.popupAnchor;
7465
7611
  },
7466
7612
 
7467
7613
  _getTooltipAnchor: function () {
7468
- return this.options.icon.options.tooltipAnchor || [0, 0];
7614
+ return this.options.icon.options.tooltipAnchor;
7469
7615
  }
7470
7616
  });
7471
7617
 
@@ -7616,7 +7762,7 @@ var Path = Layer.extend({
7616
7762
 
7617
7763
  _clickTolerance: function () {
7618
7764
  // used when doing hit detection for Canvas layers
7619
- return (this.options.stroke ? this.options.weight / 2 : 0) + (touch ? 10 : 0);
7765
+ return (this.options.stroke ? this.options.weight / 2 : 0) + this._renderer.options.tolerance;
7620
7766
  }
7621
7767
  });
7622
7768
 
@@ -7801,8 +7947,8 @@ var Circle = CircleMarker.extend({
7801
7947
  }
7802
7948
 
7803
7949
  this._point = p.subtract(map.getPixelOrigin());
7804
- this._radius = isNaN(lngR) ? 0 : Math.max(Math.round(p.x - map.project([lat2, lng - lngR]).x), 1);
7805
- this._radiusY = Math.max(Math.round(p.y - top.y), 1);
7950
+ this._radius = isNaN(lngR) ? 0 : p.x - map.project([lat2, lng - lngR]).x;
7951
+ this._radiusY = p.y - top.y;
7806
7952
 
7807
7953
  } else {
7808
7954
  var latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));
@@ -7904,6 +8050,8 @@ var Polyline = Path.extend({
7904
8050
  return !this._latlngs.length;
7905
8051
  },
7906
8052
 
8053
+ // @method closestLayerPoint: Point
8054
+ // Returns the point closest to `p` on the Polyline.
7907
8055
  closestLayerPoint: function (p) {
7908
8056
  var minDistance = Infinity,
7909
8057
  minPoint = null,
@@ -8544,8 +8692,8 @@ function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) {
8544
8692
 
8545
8693
  for (var i = 0, len = coords.length, latlng; i < len; i++) {
8546
8694
  latlng = levelsDeep ?
8547
- coordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng) :
8548
- (_coordsToLatLng || coordsToLatLng)(coords[i]);
8695
+ coordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng) :
8696
+ (_coordsToLatLng || coordsToLatLng)(coords[i]);
8549
8697
 
8550
8698
  latlngs.push(latlng);
8551
8699
  }
@@ -8558,8 +8706,8 @@ function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) {
8558
8706
  function latLngToCoords(latlng, precision) {
8559
8707
  precision = typeof precision === 'number' ? precision : 6;
8560
8708
  return latlng.alt !== undefined ?
8561
- [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision), formatNum(latlng.alt, precision)] :
8562
- [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision)];
8709
+ [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision), formatNum(latlng.alt, precision)] :
8710
+ [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision)];
8563
8711
  }
8564
8712
 
8565
8713
  // @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean): Array
@@ -8583,8 +8731,8 @@ function latLngsToCoords(latlngs, levelsDeep, closed, precision) {
8583
8731
 
8584
8732
  function getFeature(layer, newGeometry) {
8585
8733
  return layer.feature ?
8586
- extend({}, layer.feature, {geometry: newGeometry}) :
8587
- asFeature(newGeometry);
8734
+ extend({}, layer.feature, {geometry: newGeometry}) :
8735
+ asFeature(newGeometry);
8588
8736
  }
8589
8737
 
8590
8738
  // @function asFeature(geojson: Object): Object
@@ -8906,9 +9054,12 @@ var ImageOverlay = Layer.extend({
8906
9054
  },
8907
9055
 
8908
9056
  _initImage: function () {
8909
- var img = this._image = create$1('img',
8910
- 'leaflet-image-layer ' + (this._zoomAnimated ? 'leaflet-zoom-animated' : '') +
8911
- (this.options.className || ''));
9057
+ var wasElementSupplied = this._url.tagName === 'IMG';
9058
+ var img = this._image = wasElementSupplied ? this._url : create$1('img');
9059
+
9060
+ addClass(img, 'leaflet-image-layer');
9061
+ if (this._zoomAnimated) { addClass(img, 'leaflet-zoom-animated'); }
9062
+ if (this.options.className) { addClass(img, this.options.className); }
8912
9063
 
8913
9064
  img.onselectstart = falseFn;
8914
9065
  img.onmousemove = falseFn;
@@ -8926,6 +9077,11 @@ var ImageOverlay = Layer.extend({
8926
9077
  this._updateZIndex();
8927
9078
  }
8928
9079
 
9080
+ if (wasElementSupplied) {
9081
+ this._url = img.src;
9082
+ return;
9083
+ }
9084
+
8929
9085
  img.src = this._url;
8930
9086
  img.alt = this.options.alt;
8931
9087
  },
@@ -9017,8 +9173,8 @@ var VideoOverlay = ImageOverlay.extend({
9017
9173
  var wasElementSupplied = this._url.tagName === 'VIDEO';
9018
9174
  var vid = this._image = wasElementSupplied ? this._url : create$1('video');
9019
9175
 
9020
- vid.class = vid.class || '';
9021
- vid.class += 'leaflet-image-layer ' + (this._zoomAnimated ? 'leaflet-zoom-animated' : '');
9176
+ addClass(vid, 'leaflet-image-layer');
9177
+ if (this._zoomAnimated) { addClass(vid, 'leaflet-zoom-animated'); }
9022
9178
 
9023
9179
  vid.onselectstart = falseFn;
9024
9180
  vid.onmousemove = falseFn;
@@ -9027,7 +9183,16 @@ var VideoOverlay = ImageOverlay.extend({
9027
9183
  // Fired when the video has finished loading the first frame
9028
9184
  vid.onloadeddata = bind(this.fire, this, 'load');
9029
9185
 
9030
- if (wasElementSupplied) { return; }
9186
+ if (wasElementSupplied) {
9187
+ var sourceElements = vid.getElementsByTagName('source');
9188
+ var sources = [];
9189
+ for (var j = 0; j < sourceElements.length; j++) {
9190
+ sources.push(sourceElements[j].src);
9191
+ }
9192
+
9193
+ this._url = (sourceElements.length > 0) ? sources : [vid.src];
9194
+ return;
9195
+ }
9031
9196
 
9032
9197
  if (!isArray(this._url)) { this._url = [this._url]; }
9033
9198
 
@@ -9331,6 +9496,11 @@ var Popup = DivOverlay.extend({
9331
9496
  // the popup closing when another popup is opened.
9332
9497
  autoClose: true,
9333
9498
 
9499
+ // @option closeOnEscapeKey: Boolean = true
9500
+ // Set it to `false` if you want to override the default behavior of
9501
+ // the ESC key for closing of the popup.
9502
+ closeOnEscapeKey: true,
9503
+
9334
9504
  // @option closeOnClick: Boolean = *
9335
9505
  // Set it if you want to override the default behavior of the popup closing when user clicks
9336
9506
  // on the map. Defaults to the map's [`closePopupOnClick`](#map-closepopuponclick) option.
@@ -9654,7 +9824,7 @@ Layer.include({
9654
9824
  },
9655
9825
 
9656
9826
  // @method openPopup(latlng?: LatLng): this
9657
- // Opens the bound popup at the specificed `latlng` or at the default popup anchor if no `latlng` is passed.
9827
+ // Opens the bound popup at the specified `latlng` or at the default popup anchor if no `latlng` is passed.
9658
9828
  openPopup: function (layer, latlng) {
9659
9829
  if (!(layer instanceof Layer)) {
9660
9830
  latlng = layer;
@@ -9782,7 +9952,7 @@ Layer.include({
9782
9952
  * marker.bindTooltip("my tooltip text").openTooltip();
9783
9953
  * ```
9784
9954
  * Note about tooltip offset. Leaflet takes two options in consideration
9785
- * for computing tooltip offseting:
9955
+ * for computing tooltip offsetting:
9786
9956
  * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.
9787
9957
  * Add a positive x offset to move the tooltip to the right, and a positive y offset to
9788
9958
  * move it to the bottom. Negatives will move to the left and top.
@@ -9808,7 +9978,7 @@ var Tooltip = DivOverlay.extend({
9808
9978
  // @option direction: String = 'auto'
9809
9979
  // Direction where to open the tooltip. Possible values are: `right`, `left`,
9810
9980
  // `top`, `bottom`, `center`, `auto`.
9811
- // `auto` will dynamicaly switch between `right` and `left` according to the tooltip
9981
+ // `auto` will dynamically switch between `right` and `left` according to the tooltip
9812
9982
  // position on the map.
9813
9983
  direction: 'auto',
9814
9984
 
@@ -10072,7 +10242,7 @@ Layer.include({
10072
10242
  },
10073
10243
 
10074
10244
  // @method openTooltip(latlng?: LatLng): this
10075
- // Opens the bound tooltip at the specificed `latlng` or at the default tooltip anchor if no `latlng` is passed.
10245
+ // Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed.
10076
10246
  openTooltip: function (layer, latlng) {
10077
10247
  if (!(layer instanceof Layer)) {
10078
10248
  latlng = layer;
@@ -10412,7 +10582,7 @@ var GridLayer = Layer.extend({
10412
10582
  remove(this._container);
10413
10583
  map._removeZoomLimit(this);
10414
10584
  this._container = null;
10415
- this._tileZoom = null;
10585
+ this._tileZoom = undefined;
10416
10586
  },
10417
10587
 
10418
10588
  // @method bringToFront: this
@@ -10501,7 +10671,7 @@ var GridLayer = Layer.extend({
10501
10671
  // @section Extension methods
10502
10672
  // Layers extending `GridLayer` shall reimplement the following method.
10503
10673
  // @method createTile(coords: Object, done?: Function): HTMLElement
10504
- // Called only internally, must be overriden by classes extending `GridLayer`.
10674
+ // Called only internally, must be overridden by classes extending `GridLayer`.
10505
10675
  // Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback
10506
10676
  // is specified, it must be called when the tile has finished loading and drawing.
10507
10677
  createTile: function () {
@@ -10706,7 +10876,7 @@ var GridLayer = Layer.extend({
10706
10876
  }
10707
10877
  this._removeAllTiles();
10708
10878
 
10709
- this._tileZoom = null;
10879
+ this._tileZoom = undefined;
10710
10880
  },
10711
10881
 
10712
10882
  _retainParent: function (x, y, z, minZoom) {
@@ -10916,7 +11086,10 @@ var GridLayer = Layer.extend({
10916
11086
 
10917
11087
  if (!this._isValidTile(coords)) { continue; }
10918
11088
 
10919
- if (!this._tiles[this._tileCoordsToKey(coords)]) {
11089
+ var tile = this._tiles[this._tileCoordsToKey(coords)];
11090
+ if (tile) {
11091
+ tile.current = true;
11092
+ } else {
10920
11093
  queue.push(coords);
10921
11094
  }
10922
11095
  }
@@ -10968,26 +11141,26 @@ var GridLayer = Layer.extend({
10968
11141
  return this._tileCoordsToBounds(this._keyToTileCoords(key));
10969
11142
  },
10970
11143
 
10971
- // converts tile coordinates to its geographical bounds
10972
- _tileCoordsToBounds: function (coords) {
10973
-
11144
+ _tileCoordsToNwSe: function (coords) {
10974
11145
  var map = this._map,
10975
11146
  tileSize = this.getTileSize(),
10976
-
10977
11147
  nwPoint = coords.scaleBy(tileSize),
10978
11148
  sePoint = nwPoint.add(tileSize),
10979
-
10980
11149
  nw = map.unproject(nwPoint, coords.z),
10981
- se = map.unproject(sePoint, coords.z),
10982
- bounds = new LatLngBounds(nw, se);
11150
+ se = map.unproject(sePoint, coords.z);
11151
+ return [nw, se];
11152
+ },
11153
+
11154
+ // converts tile coordinates to its geographical bounds
11155
+ _tileCoordsToBounds: function (coords) {
11156
+ var bp = this._tileCoordsToNwSe(coords),
11157
+ bounds = new LatLngBounds(bp[0], bp[1]);
10983
11158
 
10984
11159
  if (!this.options.noWrap) {
10985
- map.wrapLatLngBounds(bounds);
11160
+ bounds = this._map.wrapLatLngBounds(bounds);
10986
11161
  }
10987
-
10988
11162
  return bounds;
10989
11163
  },
10990
-
10991
11164
  // converts tile coordinates to key for the tile cache
10992
11165
  _tileCoordsToKey: function (coords) {
10993
11166
  return coords.x + ':' + coords.y + ':' + coords.z;
@@ -11005,6 +11178,12 @@ var GridLayer = Layer.extend({
11005
11178
  var tile = this._tiles[key];
11006
11179
  if (!tile) { return; }
11007
11180
 
11181
+ // Cancels any pending http requests associated with the tile
11182
+ // unless we're on Android's stock browser,
11183
+ // see https://github.com/Leaflet/Leaflet/issues/137
11184
+ if (!androidStock) {
11185
+ tile.el.setAttribute('src', emptyImageUrl);
11186
+ }
11008
11187
  remove(tile.el);
11009
11188
 
11010
11189
  delete this._tiles[key];
@@ -11278,7 +11457,7 @@ var TileLayer = GridLayer.extend({
11278
11457
 
11279
11458
  // @method createTile(coords: Object, done?: Function): HTMLElement
11280
11459
  // Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)
11281
- // to return an `<img>` HTML element with the appropiate image URL given `coords`. The `done`
11460
+ // to return an `<img>` HTML element with the appropriate image URL given `coords`. The `done`
11282
11461
  // callback is called when the tile has been loaded.
11283
11462
  createTile: function (coords, done) {
11284
11463
  var tile = document.createElement('img');
@@ -11319,7 +11498,7 @@ var TileLayer = GridLayer.extend({
11319
11498
  s: this._getSubdomain(coords),
11320
11499
  x: coords.x,
11321
11500
  y: coords.y,
11322
- z: this._getZoomForUrl()
11501
+ z: coords.z ? coords.z : this._getZoomForUrl()
11323
11502
  };
11324
11503
  if (this._map && !this._map.options.crs.infinite) {
11325
11504
  var invertedY = this._globalTileRange.max.y - coords.y;
@@ -11343,7 +11522,7 @@ var TileLayer = GridLayer.extend({
11343
11522
 
11344
11523
  _tileOnError: function (done, tile, e) {
11345
11524
  var errorUrl = this.options.errorTileUrl;
11346
- if (errorUrl && tile.src !== errorUrl) {
11525
+ if (errorUrl && tile.getAttribute('src') !== errorUrl) {
11347
11526
  tile.src = errorUrl;
11348
11527
  }
11349
11528
  done(e, tile);
@@ -11384,6 +11563,7 @@ var TileLayer = GridLayer.extend({
11384
11563
  if (!tile.complete) {
11385
11564
  tile.src = emptyImageUrl;
11386
11565
  remove(tile);
11566
+ delete this._tiles[i];
11387
11567
  }
11388
11568
  }
11389
11569
  }
@@ -11474,7 +11654,10 @@ var TileLayerWMS = TileLayer.extend({
11474
11654
 
11475
11655
  options = setOptions(this, options);
11476
11656
 
11477
- wmsParams.width = wmsParams.height = options.tileSize * (options.detectRetina && retina ? 2 : 1);
11657
+ var realRetina = options.detectRetina && retina ? 2 : 1;
11658
+ var tileSize = this.getTileSize();
11659
+ wmsParams.width = tileSize.x * realRetina;
11660
+ wmsParams.height = tileSize.y * realRetina;
11478
11661
 
11479
11662
  this.wmsParams = wmsParams;
11480
11663
  },
@@ -11492,16 +11675,15 @@ var TileLayerWMS = TileLayer.extend({
11492
11675
 
11493
11676
  getTileUrl: function (coords) {
11494
11677
 
11495
- var tileBounds = this._tileCoordsToBounds(coords),
11496
- nw = this._crs.project(tileBounds.getNorthWest()),
11497
- se = this._crs.project(tileBounds.getSouthEast()),
11498
-
11678
+ var tileBounds = this._tileCoordsToNwSe(coords),
11679
+ crs = this._crs,
11680
+ bounds = toBounds(crs.project(tileBounds[0]), crs.project(tileBounds[1])),
11681
+ min = bounds.min,
11682
+ max = bounds.max,
11499
11683
  bbox = (this._wmsVersion >= 1.3 && this._crs === EPSG4326 ?
11500
- [se.y, nw.x, nw.y, se.x] :
11501
- [nw.x, se.y, se.x, nw.y]).join(','),
11502
-
11503
- url = TileLayer.prototype.getTileUrl.call(this, coords);
11504
-
11684
+ [min.y, min.x, max.y, max.x] :
11685
+ [min.x, min.y, max.x, max.y]).join(','),
11686
+ url = L.TileLayer.prototype.getTileUrl.call(this, coords);
11505
11687
  return url +
11506
11688
  getParamString(this.wmsParams, url, this.options.uppercase) +
11507
11689
  (this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;
@@ -11559,7 +11741,11 @@ var Renderer = Layer.extend({
11559
11741
  // @option padding: Number = 0.1
11560
11742
  // How much to extend the clip area around the map view (relative to its size)
11561
11743
  // e.g. 0.1 would be 10% of map view in each direction
11562
- padding: 0.1
11744
+ padding: 0.1,
11745
+
11746
+ // @option tolerance: Number = 0
11747
+ // How much to extend click tolerance round a path/object on the map
11748
+ tolerance : 0
11563
11749
  },
11564
11750
 
11565
11751
  initialize: function (options) {
@@ -11949,8 +12135,8 @@ var Canvas = Renderer.extend({
11949
12135
 
11950
12136
  var p = layer._point,
11951
12137
  ctx = this._ctx,
11952
- r = layer._radius,
11953
- s = (layer._radiusY || r) / r;
12138
+ r = Math.max(Math.round(layer._radius), 1),
12139
+ s = (Math.max(Math.round(layer._radiusY), 1) || r) / r;
11954
12140
 
11955
12141
  this._drawnLayers[layer._leaflet_id] = layer;
11956
12142
 
@@ -12071,7 +12257,7 @@ var Canvas = Renderer.extend({
12071
12257
  prev.next = next;
12072
12258
  } else if (next) {
12073
12259
  // Update first entry unless this is the
12074
- // signle entry
12260
+ // single entry
12075
12261
  this._drawFirst = next;
12076
12262
  }
12077
12263
 
@@ -12099,7 +12285,7 @@ var Canvas = Renderer.extend({
12099
12285
  next.prev = prev;
12100
12286
  } else if (prev) {
12101
12287
  // Update last entry unless this is the
12102
- // signle entry
12288
+ // single entry
12103
12289
  this._drawLast = prev;
12104
12290
  }
12105
12291
 
@@ -12243,7 +12429,7 @@ var vmlMixin = {
12243
12429
  r2 = Math.round(layer._radiusY || r);
12244
12430
 
12245
12431
  this._setPath(layer, layer._empty() ? 'M0 0' :
12246
- 'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360));
12432
+ 'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360));
12247
12433
  },
12248
12434
 
12249
12435
  _setPath: function (layer, path) {
@@ -12320,6 +12506,7 @@ var SVG = Renderer.extend({
12320
12506
  off(this._container);
12321
12507
  delete this._container;
12322
12508
  delete this._rootGroup;
12509
+ delete this._svgSize;
12323
12510
  },
12324
12511
 
12325
12512
  _onZoomStart: function () {
@@ -12432,15 +12619,15 @@ var SVG = Renderer.extend({
12432
12619
 
12433
12620
  _updateCircle: function (layer) {
12434
12621
  var p = layer._point,
12435
- r = layer._radius,
12436
- r2 = layer._radiusY || r,
12622
+ r = Math.max(Math.round(layer._radius), 1),
12623
+ r2 = Math.max(Math.round(layer._radiusY), 1) || r,
12437
12624
  arc = 'a' + r + ',' + r2 + ' 0 1,0 ';
12438
12625
 
12439
12626
  // drawing a circle with two half-arcs
12440
12627
  var d = layer._empty() ? 'M0 0' :
12441
- 'M' + (p.x - r) + ',' + p.y +
12442
- arc + (r * 2) + ',0 ' +
12443
- arc + (-r * 2) + ',0 ';
12628
+ 'M' + (p.x - r) + ',' + p.y +
12629
+ arc + (r * 2) + ',0 ' +
12630
+ arc + (-r * 2) + ',0 ';
12444
12631
 
12445
12632
  this._setPath(layer, d);
12446
12633
  },
@@ -12463,6 +12650,7 @@ if (vml) {
12463
12650
  SVG.include(vmlMixin);
12464
12651
  }
12465
12652
 
12653
+ // @namespace SVG
12466
12654
  // @factory L.svg(options?: Renderer options)
12467
12655
  // Creates a SVG renderer with the given options.
12468
12656
  function svg$1(options) {
@@ -12513,7 +12701,7 @@ Map.include({
12513
12701
 
12514
12702
  /*
12515
12703
  * @class Rectangle
12516
- * @aka L.Retangle
12704
+ * @aka L.Rectangle
12517
12705
  * @inherits Polygon
12518
12706
  *
12519
12707
  * A class for drawing rectangle overlays on a map. Extends `Polygon`.
@@ -12891,10 +13079,7 @@ var Drag = Handler.extend({
12891
13079
  this._positions.push(pos);
12892
13080
  this._times.push(time);
12893
13081
 
12894
- if (time - this._times[0] > 50) {
12895
- this._positions.shift();
12896
- this._times.shift();
12897
- }
13082
+ this._prunePositions(time);
12898
13083
  }
12899
13084
 
12900
13085
  this._map
@@ -12902,6 +13087,13 @@ var Drag = Handler.extend({
12902
13087
  .fire('drag', e);
12903
13088
  },
12904
13089
 
13090
+ _prunePositions: function (time) {
13091
+ while (this._positions.length > 1 && time - this._times[0] > 50) {
13092
+ this._positions.shift();
13093
+ this._times.shift();
13094
+ }
13095
+ },
13096
+
12905
13097
  _onZoomEnd: function () {
12906
13098
  var pxCenter = this._map.getSize().divideBy(2),
12907
13099
  pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);
@@ -12954,6 +13146,7 @@ var Drag = Handler.extend({
12954
13146
  map.fire('moveend');
12955
13147
 
12956
13148
  } else {
13149
+ this._prunePositions(+new Date());
12957
13150
 
12958
13151
  var direction = this._lastPos.subtract(this._positions[0]),
12959
13152
  duration = (this._lastTime - this._times[0]) / 1000,
@@ -13150,7 +13343,7 @@ var Keyboard = Handler.extend({
13150
13343
  } else if (key in this._zoomKeys) {
13151
13344
  map.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);
13152
13345
 
13153
- } else if (key === 27 && map._popup) {
13346
+ } else if (key === 27 && map._popup && map._popup.options.closeOnEscapeKey) {
13154
13347
  map.closePopup();
13155
13348
 
13156
13349
  } else {
@@ -13468,7 +13661,7 @@ var TouchZoom = Handler.extend({
13468
13661
  }
13469
13662
 
13470
13663
  if (!this._moved) {
13471
- map._moveStart(true);
13664
+ map._moveStart(true, false);
13472
13665
  this._moved = true;
13473
13666
  }
13474
13667