Changeset 108377 in spip-zone


Ignore:
Timestamp:
Jan 6, 2018, 8:14:45 PM (18 months ago)
Author:
brunobergot@…
Message:

version 4.44.10 ; leaflet 1.2.0 & maj des libs

Location:
_plugins_/gis/trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/gis/trunk/lib/leaflet/dist/leaflet-src.js

    r105025 r108377  
    1 /*
    2  Leaflet 1.0.3+ed36a04, a JS library for interactive maps. http://leafletjs.com
    3  (c) 2010-2016 Vladimir Agafonkin, (c) 2010-2011 CloudMade
    4 */
    5 (function (window, document, undefined) {
    6 var L = {
    7         version: "1.0.3+ed36a04"
    8 };
    9 
    10 function expose() {
    11         var oldL = window.L;
    12 
    13         L.noConflict = function () {
    14                 window.L = oldL;
    15                 return this;
    16         };
    17 
    18         window.L = L;
    19 }
    20 
    21 // define Leaflet for Node module pattern loaders, including Browserify
    22 if (typeof module === 'object' && typeof module.exports === 'object') {
    23         module.exports = L;
    24 
    25 // define Leaflet as an AMD module
    26 } else if (typeof define === 'function' && define.amd) {
    27         define(L);
    28 }
    29 
    30 // define Leaflet as a global L variable, saving the original L to restore later if needed
    31 if (typeof window !== 'undefined') {
    32         expose();
    33 }
    34 
    35 
     1/* @preserve
     2 * Leaflet 1.2.0+Detached: 1ac320ba232cb85b73ac81f3d82780c9d07f0d4e.1ac320b, a JS library for interactive maps. http://leafletjs.com
     3 * (c) 2010-2017 Vladimir Agafonkin, (c) 2010-2011 CloudMade
     4 */
     5(function (global, factory) {
     6        typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
     7        typeof define === 'function' && define.amd ? define(['exports'], factory) :
     8        (factory((global.L = {})));
     9}(this, (function (exports) { 'use strict';
     10
     11var version = "1.2.0+HEAD.1ac320b";
    3612
    3713/*
     
    4117 */
    4218
    43 L.Util = {
    44 
    45         // @function extend(dest: Object, src?: Object): Object
    46         // Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut.
    47         extend: function (dest) {
    48                 var i, j, len, src;
    49 
    50                 for (j = 1, len = arguments.length; j < len; j++) {
    51                         src = arguments[j];
    52                         for (i in src) {
    53                                 dest[i] = src[i];
    54                         }
    55                 }
    56                 return dest;
    57         },
    58 
    59         // @function create(proto: Object, properties?: Object): Object
    60         // Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create)
    61         create: Object.create || (function () {
    62                 function F() {}
    63                 return function (proto) {
    64                         F.prototype = proto;
    65                         return new F();
    66                 };
    67         })(),
    68 
    69         // @function bind(fn: Function, …): Function
    70         // Returns a new function bound to the arguments passed, like [Function.prototype.bind](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
    71         // Has a `L.bind()` shortcut.
    72         bind: function (fn, obj) {
    73                 var slice = Array.prototype.slice;
    74 
    75                 if (fn.bind) {
    76                         return fn.bind.apply(fn, slice.call(arguments, 1));
    77                 }
    78 
    79                 var args = slice.call(arguments, 2);
    80 
    81                 return function () {
    82                         return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);
    83                 };
    84         },
    85 
    86         // @function stamp(obj: Object): Number
    87         // Returns the unique ID of an object, assiging it one if it doesn't have it.
    88         stamp: function (obj) {
    89                 /*eslint-disable */
    90                 obj._leaflet_id = obj._leaflet_id || ++L.Util.lastId;
    91                 return obj._leaflet_id;
    92                 /*eslint-enable */
    93         },
    94 
    95         // @property lastId: Number
    96         // Last unique ID used by [`stamp()`](#util-stamp)
    97         lastId: 0,
    98 
    99         // @function throttle(fn: Function, time: Number, context: Object): Function
    100         // Returns a function which executes function `fn` with the given scope `context`
    101         // (so that the `this` keyword refers to `context` inside `fn`'s code). The function
    102         // `fn` will be called no more than one time per given amount of `time`. The arguments
    103         // received by the bound function will be any arguments passed when binding the
    104         // function, followed by any arguments passed when invoking the bound function.
    105         // Has an `L.bind` shortcut.
    106         throttle: function (fn, time, context) {
    107                 var lock, args, wrapperFn, later;
    108 
    109                 later = function () {
    110                         // reset lock and call if queued
    111                         lock = false;
    112                         if (args) {
    113                                 wrapperFn.apply(context, args);
    114                                 args = false;
    115                         }
    116                 };
    117 
    118                 wrapperFn = function () {
    119                         if (lock) {
    120                                 // called too soon, queue to call later
    121                                 args = arguments;
    122 
    123                         } else {
    124                                 // call and lock until later
    125                                 fn.apply(context, arguments);
    126                                 setTimeout(later, time);
    127                                 lock = true;
    128                         }
    129                 };
    130 
    131                 return wrapperFn;
    132         },
    133 
    134         // @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number
    135         // Returns the number `num` modulo `range` in such a way so it lies within
    136         // `range[0]` and `range[1]`. The returned value will be always smaller than
    137         // `range[1]` unless `includeMax` is set to `true`.
    138         wrapNum: function (x, range, includeMax) {
    139                 var max = range[1],
    140                     min = range[0],
    141                     d = max - min;
    142                 return x === max && includeMax ? x : ((x - min) % d + d) % d + min;
    143         },
    144 
    145         // @function falseFn(): Function
    146         // Returns a function which always returns `false`.
    147         falseFn: function () { return false; },
    148 
    149         // @function formatNum(num: Number, digits?: Number): Number
    150         // Returns the number `num` rounded to `digits` decimals, or to 5 decimals by default.
    151         formatNum: function (num, digits) {
    152                 var pow = Math.pow(10, digits || 5);
    153                 return Math.round(num * pow) / pow;
    154         },
    155 
    156         // @function trim(str: String): String
    157         // Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)
    158         trim: function (str) {
    159                 return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
    160         },
    161 
    162         // @function splitWords(str: String): String[]
    163         // Trims and splits the string on whitespace and returns the array of parts.
    164         splitWords: function (str) {
    165                 return L.Util.trim(str).split(/\s+/);
    166         },
    167 
    168         // @function setOptions(obj: Object, options: Object): Object
    169         // Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut.
    170         setOptions: function (obj, options) {
    171                 if (!obj.hasOwnProperty('options')) {
    172                         obj.options = obj.options ? L.Util.create(obj.options) : {};
    173                 }
    174                 for (var i in options) {
    175                         obj.options[i] = options[i];
    176                 }
    177                 return obj.options;
    178         },
    179 
    180         // @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String
    181         // Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}`
    182         // translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will
    183         // be appended at the end. If `uppercase` is `true`, the parameter names will
    184         // be uppercased (e.g. `'?A=foo&B=bar'`)
    185         getParamString: function (obj, existingUrl, uppercase) {
    186                 var params = [];
    187                 for (var i in obj) {
    188                         params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
    189                 }
    190                 return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
    191         },
    192 
    193         // @function template(str: String, data: Object): String
    194         // Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`
    195         // and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string
    196         // `('Hello foo, bar')`. You can also specify functions instead of strings for
    197         // data values — they will be evaluated passing `data` as an argument.
    198         template: function (str, data) {
    199                 return str.replace(L.Util.templateRe, function (str, key) {
    200                         var value = data[key];
    201 
    202                         if (value === undefined) {
    203                                 throw new Error('No value provided for variable ' + str);
    204 
    205                         } else if (typeof value === 'function') {
    206                                 value = value(data);
    207                         }
    208                         return value;
    209                 });
    210         },
    211 
    212         templateRe: /\{ *([\w_\-]+) *\}/g,
    213 
    214         // @function isArray(obj): Boolean
    215         // Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)
    216         isArray: Array.isArray || function (obj) {
    217                 return (Object.prototype.toString.call(obj) === '[object Array]');
    218         },
    219 
    220         // @function indexOf(array: Array, el: Object): Number
    221         // Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)
    222         indexOf: function (array, el) {
    223                 for (var i = 0; i < array.length; i++) {
    224                         if (array[i] === el) { return i; }
    225                 }
    226                 return -1;
    227         },
    228 
    229         // @property emptyImageUrl: String
    230         // Data URI string containing a base64-encoded empty GIF image.
    231         // Used as a hack to free memory from unused images on WebKit-powered
    232         // mobile devices (by setting image `src` to this string).
    233         emptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
    234 };
    235 
    236 (function () {
    237         // inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/
    238 
    239         function getPrefixed(name) {
    240                 return window['webkit' + name] || window['moz' + name] || window['ms' + name];
    241         }
    242 
    243         var lastTime = 0;
    244 
    245         // fallback for IE 7-8
    246         function timeoutDefer(fn) {
    247                 var time = +new Date(),
    248                     timeToCall = Math.max(0, 16 - (time - lastTime));
    249 
    250                 lastTime = time + timeToCall;
    251                 return window.setTimeout(fn, timeToCall);
    252         }
    253 
    254         var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer,
    255             cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') ||
    256                        getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); };
    257 
    258 
    259         // @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number
    260         // Schedules `fn` to be executed when the browser repaints. `fn` is bound to
    261         // `context` if given. When `immediate` is set, `fn` is called immediately if
    262         // the browser doesn't have native support for
    263         // [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame),
    264         // otherwise it's delayed. Returns a request ID that can be used to cancel the request.
    265         L.Util.requestAnimFrame = function (fn, context, immediate) {
    266                 if (immediate && requestFn === timeoutDefer) {
    267                         fn.call(context);
    268                 } else {
    269                         return requestFn.call(window, L.bind(fn, context));
    270                 }
    271         };
    272 
    273         // @function cancelAnimFrame(id: Number): undefined
    274         // Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame).
    275         L.Util.cancelAnimFrame = function (id) {
    276                 if (id) {
    277                         cancelFn.call(window, id);
    278                 }
     19var freeze = Object.freeze;
     20Object.freeze = function (obj) { return obj; };
     21
     22// @function extend(dest: Object, src?: Object): Object
     23// Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut.
     24function extend(dest) {
     25        var i, j, len, src;
     26
     27        for (j = 1, len = arguments.length; j < len; j++) {
     28                src = arguments[j];
     29                for (i in src) {
     30                        dest[i] = src[i];
     31                }
     32        }
     33        return dest;
     34}
     35
     36// @function create(proto: Object, properties?: Object): Object
     37// Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create)
     38var create = Object.create || (function () {
     39        function F() {}
     40        return function (proto) {
     41                F.prototype = proto;
     42                return new F();
    27943        };
    28044})();
    28145
    282 // shortcuts for most used utility functions
    283 L.extend = L.Util.extend;
    284 L.bind = L.Util.bind;
    285 L.stamp = L.Util.stamp;
    286 L.setOptions = L.Util.setOptions;
    287 
    288 
    289 
     46// @function bind(fn: Function, …): Function
     47// Returns a new function bound to the arguments passed, like [Function.prototype.bind](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
     48// Has a `L.bind()` shortcut.
     49function bind(fn, obj) {
     50        var slice = Array.prototype.slice;
     51
     52        if (fn.bind) {
     53                return fn.bind.apply(fn, slice.call(arguments, 1));
     54        }
     55
     56        var args = slice.call(arguments, 2);
     57
     58        return function () {
     59                return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);
     60        };
     61}
     62
     63// @property lastId: Number
     64// Last unique ID used by [`stamp()`](#util-stamp)
     65var lastId = 0;
     66
     67// @function stamp(obj: Object): Number
     68// Returns the unique ID of an object, assiging it one if it doesn't have it.
     69function stamp(obj) {
     70        /*eslint-disable */
     71        obj._leaflet_id = obj._leaflet_id || ++lastId;
     72        return obj._leaflet_id;
     73        /*eslint-enable */
     74}
     75
     76// @function throttle(fn: Function, time: Number, context: Object): Function
     77// Returns a function which executes function `fn` with the given scope `context`
     78// (so that the `this` keyword refers to `context` inside `fn`'s code). The function
     79// `fn` will be called no more than one time per given amount of `time`. The arguments
     80// received by the bound function will be any arguments passed when binding the
     81// function, followed by any arguments passed when invoking the bound function.
     82// Has an `L.throttle` shortcut.
     83function throttle(fn, time, context) {
     84        var lock, args, wrapperFn, later;
     85
     86        later = function () {
     87                // reset lock and call if queued
     88                lock = false;
     89                if (args) {
     90                        wrapperFn.apply(context, args);
     91                        args = false;
     92                }
     93        };
     94
     95        wrapperFn = function () {
     96                if (lock) {
     97                        // called too soon, queue to call later
     98                        args = arguments;
     99
     100                } else {
     101                        // call and lock until later
     102                        fn.apply(context, arguments);
     103                        setTimeout(later, time);
     104                        lock = true;
     105                }
     106        };
     107
     108        return wrapperFn;
     109}
     110
     111// @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number
     112// Returns the number `num` modulo `range` in such a way so it lies within
     113// `range[0]` and `range[1]`. The returned value will be always smaller than
     114// `range[1]` unless `includeMax` is set to `true`.
     115function wrapNum(x, range, includeMax) {
     116        var max = range[1],
     117            min = range[0],
     118            d = max - min;
     119        return x === max && includeMax ? x : ((x - min) % d + d) % d + min;
     120}
     121
     122// @function falseFn(): Function
     123// Returns a function which always returns `false`.
     124function falseFn() { return false; }
     125
     126// @function formatNum(num: Number, digits?: Number): Number
     127// Returns the number `num` rounded to `digits` decimals, or to 5 decimals by default.
     128function formatNum(num, digits) {
     129        var pow = Math.pow(10, digits || 5);
     130        return Math.round(num * pow) / pow;
     131}
     132
     133// @function trim(str: String): String
     134// Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)
     135function trim(str) {
     136        return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
     137}
     138
     139// @function splitWords(str: String): String[]
     140// Trims and splits the string on whitespace and returns the array of parts.
     141function splitWords(str) {
     142        return trim(str).split(/\s+/);
     143}
     144
     145// @function setOptions(obj: Object, options: Object): Object
     146// Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut.
     147function setOptions(obj, options) {
     148        if (!obj.hasOwnProperty('options')) {
     149                obj.options = obj.options ? create(obj.options) : {};
     150        }
     151        for (var i in options) {
     152                obj.options[i] = options[i];
     153        }
     154        return obj.options;
     155}
     156
     157// @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String
     158// Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}`
     159// translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will
     160// be appended at the end. If `uppercase` is `true`, the parameter names will
     161// be uppercased (e.g. `'?A=foo&B=bar'`)
     162function getParamString(obj, existingUrl, uppercase) {
     163        var params = [];
     164        for (var i in obj) {
     165                params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
     166        }
     167        return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
     168}
     169
     170var templateRe = /\{ *([\w_\-]+) *\}/g;
     171
     172// @function template(str: String, data: Object): String
     173// Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`
     174// and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string
     175// `('Hello foo, bar')`. You can also specify functions instead of strings for
     176// data values — they will be evaluated passing `data` as an argument.
     177function template(str, data) {
     178        return str.replace(templateRe, function (str, key) {
     179                var value = data[key];
     180
     181                if (value === undefined) {
     182                        throw new Error('No value provided for variable ' + str);
     183
     184                } else if (typeof value === 'function') {
     185                        value = value(data);
     186                }
     187                return value;
     188        });
     189}
     190
     191// @function isArray(obj): Boolean
     192// Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)
     193var isArray = Array.isArray || function (obj) {
     194        return (Object.prototype.toString.call(obj) === '[object Array]');
     195};
     196
     197// @function indexOf(array: Array, el: Object): Number
     198// Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)
     199function indexOf(array, el) {
     200        for (var i = 0; i < array.length; i++) {
     201                if (array[i] === el) { return i; }
     202        }
     203        return -1;
     204}
     205
     206// @property emptyImageUrl: String
     207// Data URI string containing a base64-encoded empty GIF image.
     208// Used as a hack to free memory from unused images on WebKit-powered
     209// mobile devices (by setting image `src` to this string).
     210var emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
     211
     212// inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/
     213
     214function getPrefixed(name) {
     215        return window['webkit' + name] || window['moz' + name] || window['ms' + name];
     216}
     217
     218var lastTime = 0;
     219
     220// fallback for IE 7-8
     221function timeoutDefer(fn) {
     222        var time = +new Date(),
     223            timeToCall = Math.max(0, 16 - (time - lastTime));
     224
     225        lastTime = time + timeToCall;
     226        return window.setTimeout(fn, timeToCall);
     227}
     228
     229var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer;
     230var cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') ||
     231                getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); };
     232
     233// @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number
     234// Schedules `fn` to be executed when the browser repaints. `fn` is bound to
     235// `context` if given. When `immediate` is set, `fn` is called immediately if
     236// the browser doesn't have native support for
     237// [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame),
     238// otherwise it's delayed. Returns a request ID that can be used to cancel the request.
     239function requestAnimFrame(fn, context, immediate) {
     240        if (immediate && requestFn === timeoutDefer) {
     241                fn.call(context);
     242        } else {
     243                return requestFn.call(window, bind(fn, context));
     244        }
     245}
     246
     247// @function cancelAnimFrame(id: Number): undefined
     248// Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame).
     249function cancelAnimFrame(id) {
     250        if (id) {
     251                cancelFn.call(window, id);
     252        }
     253}
     254
     255
     256var Util = (Object.freeze || Object)({
     257        freeze: freeze,
     258        extend: extend,
     259        create: create,
     260        bind: bind,
     261        lastId: lastId,
     262        stamp: stamp,
     263        throttle: throttle,
     264        wrapNum: wrapNum,
     265        falseFn: falseFn,
     266        formatNum: formatNum,
     267        trim: trim,
     268        splitWords: splitWords,
     269        setOptions: setOptions,
     270        getParamString: getParamString,
     271        template: template,
     272        isArray: isArray,
     273        indexOf: indexOf,
     274        emptyImageUrl: emptyImageUrl,
     275        requestFn: requestFn,
     276        cancelFn: cancelFn,
     277        requestAnimFrame: requestAnimFrame,
     278        cancelAnimFrame: cancelAnimFrame
     279});
    290280
    291281// @class Class
     
    297287// Thanks to John Resig and Dean Edwards for inspiration!
    298288
    299 L.Class = function () {};
    300 
    301 L.Class.extend = function (props) {
     289function Class() {}
     290
     291Class.extend = function (props) {
    302292
    303293        // @function extend(props: Object): Function
     
    317307        var parentProto = NewClass.__super__ = this.prototype;
    318308
    319         var proto = L.Util.create(parentProto);
     309        var proto = create(parentProto);
    320310        proto.constructor = NewClass;
    321311
     
    324314        // inherit parent's statics
    325315        for (var i in this) {
    326                 if (this.hasOwnProperty(i) && i !== 'prototype') {
     316                if (this.hasOwnProperty(i) && i !== 'prototype' && i !== '__super__') {
    327317                        NewClass[i] = this[i];
    328318                }
     
    331321        // mix static properties into the class
    332322        if (props.statics) {
    333                 L.extend(NewClass, props.statics);
     323                extend(NewClass, props.statics);
    334324                delete props.statics;
    335325        }
     
    337327        // mix includes into the prototype
    338328        if (props.includes) {
    339                 L.Util.extend.apply(null, [proto].concat(props.includes));
     329                checkDeprecatedMixinEvents(props.includes);
     330                extend.apply(null, [proto].concat(props.includes));
    340331                delete props.includes;
    341332        }
     
    343334        // merge options
    344335        if (proto.options) {
    345                 props.options = L.Util.extend(L.Util.create(proto.options), props.options);
     336                props.options = extend(create(proto.options), props.options);
    346337        }
    347338
    348339        // mix given properties into the prototype
    349         L.extend(proto, props);
     340        extend(proto, props);
    350341
    351342        proto._initHooks = [];
     
    373364// @function include(properties: Object): this
    374365// [Includes a mixin](#class-includes) into the current class.
    375 L.Class.include = function (props) {
    376         L.extend(this.prototype, props);
     366Class.include = function (props) {
     367        extend(this.prototype, props);
    377368        return this;
    378369};
     
    380371// @function mergeOptions(options: Object): this
    381372// [Merges `options`](#class-options) into the defaults of the class.
    382 L.Class.mergeOptions = function (options) {
    383         L.extend(this.prototype.options, options);
     373Class.mergeOptions = function (options) {
     374        extend(this.prototype.options, options);
    384375        return this;
    385376};
     
    387378// @function addInitHook(fn: Function): this
    388379// Adds a [constructor hook](#class-constructor-hooks) to the class.
    389 L.Class.addInitHook = function (fn) { // (Function) || (String, args...)
     380Class.addInitHook = function (fn) { // (Function) || (String, args...)
    390381        var args = Array.prototype.slice.call(arguments, 1);
    391382
     
    399390};
    400391
    401 
     392function checkDeprecatedMixinEvents(includes) {
     393        if (!L || !L.Mixin) { return; }
     394
     395        includes = isArray(includes) ? includes : [includes];
     396
     397        for (var i = 0; i < includes.length; i++) {
     398                if (includes[i] === L.Mixin.Events) {
     399                        console.warn('Deprecated include of L.Mixin.Events: ' +
     400                                'this property will be removed in future releases, ' +
     401                                'please inherit from L.Evented instead.', new Error().stack);
     402                }
     403        }
     404}
    402405
    403406/*
     
    426429 */
    427430
    428 
    429 L.Evented = L.Class.extend({
    430 
     431var Events = {
    431432        /* @method on(type: String, fn: Function, context?: Object): this
    432433         * Adds a listener function (`fn`) to a particular event type of the object. You can optionally specify the context of the listener (object the this keyword will point to). You can also pass several space-separated types (e.g. `'click dblclick'`).
     
    448449                } else {
    449450                        // types can be a string of space-separated words
    450                         types = L.Util.splitWords(types);
     451                        types = splitWords(types);
    451452
    452453                        for (var i = 0, len = types.length; i < len; i++) {
     
    481482
    482483                } else {
    483                         types = L.Util.splitWords(types);
     484                        types = splitWords(types);
    484485
    485486                        for (var i = 0, len = types.length; i < len; i++) {
     
    535536                        // Set all removed listeners to noop so they are not called if remove happens in fire
    536537                        for (i = 0, len = listeners.length; i < len; i++) {
    537                                 listeners[i].fn = L.Util.falseFn;
     538                                listeners[i].fn = falseFn;
    538539                        }
    539540                        // clear all listeners for a type if function isn't specified
     
    555556
    556557                                        // set the removed listener to noop so that's not called if remove happens in fire
    557                                         l.fn = L.Util.falseFn;
     558                                        l.fn = falseFn;
    558559
    559560                                        if (this._firingCount) {
     
    576577                if (!this.listens(type, propagate)) { return this; }
    577578
    578                 var event = L.Util.extend({}, data, {type: type, target: this});
     579                var event = extend({}, data, {type: type, target: this});
    579580
    580581                if (this._events) {
     
    626627                }
    627628
    628                 var handler = L.bind(function () {
     629                var handler = bind(function () {
    629630                        this
    630631                            .off(types, fn, context)
     
    642643        addEventParent: function (obj) {
    643644                this._eventParents = this._eventParents || {};
    644                 this._eventParents[L.stamp(obj)] = obj;
     645                this._eventParents[stamp(obj)] = obj;
    645646                return this;
    646647        },
     
    650651        removeEventParent: function (obj) {
    651652                if (this._eventParents) {
    652                         delete this._eventParents[L.stamp(obj)];
     653                        delete this._eventParents[stamp(obj)];
    653654                }
    654655                return this;
     
    657658        _propagateEvent: function (e) {
    658659                for (var id in this._eventParents) {
    659                         this._eventParents[id].fire(e.type, L.extend({layer: e.target}, e), true);
    660                 }
    661         }
    662 });
    663 
    664 var proto = L.Evented.prototype;
     660                        this._eventParents[id].fire(e.type, extend({layer: e.target}, e), true);
     661                }
     662        }
     663};
    665664
    666665// aliases; we should ditch those eventually
     
    668667// @method addEventListener(…): this
    669668// Alias to [`on(…)`](#evented-on)
    670 proto.addEventListener = proto.on;
     669Events.addEventListener = Events.on;
    671670
    672671// @method removeEventListener(…): this
     
    675674// @method clearAllEventListeners(…): this
    676675// Alias to [`off()`](#evented-off)
    677 proto.removeEventListener = proto.clearAllEventListeners = proto.off;
     676Events.removeEventListener = Events.clearAllEventListeners = Events.off;
    678677
    679678// @method addOneTimeEventListener(…): this
    680679// Alias to [`once(…)`](#evented-once)
    681 proto.addOneTimeEventListener = proto.once;
     680Events.addOneTimeEventListener = Events.once;
    682681
    683682// @method fireEvent(…): this
    684683// Alias to [`fire(…)`](#evented-fire)
    685 proto.fireEvent = proto.fire;
     684Events.fireEvent = Events.fire;
    686685
    687686// @method hasEventListeners(…): Boolean
    688687// Alias to [`listens(…)`](#evented-listens)
    689 proto.hasEventListeners = proto.listens;
    690 
    691 L.Mixin = {Events: proto};
    692 
    693 
    694 
    695 /*
    696  * @namespace Browser
    697  * @aka L.Browser
    698  *
    699  * A namespace with static properties for browser/feature detection used by Leaflet internally.
    700  *
    701  * @example
    702  *
    703  * ```js
    704  * if (L.Browser.ielt9) {
    705  *   alert('Upgrade your browser, dude!');
    706  * }
    707  * ```
    708  */
    709 
    710 (function () {
    711 
    712         var ua = navigator.userAgent.toLowerCase(),
    713             doc = document.documentElement,
    714 
    715             ie = 'ActiveXObject' in window,
    716 
    717             webkit    = ua.indexOf('webkit') !== -1,
    718             phantomjs = ua.indexOf('phantom') !== -1,
    719             android23 = ua.search('android [23]') !== -1,
    720             chrome    = ua.indexOf('chrome') !== -1,
    721             gecko     = ua.indexOf('gecko') !== -1  && !webkit && !window.opera && !ie,
    722 
    723             win = navigator.platform.indexOf('Win') === 0,
    724 
    725             mobile = typeof orientation !== 'undefined' || ua.indexOf('mobile') !== -1,
    726             msPointer = !window.PointerEvent && window.MSPointerEvent,
    727             pointer = window.PointerEvent || msPointer,
    728 
    729             ie3d = ie && ('transition' in doc.style),
    730             webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23,
    731             gecko3d = 'MozPerspective' in doc.style,
    732             opera12 = 'OTransition' in doc.style;
    733 
    734 
    735         var touch = !window.L_NO_TOUCH && (pointer || 'ontouchstart' in window ||
    736                         (window.DocumentTouch && document instanceof window.DocumentTouch));
    737 
    738         L.Browser = {
    739 
    740                 // @property ie: Boolean
    741                 // `true` for all Internet Explorer versions (not Edge).
    742                 ie: ie,
    743 
    744                 // @property ielt9: Boolean
    745                 // `true` for Internet Explorer versions less than 9.
    746                 ielt9: ie && !document.addEventListener,
    747 
    748                 // @property edge: Boolean
    749                 // `true` for the Edge web browser.
    750                 edge: 'msLaunchUri' in navigator && !('documentMode' in document),
    751 
    752                 // @property webkit: Boolean
    753                 // `true` for webkit-based browsers like Chrome and Safari (including mobile versions).
    754                 webkit: webkit,
    755 
    756                 // @property gecko: Boolean
    757                 // `true` for gecko-based browsers like Firefox.
    758                 gecko: gecko,
    759 
    760                 // @property android: Boolean
    761                 // `true` for any browser running on an Android platform.
    762                 android: ua.indexOf('android') !== -1,
    763 
    764                 // @property android23: Boolean
    765                 // `true` for browsers running on Android 2 or Android 3.
    766                 android23: android23,
    767 
    768                 // @property chrome: Boolean
    769                 // `true` for the Chrome browser.
    770                 chrome: chrome,
    771 
    772                 // @property safari: Boolean
    773                 // `true` for the Safari browser.
    774                 safari: !chrome && ua.indexOf('safari') !== -1,
    775 
    776 
    777                 // @property win: Boolean
    778                 // `true` when the browser is running in a Windows platform
    779                 win: win,
    780 
    781 
    782                 // @property ie3d: Boolean
    783                 // `true` for all Internet Explorer versions supporting CSS transforms.
    784                 ie3d: ie3d,
    785 
    786                 // @property webkit3d: Boolean
    787                 // `true` for webkit-based browsers supporting CSS transforms.
    788                 webkit3d: webkit3d,
    789 
    790                 // @property gecko3d: Boolean
    791                 // `true` for gecko-based browsers supporting CSS transforms.
    792                 gecko3d: gecko3d,
    793 
    794                 // @property opera12: Boolean
    795                 // `true` for the Opera browser supporting CSS transforms (version 12 or later).
    796                 opera12: opera12,
    797 
    798                 // @property any3d: Boolean
    799                 // `true` for all browsers supporting CSS transforms.
    800                 any3d: !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantomjs,
    801 
    802 
    803                 // @property mobile: Boolean
    804                 // `true` for all browsers running in a mobile device.
    805                 mobile: mobile,
    806 
    807                 // @property mobileWebkit: Boolean
    808                 // `true` for all webkit-based browsers in a mobile device.
    809                 mobileWebkit: mobile && webkit,
    810 
    811                 // @property mobileWebkit3d: Boolean
    812                 // `true` for all webkit-based browsers in a mobile device supporting CSS transforms.
    813                 mobileWebkit3d: mobile && webkit3d,
    814 
    815                 // @property mobileOpera: Boolean
    816                 // `true` for the Opera browser in a mobile device.
    817                 mobileOpera: mobile && window.opera,
    818 
    819                 // @property mobileGecko: Boolean
    820                 // `true` for gecko-based browsers running in a mobile device.
    821                 mobileGecko: mobile && gecko,
    822 
    823 
    824                 // @property touch: Boolean
    825                 // `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).
    826                 // This does not necessarily mean that the browser is running in a computer with
    827                 // a touchscreen, it only means that the browser is capable of understanding
    828                 // touch events.
    829                 touch: !!touch,
    830 
    831                 // @property msPointer: Boolean
    832                 // `true` for browsers implementing the Microsoft touch events model (notably IE10).
    833                 msPointer: !!msPointer,
    834 
    835                 // @property pointer: Boolean
    836                 // `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx).
    837                 pointer: !!pointer,
    838 
    839 
    840                 // @property retina: Boolean
    841                 // `true` for browsers on a high-resolution "retina" screen.
    842                 retina: (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1
    843         };
    844 
    845 }());
    846 
    847 
     688Events.hasEventListeners = Events.listens;
     689
     690var Evented = Class.extend(Events);
    848691
    849692/*
     
    867710 */
    868711
    869 L.Point = function (x, y, round) {
     712function Point(x, y, round) {
    870713        // @property x: Number; The `x` coordinate of the point
    871714        this.x = (round ? Math.round(x) : x);
    872715        // @property y: Number; The `y` coordinate of the point
    873716        this.y = (round ? Math.round(y) : y);
    874 };
    875 
    876 L.Point.prototype = {
     717}
     718
     719Point.prototype = {
    877720
    878721        // @method clone(): Point
    879722        // Returns a copy of the current point.
    880723        clone: function () {
    881                 return new L.Point(this.x, this.y);
     724                return new Point(this.x, this.y);
    882725        },
    883726
     
    886729        add: function (point) {
    887730                // non-destructive, returns a new point
    888                 return this.clone()._add(L.point(point));
     731                return this.clone()._add(toPoint(point));
    889732        },
    890733
     
    899742        // Returns the result of subtraction of the given point from the current.
    900743        subtract: function (point) {
    901                 return this.clone()._subtract(L.point(point));
     744                return this.clone()._subtract(toPoint(point));
    902745        },
    903746
     
    938781        // defined by `scale`.
    939782        scaleBy: function (point) {
    940                 return new L.Point(this.x * point.x, this.y * point.y);
     783                return new Point(this.x * point.x, this.y * point.y);
    941784        },
    942785
     
    945788        // each coordinate of `scale`.
    946789        unscaleBy: function (point) {
    947                 return new L.Point(this.x / point.x, this.y / point.y);
     790                return new Point(this.x / point.x, this.y / point.y);
    948791        },
    949792
     
    987830        // Returns the cartesian distance between the current and the given points.
    988831        distanceTo: function (point) {
    989                 point = L.point(point);
     832                point = toPoint(point);
    990833
    991834                var x = point.x - this.x,
     
    998841        // Returns `true` if the given point has the same coordinates.
    999842        equals: function (point) {
    1000                 point = L.point(point);
     843                point = toPoint(point);
    1001844
    1002845                return point.x === this.x &&
     
    1007850        // Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values).
    1008851        contains: function (point) {
    1009                 point = L.point(point);
     852                point = toPoint(point);
    1010853
    1011854                return Math.abs(point.x) <= Math.abs(this.x) &&
     
    1017860        toString: function () {
    1018861                return 'Point(' +
    1019                         L.Util.formatNum(this.x) + ', ' +
    1020                         L.Util.formatNum(this.y) + ')';
     862                        formatNum(this.x) + ', ' +
     863                        formatNum(this.y) + ')';
    1021864        }
    1022865};
     
    1032875// @factory L.point(coords: Object)
    1033876// Expects a plain object of the form `{x: Number, y: Number}` instead.
    1034 L.point = function (x, y, round) {
    1035         if (x instanceof L.Point) {
     877function toPoint(x, y, round) {
     878        if (x instanceof Point) {
    1036879                return x;
    1037880        }
    1038         if (L.Util.isArray(x)) {
    1039                 return new L.Point(x[0], x[1]);
     881        if (isArray(x)) {
     882                return new Point(x[0], x[1]);
    1040883        }
    1041884        if (x === undefined || x === null) {
     
    1043886        }
    1044887        if (typeof x === 'object' && 'x' in x && 'y' in x) {
    1045                 return new L.Point(x.x, x.y);
    1046         }
    1047         return new L.Point(x, y, round);
    1048 };
    1049 
    1050 
     888                return new Point(x.x, x.y);
     889        }
     890        return new Point(x, y, round);
     891}
    1051892
    1052893/*
     
    1071912 */
    1072913
    1073 L.Bounds = function (a, b) {
     914function Bounds(a, b) {
    1074915        if (!a) { return; }
    1075916
     
    1079920                this.extend(points[i]);
    1080921        }
    1081 };
    1082 
    1083 L.Bounds.prototype = {
     922}
     923
     924Bounds.prototype = {
    1084925        // @method extend(point: Point): this
    1085926        // Extends the bounds to contain the given point.
    1086927        extend: function (point) { // (Point)
    1087                 point = L.point(point);
     928                point = toPoint(point);
    1088929
    1089930                // @property min: Point
     
    1106947        // Returns the center point of the bounds.
    1107948        getCenter: function (round) {
    1108                 return new L.Point(
     949                return new Point(
    1109950                        (this.min.x + this.max.x) / 2,
    1110951                        (this.min.y + this.max.y) / 2, round);
     
    1114955        // Returns the bottom-left point of the bounds.
    1115956        getBottomLeft: function () {
    1116                 return new L.Point(this.min.x, this.max.y);
     957                return new Point(this.min.x, this.max.y);
    1117958        },
    1118959
     
    1120961        // Returns the top-right point of the bounds.
    1121962        getTopRight: function () { // -> Point
    1122                 return new L.Point(this.max.x, this.min.y);
     963                return new Point(this.max.x, this.min.y);
     964        },
     965
     966        // @method getTopLeft(): Point
     967        // Returns the top-left point of the bounds (i.e. [`this.min`](#bounds-min)).
     968        getTopLeft: function () {
     969                return this.min; // left, top
     970        },
     971
     972        // @method getBottomRight(): Point
     973        // Returns the bottom-right point of the bounds (i.e. [`this.max`](#bounds-max)).
     974        getBottomRight: function () {
     975                return this.max; // right, bottom
    1123976        },
    1124977
     
    1137990                var min, max;
    1138991
    1139                 if (typeof obj[0] === 'number' || obj instanceof L.Point) {
    1140                         obj = L.point(obj);
     992                if (typeof obj[0] === 'number' || obj instanceof Point) {
     993                        obj = toPoint(obj);
    1141994                } else {
    1142                         obj = L.bounds(obj);
    1143                 }
    1144 
    1145                 if (obj instanceof L.Bounds) {
     995                        obj = toBounds(obj);
     996                }
     997
     998                if (obj instanceof Bounds) {
    1146999                        min = obj.min;
    11471000                        max = obj.max;
     
    11601013        // intersect if they have at least one point in common.
    11611014        intersects: function (bounds) { // (Bounds) -> Boolean
    1162                 bounds = L.bounds(bounds);
     1015                bounds = toBounds(bounds);
    11631016
    11641017                var min = this.min,
     
    11761029        // overlap if their intersection is an area.
    11771030        overlaps: function (bounds) { // (Bounds) -> Boolean
    1178                 bounds = L.bounds(bounds);
     1031                bounds = toBounds(bounds);
    11791032
    11801033                var min = this.min,
     
    11941047
    11951048
    1196 // @factory L.bounds(topLeft: Point, bottomRight: Point)
    1197 // Creates a Bounds object from two coordinates (usually top-left and bottom-right corners).
     1049// @factory L.bounds(corner1: Point, corner2: Point)
     1050// Creates a Bounds object from two corners coordinate pairs.
    11981051// @alternative
    11991052// @factory L.bounds(points: Point[])
    1200 // Creates a Bounds object from the points it contains
    1201 L.bounds = function (a, b) {
    1202         if (!a || a instanceof L.Bounds) {
     1053// Creates a Bounds object from the given array of points.
     1054function toBounds(a, b) {
     1055        if (!a || a instanceof Bounds) {
    12031056                return a;
    12041057        }
    1205         return new L.Bounds(a, b);
     1058        return new Bounds(a, b);
     1059}
     1060
     1061/*
     1062 * @class LatLngBounds
     1063 * @aka L.LatLngBounds
     1064 *
     1065 * Represents a rectangular geographical area on a map.
     1066 *
     1067 * @example
     1068 *
     1069 * ```js
     1070 * var corner1 = L.latLng(40.712, -74.227),
     1071 * corner2 = L.latLng(40.774, -74.125),
     1072 * bounds = L.latLngBounds(corner1, corner2);
     1073 * ```
     1074 *
     1075 * All Leaflet methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:
     1076 *
     1077 * ```js
     1078 * map.fitBounds([
     1079 *      [40.712, -74.227],
     1080 *      [40.774, -74.125]
     1081 * ]);
     1082 * ```
     1083 *
     1084 * 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.
     1085 */
     1086
     1087function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[])
     1088        if (!corner1) { return; }
     1089
     1090        var latlngs = corner2 ? [corner1, corner2] : corner1;
     1091
     1092        for (var i = 0, len = latlngs.length; i < len; i++) {
     1093                this.extend(latlngs[i]);
     1094        }
     1095}
     1096
     1097LatLngBounds.prototype = {
     1098
     1099        // @method extend(latlng: LatLng): this
     1100        // Extend the bounds to contain the given point
     1101
     1102        // @alternative
     1103        // @method extend(otherBounds: LatLngBounds): this
     1104        // Extend the bounds to contain the given bounds
     1105        extend: function (obj) {
     1106                var sw = this._southWest,
     1107                    ne = this._northEast,
     1108                    sw2, ne2;
     1109
     1110                if (obj instanceof LatLng) {
     1111                        sw2 = obj;
     1112                        ne2 = obj;
     1113
     1114                } else if (obj instanceof LatLngBounds) {
     1115                        sw2 = obj._southWest;
     1116                        ne2 = obj._northEast;
     1117
     1118                        if (!sw2 || !ne2) { return this; }
     1119
     1120                } else {
     1121                        return obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this;
     1122                }
     1123
     1124                if (!sw && !ne) {
     1125                        this._southWest = new LatLng(sw2.lat, sw2.lng);
     1126                        this._northEast = new LatLng(ne2.lat, ne2.lng);
     1127                } else {
     1128                        sw.lat = Math.min(sw2.lat, sw.lat);
     1129                        sw.lng = Math.min(sw2.lng, sw.lng);
     1130                        ne.lat = Math.max(ne2.lat, ne.lat);
     1131                        ne.lng = Math.max(ne2.lng, ne.lng);
     1132                }
     1133
     1134                return this;
     1135        },
     1136
     1137        // @method pad(bufferRatio: Number): LatLngBounds
     1138        // Returns bigger bounds created by extending the current bounds by a given percentage in each direction.
     1139        pad: function (bufferRatio) {
     1140                var sw = this._southWest,
     1141                    ne = this._northEast,
     1142                    heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
     1143                    widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
     1144
     1145                return new LatLngBounds(
     1146                        new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
     1147                        new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));
     1148        },
     1149
     1150        // @method getCenter(): LatLng
     1151        // Returns the center point of the bounds.
     1152        getCenter: function () {
     1153                return new LatLng(
     1154                        (this._southWest.lat + this._northEast.lat) / 2,
     1155                        (this._southWest.lng + this._northEast.lng) / 2);
     1156        },
     1157
     1158        // @method getSouthWest(): LatLng
     1159        // Returns the south-west point of the bounds.
     1160        getSouthWest: function () {
     1161                return this._southWest;
     1162        },
     1163
     1164        // @method getNorthEast(): LatLng
     1165        // Returns the north-east point of the bounds.
     1166        getNorthEast: function () {
     1167                return this._northEast;
     1168        },
     1169
     1170        // @method getNorthWest(): LatLng
     1171        // Returns the north-west point of the bounds.
     1172        getNorthWest: function () {
     1173                return new LatLng(this.getNorth(), this.getWest());
     1174        },
     1175
     1176        // @method getSouthEast(): LatLng
     1177        // Returns the south-east point of the bounds.
     1178        getSouthEast: function () {
     1179                return new LatLng(this.getSouth(), this.getEast());
     1180        },
     1181
     1182        // @method getWest(): Number
     1183        // Returns the west longitude of the bounds
     1184        getWest: function () {
     1185                return this._southWest.lng;
     1186        },
     1187
     1188        // @method getSouth(): Number
     1189        // Returns the south latitude of the bounds
     1190        getSouth: function () {
     1191                return this._southWest.lat;
     1192        },
     1193
     1194        // @method getEast(): Number
     1195        // Returns the east longitude of the bounds
     1196        getEast: function () {
     1197                return this._northEast.lng;
     1198        },
     1199
     1200        // @method getNorth(): Number
     1201        // Returns the north latitude of the bounds
     1202        getNorth: function () {
     1203                return this._northEast.lat;
     1204        },
     1205
     1206        // @method contains(otherBounds: LatLngBounds): Boolean
     1207        // Returns `true` if the rectangle contains the given one.
     1208
     1209        // @alternative
     1210        // @method contains (latlng: LatLng): Boolean
     1211        // Returns `true` if the rectangle contains the given point.
     1212        contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean
     1213                if (typeof obj[0] === 'number' || obj instanceof LatLng || 'lat' in obj) {
     1214                        obj = toLatLng(obj);
     1215                } else {
     1216                        obj = toLatLngBounds(obj);
     1217                }
     1218
     1219                var sw = this._southWest,
     1220                    ne = this._northEast,
     1221                    sw2, ne2;
     1222
     1223                if (obj instanceof LatLngBounds) {
     1224                        sw2 = obj.getSouthWest();
     1225                        ne2 = obj.getNorthEast();
     1226                } else {
     1227                        sw2 = ne2 = obj;
     1228                }
     1229
     1230                return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&
     1231                       (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);
     1232        },
     1233
     1234        // @method intersects(otherBounds: LatLngBounds): Boolean
     1235        // Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.
     1236        intersects: function (bounds) {
     1237                bounds = toLatLngBounds(bounds);
     1238
     1239                var sw = this._southWest,
     1240                    ne = this._northEast,
     1241                    sw2 = bounds.getSouthWest(),
     1242                    ne2 = bounds.getNorthEast(),
     1243
     1244                    latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),
     1245                    lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);
     1246
     1247                return latIntersects && lngIntersects;
     1248        },
     1249
     1250        // @method overlaps(otherBounds: Bounds): Boolean
     1251        // Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.
     1252        overlaps: function (bounds) {
     1253                bounds = toLatLngBounds(bounds);
     1254
     1255                var sw = this._southWest,
     1256                    ne = this._northEast,
     1257                    sw2 = bounds.getSouthWest(),
     1258                    ne2 = bounds.getNorthEast(),
     1259
     1260                    latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat),
     1261                    lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng);
     1262
     1263                return latOverlaps && lngOverlaps;
     1264        },
     1265
     1266        // @method toBBoxString(): String
     1267        // Returns a string with bounding box coordinates in a 'southwest_lng,southwest_lat,northeast_lng,northeast_lat' format. Useful for sending requests to web services that return geo data.
     1268        toBBoxString: function () {
     1269                return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');
     1270        },
     1271
     1272        // @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.
     1274        equals: function (bounds, maxMargin) {
     1275                if (!bounds) { return false; }
     1276
     1277                bounds = toLatLngBounds(bounds);
     1278
     1279                return this._southWest.equals(bounds.getSouthWest(), maxMargin) &&
     1280                       this._northEast.equals(bounds.getNorthEast(), maxMargin);
     1281        },
     1282
     1283        // @method isValid(): Boolean
     1284        // Returns `true` if the bounds are properly initialized.
     1285        isValid: function () {
     1286                return !!(this._southWest && this._northEast);
     1287        }
    12061288};
    12071289
    1208 
    1209 
    1210 /*
    1211  * @class Transformation
    1212  * @aka L.Transformation
    1213  *
    1214  * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d`
    1215  * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing
    1216  * the reverse. Used by Leaflet in its projections code.
    1217  *
    1218  * @example
    1219  *
    1220  * ```js
    1221  * var transformation = new L.Transformation(2, 5, -1, 10),
    1222  *      p = L.point(1, 2),
    1223  *      p2 = transformation.transform(p), //  L.point(7, 8)
    1224  *      p3 = transformation.untransform(p2); //  L.point(1, 2)
    1225  * ```
    1226  */
    1227 
    1228 
    1229 // factory new L.Transformation(a: Number, b: Number, c: Number, d: Number)
    1230 // Creates a `Transformation` object with the given coefficients.
    1231 L.Transformation = function (a, b, c, d) {
    1232         this._a = a;
    1233         this._b = b;
    1234         this._c = c;
    1235         this._d = d;
    1236 };
    1237 
    1238 L.Transformation.prototype = {
    1239         // @method transform(point: Point, scale?: Number): Point
    1240         // Returns a transformed point, optionally multiplied by the given scale.
    1241         // Only accepts actual `L.Point` instances, not arrays.
    1242         transform: function (point, scale) { // (Point, Number) -> Point
    1243                 return this._transform(point.clone(), scale);
    1244         },
    1245 
    1246         // destructive transform (faster)
    1247         _transform: function (point, scale) {
    1248                 scale = scale || 1;
    1249                 point.x = scale * (this._a * point.x + this._b);
    1250                 point.y = scale * (this._c * point.y + this._d);
    1251                 return point;
    1252         },
    1253 
    1254         // @method untransform(point: Point, scale?: Number): Point
    1255         // Returns the reverse transformation of the given point, optionally divided
    1256         // by the given scale. Only accepts actual `L.Point` instances, not arrays.
    1257         untransform: function (point, scale) {
    1258                 scale = scale || 1;
    1259                 return new L.Point(
    1260                         (point.x / scale - this._b) / this._a,
    1261                         (point.y / scale - this._d) / this._c);
    1262         }
    1263 };
    1264 
    1265 
    1266 
    1267 /*
    1268  * @namespace DomUtil
    1269  *
    1270  * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)
    1271  * tree, used by Leaflet internally.
    1272  *
    1273  * Most functions expecting or returning a `HTMLElement` also work for
    1274  * SVG elements. The only difference is that classes refer to CSS classes
    1275  * in HTML and SVG classes in SVG.
    1276  */
    1277 
    1278 L.DomUtil = {
    1279 
    1280         // @function get(id: String|HTMLElement): HTMLElement
    1281         // Returns an element given its DOM id, or returns the element itself
    1282         // if it was passed directly.
    1283         get: function (id) {
    1284                 return typeof id === 'string' ? document.getElementById(id) : id;
    1285         },
    1286 
    1287         // @function getStyle(el: HTMLElement, styleAttrib: String): String
    1288         // Returns the value for a certain style attribute on an element,
    1289         // including computed values or values set through CSS.
    1290         getStyle: function (el, style) {
    1291 
    1292                 var value = el.style[style] || (el.currentStyle && el.currentStyle[style]);
    1293 
    1294                 if ((!value || value === 'auto') && document.defaultView) {
    1295                         var css = document.defaultView.getComputedStyle(el, null);
    1296                         value = css ? css[style] : null;
    1297                 }
    1298 
    1299                 return value === 'auto' ? null : value;
    1300         },
    1301 
    1302         // @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement
    1303         // Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element.
    1304         create: function (tagName, className, container) {
    1305 
    1306                 var el = document.createElement(tagName);
    1307                 el.className = className || '';
    1308 
    1309                 if (container) {
    1310                         container.appendChild(el);
    1311                 }
    1312 
    1313                 return el;
    1314         },
    1315 
    1316         // @function remove(el: HTMLElement)
    1317         // Removes `el` from its parent element
    1318         remove: function (el) {
    1319                 var parent = el.parentNode;
    1320                 if (parent) {
    1321                         parent.removeChild(el);
    1322                 }
    1323         },
    1324 
    1325         // @function empty(el: HTMLElement)
    1326         // Removes all of `el`'s children elements from `el`
    1327         empty: function (el) {
    1328                 while (el.firstChild) {
    1329                         el.removeChild(el.firstChild);
    1330                 }
    1331         },
    1332 
    1333         // @function toFront(el: HTMLElement)
    1334         // Makes `el` the last children of its parent, so it renders in front of the other children.
    1335         toFront: function (el) {
    1336                 el.parentNode.appendChild(el);
    1337         },
    1338 
    1339         // @function toBack(el: HTMLElement)
    1340         // Makes `el` the first children of its parent, so it renders back from the other children.
    1341         toBack: function (el) {
    1342                 var parent = el.parentNode;
    1343                 parent.insertBefore(el, parent.firstChild);
    1344         },
    1345 
    1346         // @function hasClass(el: HTMLElement, name: String): Boolean
    1347         // Returns `true` if the element's class attribute contains `name`.
    1348         hasClass: function (el, name) {
    1349                 if (el.classList !== undefined) {
    1350                         return el.classList.contains(name);
    1351                 }
    1352                 var className = L.DomUtil.getClass(el);
    1353                 return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className);
    1354         },
    1355 
    1356         // @function addClass(el: HTMLElement, name: String)
    1357         // Adds `name` to the element's class attribute.
    1358         addClass: function (el, name) {
    1359                 if (el.classList !== undefined) {
    1360                         var classes = L.Util.splitWords(name);
    1361                         for (var i = 0, len = classes.length; i < len; i++) {
    1362                                 el.classList.add(classes[i]);
    1363                         }
    1364                 } else if (!L.DomUtil.hasClass(el, name)) {
    1365                         var className = L.DomUtil.getClass(el);
    1366                         L.DomUtil.setClass(el, (className ? className + ' ' : '') + name);
    1367                 }
    1368         },
    1369 
    1370         // @function removeClass(el: HTMLElement, name: String)
    1371         // Removes `name` from the element's class attribute.
    1372         removeClass: function (el, name) {
    1373                 if (el.classList !== undefined) {
    1374                         el.classList.remove(name);
    1375                 } else {
    1376                         L.DomUtil.setClass(el, L.Util.trim((' ' + L.DomUtil.getClass(el) + ' ').replace(' ' + name + ' ', ' ')));
    1377                 }
    1378         },
    1379 
    1380         // @function setClass(el: HTMLElement, name: String)
    1381         // Sets the element's class.
    1382         setClass: function (el, name) {
    1383                 if (el.className.baseVal === undefined) {
    1384                         el.className = name;
    1385                 } else {
    1386                         // in case of SVG element
    1387                         el.className.baseVal = name;
    1388                 }
    1389         },
    1390 
    1391         // @function getClass(el: HTMLElement): String
    1392         // Returns the element's class.
    1393         getClass: function (el) {
    1394                 return el.className.baseVal === undefined ? el.className : el.className.baseVal;
    1395         },
    1396 
    1397         // @function setOpacity(el: HTMLElement, opacity: Number)
    1398         // Set the opacity of an element (including old IE support).
    1399         // `opacity` must be a number from `0` to `1`.
    1400         setOpacity: function (el, value) {
    1401 
    1402                 if ('opacity' in el.style) {
    1403                         el.style.opacity = value;
    1404 
    1405                 } else if ('filter' in el.style) {
    1406                         L.DomUtil._setOpacityIE(el, value);
    1407                 }
    1408         },
    1409 
    1410         _setOpacityIE: function (el, value) {
    1411                 var filter = false,
    1412                     filterName = 'DXImageTransform.Microsoft.Alpha';
    1413 
    1414                 // filters collection throws an error if we try to retrieve a filter that doesn't exist
    1415                 try {
    1416                         filter = el.filters.item(filterName);
    1417                 } catch (e) {
    1418                         // don't set opacity to 1 if we haven't already set an opacity,
    1419                         // it isn't needed and breaks transparent pngs.
    1420                         if (value === 1) { return; }
    1421                 }
    1422 
    1423                 value = Math.round(value * 100);
    1424 
    1425                 if (filter) {
    1426                         filter.Enabled = (value !== 100);
    1427                         filter.Opacity = value;
    1428                 } else {
    1429                         el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';
    1430                 }
    1431         },
    1432 
    1433         // @function testProp(props: String[]): String|false
    1434         // Goes through the array of style names and returns the first name
    1435         // that is a valid style name for an element. If no such name is found,
    1436         // it returns false. Useful for vendor-prefixed styles like `transform`.
    1437         testProp: function (props) {
    1438 
    1439                 var style = document.documentElement.style;
    1440 
    1441                 for (var i = 0; i < props.length; i++) {
    1442                         if (props[i] in style) {
    1443                                 return props[i];
    1444                         }
    1445                 }
    1446                 return false;
    1447         },
    1448 
    1449         // @function setTransform(el: HTMLElement, offset: Point, scale?: Number)
    1450         // Resets the 3D CSS transform of `el` so it is translated by `offset` pixels
    1451         // and optionally scaled by `scale`. Does not have an effect if the
    1452         // browser doesn't support 3D CSS transforms.
    1453         setTransform: function (el, offset, scale) {
    1454                 var pos = offset || new L.Point(0, 0);
    1455 
    1456                 el.style[L.DomUtil.TRANSFORM] =
    1457                         (L.Browser.ie3d ?
    1458                                 'translate(' + pos.x + 'px,' + pos.y + 'px)' :
    1459                                 'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') +
    1460                         (scale ? ' scale(' + scale + ')' : '');
    1461         },
    1462 
    1463         // @function setPosition(el: HTMLElement, position: Point)
    1464         // Sets the position of `el` to coordinates specified by `position`,
    1465         // using CSS translate or top/left positioning depending on the browser
    1466         // (used by Leaflet internally to position its layers).
    1467         setPosition: function (el, point) { // (HTMLElement, Point[, Boolean])
    1468 
    1469                 /*eslint-disable */
    1470                 el._leaflet_pos = point;
    1471                 /*eslint-enable */
    1472 
    1473                 if (L.Browser.any3d) {
    1474                         L.DomUtil.setTransform(el, point);
    1475                 } else {
    1476                         el.style.left = point.x + 'px';
    1477                         el.style.top = point.y + 'px';
    1478                 }
    1479         },
    1480 
    1481         // @function getPosition(el: HTMLElement): Point
    1482         // Returns the coordinates of an element previously positioned with setPosition.
    1483         getPosition: function (el) {
    1484                 // this method is only used for elements previously positioned using setPosition,
    1485                 // so it's safe to cache the position for performance
    1486 
    1487                 return el._leaflet_pos || new L.Point(0, 0);
    1488         }
    1489 };
    1490 
    1491 
    1492 (function () {
    1493         // prefix style property names
    1494 
    1495         // @property TRANSFORM: String
    1496         // Vendor-prefixed fransform style name (e.g. `'webkitTransform'` for WebKit).
    1497         L.DomUtil.TRANSFORM = L.DomUtil.testProp(
    1498                         ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
    1499 
    1500 
    1501         // webkitTransition comes first because some browser versions that drop vendor prefix don't do
    1502         // the same for the transitionend event, in particular the Android 4.1 stock browser
    1503 
    1504         // @property TRANSITION: String
    1505         // Vendor-prefixed transform style name.
    1506         var transition = L.DomUtil.TRANSITION = L.DomUtil.testProp(
    1507                         ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);
    1508 
    1509         L.DomUtil.TRANSITION_END =
    1510                         transition === 'webkitTransition' || transition === 'OTransition' ? transition + 'End' : 'transitionend';
    1511 
    1512         // @function disableTextSelection()
    1513         // Prevents the user from generating `selectstart` DOM events, usually generated
    1514         // when the user drags the mouse through a page with text. Used internally
    1515         // by Leaflet to override the behaviour of any click-and-drag interaction on
    1516         // the map. Affects drag interactions on the whole document.
    1517 
    1518         // @function enableTextSelection()
    1519         // Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection).
    1520         if ('onselectstart' in document) {
    1521                 L.DomUtil.disableTextSelection = function () {
    1522                         L.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault);
    1523                 };
    1524                 L.DomUtil.enableTextSelection = function () {
    1525                         L.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault);
    1526                 };
    1527 
    1528         } else {
    1529                 var userSelectProperty = L.DomUtil.testProp(
    1530                         ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
    1531 
    1532                 L.DomUtil.disableTextSelection = function () {
    1533                         if (userSelectProperty) {
    1534                                 var style = document.documentElement.style;
    1535                                 this._userSelect = style[userSelectProperty];
    1536                                 style[userSelectProperty] = 'none';
    1537                         }
    1538                 };
    1539                 L.DomUtil.enableTextSelection = function () {
    1540                         if (userSelectProperty) {
    1541                                 document.documentElement.style[userSelectProperty] = this._userSelect;
    1542                                 delete this._userSelect;
    1543                         }
    1544                 };
    1545         }
    1546 
    1547         // @function disableImageDrag()
    1548         // As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but
    1549         // for `dragstart` DOM events, usually generated when the user drags an image.
    1550         L.DomUtil.disableImageDrag = function () {
    1551                 L.DomEvent.on(window, 'dragstart', L.DomEvent.preventDefault);
    1552         };
    1553 
    1554         // @function enableImageDrag()
    1555         // Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection).
    1556         L.DomUtil.enableImageDrag = function () {
    1557                 L.DomEvent.off(window, 'dragstart', L.DomEvent.preventDefault);
    1558         };
    1559 
    1560         // @function preventOutline(el: HTMLElement)
    1561         // Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline)
    1562         // of the element `el` invisible. Used internally by Leaflet to prevent
    1563         // focusable elements from displaying an outline when the user performs a
    1564         // drag interaction on them.
    1565         L.DomUtil.preventOutline = function (element) {
    1566                 while (element.tabIndex === -1) {
    1567                         element = element.parentNode;
    1568                 }
    1569                 if (!element || !element.style) { return; }
    1570                 L.DomUtil.restoreOutline();
    1571                 this._outlineElement = element;
    1572                 this._outlineStyle = element.style.outline;
    1573                 element.style.outline = 'none';
    1574                 L.DomEvent.on(window, 'keydown', L.DomUtil.restoreOutline, this);
    1575         };
    1576 
    1577         // @function restoreOutline()
    1578         // Cancels the effects of a previous [`L.DomUtil.preventOutline`]().
    1579         L.DomUtil.restoreOutline = function () {
    1580                 if (!this._outlineElement) { return; }
    1581                 this._outlineElement.style.outline = this._outlineStyle;
    1582                 delete this._outlineElement;
    1583                 delete this._outlineStyle;
    1584                 L.DomEvent.off(window, 'keydown', L.DomUtil.restoreOutline, this);
    1585         };
    1586 })();
    1587 
    1588 
     1290// TODO International date line?
     1291
     1292// @factory L.latLngBounds(corner1: LatLng, corner2: LatLng)
     1293// Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle.
     1294
     1295// @alternative
     1296// @factory L.latLngBounds(latlngs: LatLng[])
     1297// Creates a `LatLngBounds` object defined by the geographical points it contains. Very useful for zooming the map to fit a particular set of locations with [`fitBounds`](#map-fitbounds).
     1298function toLatLngBounds(a, b) {
     1299        if (a instanceof LatLngBounds) {
     1300                return a;
     1301        }
     1302        return new LatLngBounds(a, b);
     1303}
    15891304
    15901305/* @class LatLng
     
    16091324 */
    16101325
    1611 L.LatLng = function (lat, lng, alt) {
     1326function LatLng(lat, lng, alt) {
    16121327        if (isNaN(lat) || isNaN(lng)) {
    16131328                throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');
     
    16271342                this.alt = +alt;
    16281343        }
    1629 };
    1630 
    1631 L.LatLng.prototype = {
     1344}
     1345
     1346LatLng.prototype = {
    16321347        // @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean
    16331348        // 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.
     
    16351350                if (!obj) { return false; }
    16361351
    1637                 obj = L.latLng(obj);
     1352                obj = toLatLng(obj);
    16381353
    16391354                var margin = Math.max(
     
    16481363        toString: function (precision) {
    16491364                return 'LatLng(' +
    1650                         L.Util.formatNum(this.lat, precision) + ', ' +
    1651                         L.Util.formatNum(this.lng, precision) + ')';
     1365                        formatNum(this.lat, precision) + ', ' +
     1366                        formatNum(this.lng, precision) + ')';
    16521367        },
    16531368
     
    16551370        // Returns the distance (in meters) to the given `LatLng` calculated using the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula).
    16561371        distanceTo: function (other) {
    1657                 return L.CRS.Earth.distance(this, L.latLng(other));
     1372                return Earth.distance(this, toLatLng(other));
    16581373        },
    16591374
     
    16611376        // Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees.
    16621377        wrap: function () {
    1663                 return L.CRS.Earth.wrapLatLng(this);
     1378                return Earth.wrapLatLng(this);
    16641379        },
    16651380
     
    16701385                    lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat);
    16711386
    1672                 return L.latLngBounds(
     1387                return toLatLngBounds(
    16731388                        [this.lat - latAccuracy, this.lng - lngAccuracy],
    16741389                        [this.lat + latAccuracy, this.lng + lngAccuracy]);
     
    16761391
    16771392        clone: function () {
    1678                 return new L.LatLng(this.lat, this.lng, this.alt);
     1393                return new LatLng(this.lat, this.lng, this.alt);
    16791394        }
    16801395};
     
    16931408// Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead.
    16941409
    1695 L.latLng = function (a, b, c) {
    1696         if (a instanceof L.LatLng) {
     1410function toLatLng(a, b, c) {
     1411        if (a instanceof LatLng) {
    16971412                return a;
    16981413        }
    1699         if (L.Util.isArray(a) && typeof a[0] !== 'object') {
     1414        if (isArray(a) && typeof a[0] !== 'object') {
    17001415                if (a.length === 3) {
    1701                         return new L.LatLng(a[0], a[1], a[2]);
     1416                        return new LatLng(a[0], a[1], a[2]);
    17021417                }
    17031418                if (a.length === 2) {
    1704                         return new L.LatLng(a[0], a[1]);
     1419                        return new LatLng(a[0], a[1]);
    17051420                }
    17061421                return null;
     
    17101425        }
    17111426        if (typeof a === 'object' && 'lat' in a) {
    1712                 return new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt);
     1427                return new LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt);
    17131428        }
    17141429        if (b === undefined) {
    17151430                return null;
    17161431        }
    1717         return new L.LatLng(a, b, c);
    1718 };
    1719 
    1720 
     1432        return new LatLng(a, b, c);
     1433}
    17211434
    17221435/*
    1723  * @class LatLngBounds
    1724  * @aka L.LatLngBounds
    1725  *
    1726  * Represents a rectangular geographical area on a map.
    1727  *
    1728  * @example
    1729  *
    1730  * ```js
    1731  * var corner1 = L.latLng(40.712, -74.227),
    1732  * corner2 = L.latLng(40.774, -74.125),
    1733  * bounds = L.latLngBounds(corner1, corner2);
    1734  * ```
    1735  *
    1736  * All Leaflet methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:
    1737  *
    1738  * ```js
    1739  * map.fitBounds([
    1740  *      [40.712, -74.227],
    1741  *      [40.774, -74.125]
    1742  * ]);
    1743  * ```
    1744  *
    1745  * 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.
    1746  */
    1747 
    1748 L.LatLngBounds = function (corner1, corner2) { // (LatLng, LatLng) or (LatLng[])
    1749         if (!corner1) { return; }
    1750 
    1751         var latlngs = corner2 ? [corner1, corner2] : corner1;
    1752 
    1753         for (var i = 0, len = latlngs.length; i < len; i++) {
    1754                 this.extend(latlngs[i]);
    1755         }
    1756 };
    1757 
    1758 L.LatLngBounds.prototype = {
    1759 
    1760         // @method extend(latlng: LatLng): this
    1761         // Extend the bounds to contain the given point
    1762 
    1763         // @alternative
    1764         // @method extend(otherBounds: LatLngBounds): this
    1765         // Extend the bounds to contain the given bounds
    1766         extend: function (obj) {
    1767                 var sw = this._southWest,
    1768                     ne = this._northEast,
    1769                     sw2, ne2;
    1770 
    1771                 if (obj instanceof L.LatLng) {
    1772                         sw2 = obj;
    1773                         ne2 = obj;
    1774 
    1775                 } else if (obj instanceof L.LatLngBounds) {
    1776                         sw2 = obj._southWest;
    1777                         ne2 = obj._northEast;
    1778 
    1779                         if (!sw2 || !ne2) { return this; }
    1780 
    1781                 } else {
    1782                         return obj ? this.extend(L.latLng(obj) || L.latLngBounds(obj)) : this;
    1783                 }
    1784 
    1785                 if (!sw && !ne) {
    1786                         this._southWest = new L.LatLng(sw2.lat, sw2.lng);
    1787                         this._northEast = new L.LatLng(ne2.lat, ne2.lng);
    1788                 } else {
    1789                         sw.lat = Math.min(sw2.lat, sw.lat);
    1790                         sw.lng = Math.min(sw2.lng, sw.lng);
    1791                         ne.lat = Math.max(ne2.lat, ne.lat);
    1792                         ne.lng = Math.max(ne2.lng, ne.lng);
    1793                 }
    1794 
    1795                 return this;
    1796         },
    1797 
    1798         // @method pad(bufferRatio: Number): LatLngBounds
    1799         // Returns bigger bounds created by extending the current bounds by a given percentage in each direction.
    1800         pad: function (bufferRatio) {
    1801                 var sw = this._southWest,
    1802                     ne = this._northEast,
    1803                     heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
    1804                     widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
    1805 
    1806                 return new L.LatLngBounds(
    1807                         new L.LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
    1808                         new L.LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));
    1809         },
    1810 
    1811         // @method getCenter(): LatLng
    1812         // Returns the center point of the bounds.
    1813         getCenter: function () {
    1814                 return new L.LatLng(
    1815                         (this._southWest.lat + this._northEast.lat) / 2,
    1816                         (this._southWest.lng + this._northEast.lng) / 2);
    1817         },
    1818 
    1819         // @method getSouthWest(): LatLng
    1820         // Returns the south-west point of the bounds.
    1821         getSouthWest: function () {
    1822                 return this._southWest;
    1823         },
    1824 
    1825         // @method getNorthEast(): LatLng
    1826         // Returns the north-east point of the bounds.
    1827         getNorthEast: function () {
    1828                 return this._northEast;
    1829         },
    1830 
    1831         // @method getNorthWest(): LatLng
    1832         // Returns the north-west point of the bounds.
    1833         getNorthWest: function () {
    1834                 return new L.LatLng(this.getNorth(), this.getWest());
    1835         },
    1836 
    1837         // @method getSouthEast(): LatLng
    1838         // Returns the south-east point of the bounds.
    1839         getSouthEast: function () {
    1840                 return new L.LatLng(this.getSouth(), this.getEast());
    1841         },
    1842 
    1843         // @method getWest(): Number
    1844         // Returns the west longitude of the bounds
    1845         getWest: function () {
    1846                 return this._southWest.lng;
    1847         },
    1848 
    1849         // @method getSouth(): Number
    1850         // Returns the south latitude of the bounds
    1851         getSouth: function () {
    1852                 return this._southWest.lat;
    1853         },
    1854 
    1855         // @method getEast(): Number
    1856         // Returns the east longitude of the bounds
    1857         getEast: function () {
    1858                 return this._northEast.lng;
    1859         },
    1860 
    1861         // @method getNorth(): Number
    1862         // Returns the north latitude of the bounds
    1863         getNorth: function () {
    1864                 return this._northEast.lat;
    1865         },
    1866 
    1867         // @method contains(otherBounds: LatLngBounds): Boolean
    1868         // Returns `true` if the rectangle contains the given one.
    1869 
    1870         // @alternative
    1871         // @method contains (latlng: LatLng): Boolean
    1872         // Returns `true` if the rectangle contains the given point.
    1873         contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean
    1874                 if (typeof obj[0] === 'number' || obj instanceof L.LatLng || 'lat' in obj) {
    1875                         obj = L.latLng(obj);
    1876                 } else {
    1877                         obj = L.latLngBounds(obj);
    1878                 }
    1879 
    1880                 var sw = this._southWest,
    1881                     ne = this._northEast,
    1882                     sw2, ne2;
    1883 
    1884                 if (obj instanceof L.LatLngBounds) {
    1885                         sw2 = obj.getSouthWest();
    1886                         ne2 = obj.getNorthEast();
    1887                 } else {
    1888                         sw2 = ne2 = obj;
    1889                 }
    1890 
    1891                 return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&
    1892                        (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);
    1893         },
    1894 
    1895         // @method intersects(otherBounds: LatLngBounds): Boolean
    1896         // Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.
    1897         intersects: function (bounds) {
    1898                 bounds = L.latLngBounds(bounds);
    1899 
    1900                 var sw = this._southWest,
    1901                     ne = this._northEast,
    1902                     sw2 = bounds.getSouthWest(),
    1903                     ne2 = bounds.getNorthEast(),
    1904 
    1905                     latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),
    1906                     lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);
    1907 
    1908                 return latIntersects && lngIntersects;
    1909         },
    1910 
    1911         // @method overlaps(otherBounds: Bounds): Boolean
    1912         // Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.
    1913         overlaps: function (bounds) {
    1914                 bounds = L.latLngBounds(bounds);
    1915 
    1916                 var sw = this._southWest,
    1917                     ne = this._northEast,
    1918                     sw2 = bounds.getSouthWest(),
    1919                     ne2 = bounds.getNorthEast(),
    1920 
    1921                     latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat),
    1922                     lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng);
    1923 
    1924                 return latOverlaps && lngOverlaps;
    1925         },
    1926 
    1927         // @method toBBoxString(): String
    1928         // Returns a string with bounding box coordinates in a 'southwest_lng,southwest_lat,northeast_lng,northeast_lat' format. Useful for sending requests to web services that return geo data.
    1929         toBBoxString: function () {
    1930                 return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');
    1931         },
    1932 
    1933         // @method equals(otherBounds: LatLngBounds): Boolean
    1934         // Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds.
    1935         equals: function (bounds) {
    1936                 if (!bounds) { return false; }
    1937 
    1938                 bounds = L.latLngBounds(bounds);
    1939 
    1940                 return this._southWest.equals(bounds.getSouthWest()) &&
    1941                        this._northEast.equals(bounds.getNorthEast());
    1942         },
    1943 
    1944         // @method isValid(): Boolean
    1945         // Returns `true` if the bounds are properly initialized.
    1946         isValid: function () {
    1947                 return !!(this._southWest && this._northEast);
    1948         }
    1949 };
    1950 
    1951 // TODO International date line?
    1952 
    1953 // @factory L.latLngBounds(corner1: LatLng, corner2: LatLng)
    1954 // Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle.
    1955 
    1956 // @alternative
    1957 // @factory L.latLngBounds(latlngs: LatLng[])
    1958 // Creates a `LatLngBounds` object defined by the geographical points it contains. Very useful for zooming the map to fit a particular set of locations with [`fitBounds`](#map-fitbounds).
    1959 L.latLngBounds = function (a, b) {
    1960         if (a instanceof L.LatLngBounds) {
    1961                 return a;
    1962         }
    1963         return new L.LatLngBounds(a, b);
    1964 };
    1965 
    1966 
    1967 
    1968 /*
    1969  * @namespace Projection
    1970  * @section
    1971  * Leaflet comes with a set of already defined Projections out of the box:
    1972  *
    1973  * @projection L.Projection.LonLat
    1974  *
    1975  * Equirectangular, or Plate Carree projection — the most simple projection,
    1976  * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as
    1977  * latitude. Also suitable for flat worlds, e.g. game maps. Used by the
    1978  * `EPSG:3395` and `Simple` CRS.
    1979  */
    1980 
    1981 L.Projection = {};
    1982 
    1983 L.Projection.LonLat = {
    1984         project: function (latlng) {
    1985                 return new L.Point(latlng.lng, latlng.lat);
    1986         },
    1987 
    1988         unproject: function (point) {
    1989                 return new L.LatLng(point.y, point.x);
    1990         },
    1991 
    1992         bounds: L.bounds([-180, -90], [180, 90])
    1993 };
    1994 
    1995 
    1996 
    1997 /*
    1998  * @namespace Projection
    1999  * @projection L.Projection.SphericalMercator
    2000  *
    2001  * Spherical Mercator projection — the most common projection for online maps,
    2002  * used by almost all free and commercial tile providers. Assumes that Earth is
    2003  * a sphere. Used by the `EPSG:3857` CRS.
    2004  */
    2005 
    2006 L.Projection.SphericalMercator = {
    2007 
    2008         R: 6378137,
    2009         MAX_LATITUDE: 85.0511287798,
    2010 
    2011         project: function (latlng) {
    2012                 var d = Math.PI / 180,
    2013                     max = this.MAX_LATITUDE,
    2014                     lat = Math.max(Math.min(max, latlng.lat), -max),
    2015                     sin = Math.sin(lat * d);
    2016 
    2017                 return new L.Point(
    2018                                 this.R * latlng.lng * d,
    2019                                 this.R * Math.log((1 + sin) / (1 - sin)) / 2);
    2020         },
    2021 
    2022         unproject: function (point) {
    2023                 var d = 180 / Math.PI;
    2024 
    2025                 return new L.LatLng(
    2026                         (2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d,
    2027                         point.x * d / this.R);
    2028         },
    2029 
    2030         bounds: (function () {
    2031                 var d = 6378137 * Math.PI;
    2032                 return L.bounds([-d, -d], [d, d]);
    2033         })()
    2034 };
    2035 
    2036 
    2037 
    2038 /*
    2039  * @class CRS
    2040  * @aka L.CRS
    2041  * Abstract class that defines coordinate reference systems for projecting
     1436 * @namespace CRS
     1437 * @crs L.CRS.Base
     1438 * Object that defines coordinate reference systems for projecting
    20421439 * geographical points into pixel (screen) coordinates and back (and to
    20431440 * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See
     
    20491446 */
    20501447
    2051 L.CRS = {
     1448var CRS = {
    20521449        // @method latLngToPoint(latlng: LatLng, zoom: Number): Point
    20531450        // Projects geographical coordinates into pixel coordinates for a given zoom.
     
    21081505                    max = this.transformation.transform(b.max, s);
    21091506
    2110                 return L.bounds(min, max);
     1507                return new Bounds(min, max);
    21111508        },
    21121509
     
    21351532        // Returns a `LatLng` where lat and lng has been wrapped according to the
    21361533        // CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds.
    2137         // Only accepts actual `L.LatLng` instances, not arrays.
    21381534        wrapLatLng: function (latlng) {
    2139                 var lng = this.wrapLng ? L.Util.wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng,
    2140                     lat = this.wrapLat ? L.Util.wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat,
     1535                var lng = this.wrapLng ? wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng,
     1536                    lat = this.wrapLat ? wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat,
    21411537                    alt = latlng.alt;
    21421538
    2143                 return L.latLng(lat, lng, alt);
     1539                return new LatLng(lat, lng, alt);
    21441540        },
    21451541
     
    21601556                var sw = bounds.getSouthWest(),
    21611557                    ne = bounds.getNorthEast(),
    2162                     newSw = L.latLng({lat: sw.lat - latShift, lng: sw.lng - lngShift}),
    2163                     newNe = L.latLng({lat: ne.lat - latShift, lng: ne.lng - lngShift});
    2164 
    2165                 return new L.LatLngBounds(newSw, newNe);
     1558                    newSw = new LatLng(sw.lat - latShift, sw.lng - lngShift),
     1559                    newNe = new LatLng(ne.lat - latShift, ne.lng - lngShift);
     1560
     1561                return new LatLngBounds(newSw, newNe);
    21661562        }
    21671563};
    2168 
    2169 
    2170 
    2171 /*
    2172  * @namespace CRS
    2173  * @crs L.CRS.Simple
    2174  *
    2175  * A simple CRS that maps longitude and latitude into `x` and `y` directly.
    2176  * May be used for maps of flat surfaces (e.g. game maps). Note that the `y`
    2177  * axis should still be inverted (going from bottom to top). `distance()` returns
    2178  * simple euclidean distance.
    2179  */
    2180 
    2181 L.CRS.Simple = L.extend({}, L.CRS, {
    2182         projection: L.Projection.LonLat,
    2183         transformation: new L.Transformation(1, 0, -1, 0),
    2184 
    2185         scale: function (zoom) {
    2186                 return Math.pow(2, zoom);
    2187         },
    2188 
    2189         zoom: function (scale) {
    2190                 return Math.log(scale) / Math.LN2;
    2191         },
    2192 
    2193         distance: function (latlng1, latlng2) {
    2194                 var dx = latlng2.lng - latlng1.lng,
    2195                     dy = latlng2.lat - latlng1.lat;
    2196 
    2197                 return Math.sqrt(dx * dx + dy * dy);
    2198         },
    2199 
    2200         infinite: true
    2201 });
    2202 
    2203 
    22041564
    22051565/*
     
    22131573 */
    22141574
    2215 L.CRS.Earth = L.extend({}, L.CRS, {
     1575var Earth = extend({}, CRS, {
    22161576        wrapLng: [-180, 180],
    22171577
     
    22331593});
    22341594
    2235 
     1595/*
     1596 * @namespace Projection
     1597 * @projection L.Projection.SphericalMercator
     1598 *
     1599 * Spherical Mercator projection — the most common projection for online maps,
     1600 * used by almost all free and commercial tile providers. Assumes that Earth is
     1601 * a sphere. Used by the `EPSG:3857` CRS.
     1602 */
     1603
     1604var SphericalMercator = {
     1605
     1606        R: 6378137,
     1607        MAX_LATITUDE: 85.0511287798,
     1608
     1609        project: function (latlng) {
     1610                var d = Math.PI / 180,
     1611                    max = this.MAX_LATITUDE,
     1612                    lat = Math.max(Math.min(max, latlng.lat), -max),
     1613                    sin = Math.sin(lat * d);
     1614
     1615                return new Point(
     1616                                this.R * latlng.lng * d,
     1617                                this.R * Math.log((1 + sin) / (1 - sin)) / 2);
     1618        },
     1619
     1620        unproject: function (point) {
     1621                var d = 180 / Math.PI;
     1622
     1623                return new LatLng(
     1624                        (2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d,
     1625                        point.x * d / this.R);
     1626        },
     1627
     1628        bounds: (function () {
     1629                var d = 6378137 * Math.PI;
     1630                return new Bounds([-d, -d], [d, d]);
     1631        })()
     1632};
     1633
     1634/*
     1635 * @class Transformation
     1636 * @aka L.Transformation
     1637 *
     1638 * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d`
     1639 * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing
     1640 * the reverse. Used by Leaflet in its projections code.
     1641 *
     1642 * @example
     1643 *
     1644 * ```js
     1645 * var transformation = L.transformation(2, 5, -1, 10),
     1646 *      p = L.point(1, 2),
     1647 *      p2 = transformation.transform(p), //  L.point(7, 8)
     1648 *      p3 = transformation.untransform(p2); //  L.point(1, 2)
     1649 * ```
     1650 */
     1651
     1652
     1653// factory new L.Transformation(a: Number, b: Number, c: Number, d: Number)
     1654// Creates a `Transformation` object with the given coefficients.
     1655function Transformation(a, b, c, d) {
     1656        if (isArray(a)) {
     1657                // use array properties
     1658                this._a = a[0];
     1659                this._b = a[1];
     1660                this._c = a[2];
     1661                this._d = a[3];
     1662                return;
     1663        }
     1664        this._a = a;
     1665        this._b = b;
     1666        this._c = c;
     1667        this._d = d;
     1668}
     1669
     1670Transformation.prototype = {
     1671        // @method transform(point: Point, scale?: Number): Point
     1672        // Returns a transformed point, optionally multiplied by the given scale.
     1673        // Only accepts actual `L.Point` instances, not arrays.
     1674        transform: function (point, scale) { // (Point, Number) -> Point
     1675                return this._transform(point.clone(), scale);
     1676        },
     1677
     1678        // destructive transform (faster)
     1679        _transform: function (point, scale) {
     1680                scale = scale || 1;
     1681                point.x = scale * (this._a * point.x + this._b);
     1682                point.y = scale * (this._c * point.y + this._d);
     1683                return point;
     1684        },
     1685
     1686        // @method untransform(point: Point, scale?: Number): Point
     1687        // Returns the reverse transformation of the given point, optionally divided
     1688        // by the given scale. Only accepts actual `L.Point` instances, not arrays.
     1689        untransform: function (point, scale) {
     1690                scale = scale || 1;
     1691                return new Point(
     1692                        (point.x / scale - this._b) / this._a,
     1693                        (point.y / scale - this._d) / this._c);
     1694        }
     1695};
     1696
     1697// factory L.transformation(a: Number, b: Number, c: Number, d: Number)
     1698
     1699// @factory L.transformation(a: Number, b: Number, c: Number, d: Number)
     1700// Instantiates a Transformation object with the given coefficients.
     1701
     1702// @alternative
     1703// @factory L.transformation(coefficients: Array): Transformation
     1704// Expects an coeficients array of the form
     1705// `[a: Number, b: Number, c: Number, d: Number]`.
     1706
     1707function toTransformation(a, b, c, d) {
     1708        return new Transformation(a, b, c, d);
     1709}
    22361710
    22371711/*
     
    22441718 */
    22451719
    2246 L.CRS.EPSG3857 = L.extend({}, L.CRS.Earth, {
     1720var EPSG3857 = extend({}, Earth, {
    22471721        code: 'EPSG:3857',
    2248         projection: L.Projection.SphericalMercator,
     1722        projection: SphericalMercator,
    22491723
    22501724        transformation: (function () {
    2251                 var scale = 0.5 / (Math.PI * L.Projection.SphericalMercator.R);
    2252                 return new L.Transformation(scale, 0.5, -scale, 0.5);
     1725                var scale = 0.5 / (Math.PI * SphericalMercator.R);
     1726                return toTransformation(scale, 0.5, -scale, 0.5);
    22531727        }())
    22541728});
    22551729
    2256 L.CRS.EPSG900913 = L.extend({}, L.CRS.EPSG3857, {
     1730var EPSG900913 = extend({}, EPSG3857, {
    22571731        code: 'EPSG:900913'
    22581732});
    22591733
    2260 
     1734// @namespace SVG; @section
     1735// There are several static functions which can be called without instantiating L.SVG:
     1736
     1737// @function create(name: String): SVGElement
     1738// Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement),
     1739// corresponding to the class name passed. For example, using 'line' will return
     1740// an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement).
     1741function svgCreate(name) {
     1742        return document.createElementNS('http://www.w3.org/2000/svg', name);
     1743}
     1744
     1745// @function pointsToPath(rings: Point[], closed: Boolean): String
     1746// Generates a SVG path string for multiple rings, with each ring turning
     1747// into "M..L..L.." instructions
     1748function pointsToPath(rings, closed) {
     1749        var str = '',
     1750        i, j, len, len2, points, p;
     1751
     1752        for (i = 0, len = rings.length; i < len; i++) {
     1753                points = rings[i];
     1754
     1755                for (j = 0, len2 = points.length; j < len2; j++) {
     1756                        p = points[j];
     1757                        str += (j ? 'L' : 'M') + p.x + ' ' + p.y;
     1758                }
     1759
     1760                // closes the ring for polygons; "x" is VML syntax
     1761                str += closed ? (svg ? 'z' : 'x') : '';
     1762        }
     1763
     1764        // SVG complains about empty path strings
     1765        return str || 'M0 0';
     1766}
    22611767
    22621768/*
    2263  * @namespace CRS
    2264  * @crs L.CRS.EPSG4326
    2265  *
    2266  * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection.
    2267  *
    2268  * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic),
    2269  * which is a breaking change from 0.7.x behaviour.  If you are using a `TileLayer`
    2270  * with this CRS, ensure that there are two 256x256 pixel tiles covering the
    2271  * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90),
    2272  * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set.
     1769 * @namespace Browser
     1770 * @aka L.Browser
     1771 *
     1772 * A namespace with static properties for browser/feature detection used by Leaflet internally.
     1773 *
     1774 * @example
     1775 *
     1776 * ```js
     1777 * if (L.Browser.ielt9) {
     1778 *   alert('Upgrade your browser, dude!');
     1779 * }
     1780 * ```
    22731781 */
    22741782
    2275 L.CRS.EPSG4326 = L.extend({}, L.CRS.Earth, {
    2276         code: 'EPSG:4326',
    2277         projection: L.Projection.LonLat,
    2278         transformation: new L.Transformation(1 / 180, 1, -1 / 180, 0.5)
     1783var style$1 = document.documentElement.style;
     1784
     1785// @property ie: Boolean; `true` for all Internet Explorer versions (not Edge).
     1786var ie = 'ActiveXObject' in window;
     1787
     1788// @property ielt9: Boolean; `true` for Internet Explorer versions less than 9.
     1789var ielt9 = ie && !document.addEventListener;
     1790
     1791// @property edge: Boolean; `true` for the Edge web browser.
     1792var edge = 'msLaunchUri' in navigator && !('documentMode' in document);
     1793
     1794// @property webkit: Boolean;
     1795// `true` for webkit-based browsers like Chrome and Safari (including mobile versions).
     1796var webkit = userAgentContains('webkit');
     1797
     1798// @property android: Boolean
     1799// `true` for any browser running on an Android platform.
     1800var android = userAgentContains('android');
     1801
     1802// @property android23: Boolean; `true` for browsers running on Android 2 or Android 3.
     1803var android23 = userAgentContains('android 2') || userAgentContains('android 3');
     1804
     1805// @property opera: Boolean; `true` for the Opera browser
     1806var opera = !!window.opera;
     1807
     1808// @property chrome: Boolean; `true` for the Chrome browser.
     1809var chrome = userAgentContains('chrome');
     1810
     1811// @property gecko: Boolean; `true` for gecko-based browsers like Firefox.
     1812var gecko = userAgentContains('gecko') && !webkit && !opera && !ie;
     1813
     1814// @property safari: Boolean; `true` for the Safari browser.
     1815var safari = !chrome && userAgentContains('safari');
     1816
     1817var phantom = userAgentContains('phantom');
     1818
     1819// @property opera12: Boolean
     1820// `true` for the Opera browser supporting CSS transforms (version 12 or later).
     1821var opera12 = 'OTransition' in style$1;
     1822
     1823// @property win: Boolean; `true` when the browser is running in a Windows platform
     1824var win = navigator.platform.indexOf('Win') === 0;
     1825
     1826// @property ie3d: Boolean; `true` for all Internet Explorer versions supporting CSS transforms.
     1827var ie3d = ie && ('transition' in style$1);
     1828
     1829// @property webkit3d: Boolean; `true` for webkit-based browsers supporting CSS transforms.
     1830var webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23;
     1831
     1832// @property gecko3d: Boolean; `true` for gecko-based browsers supporting CSS transforms.
     1833var gecko3d = 'MozPerspective' in style$1;
     1834
     1835// @property any3d: Boolean
     1836// `true` for all browsers supporting CSS transforms.
     1837var any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantom;
     1838
     1839// @property mobile: Boolean; `true` for all browsers running in a mobile device.
     1840var mobile = typeof orientation !== 'undefined' || userAgentContains('mobile');
     1841
     1842// @property mobileWebkit: Boolean; `true` for all webkit-based browsers in a mobile device.
     1843var mobileWebkit = mobile && webkit;
     1844
     1845// @property mobileWebkit3d: Boolean
     1846// `true` for all webkit-based browsers in a mobile device supporting CSS transforms.
     1847var mobileWebkit3d = mobile && webkit3d;
     1848
     1849// @property msPointer: Boolean
     1850// `true` for browsers implementing the Microsoft touch events model (notably IE10).
     1851var msPointer = !window.PointerEvent && window.MSPointerEvent;
     1852
     1853// @property pointer: Boolean
     1854// `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx).
     1855var pointer = !!(window.PointerEvent || msPointer);
     1856
     1857// @property touch: Boolean
     1858// `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).
     1859// This does not necessarily mean that the browser is running in a computer with
     1860// a touchscreen, it only means that the browser is capable of understanding
     1861// touch events.
     1862var touch = !window.L_NO_TOUCH && (pointer || 'ontouchstart' in window ||
     1863                (window.DocumentTouch && document instanceof window.DocumentTouch));
     1864
     1865// @property mobileOpera: Boolean; `true` for the Opera browser in a mobile device.
     1866var mobileOpera = mobile && opera;
     1867
     1868// @property mobileGecko: Boolean
     1869// `true` for gecko-based browsers running in a mobile device.
     1870var mobileGecko = mobile && gecko;
     1871
     1872// @property retina: Boolean
     1873// `true` for browsers on a high-resolution "retina" screen.
     1874var retina = (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1;
     1875
     1876
     1877// @property canvas: Boolean
     1878// `true` when the browser supports [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
     1879var canvas = (function () {
     1880        return !!document.createElement('canvas').getContext;
     1881}());
     1882
     1883// @property svg: Boolean
     1884// `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG).
     1885var svg = !!(document.createElementNS && svgCreate('svg').createSVGRect);
     1886
     1887// @property vml: Boolean
     1888// `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language).
     1889var vml = !svg && (function () {
     1890        try {
     1891                var div = document.createElement('div');
     1892                div.innerHTML = '<v:shape adj="1"/>';
     1893
     1894                var shape = div.firstChild;
     1895                shape.style.behavior = 'url(#default#VML)';
     1896
     1897                return shape && (typeof shape.adj === 'object');
     1898
     1899        } catch (e) {
     1900                return false;
     1901        }
     1902}());
     1903
     1904
     1905function userAgentContains(str) {
     1906        return navigator.userAgent.toLowerCase().indexOf(str) >= 0;
     1907}
     1908
     1909
     1910var Browser = (Object.freeze || Object)({
     1911        ie: ie,
     1912        ielt9: ielt9,
     1913        edge: edge,
     1914        webkit: webkit,
     1915        android: android,
     1916        android23: android23,
     1917        opera: opera,
     1918        chrome: chrome,
     1919        gecko: gecko,
     1920        safari: safari,
     1921        phantom: phantom,
     1922        opera12: opera12,
     1923        win: win,
     1924        ie3d: ie3d,
     1925        webkit3d: webkit3d,
     1926        gecko3d: gecko3d,
     1927        any3d: any3d,
     1928        mobile: mobile,
     1929        mobileWebkit: mobileWebkit,
     1930        mobileWebkit3d: mobileWebkit3d,
     1931        msPointer: msPointer,
     1932        pointer: pointer,
     1933        touch: touch,
     1934        mobileOpera: mobileOpera,
     1935        mobileGecko: mobileGecko,
     1936        retina: retina,
     1937        canvas: canvas,
     1938        svg: svg,
     1939        vml: vml
    22791940});
    22801941
    2281 
     1942/*
     1943 * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.
     1944 */
     1945
     1946
     1947var POINTER_DOWN =   msPointer ? 'MSPointerDown'   : 'pointerdown';
     1948var POINTER_MOVE =   msPointer ? 'MSPointerMove'   : 'pointermove';
     1949var POINTER_UP =     msPointer ? 'MSPointerUp'     : 'pointerup';
     1950var POINTER_CANCEL = msPointer ? 'MSPointerCancel' : 'pointercancel';
     1951var TAG_WHITE_LIST = ['INPUT', 'SELECT', 'OPTION'];
     1952var _pointers = {};
     1953var _pointerDocListener = false;
     1954
     1955// DomEvent.DoubleTap needs to know about this
     1956var _pointersCount = 0;
     1957
     1958// Provides a touch events wrapper for (ms)pointer events.
     1959// ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
     1960
     1961function addPointerListener(obj, type, handler, id) {
     1962        if (type === 'touchstart') {
     1963                _addPointerStart(obj, handler, id);
     1964
     1965        } else if (type === 'touchmove') {
     1966                _addPointerMove(obj, handler, id);
     1967
     1968        } else if (type === 'touchend') {
     1969                _addPointerEnd(obj, handler, id);
     1970        }
     1971
     1972        return this;
     1973}
     1974
     1975function removePointerListener(obj, type, id) {
     1976        var handler = obj['_leaflet_' + type + id];
     1977
     1978        if (type === 'touchstart') {
     1979                obj.removeEventListener(POINTER_DOWN, handler, false);
     1980
     1981        } else if (type === 'touchmove') {
     1982                obj.removeEventListener(POINTER_MOVE, handler, false);
     1983
     1984        } else if (type === 'touchend') {
     1985                obj.removeEventListener(POINTER_UP, handler, false);
     1986                obj.removeEventListener(POINTER_CANCEL, handler, false);
     1987        }
     1988
     1989        return this;
     1990}
     1991
     1992function _addPointerStart(obj, handler, id) {
     1993        var onDown = bind(function (e) {
     1994                if (e.pointerType !== 'mouse' && e.pointerType !== e.MSPOINTER_TYPE_MOUSE && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) {
     1995                        // In IE11, some touch events needs to fire for form controls, or
     1996                        // the controls will stop working. We keep a whitelist of tag names that
     1997                        // need these events. For other target tags, we prevent default on the event.
     1998                        if (TAG_WHITE_LIST.indexOf(e.target.tagName) < 0) {
     1999                                preventDefault(e);
     2000                        } else {
     2001                                return;
     2002                        }
     2003                }
     2004
     2005                _handlePointer(e, handler);
     2006        });
     2007
     2008        obj['_leaflet_touchstart' + id] = onDown;
     2009        obj.addEventListener(POINTER_DOWN, onDown, false);
     2010
     2011        // need to keep track of what pointers and how many are active to provide e.touches emulation
     2012        if (!_pointerDocListener) {
     2013                // we listen documentElement as any drags that end by moving the touch off the screen get fired there
     2014                document.documentElement.addEventListener(POINTER_DOWN, _globalPointerDown, true);
     2015                document.documentElement.addEventListener(POINTER_MOVE, _globalPointerMove, true);
     2016                document.documentElement.addEventListener(POINTER_UP, _globalPointerUp, true);
     2017                document.documentElement.addEventListener(POINTER_CANCEL, _globalPointerUp, true);
     2018
     2019                _pointerDocListener = true;
     2020        }
     2021}
     2022
     2023function _globalPointerDown(e) {
     2024        _pointers[e.pointerId] = e;
     2025        _pointersCount++;
     2026}
     2027
     2028function _globalPointerMove(e) {
     2029        if (_pointers[e.pointerId]) {
     2030                _pointers[e.pointerId] = e;
     2031        }
     2032}
     2033
     2034function _globalPointerUp(e) {
     2035        delete _pointers[e.pointerId];
     2036        _pointersCount--;
     2037}
     2038
     2039function _handlePointer(e, handler) {
     2040        e.touches = [];
     2041        for (var i in _pointers) {
     2042                e.touches.push(_pointers[i]);
     2043        }
     2044        e.changedTouches = [e];
     2045
     2046        handler(e);
     2047}
     2048
     2049function _addPointerMove(obj, handler, id) {
     2050        var onMove = function (e) {
     2051                // don't fire touch moves when mouse isn't down
     2052                if ((e.pointerType === e.MSPOINTER_TYPE_MOUSE || e.pointerType === 'mouse') && e.buttons === 0) { return; }
     2053
     2054                _handlePointer(e, handler);
     2055        };
     2056
     2057        obj['_leaflet_touchmove' + id] = onMove;
     2058        obj.addEventListener(POINTER_MOVE, onMove, false);
     2059}
     2060
     2061function _addPointerEnd(obj, handler, id) {
     2062        var onUp = function (e) {
     2063                _handlePointer(e, handler);
     2064        };
     2065
     2066        obj['_leaflet_touchend' + id] = onUp;
     2067        obj.addEventListener(POINTER_UP, onUp, false);
     2068        obj.addEventListener(POINTER_CANCEL, onUp, false);
     2069}
     2070
     2071/*
     2072 * Extends the event handling code with double tap support for mobile browsers.
     2073 */
     2074
     2075var _touchstart = msPointer ? 'MSPointerDown' : pointer ? 'pointerdown' : 'touchstart';
     2076var _touchend = msPointer ? 'MSPointerUp' : pointer ? 'pointerup' : 'touchend';
     2077var _pre = '_leaflet_';
     2078
     2079// inspired by Zepto touch code by Thomas Fuchs
     2080function addDoubleTapListener(obj, handler, id) {
     2081        var last, touch$$1,
     2082            doubleTap = false,
     2083            delay = 250;
     2084
     2085        function onTouchStart(e) {
     2086                var count;
     2087
     2088                if (pointer) {
     2089                        if ((!edge) || e.pointerType === 'mouse') { return; }
     2090                        count = _pointersCount;
     2091                } else {
     2092                        count = e.touches.length;
     2093                }
     2094
     2095                if (count > 1) { return; }
     2096
     2097                var now = Date.now(),
     2098                    delta = now - (last || now);
     2099
     2100                touch$$1 = e.touches ? e.touches[0] : e;
     2101                doubleTap = (delta > 0 && delta <= delay);
     2102                last = now;
     2103        }
     2104
     2105        function onTouchEnd(e) {
     2106                if (doubleTap && !touch$$1.cancelBubble) {
     2107                        if (pointer) {
     2108                                if ((!edge) || e.pointerType === 'mouse') { return; }
     2109                                // work around .type being readonly with MSPointer* events
     2110                                var newTouch = {},
     2111                                    prop, i;
     2112
     2113                                for (i in touch$$1) {
     2114                                        prop = touch$$1[i];
     2115                                        newTouch[i] = prop && prop.bind ? prop.bind(touch$$1) : prop;
     2116                                }
     2117                                touch$$1 = newTouch;
     2118                        }
     2119                        touch$$1.type = 'dblclick';
     2120                        handler(touch$$1);
     2121                        last = null;
     2122                }
     2123        }
     2124
     2125        obj[_pre + _touchstart + id] = onTouchStart;
     2126        obj[_pre + _touchend + id] = onTouchEnd;
     2127        obj[_pre + 'dblclick' + id] = handler;
     2128
     2129        obj.addEventListener(_touchstart, onTouchStart, false);
     2130        obj.addEventListener(_touchend, onTouchEnd, false);
     2131
     2132        // On some platforms (notably, chrome<55 on win10 + touchscreen + mouse),
     2133        // the browser doesn't fire touchend/pointerup events but does fire
     2134        // native dblclicks. See #4127.
     2135        // Edge 14 also fires native dblclicks, but only for pointerType mouse, see #5180.
     2136        obj.addEventListener('dblclick', handler, false);
     2137
     2138        return this;
     2139}
     2140
     2141function removeDoubleTapListener(obj, id) {
     2142        var touchstart = obj[_pre + _touchstart + id],
     2143            touchend = obj[_pre + _touchend + id],
     2144            dblclick = obj[_pre + 'dblclick' + id];
     2145
     2146        obj.removeEventListener(_touchstart, touchstart, false);
     2147        obj.removeEventListener(_touchend, touchend, false);
     2148        if (!edge) {
     2149                obj.removeEventListener('dblclick', dblclick, false);
     2150        }
     2151
     2152        return this;
     2153}
     2154
     2155/*
     2156 * @namespace DomEvent
     2157 * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally.
     2158 */
     2159
     2160// Inspired by John Resig, Dean Edwards and YUI addEvent implementations.
     2161
     2162// @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this
     2163// Adds a listener function (`fn`) to a particular DOM event type of the
     2164// element `el`. You can optionally specify the context of the listener
     2165// (object the `this` keyword will point to). You can also pass several
     2166// space-separated types (e.g. `'click dblclick'`).
     2167
     2168// @alternative
     2169// @function on(el: HTMLElement, eventMap: Object, context?: Object): this
     2170// Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
     2171function on(obj, types, fn, context) {
     2172
     2173        if (typeof types === 'object') {
     2174                for (var type in types) {
     2175                        addOne(obj, type, types[type], fn);
     2176                }
     2177        } else {
     2178                types = splitWords(types);
     2179
     2180                for (var i = 0, len = types.length; i < len; i++) {
     2181                        addOne(obj, types[i], fn, context);
     2182                }
     2183        }
     2184
     2185        return this;
     2186}
     2187
     2188var eventsKey = '_leaflet_events';
     2189
     2190// @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.
     2193// Note that if you passed a custom context to on, you must pass the same
     2194// context to `off` in order to remove the listener.
     2195
     2196// @alternative
     2197// @function off(el: HTMLElement, eventMap: Object, context?: Object): this
     2198// 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
     2203function off(obj, types, fn, context) {
     2204
     2205        if (typeof types === 'object') {
     2206                for (var type in types) {
     2207                        removeOne(obj, type, types[type], fn);
     2208                }
     2209        } else if (types) {
     2210                types = splitWords(types);
     2211
     2212                for (var i = 0, len = types.length; i < len; i++) {
     2213                        removeOne(obj, types[i], fn, context);
     2214                }
     2215        } else {
     2216                for (var j in obj[eventsKey]) {
     2217                        removeOne(obj, j, obj[eventsKey][j]);
     2218                }
     2219                delete obj[eventsKey];
     2220        }
     2221
     2222        return this;
     2223}
     2224
     2225function addOne(obj, type, fn, context) {
     2226        var id = type + stamp(fn) + (context ? '_' + stamp(context) : '');
     2227
     2228        if (obj[eventsKey] && obj[eventsKey][id]) { return this; }
     2229
     2230        var handler = function (e) {
     2231                return fn.call(context || obj, e || window.event);
     2232        };
     2233
     2234        var originalHandler = handler;
     2235
     2236        if (pointer && type.indexOf('touch') === 0) {
     2237                // Needs DomEvent.Pointer.js
     2238                addPointerListener(obj, type, handler, id);
     2239
     2240        } else if (touch && (type === 'dblclick') && addDoubleTapListener &&
     2241                   !(pointer && chrome)) {
     2242                // Chrome >55 does not need the synthetic dblclicks from addDoubleTapListener
     2243                // See #5180
     2244                addDoubleTapListener(obj, handler, id);
     2245
     2246        } else if ('addEventListener' in obj) {
     2247
     2248                if (type === 'mousewheel') {
     2249                        obj.addEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false);
     2250
     2251                } else if ((type === 'mouseenter') || (type === 'mouseleave')) {
     2252                        handler = function (e) {
     2253                                e = e || window.event;
     2254                                if (isExternalTarget(obj, e)) {
     2255                                        originalHandler(e);
     2256                                }
     2257                        };
     2258                        obj.addEventListener(type === 'mouseenter' ? 'mouseover' : 'mouseout', handler, false);
     2259
     2260                } else {
     2261                        if (type === 'click' && android) {
     2262                                handler = function (e) {
     2263                                        filterClick(e, originalHandler);
     2264                                };
     2265                        }
     2266                        obj.addEventListener(type, handler, false);
     2267                }
     2268
     2269        } else if ('attachEvent' in obj) {
     2270                obj.attachEvent('on' + type, handler);
     2271        }
     2272
     2273        obj[eventsKey] = obj[eventsKey] || {};
     2274        obj[eventsKey][id] = handler;
     2275}
     2276
     2277function removeOne(obj, type, fn, context) {
     2278
     2279        var id = type + stamp(fn) + (context ? '_' + stamp(context) : ''),
     2280            handler = obj[eventsKey] && obj[eventsKey][id];
     2281
     2282        if (!handler) { return this; }
     2283
     2284        if (pointer && type.indexOf('touch') === 0) {
     2285                removePointerListener(obj, type, id);
     2286
     2287        } else if (touch && (type === 'dblclick') && removeDoubleTapListener) {
     2288                removeDoubleTapListener(obj, id);
     2289
     2290        } else if ('removeEventListener' in obj) {
     2291
     2292                if (type === 'mousewheel') {
     2293                        obj.removeEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false);
     2294
     2295                } else {
     2296                        obj.removeEventListener(
     2297                                type === 'mouseenter' ? 'mouseover' :
     2298                                type === 'mouseleave' ? 'mouseout' : type, handler, false);
     2299                }
     2300
     2301        } else if ('detachEvent' in obj) {
     2302                obj.detachEvent('on' + type, handler);
     2303        }
     2304
     2305        obj[eventsKey][id] = null;
     2306}
     2307
     2308// @function stopPropagation(ev: DOMEvent): this
     2309// Stop the given event from propagation to parent elements. Used inside the listener functions:
     2310// ```js
     2311// L.DomEvent.on(div, 'click', function (ev) {
     2312//      L.DomEvent.stopPropagation(ev);
     2313// });
     2314// ```
     2315function stopPropagation(e) {
     2316
     2317        if (e.stopPropagation) {
     2318                e.stopPropagation();
     2319        } else if (e.originalEvent) {  // In case of Leaflet event.
     2320                e.originalEvent._stopped = true;
     2321        } else {
     2322                e.cancelBubble = true;
     2323        }
     2324        skipped(e);
     2325
     2326        return this;
     2327}
     2328
     2329// @function disableScrollPropagation(el: HTMLElement): this
     2330// Adds `stopPropagation` to the element's `'mousewheel'` events (plus browser variants).
     2331function disableScrollPropagation(el) {
     2332        addOne(el, 'mousewheel', stopPropagation);
     2333        return this;
     2334}
     2335
     2336// @function disableClickPropagation(el: HTMLElement): this
     2337// Adds `stopPropagation` to the element's `'click'`, `'doubleclick'`,
     2338// `'mousedown'` and `'touchstart'` events (plus browser variants).
     2339function disableClickPropagation(el) {
     2340        on(el, 'mousedown touchstart dblclick', stopPropagation);
     2341        addOne(el, 'click', fakeStop);
     2342        return this;
     2343}
     2344
     2345// @function preventDefault(ev: DOMEvent): this
     2346// Prevents the default action of the DOM Event `ev` from happening (such as
     2347// following a link in the href of the a element, or doing a POST request
     2348// with page reload when a `<form>` is submitted).
     2349// Use it inside listener functions.
     2350function preventDefault(e) {
     2351        if (e.preventDefault) {
     2352                e.preventDefault();
     2353        } else {
     2354                e.returnValue = false;
     2355        }
     2356        return this;
     2357}
     2358
     2359// @function stop(ev): this
     2360// Does `stopPropagation` and `preventDefault` at the same time.
     2361function stop(e) {
     2362        preventDefault(e);
     2363        stopPropagation(e);
     2364        return this;
     2365}
     2366
     2367// @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point
     2368// Gets normalized mouse position from a DOM event relative to the
     2369// `container` or to the whole page if not specified.
     2370function getMousePosition(e, container) {
     2371        if (!container) {
     2372                return new Point(e.clientX, e.clientY);
     2373        }
     2374
     2375        var rect = container.getBoundingClientRect();
     2376
     2377        return new Point(
     2378                e.clientX - rect.left - container.clientLeft,
     2379                e.clientY - rect.top - container.clientTop);
     2380}
     2381
     2382// Chrome on Win scrolls double the pixels as in other platforms (see #4538),
     2383// and Firefox scrolls device pixels, not CSS pixels
     2384var wheelPxFactor =
     2385        (win && chrome) ? 2 * window.devicePixelRatio :
     2386        gecko ? window.devicePixelRatio : 1;
     2387
     2388// @function getWheelDelta(ev: DOMEvent): Number
     2389// Gets normalized wheel delta from a mousewheel DOM event, in vertical
     2390// pixels scrolled (negative if scrolling down).
     2391// Events from pointing devices without precise scrolling are mapped to
     2392// a best guess of 60 pixels.
     2393function getWheelDelta(e) {
     2394        return (edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta
     2395               (e.deltaY && e.deltaMode === 0) ? -e.deltaY / wheelPxFactor : // Pixels
     2396               (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines
     2397               (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages
     2398               (e.deltaX || e.deltaZ) ? 0 :     // Skip horizontal/depth wheel events
     2399               e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels
     2400               (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines
     2401               e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages
     2402               0;
     2403}
     2404
     2405var skipEvents = {};
     2406
     2407function fakeStop(e) {
     2408        // fakes stopPropagation by setting a special event flag, checked/reset with skipped(e)
     2409        skipEvents[e.type] = true;
     2410}
     2411
     2412function skipped(e) {
     2413        var events = skipEvents[e.type];
     2414        // reset when checking, as it's only used in map container and propagates outside of the map
     2415        skipEvents[e.type] = false;
     2416        return events;
     2417}
     2418
     2419// check if element really left/entered the event target (for mouseenter/mouseleave)
     2420function isExternalTarget(el, e) {
     2421
     2422        var related = e.relatedTarget;
     2423
     2424        if (!related) { return true; }
     2425
     2426        try {
     2427                while (related && (related !== el)) {
     2428                        related = related.parentNode;
     2429                }
     2430        } catch (err) {
     2431                return false;
     2432        }
     2433        return (related !== el);
     2434}
     2435
     2436var lastClick;
     2437
     2438// this is a horrible workaround for a bug in Android where a single touch triggers two click events
     2439function filterClick(e, handler) {
     2440        var timeStamp = (e.timeStamp || (e.originalEvent && e.originalEvent.timeStamp)),
     2441            elapsed = lastClick && (timeStamp - lastClick);
     2442
     2443        // are they closer together than 500ms yet more than 100ms?
     2444        // Android typically triggers them ~300ms apart while multiple listeners
     2445        // on the same event should be triggered far faster;
     2446        // or check if click is simulated on the element, and if it is, reject any non-simulated events
     2447
     2448        if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) {
     2449                stop(e);
     2450                return;
     2451        }
     2452        lastClick = timeStamp;
     2453
     2454        handler(e);
     2455}
     2456
     2457
     2458
     2459
     2460var DomEvent = (Object.freeze || Object)({
     2461        on: on,
     2462        off: off,
     2463        stopPropagation: stopPropagation,
     2464        disableScrollPropagation: disableScrollPropagation,
     2465        disableClickPropagation: disableClickPropagation,
     2466        preventDefault: preventDefault,
     2467        stop: stop,
     2468        getMousePosition: getMousePosition,
     2469        getWheelDelta: getWheelDelta,
     2470        fakeStop: fakeStop,
     2471        skipped: skipped,
     2472        isExternalTarget: isExternalTarget,
     2473        addListener: on,
     2474        removeListener: off
     2475});
     2476
     2477/*
     2478 * @namespace DomUtil
     2479 *
     2480 * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)
     2481 * tree, used by Leaflet internally.
     2482 *
     2483 * Most functions expecting or returning a `HTMLElement` also work for
     2484 * SVG elements. The only difference is that classes refer to CSS classes
     2485 * in HTML and SVG classes in SVG.
     2486 */
     2487
     2488
     2489// @property TRANSFORM: String
     2490// Vendor-prefixed transform style name (e.g. `'webkitTransform'` for WebKit).
     2491var TRANSFORM = testProp(
     2492        ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
     2493
     2494// webkitTransition comes first because some browser versions that drop vendor prefix don't do
     2495// the same for the transitionend event, in particular the Android 4.1 stock browser
     2496
     2497// @property TRANSITION: String
     2498// Vendor-prefixed transition style name.
     2499var TRANSITION = testProp(
     2500        ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);
     2501
     2502// @property TRANSITION_END: String
     2503// Vendor-prefixed transitionend event name.
     2504var TRANSITION_END =
     2505        TRANSITION === 'webkitTransition' || TRANSITION === 'OTransition' ? TRANSITION + 'End' : 'transitionend';
     2506
     2507
     2508// @function get(id: String|HTMLElement): HTMLElement
     2509// Returns an element given its DOM id, or returns the element itself
     2510// if it was passed directly.
     2511function get(id) {
     2512        return typeof id === 'string' ? document.getElementById(id) : id;
     2513}
     2514
     2515// @function getStyle(el: HTMLElement, styleAttrib: String): String
     2516// Returns the value for a certain style attribute on an element,
     2517// including computed values or values set through CSS.
     2518function getStyle(el, style) {
     2519        var value = el.style[style] || (el.currentStyle && el.currentStyle[style]);
     2520
     2521        if ((!value || value === 'auto') && document.defaultView) {
     2522                var css = document.defaultView.getComputedStyle(el, null);
     2523                value = css ? css[style] : null;
     2524        }
     2525        return value === 'auto' ? null : value;
     2526}
     2527
     2528// @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement
     2529// Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element.
     2530function create$1(tagName, className, container) {
     2531        var el = document.createElement(tagName);
     2532        el.className = className || '';
     2533
     2534        if (container) {
     2535                container.appendChild(el);
     2536        }
     2537        return el;
     2538}
     2539
     2540// @function remove(el: HTMLElement)
     2541// Removes `el` from its parent element
     2542function remove(el) {
     2543        var parent = el.parentNode;
     2544        if (parent) {
     2545                parent.removeChild(el);
     2546        }
     2547}
     2548
     2549// @function empty(el: HTMLElement)
     2550// Removes all of `el`'s children elements from `el`
     2551function empty(el) {
     2552        while (el.firstChild) {
     2553                el.removeChild(el.firstChild);
     2554        }
     2555}
     2556
     2557// @function toFront(el: HTMLElement)
     2558// Makes `el` the last child of its parent, so it renders in front of the other children.
     2559function toFront(el) {
     2560        var parent = el.parentNode;
     2561        if (parent.lastChild !== el) {
     2562                parent.appendChild(el);
     2563        }
     2564}
     2565
     2566// @function toBack(el: HTMLElement)
     2567// Makes `el` the first child of its parent, so it renders behind the other children.
     2568function toBack(el) {
     2569        var parent = el.parentNode;
     2570        if (parent.firstChild !== el) {
     2571                parent.insertBefore(el, parent.firstChild);
     2572        }
     2573}
     2574
     2575// @function hasClass(el: HTMLElement, name: String): Boolean
     2576// Returns `true` if the element's class attribute contains `name`.
     2577function hasClass(el, name) {
     2578        if (el.classList !== undefined) {
     2579                return el.classList.contains(name);
     2580        }
     2581        var className = getClass(el);
     2582        return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className);
     2583}
     2584
     2585// @function addClass(el: HTMLElement, name: String)
     2586// Adds `name` to the element's class attribute.
     2587function addClass(el, name) {
     2588        if (el.classList !== undefined) {
     2589                var classes = splitWords(name);
     2590                for (var i = 0, len = classes.length; i < len; i++) {
     2591                        el.classList.add(classes[i]);
     2592                }
     2593        } else if (!hasClass(el, name)) {
     2594                var className = getClass(el);
     2595                setClass(el, (className ? className + ' ' : '') + name);
     2596        }
     2597}
     2598
     2599// @function removeClass(el: HTMLElement, name: String)
     2600// Removes `name` from the element's class attribute.
     2601function removeClass(el, name) {
     2602        if (el.classList !== undefined) {
     2603                el.classList.remove(name);
     2604        } else {
     2605                setClass(el, trim((' ' + getClass(el) + ' ').replace(' ' + name + ' ', ' ')));
     2606        }
     2607}
     2608
     2609// @function setClass(el: HTMLElement, name: String)
     2610// Sets the element's class.
     2611function setClass(el, name) {
     2612        if (el.className.baseVal === undefined) {
     2613                el.className = name;
     2614        } else {
     2615                // in case of SVG element
     2616                el.className.baseVal = name;
     2617        }
     2618}
     2619
     2620// @function getClass(el: HTMLElement): String
     2621// Returns the element's class.
     2622function getClass(el) {
     2623        return el.className.baseVal === undefined ? el.className : el.className.baseVal;
     2624}
     2625
     2626// @function setOpacity(el: HTMLElement, opacity: Number)
     2627// Set the opacity of an element (including old IE support).
     2628// `opacity` must be a number from `0` to `1`.
     2629function setOpacity(el, value) {
     2630        if ('opacity' in el.style) {
     2631                el.style.opacity = value;
     2632        } else if ('filter' in el.style) {
     2633                _setOpacityIE(el, value);
     2634        }
     2635}
     2636
     2637function _setOpacityIE(el, value) {
     2638        var filter = false,
     2639            filterName = 'DXImageTransform.Microsoft.Alpha';
     2640
     2641        // filters collection throws an error if we try to retrieve a filter that doesn't exist
     2642        try {
     2643                filter = el.filters.item(filterName);
     2644        } catch (e) {
     2645                // don't set opacity to 1 if we haven't already set an opacity,
     2646                // it isn't needed and breaks transparent pngs.
     2647                if (value === 1) { return; }
     2648        }
     2649
     2650        value = Math.round(value * 100);
     2651
     2652        if (filter) {
     2653                filter.Enabled = (value !== 100);
     2654                filter.Opacity = value;
     2655        } else {
     2656                el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';
     2657        }
     2658}
     2659
     2660// @function testProp(props: String[]): String|false
     2661// Goes through the array of style names and returns the first name
     2662// that is a valid style name for an element. If no such name is found,
     2663// it returns false. Useful for vendor-prefixed styles like `transform`.
     2664function testProp(props) {
     2665        var style = document.documentElement.style;
     2666
     2667        for (var i = 0; i < props.length; i++) {
     2668                if (props[i] in style) {
     2669                        return props[i];
     2670                }
     2671        }
     2672        return false;
     2673}
     2674
     2675// @function setTransform(el: HTMLElement, offset: Point, scale?: Number)
     2676// Resets the 3D CSS transform of `el` so it is translated by `offset` pixels
     2677// and optionally scaled by `scale`. Does not have an effect if the
     2678// browser doesn't support 3D CSS transforms.
     2679function setTransform(el, offset, scale) {
     2680        var pos = offset || new Point(0, 0);
     2681
     2682        el.style[TRANSFORM] =
     2683                (ie3d ?
     2684                        'translate(' + pos.x + 'px,' + pos.y + 'px)' :
     2685                        'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') +
     2686                (scale ? ' scale(' + scale + ')' : '');
     2687}
     2688
     2689// @function setPosition(el: HTMLElement, position: Point)
     2690// Sets the position of `el` to coordinates specified by `position`,
     2691// using CSS translate or top/left positioning depending on the browser
     2692// (used by Leaflet internally to position its layers).
     2693function setPosition(el, point) {
     2694
     2695        /*eslint-disable */
     2696        el._leaflet_pos = point;
     2697        /*eslint-enable */
     2698
     2699        if (any3d) {
     2700                setTransform(el, point);
     2701        } else {
     2702                el.style.left = point.x + 'px';
     2703                el.style.top = point.y + 'px';
     2704        }
     2705}
     2706
     2707// @function getPosition(el: HTMLElement): Point
     2708// Returns the coordinates of an element previously positioned with setPosition.
     2709function getPosition(el) {
     2710        // this method is only used for elements previously positioned using setPosition,
     2711        // so it's safe to cache the position for performance
     2712
     2713        return el._leaflet_pos || new Point(0, 0);
     2714}
     2715
     2716// @function disableTextSelection()
     2717// Prevents the user from generating `selectstart` DOM events, usually generated
     2718// when the user drags the mouse through a page with text. Used internally
     2719// by Leaflet to override the behaviour of any click-and-drag interaction on
     2720// the map. Affects drag interactions on the whole document.
     2721
     2722// @function enableTextSelection()
     2723// Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection).
     2724var disableTextSelection;
     2725var enableTextSelection;
     2726var _userSelect;
     2727if ('onselectstart' in document) {
     2728        disableTextSelection = function () {
     2729                on(window, 'selectstart', preventDefault);
     2730        };
     2731        enableTextSelection = function () {
     2732                off(window, 'selectstart', preventDefault);
     2733        };
     2734} else {
     2735        var userSelectProperty = testProp(
     2736                ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
     2737
     2738        disableTextSelection = function () {
     2739                if (userSelectProperty) {
     2740                        var style = document.documentElement.style;
     2741                        _userSelect = style[userSelectProperty];
     2742                        style[userSelectProperty] = 'none';
     2743                }
     2744        };
     2745        enableTextSelection = function () {
     2746                if (userSelectProperty) {
     2747                        document.documentElement.style[userSelectProperty] = _userSelect;
     2748                        _userSelect = undefined;
     2749                }
     2750        };
     2751}
     2752
     2753// @function disableImageDrag()
     2754// As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but
     2755// for `dragstart` DOM events, usually generated when the user drags an image.
     2756function disableImageDrag() {
     2757        on(window, 'dragstart', preventDefault);
     2758}
     2759
     2760// @function enableImageDrag()
     2761// Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection).
     2762function enableImageDrag() {
     2763        off(window, 'dragstart', preventDefault);
     2764}
     2765
     2766var _outlineElement;
     2767var _outlineStyle;
     2768// @function preventOutline(el: HTMLElement)
     2769// Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline)
     2770// of the element `el` invisible. Used internally by Leaflet to prevent
     2771// focusable elements from displaying an outline when the user performs a
     2772// drag interaction on them.
     2773function preventOutline(element) {
     2774        while (element.tabIndex === -1) {
     2775                element = element.parentNode;
     2776        }
     2777        if (!element.style) { return; }
     2778        restoreOutline();
     2779        _outlineElement = element;
     2780        _outlineStyle = element.style.outline;
     2781        element.style.outline = 'none';
     2782        on(window, 'keydown', restoreOutline);
     2783}
     2784
     2785// @function restoreOutline()
     2786// Cancels the effects of a previous [`L.DomUtil.preventOutline`]().
     2787function restoreOutline() {
     2788        if (!_outlineElement) { return; }
     2789        _outlineElement.style.outline = _outlineStyle;
     2790        _outlineElement = undefined;
     2791        _outlineStyle = undefined;
     2792        off(window, 'keydown', restoreOutline);
     2793}
     2794
     2795
     2796var DomUtil = (Object.freeze || Object)({
     2797        TRANSFORM: TRANSFORM,
     2798        TRANSITION: TRANSITION,
     2799        TRANSITION_END: TRANSITION_END,
     2800        get: get,
     2801        getStyle: getStyle,
     2802        create: create$1,
     2803        remove: remove,
     2804        empty: empty,
     2805        toFront: toFront,
     2806        toBack: toBack,
     2807        hasClass: hasClass,
     2808        addClass: addClass,
     2809        removeClass: removeClass,
     2810        setClass: setClass,
     2811        getClass: getClass,
     2812        setOpacity: setOpacity,
     2813        testProp: testProp,
     2814        setTransform: setTransform,
     2815        setPosition: setPosition,
     2816        getPosition: getPosition,
     2817        disableTextSelection: disableTextSelection,
     2818        enableTextSelection: enableTextSelection,
     2819        disableImageDrag: disableImageDrag,
     2820        enableImageDrag: enableImageDrag,
     2821        preventOutline: preventOutline,
     2822        restoreOutline: restoreOutline
     2823});
     2824
     2825/*
     2826 * @class PosAnimation
     2827 * @aka L.PosAnimation
     2828 * @inherits Evented
     2829 * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9.
     2830 *
     2831 * @example
     2832 * ```js
     2833 * var fx = new L.PosAnimation();
     2834 * fx.run(el, [300, 500], 0.5);
     2835 * ```
     2836 *
     2837 * @constructor L.PosAnimation()
     2838 * Creates a `PosAnimation` object.
     2839 *
     2840 */
     2841
     2842var PosAnimation = Evented.extend({
     2843
     2844        // @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)
     2845        // Run an animation of a given element to a new position, optionally setting
     2846        // duration in seconds (`0.25` by default) and easing linearity factor (3rd
     2847        // argument of the [cubic bezier curve](http://cubic-bezier.com/#0,0,.5,1),
     2848        // `0.5` by default).
     2849        run: function (el, newPos, duration, easeLinearity) {
     2850                this.stop();
     2851
     2852                this._el = el;
     2853                this._inProgress = true;
     2854                this._duration = duration || 0.25;
     2855                this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);
     2856
     2857                this._startPos = getPosition(el);
     2858                this._offset = newPos.subtract(this._startPos);
     2859                this._startTime = +new Date();
     2860
     2861                // @event start: Event
     2862                // Fired when the animation starts
     2863                this.fire('start');
     2864
     2865                this._animate();
     2866        },
     2867
     2868        // @method stop()
     2869        // Stops the animation (if currently running).
     2870        stop: function () {
     2871                if (!this._inProgress) { return; }
     2872
     2873                this._step(true);
     2874                this._complete();
     2875        },
     2876
     2877        _animate: function () {
     2878                // animation loop
     2879                this._animId = requestAnimFrame(this._animate, this);
     2880                this._step();
     2881        },
     2882
     2883        _step: function (round) {
     2884                var elapsed = (+new Date()) - this._startTime,
     2885                    duration = this._duration * 1000;
     2886
     2887                if (elapsed < duration) {
     2888                        this._runFrame(this._easeOut(elapsed / duration), round);
     2889                } else {
     2890                        this._runFrame(1);
     2891                        this._complete();
     2892                }
     2893        },
     2894
     2895        _runFrame: function (progress, round) {
     2896                var pos = this._startPos.add(this._offset.multiplyBy(progress));
     2897                if (round) {
     2898                        pos._round();
     2899                }
     2900                setPosition(this._el, pos);
     2901
     2902                // @event step: Event
     2903                // Fired continuously during the animation.
     2904                this.fire('step');
     2905        },
     2906
     2907        _complete: function () {
     2908                cancelAnimFrame(this._animId);
     2909
     2910                this._inProgress = false;
     2911                // @event end: Event
     2912                // Fired when the animation ends.
     2913                this.fire('end');
     2914        },
     2915
     2916        _easeOut: function (t) {
     2917                return 1 - Math.pow(1 - t, this._easeOutPower);
     2918        }
     2919});
    22822920
    22832921/*
     
    23002938 */
    23012939
    2302 L.Map = L.Evented.extend({
     2940var Map = Evented.extend({
    23032941
    23042942        options: {
     
    23072945                // The [Coordinate Reference System](#crs) to use. Don't change this if you're not
    23082946                // sure what it means.
    2309                 crs: L.CRS.EPSG3857,
     2947                crs: EPSG3857,
    23102948
    23112949                // @option center: LatLng = undefined
     
    23172955                zoom: undefined,
    23182956
    2319                 // @option minZoom: Number = undefined
    2320                 // Minimum zoom level of the map. Overrides any `minZoom` option set on map layers.
     2957                // @option minZoom: Number = *
     2958                // Minimum zoom level of the map.
     2959                // If not specified and at least one `GridLayer` or `TileLayer` is in the map,
     2960                // the lowest of their `minZoom` options will be used instead.
    23212961                minZoom: undefined,
    23222962
    2323                 // @option maxZoom: Number = undefined
    2324                 // Maximum zoom level of the map. Overrides any `maxZoom` option set on map layers.
     2963                // @option maxZoom: Number = *
     2964                // Maximum zoom level of the map.
     2965                // If not specified and at least one `GridLayer` or `TileLayer` is in the map,
     2966                // the highest of their `maxZoom` options will be used instead.
    23252967                maxZoom: undefined,
    23262968
     
    23913033
    23923034        initialize: function (id, options) { // (HTMLElement or String, Object)
    2393                 options = L.setOptions(this, options);
     3035                options = setOptions(this, options);
    23943036
    23953037                this._initContainer(id);
     
    23973039
    23983040                // hack for https://github.com/Leaflet/Leaflet/issues/1980
    2399                 this._onResize = L.bind(this._onResize, this);
     3041                this._onResize = bind(this._onResize, this);
    24003042
    24013043                this._initEvents();
     
    24103052
    24113053                if (options.center && options.zoom !== undefined) {
    2412                         this.setView(L.latLng(options.center), options.zoom, {reset: true});
     3054                        this.setView(toLatLng(options.center), options.zoom, {reset: true});
    24133055                }
    24143056
     
    24213063
    24223064                // don't animate on browsers without hardware-accelerated transitions or old Android/Opera
    2423                 this._zoomAnimated = L.DomUtil.TRANSITION && L.Browser.any3d && !L.Browser.mobileOpera &&
     3065                this._zoomAnimated = TRANSITION && any3d && !mobileOpera &&
    24243066                                this.options.zoomAnimation;
    24253067
     
    24283070                if (this._zoomAnimated) {
    24293071                        this._createAnimProxy();
    2430                         L.DomEvent.on(this._proxy, L.DomUtil.TRANSITION_END, this._catchTransitionEnd, this);
     3072                        on(this._proxy, TRANSITION_END, this._catchTransitionEnd, this);
    24313073                }
    24323074
     
    24433085
    24443086                zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
    2445                 center = this._limitCenter(L.latLng(center), zoom, this.options.maxBounds);
     3087                center = this._limitCenter(toLatLng(center), zoom, this.options.maxBounds);
    24463088                options = options || {};
    24473089
     
    24513093
    24523094                        if (options.animate !== undefined) {
    2453                                 options.zoom = L.extend({animate: options.animate}, options.zoom);
    2454                                 options.pan = L.extend({animate: options.animate, duration: options.duration}, options.pan);
     3095                                options.zoom = extend({animate: options.animate}, options.zoom);
     3096                                options.pan = extend({animate: options.animate, duration: options.duration}, options.pan);
    24553097                        }
    24563098
     
    24733115        },
    24743116
    2475         // @method setZoom(zoom: Number, options: Zoom/pan options): this
     3117        // @method setZoom(zoom: Number, options?: Zoom/pan options): this
    24763118        // Sets the zoom of the map.
    24773119        setZoom: function (zoom, options) {
     
    24863128        // Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
    24873129        zoomIn: function (delta, options) {
    2488                 delta = delta || (L.Browser.any3d ? this.options.zoomDelta : 1);
     3130                delta = delta || (any3d ? this.options.zoomDelta : 1);
    24893131                return this.setZoom(this._zoom + delta, options);
    24903132        },
     
    24933135        // Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
    24943136        zoomOut: function (delta, options) {
    2495                 delta = delta || (L.Browser.any3d ? this.options.zoomDelta : 1);
     3137                delta = delta || (any3d ? this.options.zoomDelta : 1);
    24963138                return this.setZoom(this._zoom - delta, options);
    24973139        },
     
    25063148                var scale = this.getZoomScale(zoom),
    25073149                    viewHalf = this.getSize().divideBy(2),
    2508                     containerPoint = latlng instanceof L.Point ? latlng : this.latLngToContainerPoint(latlng),
     3150                    containerPoint = latlng instanceof Point ? latlng : this.latLngToContainerPoint(latlng),
    25093151
    25103152                    centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),
     
    25173159
    25183160                options = options || {};
    2519                 bounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds);
    2520 
    2521                 var paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
    2522                     paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]),
     3161                bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);
     3162
     3163                var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
     3164                    paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
    25233165
    25243166                    zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
    25253167
    25263168                zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
     3169
     3170                if (zoom === Infinity) {
     3171                        return {
     3172                                center: bounds.getCenter(),
     3173                                zoom: zoom
     3174                        };
     3175                }
    25273176
    25283177                var paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),
     
    25433192        fitBounds: function (bounds, options) {
    25443193
    2545                 bounds = L.latLngBounds(bounds);
     3194                bounds = toLatLngBounds(bounds);
    25463195
    25473196                if (!bounds.isValid()) {
     
    25663215        },
    25673216
    2568         // @method panBy(offset: Point): this
     3217        // @method panBy(offset: Point, options?: Pan options): this
    25693218        // Pans the map by a given number of pixels (animated).
    25703219        panBy: function (offset, options) {
    2571                 offset = L.point(offset).round();
     3220                offset = toPoint(offset).round();
    25723221                options = options || {};
    25733222
     
    25833232
    25843233                if (!this._panAnim) {
    2585                         this._panAnim = new L.PosAnimation();
     3234                        this._panAnim = new PosAnimation();
    25863235
    25873236                        this._panAnim.on({
     
    25983247                // animate pan unless animate: false specified
    25993248                if (options.animate !== false) {
    2600                         L.DomUtil.addClass(this._mapPane, 'leaflet-pan-anim');
     3249                        addClass(this._mapPane, 'leaflet-pan-anim');
    26013250
    26023251                        var newPos = this._getMapPanePos().subtract(offset).round();
     
    26163265
    26173266                options = options || {};
    2618                 if (options.animate === false || !L.Browser.any3d) {
     3267                if (options.animate === false || !any3d) {
    26193268                        return this.setView(targetCenter, targetZoom, options);
    26203269                }
     
    26273276                    startZoom = this._zoom;
    26283277
    2629                 targetCenter = L.latLng(targetCenter);
     3278                targetCenter = toLatLng(targetCenter);
    26303279                targetZoom = targetZoom === undefined ? startZoom : targetZoom;
    26313280
     
    26713320
    26723321                        if (t <= 1) {
    2673                                 this._flyToFrame = L.Util.requestAnimFrame(frame, this);
     3322                                this._flyToFrame = requestAnimFrame(frame, this);
    26743323
    26753324                                this._move(
     
    27023351        // Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option).
    27033352        setMaxBounds: function (bounds) {
    2704                 bounds = L.latLngBounds(bounds);
     3353                bounds = toLatLngBounds(bounds);
    27053354
    27063355                if (!bounds.isValid()) {
     
    27493398                this._enforcingBounds = true;
    27503399                var center = this.getCenter(),
    2751                     newCenter = this._limitCenter(center, this._zoom, L.latLngBounds(bounds));
     3400                    newCenter = this._limitCenter(center, this._zoom, toLatLngBounds(bounds));
    27523401
    27533402                if (!center.equals(newCenter)) {
     
    27753424                if (!this._loaded) { return this; }
    27763425
    2777                 options = L.extend({
     3426                options = extend({
    27783427                        animate: false,
    27793428                        pan: true
     
    28033452                        if (options.debounceMoveend) {
    28043453                                clearTimeout(this._sizeTimer);
    2805                                 this._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200);
     3454                                this._sizeTimer = setTimeout(bind(this.fire, this, 'moveend'), 200);
    28063455                        } else {
    28073456                                this.fire('moveend');
     
    28403489        locate: function (options) {
    28413490
    2842                 options = this._locateOptions = L.extend({
     3491                options = this._locateOptions = extend({
    28433492                        timeout: 10000,
    28443493                        watch: false
     
    28573506                }
    28583507
    2859                 var onResponse = L.bind(this._handleGeolocationResponse, this),
    2860                     onError = L.bind(this._handleGeolocationError, this);
     3508                var onResponse = bind(this._handleGeolocationResponse, this),
     3509                    onError = bind(this._handleGeolocationError, this);
    28613510
    28623511                if (options.watch) {
     
    29053554                var lat = pos.coords.latitude,
    29063555                    lng = pos.coords.longitude,
    2907                     latlng = new L.LatLng(lat, lng),
     3556                    latlng = new LatLng(lat, lng),
    29083557                    bounds = latlng.toBounds(pos.coords.accuracy),
    29093558                    options = this._locateOptions;
     
    29723621                }
    29733622
    2974                 L.DomUtil.remove(this._mapPane);
     3623                remove(this._mapPane);
    29753624
    29763625                if (this._clearControlPos) {
     
    29873636                }
    29883637
    2989                 for (var i in this._layers) {
     3638                var i;
     3639                for (i in this._layers) {
    29903640                        this._layers[i].remove();
    29913641                }
     3642                for (i in this._panes) {
     3643                        remove(this._panes[i]);
     3644                }
     3645
     3646                this._layers = [];
     3647                this._panes = [];
     3648                delete this._mapPane;
     3649                delete this._renderer;
    29923650
    29933651                return this;
     
    29973655        // @method createPane(name: String, container?: HTMLElement): HTMLElement
    29983656        // Creates a new [map pane](#map-pane) with the given name if it doesn't exist already,
    2999         // then returns it. The pane is created as a children of `container`, or
    3000         // as a children of the main map pane if not set.
     3657        // then returns it. The pane is created as a child of `container`, or
     3658        // as a child of the main map pane if not set.
    30013659        createPane: function (name, container) {
    30023660                var className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''),
    3003                     pane = L.DomUtil.create('div', className, container || this._mapPane);
     3661                    pane = create$1('div', className, container || this._mapPane);
    30043662
    30053663                if (name) {
     
    30353693                    ne = this.unproject(bounds.getTopRight());
    30363694
    3037                 return new L.LatLngBounds(sw, ne);
     3695                return new LatLngBounds(sw, ne);
    30383696        },
    30393697
     
    30583716        // the given bounds in its entirety.
    30593717        getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
    3060                 bounds = L.latLngBounds(bounds);
    3061                 padding = L.point(padding || [0, 0]);
     3718                bounds = toLatLngBounds(bounds);
     3719                padding = toPoint(padding || [0, 0]);
    30623720
    30633721                var zoom = this.getZoom() || 0,
     
    30673725                    se = bounds.getSouthEast(),
    30683726                    size = this.getSize().subtract(padding),
    3069                     boundsSize = L.bounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),
    3070                     snap = L.Browser.any3d ? this.options.zoomSnap : 1;
    3071 
    3072                 var scale = Math.min(size.x / boundsSize.x, size.y / boundsSize.y);
     3727                    boundsSize = toBounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),
     3728                    snap = any3d ? this.options.zoomSnap : 1,
     3729                    scalex = size.x / boundsSize.x,
     3730                    scaley = size.y / boundsSize.y,
     3731                    scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);
     3732
    30733733                zoom = this.getScaleZoom(scale, zoom);
    30743734
     
    30853745        getSize: function () {
    30863746                if (!this._size || this._sizeChanged) {
    3087                         this._size = new L.Point(
     3747                        this._size = new Point(
    30883748                                this._container.clientWidth || 0,
    30893749                                this._container.clientHeight || 0);
     
    30993759        getPixelBounds: function (center, zoom) {
    31003760                var topLeftPoint = this._getTopLeftPoint(center, zoom);
    3101                 return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
     3761                return new Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
    31023762        },
    31033763
     
    31723832        project: function (latlng, zoom) {
    31733833                zoom = zoom === undefined ? this._zoom : zoom;
    3174                 return this.options.crs.latLngToPoint(L.latLng(latlng), zoom);
     3834                return this.options.crs.latLngToPoint(toLatLng(latlng), zoom);
    31753835        },
    31763836
     
    31793839        unproject: function (point, zoom) {
    31803840                zoom = zoom === undefined ? this._zoom : zoom;
    3181                 return this.options.crs.pointToLatLng(L.point(point), zoom);
     3841                return this.options.crs.pointToLatLng(toPoint(point), zoom);
    31823842        },
    31833843
     
    31863846        // returns the corresponding geographical coordinate (for the current zoom level).
    31873847        layerPointToLatLng: function (point) {
    3188                 var projectedPoint = L.point(point).add(this.getPixelOrigin());
     3848                var projectedPoint = toPoint(point).add(this.getPixelOrigin());
    31893849                return this.unproject(projectedPoint);
    31903850        },
     
    31943854        // relative to the [origin pixel](#map-getpixelorigin).
    31953855        latLngToLayerPoint: function (latlng) {
    3196                 var projectedPoint = this.project(L.latLng(latlng))._round();
     3856                var projectedPoint = this.project(toLatLng(latlng))._round();
    31973857                return projectedPoint._subtract(this.getPixelOrigin());
    31983858        },
     
    32053865        // value is between -180 and +180 degrees.
    32063866        wrapLatLng: function (latlng) {
    3207                 return this.options.crs.wrapLatLng(L.latLng(latlng));
     3867                return this.options.crs.wrapLatLng(toLatLng(latlng));
    32083868        },
    32093869
     
    32153875        // overlaps the CRS's bounds.
    32163876        wrapLatLngBounds: function (latlng) {
    3217                 return this.options.crs.wrapLatLngBounds(L.latLngBounds(latlng));
     3877                return this.options.crs.wrapLatLngBounds(toLatLngBounds(latlng));
    32183878        },
    32193879
     
    32223882        // the map's CRS. By default this measures distance in meters.
    32233883        distance: function (latlng1, latlng2) {
    3224                 return this.options.crs.distance(L.latLng(latlng1), L.latLng(latlng2));
     3884                return this.options.crs.distance(toLatLng(latlng1), toLatLng(latlng2));
    32253885        },
    32263886
     
    32293889        // pixel coordinate relative to the [origin pixel](#map-getpixelorigin).
    32303890        containerPointToLayerPoint: function (point) { // (Point)
    3231                 return L.point(point).subtract(this._getMapPanePos());
     3891                return toPoint(point).subtract(this._getMapPanePos());
    32323892        },
    32333893
     
    32363896        // returns the corresponding pixel coordinate relative to the map container.
    32373897        layerPointToContainerPoint: function (point) { // (Point)
    3238                 return L.point(point).add(this._getMapPanePos());
     3898                return toPoint(point).add(this._getMapPanePos());
    32393899        },
    32403900
     
    32433903        // the corresponding geographical coordinate (for the current zoom level).
    32443904        containerPointToLatLng: function (point) {
    3245                 var layerPoint = this.containerPointToLayerPoint(L.point(point));
     3905                var layerPoint = this.containerPointToLayerPoint(toPoint(point));
    32463906                return this.layerPointToLatLng(layerPoint);
    32473907        },
     
    32513911        // relative to the map container.
    32523912        latLngToContainerPoint: function (latlng) {
    3253                 return this.layerPointToContainerPoint(this.latLngToLayerPoint(L.latLng(latlng)));
     3913                return this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng)));
    32543914        },
    32553915
     
    32583918        // map container where the event took place.
    32593919        mouseEventToContainerPoint: function (e) {
    3260                 return L.DomEvent.getMousePosition(e, this._container);
     3920                return getMousePosition(e, this._container);
    32613921        },
    32623922
     
    32793939
    32803940        _initContainer: function (id) {
    3281                 var container = this._container = L.DomUtil.get(id);
     3941                var container = this._container = get(id);
    32823942
    32833943                if (!container) {
     
    32873947                }
    32883948
    3289                 L.DomEvent.addListener(container, 'scroll', this._onScroll, this);
    3290                 this._containerId = L.Util.stamp(container);
     3949                on(container, 'scroll', this._onScroll, this);
     3950                this._containerId = stamp(container);
    32913951        },
    32923952
     
    32943954                var container = this._container;
    32953955
    3296                 this._fadeAnimated = this.options.fadeAnimation && L.Browser.any3d;
    3297 
    3298                 L.DomUtil.addClass(container, 'leaflet-container' +
    3299                         (L.Browser.touch ? ' leaflet-touch' : '') +
    3300                         (L.Browser.retina ? ' leaflet-retina' : '') +
    3301                         (L.Browser.ielt9 ? ' leaflet-oldie' : '') +
    3302                         (L.Browser.safari ? ' leaflet-safari' : '') +
     3956                this._fadeAnimated = this.options.fadeAnimation && any3d;
     3957
     3958                addClass(container, 'leaflet-container' +
     3959                        (touch ? ' leaflet-touch' : '') +
     3960                        (retina ? ' leaflet-retina' : '') +
     3961                        (ielt9 ? ' leaflet-oldie' : '') +
     3962                        (safari ? ' leaflet-safari' : '') +
    33033963                        (this._fadeAnimated ? ' leaflet-fade-anim' : ''));
    33043964
    3305                 var position = L.DomUtil.getStyle(container, 'position');
     3965                var position = getStyle(container, 'position');
    33063966
    33073967                if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') {
     
    33333993
    33343994                this._mapPane = this.createPane('mapPane', this._container);
    3335                 L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
     3995                setPosition(this._mapPane, new Point(0, 0));
    33363996
    33373997                // @pane tilePane: HTMLElement = 200
     
    33554015
    33564016                if (!this.options.markerZoomAnimation) {
    3357                         L.DomUtil.addClass(panes.markerPane, 'leaflet-zoom-hide');
    3358                         L.DomUtil.addClass(panes.shadowPane, 'leaflet-zoom-hide');
     4017                        addClass(panes.markerPane, 'leaflet-zoom-hide');
     4018                        addClass(panes.shadowPane, 'leaflet-zoom-hide');
    33594019                }
    33604020        },
     
    33654025        // @section Map state change events
    33664026        _resetView: function (center, zoom) {
    3367                 L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
     4027                setPosition(this._mapPane, new Point(0, 0));
    33684028
    33694029                var loading = !this._loaded;
     
    34404100
    34414101        _stop: function () {
    3442                 L.Util.cancelAnimFrame(this._flyToFrame);
     4102                cancelAnimFrame(this._flyToFrame);
    34434103                if (this._panAnim) {
    34444104                        this._panAnim.stop();
     
    34484108
    34494109        _rawPanBy: function (offset) {
    3450                 L.DomUtil.setPosition(this._mapPane, this._getMapPanePos().subtract(offset));
     4110                setPosition(this._mapPane, this._getMapPanePos().subtract(offset));
    34514111        },
    34524112
     
    34704130
    34714131        // @section Interaction events
    3472         _initEvents: function (remove) {
    3473                 if (!L.DomEvent) { return; }
    3474 
     4132        _initEvents: function (remove$$1) {
    34754133                this._targets = {};
    3476                 this._targets[L.stamp(this._container)] = this;
    3477 
    3478                 var onOff = remove ? 'off' : 'on';
     4134                this._targets[stamp(this._container)] = this;
     4135
     4136                var onOff = remove$$1 ? off : on;
    34794137
    34804138                // @event click: MouseEvent
     
    34994157                // @event keypress: KeyboardEvent
    35004158                // Fired when the user presses a key from the keyboard while the map is focused.
    3501                 L.DomEvent[onOff](this._container, 'click dblclick mousedown mouseup ' +
     4159                onOff(this._container, 'click dblclick mousedown mouseup ' +
    35024160                        'mouseover mouseout mousemove contextmenu keypress', this._handleDOMEvent, this);
    35034161
    35044162                if (this.options.trackResize) {
    3505                         L.DomEvent[onOff](window, 'resize', this._onResize, this);
    3506                 }
    3507 
    3508                 if (L.Browser.any3d && this.options.transform3DLimit) {
    3509                         this[onOff]('moveend', this._onMoveEnd);
     4163                        onOff(window, 'resize', this._onResize, this);
     4164                }
     4165
     4166                if (any3d && this.options.transform3DLimit) {
     4167                        (remove$$1 ? this.off : this.on).call(this, 'moveend', this._onMoveEnd);
    35104168                }
    35114169        },
    35124170
    35134171        _onResize: function () {
    3514                 L.Util.cancelAnimFrame(this._resizeRequest);
    3515                 this._resizeRequest = L.Util.requestAnimFrame(
     4172                cancelAnimFrame(this._resizeRequest);
     4173                this._resizeRequest = requestAnimFrame(
    35164174                        function () { this.invalidateSize({debounceMoveend: true}); }, this);
    35174175        },
     
    35394197
    35404198                while (src) {
    3541                         target = this._targets[L.stamp(src)];
     4199                        target = this._targets[stamp(src)];
    35424200                        if (target && (type === 'click' || type === 'preclick') && !e._simulated && this._draggableMoved(target)) {
    35434201                                // Prevent firing click after you just dragged an object.
     
    35464204                        }
    35474205                        if (target && target.listens(type, true)) {
    3548                                 if (isHover && !L.DomEvent._isExternalTarget(src, e)) { break; }
     4206                                if (isHover && !isExternalTarget(src, e)) { break; }
    35494207                                targets.push(target);
    35504208                                if (isHover) { break; }
     
    35534211                        src = src.parentNode;
    35544212                }
    3555                 if (!targets.length && !dragging && !isHover && L.DomEvent._isExternalTarget(src, e)) {
     4213                if (!targets.length && !dragging && !isHover && isExternalTarget(src, e)) {
    35564214                        targets = [this];
    35574215                }
     
    35604218
    35614219        _handleDOMEvent: function (e) {
    3562                 if (!this._loaded || L.DomEvent._skipped(e)) { return; }
    3563 
    3564                 var type = e.type === 'keypress' && e.keyCode === 13 ? 'click' : e.type;
    3565 
    3566                 if (type === 'mousedown') {
     4220                if (!this._loaded || skipped(e)) { return; }
     4221
     4222                var type = e.type;
     4223
     4224                if (type === 'mousedown' || type === 'keypress') {
    35674225                        // prevents outline when clicking on keyboard-focusable element
    3568                         L.DomUtil.preventOutline(e.target || e.srcElement);
     4226                        preventOutline(e.target || e.srcElement);
    35694227                }
    35704228
    35714229                this._fireDOMEvent(e, type);
    35724230        },
     4231
     4232        _mouseEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu'],
    35734233
    35744234        _fireDOMEvent: function (e, type, targets) {
     
    35804240                        // want something to happen on click before any existing click
    35814241                        // handlers start running).
    3582                         var synth = L.Util.extend({}, e);
     4242                        var synth = extend({}, e);
    35834243                        synth.type = 'preclick';
    35844244                        this._fireDOMEvent(synth, synth.type, targets);
     
    35944254                var target = targets[0];
    35954255                if (type === 'contextmenu' && target.listens(type, true)) {
    3596                         L.DomEvent.preventDefault(e);
     4256                        preventDefault(e);
    35974257                }
    35984258
     
    36024262
    36034263                if (e.type !== 'keypress') {
    3604                         var isMarker = target instanceof L.Marker;
     4264                        var isMarker = (target.options && 'icon' in target.options);
    36054265                        data.containerPoint = isMarker ?
    36064266                                        this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
     
    36124272                        targets[i].fire(type, data, true);
    36134273                        if (data.originalEvent._stopped ||
    3614                                 (targets[i].options.nonBubblingEvents && L.Util.indexOf(targets[i].options.nonBubblingEvents, type) !== -1)) { return; }
     4274                                (targets[i].options.bubblingMouseEvents === false && indexOf(this._mouseEvents, type) !== -1)) { return; }
    36154275                }
    36164276        },
     
    36464306
    36474307        _getMapPanePos: function () {
    3648                 return L.DomUtil.getPosition(this._mapPane) || new L.Point(0, 0);
     4308                return getPosition(this._mapPane) || new Point(0, 0);
    36494309        },
    36504310
     
    36734333        _latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) {
    36744334                var topLeft = this._getNewPixelOrigin(center, zoom);
    3675                 return L.bounds([
     4335                return toBounds([
    36764336                        this.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft),
    36774337                        this.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft),
     
    36984358                var centerPoint = this.project(center, zoom),
    36994359                    viewHalf = this.getSize().divideBy(2),
    3700                     viewBounds = new L.Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
     4360                    viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
    37014361                    offset = this._getBoundsOffset(viewBounds, bounds, zoom);
    37024362
     
    37164376
    37174377                var viewBounds = this.getPixelBounds(),
    3718                     newBounds = new L.Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));
     4378                    newBounds = new Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));
    37194379
    37204380                return offset.add(this._getBoundsOffset(newBounds, bounds));
     
    37234383        // returns offset needed for pxBounds to get inside maxBounds at a specified zoom
    37244384        _getBoundsOffset: function (pxBounds, maxBounds, zoom) {
    3725                 var projectedMaxBounds = L.bounds(
     4385                var projectedMaxBounds = toBounds(
    37264386                        this.project(maxBounds.getNorthEast(), zoom),
    37274387                        this.project(maxBounds.getSouthWest(), zoom)
     
    37334393                    dy = this._rebound(minOffset.y, -maxOffset.y);
    37344394
    3735                 return new L.Point(dx, dy);
     4395                return new Point(dx, dy);
    37364396        },
    37374397
     
    37454405                var min = this.getMinZoom(),
    37464406                    max = this.getMaxZoom(),
    3747                     snap = L.Browser.any3d ? this.options.zoomSnap : 1;
     4407                    snap = any3d ? this.options.zoomSnap : 1;
    37484408                if (snap) {
    37494409                        zoom = Math.round(zoom / snap) * snap;
     
    37574417
    37584418        _onPanTransitionEnd: function () {
    3759                 L.DomUtil.removeClass(this._mapPane, 'leaflet-pan-anim');
     4419                removeClass(this._mapPane, 'leaflet-pan-anim');
    37604420                this.fire('moveend');
    37614421        },
     
    37754435        _createAnimProxy: function () {
    37764436
    3777                 var proxy = this._proxy = L.DomUtil.create('div', 'leaflet-proxy leaflet-zoom-animated');
     4437                var proxy = this._proxy = create$1('div', 'leaflet-proxy leaflet-zoom-animated');
    37784438                this._panes.mapPane.appendChild(proxy);
    37794439
    37804440                this.on('zoomanim', function (e) {
    3781                         var prop = L.DomUtil.TRANSFORM,
    3782                             transform = proxy.style[prop];
    3783 
    3784                         L.DomUtil.setTransform(proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));
     4441                        var prop = TRANSFORM,
     4442                            transform = this._proxy.style[prop];
     4443
     4444                        setTransform(this._proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));
    37854445
    37864446                        // workaround for case when transform is the same and so transitionend event is not fired
    3787                         if (transform === proxy.style[prop] && this._animatingZoom) {
     4447                        if (transform === this._proxy.style[prop] && this._animatingZoom) {
    37884448                                this._onZoomTransitionEnd();
    37894449                        }
     
    37934453                        var c = this.getCenter(),
    37944454                            z = this.getZoom();
    3795                         L.DomUtil.setTransform(proxy, this.project(c, z), this.getZoomScale(z, 1));
     4455                        setTransform(this._proxy, this.project(c, z), this.getZoomScale(z, 1));
    37964456                }, this);
     4457
     4458                this._on('unload', this._destroyAnimProxy, this);
     4459        },
     4460
     4461        _destroyAnimProxy: function () {
     4462                remove(this._proxy);
     4463                delete this._proxy;
    37974464        },
    37984465
     
    38244491                if (options.animate !== true && !this.getSize().contains(offset)) { return false; }
    38254492
    3826                 L.Util.requestAnimFrame(function () {
     4493                requestAnimFrame(function () {
    38274494                        this
    38284495                            ._moveStart(true)
     
    38414508                        this._animateToZoom = zoom;
    38424509
    3843                         L.DomUtil.addClass(this._mapPane, 'leaflet-zoom-anim');
     4510                        addClass(this._mapPane, 'leaflet-zoom-anim');
    38444511                }
    38454512
     
    38534520
    38544521                // Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693
    3855                 setTimeout(L.bind(this._onZoomTransitionEnd, this), 250);
     4522                setTimeout(bind(this._onZoomTransitionEnd, this), 250);
    38564523        },
    38574524
     
    38594526                if (!this._animatingZoom) { return; }
    38604527
    3861                 L.DomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim');
     4528                removeClass(this._mapPane, 'leaflet-zoom-anim');
    38624529
    38634530                this._animatingZoom = false;
     
    38664533
    38674534                // This anim frame should prevent an obscure iOS webkit tile loading race condition.
    3868                 L.Util.requestAnimFrame(function () {
     4535                requestAnimFrame(function () {
    38694536                        this._moveEnd(true);
    38704537                }, this);
     
    38824549// Instantiates a map object given an instance of a `<div>` HTML element
    38834550// and optionally an object literal with `Map options`.
    3884 L.map = function (id, options) {
    3885         return new L.Map(id, options);
     4551function createMap(id, options) {
     4552        return new Map(id, options);
     4553}
     4554
     4555/*
     4556 * @class Control
     4557 * @aka L.Control
     4558 * @inherits Class
     4559 *
     4560 * L.Control is a base class for implementing map controls. Handles positioning.
     4561 * All other controls extend from this class.
     4562 */
     4563
     4564var Control = Class.extend({
     4565        // @section
     4566        // @aka Control options
     4567        options: {
     4568                // @option position: String = 'topright'
     4569                // The position of the control (one of the map corners). Possible values are `'topleft'`,
     4570                // `'topright'`, `'bottomleft'` or `'bottomright'`
     4571                position: 'topright'
     4572        },
     4573
     4574        initialize: function (options) {
     4575                setOptions(this, options);
     4576        },
     4577
     4578        /* @section
     4579         * Classes extending L.Control will inherit the following methods:
     4580         *
     4581         * @method getPosition: string
     4582         * Returns the position of the control.
     4583         */
     4584        getPosition: function () {
     4585                return this.options.position;
     4586        },
     4587
     4588        // @method setPosition(position: string): this
     4589        // Sets the position of the control.
     4590        setPosition: function (position) {
     4591                var map = this._map;
     4592
     4593                if (map) {
     4594                        map.removeControl(this);
     4595                }
     4596
     4597                this.options.position = position;
     4598
     4599                if (map) {
     4600                        map.addControl(this);
     4601                }
     4602
     4603                return this;
     4604        },
     4605
     4606        // @method getContainer: HTMLElement
     4607        // Returns the HTMLElement that contains the control.
     4608        getContainer: function () {
     4609                return this._container;
     4610        },
     4611
     4612        // @method addTo(map: Map): this
     4613        // Adds the control to the given map.
     4614        addTo: function (map) {
     4615                this.remove();
     4616                this._map = map;
     4617
     4618                var container = this._container = this.onAdd(map),
     4619                    pos = this.getPosition(),
     4620                    corner = map._controlCorners[pos];
     4621
     4622                addClass(container, 'leaflet-control');
     4623
     4624                if (pos.indexOf('bottom') !== -1) {
     4625                        corner.insertBefore(container, corner.firstChild);
     4626                } else {
     4627                        corner.appendChild(container);
     4628                }
     4629
     4630                return this;
     4631        },
     4632
     4633        // @method remove: this
     4634        // Removes the control from the map it is currently active on.
     4635        remove: function () {
     4636                if (!this._map) {
     4637                        return this;
     4638                }
     4639
     4640                remove(this._container);
     4641
     4642                if (this.onRemove) {
     4643                        this.onRemove(this._map);
     4644                }
     4645
     4646                this._map = null;
     4647
     4648                return this;
     4649        },
     4650
     4651        _refocusOnMap: function (e) {
     4652                // if map exists and event is not a keyboard event
     4653                if (this._map && e && e.screenX > 0 && e.screenY > 0) {
     4654                        this._map.getContainer().focus();
     4655                }
     4656        }
     4657});
     4658
     4659var control = function (options) {
     4660        return new Control(options);
    38864661};
    38874662
    3888 
    3889 
     4663/* @section Extension methods
     4664 * @uninheritable
     4665 *
     4666 * Every control should extend from `L.Control` and (re-)implement the following methods.
     4667 *
     4668 * @method onAdd(map: Map): HTMLElement
     4669 * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo).
     4670 *
     4671 * @method onRemove(map: Map)
     4672 * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove).
     4673 */
     4674
     4675/* @namespace Map
     4676 * @section Methods for Layers and Controls
     4677 */
     4678Map.include({
     4679        // @method addControl(control: Control): this
     4680        // Adds the given control to the map
     4681        addControl: function (control) {
     4682                control.addTo(this);
     4683                return this;
     4684        },
     4685
     4686        // @method removeControl(control: Control): this
     4687        // Removes the given control from the map
     4688        removeControl: function (control) {
     4689                control.remove();
     4690                return this;
     4691        },
     4692
     4693        _initControlPos: function () {
     4694                var corners = this._controlCorners = {},
     4695                    l = 'leaflet-',
     4696                    container = this._controlContainer =
     4697                            create$1('div', l + 'control-container', this._container);
     4698
     4699                function createCorner(vSide, hSide) {
     4700                        var className = l + vSide + ' ' + l + hSide;
     4701
     4702                        corners[vSide + hSide] = create$1('div', className, container);
     4703                }
     4704
     4705                createCorner('top', 'left');
     4706                createCorner('top', 'right');
     4707                createCorner('bottom', 'left');
     4708                createCorner('bottom', 'right');
     4709        },
     4710
     4711        _clearControlPos: function () {
     4712                for (var i in this._controlCorners) {
     4713                        remove(this._controlCorners[i]);
     4714                }
     4715                remove(this._controlContainer);
     4716                delete this._controlCorners;
     4717                delete this._controlContainer;
     4718        }
     4719});
     4720
     4721/*
     4722 * @class Control.Layers
     4723 * @aka L.Control.Layers
     4724 * @inherits Control
     4725 *
     4726 * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](http://leafletjs.com/examples/layers-control/)). Extends `Control`.
     4727 *
     4728 * @example
     4729 *
     4730 * ```js
     4731 * var baseLayers = {
     4732 *      "Mapbox": mapbox,
     4733 *      "OpenStreetMap": osm
     4734 * };
     4735 *
     4736 * var overlays = {
     4737 *      "Marker": marker,
     4738 *      "Roads": roadsLayer
     4739 * };
     4740 *
     4741 * L.control.layers(baseLayers, overlays).addTo(map);
     4742 * ```
     4743 *
     4744 * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values:
     4745 *
     4746 * ```js
     4747 * {
     4748 *     "<someName1>": layer1,
     4749 *     "<someName2>": layer2
     4750 * }
     4751 * ```
     4752 *
     4753 * The layer names can contain HTML, which allows you to add additional styling to the items:
     4754 *
     4755 * ```js
     4756 * {"<img src='my-layer-icon' /> <span class='my-layer-item'>My Layer</span>": myLayer}
     4757 * ```
     4758 */
     4759
     4760var Layers = Control.extend({
     4761        // @section
     4762        // @aka Control.Layers options
     4763        options: {
     4764                // @option collapsed: Boolean = true
     4765                // If `true`, the control will be collapsed into an icon and expanded on mouse hover or touch.
     4766                collapsed: true,
     4767                position: 'topright',
     4768
     4769                // @option autoZIndex: Boolean = true
     4770                // If `true`, the control will assign zIndexes in increasing order to all of its layers so that the order is preserved when switching them on/off.
     4771                autoZIndex: true,
     4772
     4773                // @option hideSingleBase: Boolean = false
     4774                // If `true`, the base layers in the control will be hidden when there is only one.
     4775                hideSingleBase: false,
     4776
     4777                // @option sortLayers: Boolean = false
     4778                // Whether to sort the layers. When `false`, layers will keep the order
     4779                // in which they were added to the control.
     4780                sortLayers: false,
     4781
     4782                // @option sortFunction: Function = *
     4783                // A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
     4784                // that will be used for sorting the layers, when `sortLayers` is `true`.
     4785                // The function receives both the `L.Layer` instances and their names, as in
     4786                // `sortFunction(layerA, layerB, nameA, nameB)`.
     4787                // By default, it sorts layers alphabetically by their name.
     4788                sortFunction: function (layerA, layerB, nameA, nameB) {
     4789                        return nameA < nameB ? -1 : (nameB < nameA ? 1 : 0);
     4790                }
     4791        },
     4792
     4793        initialize: function (baseLayers, overlays, options) {
     4794                setOptions(this, options);
     4795
     4796                this._layerControlInputs = [];
     4797                this._layers = [];
     4798                this._lastZIndex = 0;
     4799                this._handlingClick = false;
     4800
     4801                for (var i in baseLayers) {
     4802                        this._addLayer(baseLayers[i], i);
     4803                }
     4804
     4805                for (i in overlays) {
     4806                        this._addLayer(overlays[i], i, true);
     4807                }
     4808        },
     4809
     4810        onAdd: function (map) {
     4811                this._initLayout();
     4812                this._update();
     4813
     4814                this._map = map;
     4815                map.on('zoomend', this._checkDisabledLayers, this);
     4816
     4817                for (var i = 0; i < this._layers.length; i++) {
     4818                        this._layers[i].layer.on('add remove', this._onLayerChange, this);
     4819                }
     4820
     4821                return this._container;
     4822        },
     4823
     4824        addTo: function (map) {
     4825                Control.prototype.addTo.call(this, map);
     4826                // Trigger expand after Layers Control has been inserted into DOM so that is now has an actual height.
     4827                return this._expandIfNotCollapsed();
     4828        },
     4829
     4830        onRemove: function () {
     4831                this._map.off('zoomend', this._checkDisabledLayers, this);
     4832
     4833                for (var i = 0; i < this._layers.length; i++) {
     4834                        this._layers[i].layer.off('add remove', this._onLayerChange, this);
     4835                }
     4836        },
     4837
     4838        // @method addBaseLayer(layer: Layer, name: String): this
     4839        // Adds a base layer (radio button entry) with the given name to the control.
     4840        addBaseLayer: function (layer, name) {
     4841                this._addLayer(layer, name);
     4842                return (this._map) ? this._update() : this;
     4843        },
     4844
     4845        // @method addOverlay(layer: Layer, name: String): this
     4846        // Adds an overlay (checkbox entry) with the given name to the control.
     4847        addOverlay: function (layer, name) {
     4848                this._addLayer(layer, name, true);
     4849                return (this._map) ? this._update() : this;
     4850        },
     4851
     4852        // @method removeLayer(layer: Layer): this
     4853        // Remove the given layer from the control.
     4854        removeLayer: function (layer) {
     4855                layer.off('add remove', this._onLayerChange, this);
     4856
     4857                var obj = this._getLayer(stamp(layer));
     4858                if (obj) {
     4859                        this._layers.splice(this._layers.indexOf(obj), 1);
     4860                }
     4861                return (this._map) ? this._update() : this;
     4862        },
     4863
     4864        // @method expand(): this
     4865        // Expand the control container if collapsed.
     4866        expand: function () {
     4867                addClass(this._container, 'leaflet-control-layers-expanded');
     4868                this._form.style.height = null;
     4869                var acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);
     4870                if (acceptableHeight < this._form.clientHeight) {
     4871                        addClass(this._form, 'leaflet-control-layers-scrollbar');
     4872                        this._form.style.height = acceptableHeight + 'px';
     4873                } else {
     4874                        removeClass(this._form, 'leaflet-control-layers-scrollbar');
     4875                }
     4876                this._checkDisabledLayers();
     4877                return this;
     4878        },
     4879
     4880        // @method collapse(): this
     4881        // Collapse the control container if expanded.
     4882        collapse: function () {
     4883                removeClass(this._container, 'leaflet-control-layers-expanded');
     4884                return this;
     4885        },
     4886
     4887        _initLayout: function () {
     4888                var className = 'leaflet-control-layers',
     4889                    container = this._container = create$1('div', className),
     4890                    collapsed = this.options.collapsed;
     4891
     4892                // makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released
     4893                container.setAttribute('aria-haspopup', true);
     4894
     4895                disableClickPropagation(container);
     4896                disableScrollPropagation(container);
     4897
     4898                var form = this._form = create$1('form', className + '-list');
     4899
     4900                if (collapsed) {
     4901                        this._map.on('click', this.collapse, this);
     4902
     4903                        if (!android) {
     4904                                on(container, {
     4905                                        mouseenter: this.expand,
     4906                                        mouseleave: this.collapse
     4907                                }, this);
     4908                        }
     4909                }
     4910
     4911                var link = this._layersLink = create$1('a', className + '-toggle', container);
     4912                link.href = '#';
     4913                link.title = 'Layers';
     4914
     4915                if (touch) {
     4916                        on(link, 'click', stop);
     4917                        on(link, 'click', this.expand, this);
     4918                } else {
     4919                        on(link, 'focus', this.expand, this);
     4920                }
     4921
     4922                if (!collapsed) {
     4923                        this.expand();
     4924                }
     4925
     4926                this._baseLayersList = create$1('div', className + '-base', form);
     4927                this._separator = create$1('div', className + '-separator', form);
     4928                this._overlaysList = create$1('div', className + '-overlays', form);
     4929
     4930                container.appendChild(form);
     4931        },
     4932
     4933        _getLayer: function (id) {
     4934                for (var i = 0; i < this._layers.length; i++) {
     4935
     4936                        if (this._layers[i] && stamp(this._layers[i].layer) === id) {
     4937                                return this._layers[i];
     4938                        }
     4939                }
     4940        },
     4941
     4942        _addLayer: function (layer, name, overlay) {
     4943                if (this._map) {
     4944                        layer.on('add remove', this._onLayerChange, this);
     4945                }
     4946
     4947                this._layers.push({
     4948                        layer: layer,
     4949                        name: name,
     4950                        overlay: overlay
     4951                });
     4952
     4953                if (this.options.sortLayers) {
     4954                        this._layers.sort(bind(function (a, b) {
     4955                                return this.options.sortFunction(a.layer, b.layer, a.name, b.name);
     4956                        }, this));
     4957                }
     4958
     4959                if (this.options.autoZIndex && layer.setZIndex) {
     4960                        this._lastZIndex++;
     4961                        layer.setZIndex(this._lastZIndex);
     4962                }
     4963
     4964                this._expandIfNotCollapsed();
     4965        },
     4966
     4967        _update: function () {
     4968                if (!this._container) { return this; }
     4969
     4970                empty(this._baseLayersList);
     4971                empty(this._overlaysList);
     4972
     4973                this._layerControlInputs = [];
     4974                var baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;
     4975
     4976                for (i = 0; i < this._layers.length; i++) {
     4977                        obj = this._layers[i];
     4978                        this._addItem(obj);
     4979                        overlaysPresent = overlaysPresent || obj.overlay;
     4980                        baseLayersPresent = baseLayersPresent || !obj.overlay;
     4981                        baseLayersCount += !obj.overlay ? 1 : 0;
     4982                }
     4983
     4984                // Hide base layers section if there's only one layer.
     4985                if (this.options.hideSingleBase) {
     4986                        baseLayersPresent = baseLayersPresent && baseLayersCount > 1;
     4987                        this._baseLayersList.style.display = baseLayersPresent ? '' : 'none';
     4988                }
     4989
     4990                this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
     4991
     4992                return this;
     4993        },
     4994
     4995        _onLayerChange: function (e) {
     4996                if (!this._handlingClick) {
     4997                        this._update();
     4998                }
     4999
     5000                var obj = this._getLayer(stamp(e.target));
     5001
     5002                // @namespace Map
     5003                // @section Layer events
     5004                // @event baselayerchange: LayersControlEvent
     5005                // Fired when the base layer is changed through the [layer control](#control-layers).
     5006                // @event overlayadd: LayersControlEvent
     5007                // Fired when an overlay is selected through the [layer control](#control-layers).
     5008                // @event overlayremove: LayersControlEvent
     5009                // Fired when an overlay is deselected through the [layer control](#control-layers).
     5010                // @namespace Control.Layers
     5011                var type = obj.overlay ?
     5012                        (e.type === 'add' ? 'overlayadd' : 'overlayremove') :
     5013                        (e.type === 'add' ? 'baselayerchange' : null);
     5014
     5015                if (type) {
     5016                        this._map.fire(type, obj);
     5017                }
     5018        },
     5019
     5020        // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
     5021        _createRadioElement: function (name, checked) {
     5022
     5023                var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' +
     5024                                name + '"' + (checked ? ' checked="checked"' : '') + '/>';
     5025
     5026                var radioFragment = document.createElement('div');
     5027                radioFragment.innerHTML = radioHtml;
     5028
     5029                return radioFragment.firstChild;
     5030        },
     5031
     5032        _addItem: function (obj) {
     5033                var label = document.createElement('label'),
     5034                    checked = this._map.hasLayer(obj.layer),
     5035                    input;
     5036
     5037                if (obj.overlay) {
     5038                        input = document.createElement('input');
     5039                        input.type = 'checkbox';
     5040                        input.className = 'leaflet-control-layers-selector';
     5041                        input.defaultChecked = checked;
     5042                } else {
     5043                        input = this._createRadioElement('leaflet-base-layers', checked);
     5044                }
     5045
     5046                this._layerControlInputs.push(input);
     5047                input.layerId = stamp(obj.layer);
     5048
     5049                on(input, 'click', this._onInputClick, this);
     5050
     5051                var name = document.createElement('span');
     5052                name.innerHTML = ' ' + obj.name;
     5053
     5054                // Helps from preventing layer control flicker when checkboxes are disabled
     5055                // https://github.com/Leaflet/Leaflet/issues/2771
     5056                var holder = document.createElement('div');
     5057
     5058                label.appendChild(holder);
     5059                holder.appendChild(input);
     5060                holder.appendChild(name);
     5061
     5062                var container = obj.overlay ? this._overlaysList : this._baseLayersList;
     5063                container.appendChild(label);
     5064
     5065                this._checkDisabledLayers();
     5066                return label;
     5067        },
     5068
     5069        _onInputClick: function () {
     5070                var inputs = this._layerControlInputs,
     5071                    input, layer;
     5072                var addedLayers = [],
     5073                    removedLayers = [];
     5074
     5075                this._handlingClick = true;
     5076
     5077                for (var i = inputs.length - 1; i >= 0; i--) {
     5078                        input = inputs[i];
     5079                        layer = this._getLayer(input.layerId).layer;
     5080
     5081                        if (input.checked) {
     5082                                addedLayers.push(layer);
     5083                        } else if (!input.checked) {
     5084                                removedLayers.push(layer);
     5085                        }
     5086                }
     5087
     5088                // Bugfix issue 2318: Should remove all old layers before readding new ones
     5089                for (i = 0; i < removedLayers.length; i++) {
     5090                        if (this._map.hasLayer(removedLayers[i])) {
     5091                                this._map.removeLayer(removedLayers[i]);
     5092                        }
     5093                }
     5094                for (i = 0; i < addedLayers.length; i++) {
     5095                        if (!this._map.hasLayer(addedLayers[i])) {
     5096                                this._map.addLayer(addedLayers[i]);
     5097                        }
     5098                }
     5099
     5100                this._handlingClick = false;
     5101
     5102                this._refocusOnMap();
     5103        },
     5104
     5105        _checkDisabledLayers: function () {
     5106                var inputs = this._layerControlInputs,
     5107                    input,
     5108                    layer,
     5109                    zoom = this._map.getZoom();
     5110
     5111                for (var i = inputs.length - 1; i >= 0; i--) {
     5112                        input = inputs[i];
     5113                        layer = this._getLayer(input.layerId).layer;
     5114                        input.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) ||
     5115                                         (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom);
     5116
     5117                }
     5118        },
     5119
     5120        _expandIfNotCollapsed: function () {
     5121                if (this._map && !this.options.collapsed) {
     5122                        this.expand();
     5123                }
     5124                return this;
     5125        },
     5126
     5127        _expand: function () {
     5128                // Backward compatibility, remove me in 1.1.
     5129                return this.expand();
     5130        },
     5131
     5132        _collapse: function () {
     5133                // Backward compatibility, remove me in 1.1.
     5134                return this.collapse();
     5135        }
     5136
     5137});
     5138
     5139
     5140// @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options)
     5141// Creates an attribution control with the given layers. Base layers will be switched with radio buttons, while overlays will be switched with checkboxes. Note that all base layers should be passed in the base layers object, but only one should be added to the map during map instantiation.
     5142var layers = function (baseLayers, overlays, options) {
     5143        return new Layers(baseLayers, overlays, options);
     5144};
     5145
     5146/*
     5147 * @class Control.Zoom
     5148 * @aka L.Control.Zoom
     5149 * @inherits Control
     5150 *
     5151 * A basic zoom control with two buttons (zoom in and zoom out). It is put on the map by default unless you set its [`zoomControl` option](#map-zoomcontrol) to `false`. Extends `Control`.
     5152 */
     5153
     5154var Zoom = Control.extend({
     5155        // @section
     5156        // @aka Control.Zoom options
     5157        options: {
     5158                position: 'topleft',
     5159
     5160                // @option zoomInText: String = '+'
     5161                // The text set on the 'zoom in' button.
     5162                zoomInText: '+',
     5163
     5164                // @option zoomInTitle: String = 'Zoom in'
     5165                // The title set on the 'zoom in' button.
     5166                zoomInTitle: 'Zoom in',
     5167
     5168                // @option zoomOutText: String = '&#x2212;'
     5169                // The text set on the 'zoom out' button.
     5170                zoomOutText: '&#x2212;',
     5171
     5172                // @option zoomOutTitle: String = 'Zoom out'
     5173                // The title set on the 'zoom out' button.
     5174                zoomOutTitle: 'Zoom out'
     5175        },
     5176
     5177        onAdd: function (map) {
     5178                var zoomName = 'leaflet-control-zoom',
     5179                    container = create$1('div', zoomName + ' leaflet-bar'),
     5180                    options = this.options;
     5181
     5182                this._zoomInButton  = this._createButton(options.zoomInText, options.zoomInTitle,
     5183                        zoomName + '-in',  container, this._zoomIn);
     5184                this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,
     5185                        zoomName + '-out', container, this._zoomOut);
     5186
     5187                this._updateDisabled();
     5188                map.on('zoomend zoomlevelschange', this._updateDisabled, this);
     5189
     5190                return container;
     5191        },
     5192
     5193        onRemove: function (map) {
     5194                map.off('zoomend zoomlevelschange', this._updateDisabled, this);
     5195        },
     5196
     5197        disable: function () {
     5198                this._disabled = true;
     5199                this._updateDisabled();
     5200                return this;
     5201        },
     5202
     5203        enable: function () {
     5204                this._disabled = false;
     5205                this._updateDisabled();
     5206                return this;
     5207        },
     5208
     5209        _zoomIn: function (e) {
     5210                if (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {
     5211                        this._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
     5212                }
     5213        },
     5214
     5215        _zoomOut: function (e) {
     5216                if (!this._disabled && this._map._zoom > this._map.getMinZoom()) {
     5217                        this._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
     5218                }
     5219        },
     5220
     5221        _createButton: function (html, title, className, container, fn) {
     5222                var link = create$1('a', className, container);
     5223                link.innerHTML = html;
     5224                link.href = '#';
     5225                link.title = title;
     5226
     5227                /*
     5228                 * Will force screen readers like VoiceOver to read this as "Zoom in - button"
     5229                 */
     5230                link.setAttribute('role', 'button');
     5231                link.setAttribute('aria-label', title);
     5232
     5233                disableClickPropagation(link);
     5234                on(link, 'click', stop);
     5235                on(link, 'click', fn, this);
     5236                on(link, 'click', this._refocusOnMap, this);
     5237
     5238                return link;
     5239        },
     5240
     5241        _updateDisabled: function () {
     5242                var map = this._map,
     5243                    className = 'leaflet-disabled';
     5244
     5245                removeClass(this._zoomInButton, className);
     5246                removeClass(this._zoomOutButton, className);
     5247
     5248                if (this._disabled || map._zoom === map.getMinZoom()) {
     5249                        addClass(this._zoomOutButton, className);
     5250                }
     5251                if (this._disabled || map._zoom === map.getMaxZoom()) {
     5252                        addClass(this._zoomInButton, className);
     5253                }
     5254        }
     5255});
     5256
     5257// @namespace Map
     5258// @section Control options
     5259// @option zoomControl: Boolean = true
     5260// Whether a [zoom control](#control-zoom) is added to the map by default.
     5261Map.mergeOptions({
     5262        zoomControl: true
     5263});
     5264
     5265Map.addInitHook(function () {
     5266        if (this.options.zoomControl) {
     5267                this.zoomControl = new Zoom();
     5268                this.addControl(this.zoomControl);
     5269        }
     5270});
     5271
     5272// @namespace Control.Zoom
     5273// @factory L.control.zoom(options: Control.Zoom options)
     5274// Creates a zoom control
     5275var zoom = function (options) {
     5276        return new Zoom(options);
     5277};
     5278
     5279/*
     5280 * @class Control.Scale
     5281 * @aka L.Control.Scale
     5282 * @inherits Control
     5283 *
     5284 * A simple scale control that shows the scale of the current center of screen in metric (m/km) and imperial (mi/ft) systems. Extends `Control`.
     5285 *
     5286 * @example
     5287 *
     5288 * ```js
     5289 * L.control.scale().addTo(map);
     5290 * ```
     5291 */
     5292
     5293var Scale = Control.extend({
     5294        // @section
     5295        // @aka Control.Scale options
     5296        options: {
     5297                position: 'bottomleft',
     5298
     5299                // @option maxWidth: Number = 100
     5300                // Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).
     5301                maxWidth: 100,
     5302
     5303                // @option metric: Boolean = True
     5304                // Whether to show the metric scale line (m/km).
     5305                metric: true,
     5306
     5307                // @option imperial: Boolean = True
     5308                // Whether to show the imperial scale line (mi/ft).
     5309                imperial: true
     5310
     5311                // @option updateWhenIdle: Boolean = false
     5312                // If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).
     5313        },
     5314
     5315        onAdd: function (map) {
     5316                var className = 'leaflet-control-scale',
     5317                    container = create$1('div', className),
     5318                    options = this.options;
     5319
     5320                this._addScales(options, className + '-line', container);
     5321
     5322                map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
     5323                map.whenReady(this._update, this);
     5324
     5325                return container;
     5326        },
     5327
     5328        onRemove: function (map) {
     5329                map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
     5330        },
     5331
     5332        _addScales: function (options, className, container) {
     5333                if (options.metric) {
     5334                        this._mScale = create$1('div', className, container);
     5335                }
     5336                if (options.imperial) {
     5337                        this._iScale = create$1('div', className, container);
     5338                }
     5339        },
     5340
     5341        _update: function () {
     5342                var map = this._map,
     5343                    y = map.getSize().y / 2;
     5344
     5345                var maxMeters = map.distance(
     5346                                map.containerPointToLatLng([0, y]),
     5347                                map.containerPointToLatLng([this.options.maxWidth, y]));
     5348
     5349                this._updateScales(maxMeters);
     5350        },
     5351
     5352        _updateScales: function (maxMeters) {
     5353                if (this.options.metric && maxMeters) {
     5354                        this._updateMetric(maxMeters);
     5355                }
     5356                if (this.options.imperial && maxMeters) {
     5357                        this._updateImperial(maxMeters);
     5358                }
     5359        },
     5360
     5361        _updateMetric: function (maxMeters) {
     5362                var meters = this._getRoundNum(maxMeters),
     5363                    label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';
     5364
     5365                this._updateScale(this._mScale, label, meters / maxMeters);
     5366        },
     5367
     5368        _updateImperial: function (maxMeters) {
     5369                var maxFeet = maxMeters * 3.2808399,
     5370                    maxMiles, miles, feet;
     5371
     5372                if (maxFeet > 5280) {
     5373                        maxMiles = maxFeet / 5280;
     5374                        miles = this._getRoundNum(maxMiles);
     5375                        this._updateScale(this._iScale, miles + ' mi', miles / maxMiles);
     5376
     5377                } else {
     5378                        feet = this._getRoundNum(maxFeet);
     5379                        this._updateScale(this._iScale, feet + ' ft', feet / maxFeet);
     5380                }
     5381        },
     5382
     5383        _updateScale: function (scale, text, ratio) {
     5384                scale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';
     5385                scale.innerHTML = text;
     5386        },
     5387
     5388        _getRoundNum: function (num) {
     5389                var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),
     5390                    d = num / pow10;
     5391
     5392                d = d >= 10 ? 10 :
     5393                    d >= 5 ? 5 :
     5394                    d >= 3 ? 3 :
     5395                    d >= 2 ? 2 : 1;
     5396
     5397                return pow10 * d;
     5398        }
     5399});
     5400
     5401
     5402// @factory L.control.scale(options?: Control.Scale options)
     5403// Creates an scale control with the given options.
     5404var scale = function (options) {
     5405        return new Scale(options);
     5406};
     5407
     5408/*
     5409 * @class Control.Attribution
     5410 * @aka L.Control.Attribution
     5411 * @inherits Control
     5412 *
     5413 * The attribution control allows you to display attribution data in a small text box on a map. It is put on the map by default unless you set its [`attributionControl` option](#map-attributioncontrol) to `false`, and it fetches attribution texts from layers with the [`getAttribution` method](#layer-getattribution) automatically. Extends Control.
     5414 */
     5415
     5416var Attribution = Control.extend({
     5417        // @section
     5418        // @aka Control.Attribution options
     5419        options: {
     5420                position: 'bottomright',
     5421
     5422                // @option prefix: String = 'Leaflet'
     5423                // The HTML text shown before the attributions. Pass `false` to disable.
     5424                prefix: '<a href="http://leafletjs.com" title="A JS library for interactive maps">Leaflet</a>'
     5425        },
     5426
     5427        initialize: function (options) {
     5428                setOptions(this, options);
     5429
     5430                this._attributions = {};
     5431        },
     5432
     5433        onAdd: function (map) {
     5434                map.attributionControl = this;
     5435                this._container = create$1('div', 'leaflet-control-attribution');
     5436                disableClickPropagation(this._container);
     5437
     5438                // TODO ugly, refactor
     5439                for (var i in map._layers) {
     5440                        if (map._layers[i].getAttribution) {
     5441                                this.addAttribution(map._layers[i].getAttribution());
     5442                        }
     5443                }
     5444
     5445                this._update();
     5446
     5447                return this._container;
     5448        },
     5449
     5450        // @method setPrefix(prefix: String): this
     5451        // Sets the text before the attributions.
     5452        setPrefix: function (prefix) {
     5453                this.options.prefix = prefix;
     5454                this._update();
     5455                return this;
     5456        },
     5457
     5458        // @method addAttribution(text: String): this
     5459        // Adds an attribution text (e.g. `'Vector data &copy; Mapbox'`).
     5460        addAttribution: function (text) {
     5461                if (!text) { return this; }
     5462
     5463                if (!this._attributions[text]) {
     5464                        this._attributions[text] = 0;
     5465                }
     5466                this._attributions[text]++;
     5467
     5468                this._update();
     5469
     5470                return this;
     5471        },
     5472
     5473        // @method removeAttribution(text: String): this
     5474        // Removes an attribution text.
     5475        removeAttribution: function (text) {
     5476                if (!text) { return this; }
     5477
     5478                if (this._attributions[text]) {
     5479                        this._attributions[text]--;
     5480                        this._update();
     5481                }
     5482
     5483                return this;
     5484        },
     5485
     5486        _update: function () {
     5487                if (!this._map) { return; }
     5488
     5489                var attribs = [];
     5490
     5491                for (var i in this._attributions) {
     5492                        if (this._attributions[i]) {
     5493                                attribs.push(i);
     5494                        }
     5495                }
     5496
     5497                var prefixAndAttribs = [];
     5498
     5499                if (this.options.prefix) {
     5500                        prefixAndAttribs.push(this.options.prefix);
     5501                }
     5502                if (attribs.length) {
     5503                        prefixAndAttribs.push(attribs.join(', '));
     5504                }
     5505
     5506                this._container.innerHTML = prefixAndAttribs.join(' | ');
     5507        }
     5508});
     5509
     5510// @namespace Map
     5511// @section Control options
     5512// @option attributionControl: Boolean = true
     5513// Whether a [attribution control](#control-attribution) is added to the map by default.
     5514Map.mergeOptions({
     5515        attributionControl: true
     5516});
     5517
     5518Map.addInitHook(function () {
     5519        if (this.options.attributionControl) {
     5520                new Attribution().addTo(this);
     5521        }
     5522});
     5523
     5524// @namespace Control.Attribution
     5525// @factory L.control.attribution(options: Control.Attribution options)
     5526// Creates an attribution control.
     5527var attribution = function (options) {
     5528        return new Attribution(options);
     5529};
     5530
     5531Control.Layers = Layers;
     5532Control.Zoom = Zoom;
     5533Control.Scale = Scale;
     5534Control.Attribution = Attribution;
     5535
     5536control.layers = layers;
     5537control.zoom = zoom;
     5538control.scale = scale;
     5539control.attribution = attribution;
     5540
     5541/*
     5542        L.Handler is a base class for handler classes that are used internally to inject
     5543        interaction features like dragging to classes like Map and Marker.
     5544*/
     5545
     5546// @class Handler
     5547// @aka L.Handler
     5548// Abstract class for map interaction handlers
     5549
     5550var Handler = Class.extend({
     5551        initialize: function (map) {
     5552                this._map = map;
     5553        },
     5554
     5555        // @method enable(): this
     5556        // Enables the handler
     5557        enable: function () {
     5558                if (this._enabled) { return this; }
     5559
     5560                this._enabled = true;
     5561                this.addHooks();
     5562                return this;
     5563        },
     5564
     5565        // @method disable(): this
     5566        // Disables the handler
     5567        disable: function () {
     5568                if (!this._enabled) { return this; }
     5569
     5570                this._enabled = false;
     5571                this.removeHooks();
     5572                return this;
     5573        },
     5574
     5575        // @method enabled(): Boolean
     5576        // Returns `true` if the handler is enabled
     5577        enabled: function () {
     5578                return !!this._enabled;
     5579        }
     5580
     5581        // @section Extension methods
     5582        // Classes inheriting from `Handler` must implement the two following methods:
     5583        // @method addHooks()
     5584        // Called when the handler is enabled, should add event hooks.
     5585        // @method removeHooks()
     5586        // Called when the handler is disabled, should remove the event hooks added previously.
     5587});
     5588
     5589var Mixin = {Events: Events};
     5590
     5591/*
     5592 * @class Draggable
     5593 * @aka L.Draggable
     5594 * @inherits Evented
     5595 *
     5596 * A class for making DOM elements draggable (including touch support).
     5597 * Used internally for map and marker dragging. Only works for elements
     5598 * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).
     5599 *
     5600 * @example
     5601 * ```js
     5602 * var draggable = new L.Draggable(elementToDrag);
     5603 * draggable.enable();
     5604 * ```
     5605 */
     5606
     5607var START = touch ? 'touchstart mousedown' : 'mousedown';
     5608var END = {
     5609        mousedown: 'mouseup',
     5610        touchstart: 'touchend',
     5611        pointerdown: 'touchend',
     5612        MSPointerDown: 'touchend'
     5613};
     5614var MOVE = {
     5615        mousedown: 'mousemove',
     5616        touchstart: 'touchmove',
     5617        pointerdown: 'touchmove',
     5618        MSPointerDown: 'touchmove'
     5619};
     5620
     5621
     5622var Draggable = Evented.extend({
     5623
     5624        options: {
     5625                // @section
     5626                // @aka Draggable options
     5627                // @option clickTolerance: Number = 3
     5628                // The max number of pixels a user can shift the mouse pointer during a click
     5629                // for it to be considered a valid click (as opposed to a mouse drag).
     5630                clickTolerance: 3
     5631        },
     5632
     5633        // @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline?: Boolean, options?: Draggable options)
     5634        // Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).
     5635        initialize: function (element, dragStartTarget, preventOutline$$1, options) {
     5636                setOptions(this, options);
     5637
     5638                this._element = element;
     5639                this._dragStartTarget = dragStartTarget || element;
     5640                this._preventOutline = preventOutline$$1;
     5641        },
     5642
     5643        // @method enable()
     5644        // Enables the dragging ability
     5645        enable: function () {
     5646                if (this._enabled) { return; }
     5647
     5648                on(this._dragStartTarget, START, this._onDown, this);
     5649
     5650                this._enabled = true;
     5651        },
     5652
     5653        // @method disable()
     5654        // Disables the dragging ability
     5655        disable: function () {
     5656                if (!this._enabled) { return; }
     5657
     5658                // If we're currently dragging this draggable,
     5659                // disabling it counts as first ending the drag.
     5660                if (Draggable._dragging === this) {
     5661                        this.finishDrag();
     5662                }
     5663
     5664                off(this._dragStartTarget, START, this._onDown, this);
     5665
     5666                this._enabled = false;
     5667                this._moved = false;
     5668        },
     5669
     5670        _onDown: function (e) {
     5671                // Ignore simulated events, since we handle both touch and
     5672                // mouse explicitly; otherwise we risk getting duplicates of
     5673                // touch events, see #4315.
     5674                // Also ignore the event if disabled; this happens in IE11
     5675                // under some circumstances, see #3666.
     5676                if (e._simulated || !this._enabled) { return; }
     5677
     5678                this._moved = false;
     5679
     5680                if (hasClass(this._element, 'leaflet-zoom-anim')) { return; }
     5681
     5682                if (Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }
     5683                Draggable._dragging = this;  // Prevent dragging multiple objects at once.
     5684
     5685                if (this._preventOutline) {
     5686                        preventOutline(this._element);
     5687                }
     5688
     5689                disableImageDrag();
     5690                disableTextSelection();
     5691
     5692                if (this._moving) { return; }
     5693
     5694                // @event down: Event
     5695                // Fired when a drag is about to start.
     5696                this.fire('down');
     5697
     5698                var first = e.touches ? e.touches[0] : e;
     5699
     5700                this._startPoint = new Point(first.clientX, first.clientY);
     5701
     5702                on(document, MOVE[e.type], this._onMove, this);
     5703                on(document, END[e.type], this._onUp, this);
     5704        },
     5705
     5706        _onMove: function (e) {
     5707                // Ignore simulated events, since we handle both touch and
     5708                // mouse explicitly; otherwise we risk getting duplicates of
     5709      &n