PageSourceSearch

https://benais.fr/wp-content/themes/cctoval/js/leaflet-src.js

js benais.fr collected 2026-10-02 23:58:09 UTC 423,269 bytes, 14,017 lines download raw bytes

vendor: 2,339 bytes, lines 1-73
1/* @preserve
2 * Leaflet 1.7.1+master.0a61e90, a JS library for interactive maps. http://leafletjs.com
3 * (c) 2010-2021 Vladimir Agafonkin, (c) 2010-2011 CloudMade
4 */
5
6(function (global, factory) {
7  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
8  typeof define === 'function' && define.amd ? define(['exports'], factory) :
9  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.L = {}));
10})(this, (function (exports) { 'use strict';
11
12  var version = "1.7.1+master.0a61e906";
13
14  /*
15   * @namespace Util
16   *
17   * Various utility functions, used by Leaflet internally.
18   */
19
20  // @function extend(dest: Object, src?: Object): Object
21  // Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut.
22  function extend(dest) {
23  	var i, j, len, src;
24
25  	for (j = 1, len = arguments.length; j < len; j++) {
26  		src = arguments[j];
27  		for (i in src) {
28  			dest[i] = src[i];
29  		}
30  	}
31  	return dest;
32  }
33
34  // @function create(proto: Object, properties?: Object): Object
35  // Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create)
36  var create$2 = Object.create || (function () {
37  	function F() {}
38  	return function (proto) {
39  		F.prototype = proto;
40  		return new F();
41  	};
42  })();
43
44  // @function bind(fn: Function, …): Function
45  // 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).
46  // Has a `L.bind()` shortcut.
47  function bind(fn, obj) {
48  	var slice = Array.prototype.slice;
49
50  	if (fn.bind) {
51  		return fn.bind.apply(fn, slice.call(arguments, 1));
52  	}
53
54  	var args = slice.call(arguments, 2);
55
56  	return function () {
57  		return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);
58  	};
59  }
60
61  // @property lastId: Number
62  // Last unique ID used by [`stamp()`](#util-stamp)
63  var lastId = 0;
64
65  // @function stamp(obj: Object): Number
66  // Returns the unique ID of an object, assigning it one if it doesn't have it.
67  function stamp(obj) {
68  	if (!('_leaflet_id' in obj)) {
69  		obj['_leaflet_id'] = ++lastId;
70  	}
71  	return obj._leaflet_id;
72  }
73
vendor: 11,150 bytes, lines 74-404
74  // @function throttle(fn: Function, time: Number, context: Object): Function
75  // Returns a function which executes function `fn` with the given scope `context`
76  // (so that the `this` keyword refers to `context` inside `fn`'s code). The function
77  // `fn` will be called no more than one time per given amount of `time`. The arguments
78  // received by the bound function will be any arguments passed when binding the
79  // function, followed by any arguments passed when invoking the bound function.
80  // Has an `L.throttle` shortcut.
81  function throttle(fn, time, context) {
82  	var lock, args, wrapperFn, later;
83
84  	later = function () {
85  		// reset lock and call if queued
86  		lock = false;
87  		if (args) {
88  			wrapperFn.apply(context, args);
89  			args = false;
90  		}
91  	};
92
93  	wrapperFn = function () {
94  		if (lock) {
95  			// called too soon, queue to call later
96  			args = arguments;
97
98  		} else {
99  			// call and lock until later
100  			fn.apply(context, arguments);
101  			setTimeout(later, time);
102  			lock = true;
103  		}
104  	};
105
106  	return wrapperFn;
107  }
108
109  // @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number
110  // Returns the number `num` modulo `range` in such a way so it lies within
111  // `range[0]` and `range[1]`. The returned value will be always smaller than
112  // `range[1]` unless `includeMax` is set to `true`.
113  function wrapNum(x, range, includeMax) {
114  	var max = range[1],
115  	    min = range[0],
116  	    d = max - min;
117  	return x === max && includeMax ? x : ((x - min) % d + d) % d + min;
118  }
119
120  // @function falseFn(): Function
121  // Returns a function which always returns `false`.
122  function falseFn() { return false; }
123
124  // @function formatNum(num: Number, precision?: Number|false): Number
125  // Returns the number `num` rounded with specified `precision`.
126  // The default `precision` value is 6 decimal places.
127  // `false` can be passed to skip any processing (can be useful to avoid round-off errors).
128  function formatNum(num, precision) {
129  	if (precision === false) { return num; }
130  	var pow = Math.pow(10, precision === undefined ? 6 : precision);
131  	return Math.round(num * pow) / pow;
132  }
133
134  // @function trim(str: String): String
135  // Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)
136  function trim(str) {
137  	return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
138  }
139
140  // @function splitWords(str: String): String[]
141  // Trims and splits the string on whitespace and returns the array of parts.
142  function splitWords(str) {
143  	return trim(str).split(/\s+/);
144  }
145
146  // @function setOptions(obj: Object, options: Object): Object
147  // Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut.
148  function setOptions(obj, options) {
149  	if (!Object.prototype.hasOwnProperty.call(obj, 'options')) {
150  		obj.options = obj.options ? create$2(obj.options) : {};
151  	}
152  	for (var i in options) {
153  		obj.options[i] = options[i];
154  	}
155  	return obj.options;
156  }
157
158  // @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String
159  // Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}`
160  // translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will
161  // be appended at the end. If `uppercase` is `true`, the parameter names will
162  // be uppercased (e.g. `'?A=foo&B=bar'`)
163  function getParamString(obj, existingUrl, uppercase) {
164  	var params = [];
165  	for (var i in obj) {
166  		params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
167  	}
168  	return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
169  }
170
171  var templateRe = /\{ *([\w_ -]+) *\}/g;
172
173  // @function template(str: String, data: Object): String
174  // Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`
175  // and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string
176  // `('Hello foo, bar')`. You can also specify functions instead of strings for
177  // data values — they will be evaluated passing `data` as an argument.
178  function template(str, data) {
179  	return str.replace(templateRe, function (str, key) {
180  		var value = data[key];
181
182  		if (value === undefined) {
183  			throw new Error('No value provided for variable ' + str);
184
185  		} else if (typeof value === 'function') {
186  			value = value(data);
187  		}
188  		return value;
189  	});
190  }
191
192  // @function isArray(obj): Boolean
193  // Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)
194  var isArray = Array.isArray || function (obj) {
195  	return (Object.prototype.toString.call(obj) === '[object Array]');
196  };
197
198  // @function indexOf(array: Array, el: Object): Number
199  // Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)
200  function indexOf(array, el) {
201  	for (var i = 0; i < array.length; i++) {
202  		if (array[i] === el) { return i; }
203  	}
204  	return -1;
205  }
206
207  // @property emptyImageUrl: String
208  // Data URI string containing a base64-encoded empty GIF image.
209  // Used as a hack to free memory from unused images on WebKit-powered
210  // mobile devices (by setting image `src` to this string).
211  var emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
212
213  // inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/
214
215  function getPrefixed(name) {
216  	return window['webkit' + name] || window['moz' + name] || window['ms' + name];
217  }
218
219  var lastTime = 0;
220
221  // fallback for IE 7-8
222  function timeoutDefer(fn) {
223  	var time = +new Date(),
224  	    timeToCall = Math.max(0, 16 - (time - lastTime));
225
226  	lastTime = time + timeToCall;
227  	return window.setTimeout(fn, timeToCall);
228  }
229
230  var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer;
231  var cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') ||
232  		getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); };
233
234  // @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number
235  // Schedules `fn` to be executed when the browser repaints. `fn` is bound to
236  // `context` if given. When `immediate` is set, `fn` is called immediately if
237  // the browser doesn't have native support for
238  // [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame),
239  // otherwise it's delayed. Returns a request ID that can be used to cancel the request.
240  function requestAnimFrame(fn, context, immediate) {
241  	if (immediate && requestFn === timeoutDefer) {
242  		fn.call(context);
243  	} else {
244  		return requestFn.call(window, bind(fn, context));
245  	}
246  }
247
248  // @function cancelAnimFrame(id: Number): undefined
249  // Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame).
250  function cancelAnimFrame(id) {
251  	if (id) {
252  		cancelFn.call(window, id);
253  	}
254  }
255
256  var Util = {
257    __proto__: null,
258    extend: extend,
259    create: create$2,
260    bind: bind,
261    get lastId () { return 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  };
280
281  // @class Class
282  // @aka L.Class
283
284  // @section
285  // @uninheritable
286
287  // Thanks to John Resig and Dean Edwards for inspiration!
288
289  function Class() {}
290
291  Class.extend = function (props) {
292
293  	// @function extend(props: Object): Function
294  	// [Extends the current class](#class-inheritance) given the properties to be included.
295  	// Returns a Javascript function that is a class constructor (to be called with `new`).
296  	var NewClass = function () {
297
298  		// call the constructor
299  		if (this.initialize) {
300  			this.initialize.apply(this, arguments);
301  		}
302
303  		// call all constructor hooks
304  		this.callInitHooks();
305  	};
306
307  	var parentProto = NewClass.__super__ = this.prototype;
308
309  	var proto = create$2(parentProto);
310  	proto.constructor = NewClass;
311
312  	NewClass.prototype = proto;
313
314  	// inherit parent's statics
315  	for (var i in this) {
316  		if (Object.prototype.hasOwnProperty.call(this, i) && i !== 'prototype' && i !== '__super__') {
317  			NewClass[i] = this[i];
318  		}
319  	}
320
321  	// mix static properties into the class
322  	if (props.statics) {
323  		extend(NewClass, props.statics);
324  	}
325
326  	// mix includes into the prototype
327  	if (props.includes) {
328  		checkDeprecatedMixinEvents(props.includes);
329  		extend.apply(null, [proto].concat(props.includes));
330  	}
331
332  	// mix given properties into the prototype
333  	extend(proto, props);
334  	delete proto.statics;
335  	delete proto.includes;
336
337  	// merge options
338  	if (proto.options) {
339  		proto.options = parentProto.options ? create$2(parentProto.options) : {};
340  		extend(proto.options, props.options);
341  	}
342
343  	proto._initHooks = [];
344
345  	// add method for calling all hooks
346  	proto.callInitHooks = function () {
347
348  		if (this._initHooksCalled) { return; }
349
350  		if (parentProto.callInitHooks) {
351  			parentProto.callInitHooks.call(this);
352  		}
353
354  		this._initHooksCalled = true;
355
356  		for (var i = 0, len = proto._initHooks.length; i < len; i++) {
357  			proto._initHooks[i].call(this);
358  		}
359  	};
360
361  	return NewClass;
362  };
363
364
365  // @function include(properties: Object): this
366  // [Includes a mixin](#class-includes) into the current class.
367  Class.include = function (props) {
368  	var parentOptions = this.prototype.options;
369  	extend(this.prototype, props);
370  	if (props.options) {
371  		this.prototype.options = parentOptions;
372  		this.mergeOptions(props.options);
373  	}
374  	return this;
375  };
376
377  // @function mergeOptions(options: Object): this
378  // [Merges `options`](#class-options) into the defaults of the class.
379  Class.mergeOptions = function (options) {
380  	extend(this.prototype.options, options);
381  	return this;
382  };
383
384  // @function addInitHook(fn: Function): this
385  // Adds a [constructor hook](#class-constructor-hooks) to the class.
386  Class.addInitHook = function (fn) { // (Function) || (String, args...)
387  	var args = Array.prototype.slice.call(arguments, 1);
388
389  	var init = typeof fn === 'function' ? fn : function () {
390  		this[fn].apply(this, args);
391  	};
392
393  	this.prototype._initHooks = this.prototype._initHooks || [];
394  	this.prototype._initHooks.push(init);
395  	return this;
396  };
397
398  function checkDeprecatedMixinEvents(includes) {
399  	if (typeof L === 'undefined' || !L || !L.Mixin) { return; }
400
401  	includes = isArray(includes) ? includes : [includes];
402
403  	for (var i = 0; i < includes.length; i++) {
404  		if (includes[i] === L.Mixin.Events) {
405  			console.warn('Deprecated include of L.Mixin.Events: ' +
406  				'this property will be removed in future releases, ' +
407  				'please inherit from L.Evented instead.', new Error().stack);
408  		}
409  	}
410  }
411
412  /*
413   * @class Evented
414   * @aka L.Evented
415   * @inherits Class
416   *
417   * A set of methods shared between event-powered classes (like `Map` and `Marker`). Generally, events allow you to execute some function when something happens with an object (e.g. the user clicks on the map, causing the map to fire `'click'` event).
418   *
419   * @example
420   *
421   * ```js
422   * map.on('click', function(e) {
423   * 	alert(e.latlng);
424   * } );
425   * ```
426   *
427   * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function:
428   *
429   * ```js
430   * function onClick(e) { ... }
431   *
432   * map.on('click', onClick);
433   * map.off('click', onClick);
434   * ```
435   */
436
437  var Events = {
438  	/* @method on(type: String, fn: Function, context?: Object): this
439  	 * 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'`).
440  	 *
441  	 * @alternative
442  	 * @method on(eventMap: Object): this
443  	 * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
444  	 */
445  	on: function (types, fn, context) {
446
447  		// types can be a map of types/handlers
448  		if (typeof types === 'object') {
449  			for (var type in types) {
450  				// we don't process space-separated events here for performance;
451  				// it's a hot path since Layer uses the on(obj) syntax
452  				this._on(type, types[type], fn);
453  			}
454
455  		} else {
456  			// types can be a string of space-separated words
457  			types = splitWords(types);
458
459  			for (var i = 0, len = types.length; i < len; i++) {
460  				this._on(types[i], fn, context);
461  			}
462  		}
463
464  		return this;
465  	},
466
467  	/* @method off(type: String, fn?: Function, context?: Object): this
468  	 * Removes a previously added listener function. If no function is specified, it will remove all the listeners of that particular event from the object. Note that if you passed a custom context to `on`, you must pass the same context to `off` in order to remove the listener.
469  	 *
470  	 * @alternative
471  	 * @method off(eventMap: Object): this
472  	 * Removes a set of type/listener pairs.
473  	 *
474  	 * @alternative
475  	 * @method off: this
476  	 * Removes all listeners to all events on the object. This includes implicitly attached events.
477  	 */
478  	off: function (types, fn, context) {
479
480  		if (!arguments.length) {
481  			// clear all listeners if called without arguments
482  			delete this._events;
483
484  		} else if (typeof types === 'object') {
485  			for (var type in types) {
486  				this._off(type, types[type], fn);
487  			}
488
489  		} else {
490  			types = splitWords(types);
491
492  			var removeAll = arguments.length === 1;
493  			for (var i = 0, len = types.length; i < len; i++) {
494  				if (removeAll) {
495  					this._off(types[i]);
496  				} else {
497  					this._off(types[i], fn, context);
498  				}
499  			}
500  		}
501
502  		return this;
503  	},
504
505  	// attach listener (without syntactic sugar now)
506  	_on: function (type, fn, context) {
507  		if (typeof fn !== 'function') {
508  			console.warn('wrong listener type: ' + typeof fn);
509  			return;
510  		}
511  		this._events = this._events || {};
512
513  		/* get/init listeners for type */
514  		var typeListeners = this._events[type];
515  		if (!typeListeners) {
516  			typeListeners = [];
517  			this._events[type] = typeListeners;
518  		}
519
520  		if (context === this) {
521  			// Less memory footprint.
522  			context = undefined;
523  		}
524  		var newListener = {fn: fn, ctx: context},
525  		    listeners = typeListeners;
526
527  		// check if fn already there
528  		for (var i = 0, len = listeners.length; i < len; i++) {
529  			if (listeners[i].fn === fn && listeners[i].ctx === context) {
530  				return;
531  			}
532  		}
533
534  		listeners.push(newListener);
535  	},
536
537  	_off: function (type, fn, context) {
538  		var listeners,
539  		    i,
540  		    len;
541
542  		if (!this._events) { return; }
543
544  		listeners = this._events[type];
545
546  		if (!listeners) {
547  			return;
548  		}
549
550  		if (arguments.length === 1) { // remove all
551  			if (this._firingCount) {
552  				// Set all removed listeners to noop
553  				// so they are not called if remove happens in fire
554  				for (i = 0, len = listeners.length; i < len; i++) {
555  					listeners[i].fn = falseFn;
556  				}
557  			}
558  			// clear all listeners for a type if function isn't specified
559  			delete this._events[type];
560  			return;
561  		}
562
563  		if (context === this) {
564  			context = undefined;
565  		}
566
567  		if (typeof fn !== 'function') {
568  			console.warn('wrong listener type: ' + typeof fn);
569  			return;
570  		}
571  		// find fn and remove it
572  		for (i = 0, len = listeners.length; i < len; i++) {
573  			var l = listeners[i];
574  			if (l.ctx !== context) { continue; }
575  			if (l.fn === fn) {
576  				if (this._firingCount) {
577  					// set the removed listener to noop so that's not called if remove happens in fire
578  					l.fn = falseFn;
579
580  					/* copy array in case events are being fired */
581  					this._events[type] = listeners = listeners.slice();
582  				}
583  				listeners.splice(i, 1);
584
585  				return;
586  			}
587  		}
588  		console.warn('listener not found');
589  	},
590
591  	// @method fire(type: String, data?: Object, propagate?: Boolean): this
592  	// Fires an event of the specified type. You can optionally provide a data
593  	// object — the first argument of the listener function will contain its
594  	// properties. The event can optionally be propagated to event parents.
595  	fire: function (type, data, propagate) {
vendor: 9,254 bytes, lines 596-918
596  		if (!this.listens(type, propagate)) { return this; }
597
598  		var event = extend({}, data, {
599  			type: type,
600  			target: this,
601  			sourceTarget: data && data.sourceTarget || this
602  		});
603
604  		if (this._events) {
605  			var listeners = this._events[type];
606
607  			if (listeners) {
608  				this._firingCount = (this._firingCount + 1) || 1;
609  				for (var i = 0, len = listeners.length; i < len; i++) {
610  					var l = listeners[i];
611  					l.fn.call(l.ctx || this, event);
612  				}
613
614  				this._firingCount--;
615  			}
616  		}
617
618  		if (propagate) {
619  			// propagate the event to parents (set with addEventParent)
620  			this._propagateEvent(event);
621  		}
622
623  		return this;
624  	},
625
626  	// @method listens(type: String, propagate?: Boolean): Boolean
627  	// Returns `true` if a particular event type has any listeners attached to it.
628  	// The verification can optionally be propagated, it will return `true` if parents have the listener attached to it.
629  	listens: function (type, propagate) {
630  		if (typeof type !== 'string') {
631  			console.warn('"string" type argument expected');
632  		}
633  		var listeners = this._events && this._events[type];
634  		if (listeners && listeners.length) { return true; }
635
636  		if (propagate) {
637  			// also check parents for listeners if event propagates
638  			for (var id in this._eventParents) {
639  				if (this._eventParents[id].listens(type, propagate)) { return true; }
640  			}
641  		}
642  		return false;
643  	},
644
645  	// @method once(…): this
646  	// Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed.
647  	once: function (types, fn, context) {
648
649  		if (typeof types === 'object') {
650  			for (var type in types) {
651  				this.once(type, types[type], fn);
652  			}
653  			return this;
654  		}
655
656  		var handler = bind(function () {
657  			this
658  			    .off(types, fn, context)
659  			    .off(types, handler, context);
660  		}, this);
661
662  		// add a listener that's executed once and removed after that
663  		return this
664  		    .on(types, fn, context)
665  		    .on(types, handler, context);
666  	},
667
668  	// @method addEventParent(obj: Evented): this
669  	// Adds an event parent - an `Evented` that will receive propagated events
670  	addEventParent: function (obj) {
671  		this._eventParents = this._eventParents || {};
672  		this._eventParents[stamp(obj)] = obj;
673  		return this;
674  	},
675
676  	// @method removeEventParent(obj: Evented): this
677  	// Removes an event parent, so it will stop receiving propagated events
678  	removeEventParent: function (obj) {
679  		if (this._eventParents) {
680  			delete this._eventParents[stamp(obj)];
681  		}
682  		return this;
683  	},
684
685  	_propagateEvent: function (e) {
686  		for (var id in this._eventParents) {
687  			this._eventParents[id].fire(e.type, extend({
688  				layer: e.target,
689  				propagatedFrom: e.target
690  			}, e), true);
691  		}
692  	}
693  };
694
695  // aliases; we should ditch those eventually
696
697  // @method addEventListener(…): this
698  // Alias to [`on(…)`](#evented-on)
699  Events.addEventListener = Events.on;
700
701  // @method removeEventListener(…): this
702  // Alias to [`off(…)`](#evented-off)
703
704  // @method clearAllEventListeners(…): this
705  // Alias to [`off()`](#evented-off)
706  Events.removeEventListener = Events.clearAllEventListeners = Events.off;
707
708  // @method addOneTimeEventListener(…): this
709  // Alias to [`once(…)`](#evented-once)
710  Events.addOneTimeEventListener = Events.once;
711
712  // @method fireEvent(…): this
713  // Alias to [`fire(…)`](#evented-fire)
714  Events.fireEvent = Events.fire;
715
716  // @method hasEventListeners(…): Boolean
717  // Alias to [`listens(…)`](#evented-listens)
718  Events.hasEventListeners = Events.listens;
719
720  var Evented = Class.extend(Events);
721
722  /*
723   * @class Point
724   * @aka L.Point
725   *
726   * Represents a point with `x` and `y` coordinates in pixels.
727   *
728   * @example
729   *
730   * ```js
731   * var point = L.point(200, 300);
732   * ```
733   *
734   * All Leaflet methods and options that accept `Point` objects also accept them in a simple Array form (unless noted otherwise), so these lines are equivalent:
735   *
736   * ```js
737   * map.panBy([200, 300]);
738   * map.panBy(L.point(200, 300));
739   * ```
740   *
741   * Note that `Point` does not inherit from Leaflet's `Class` object,
742   * which means new classes can't inherit from it, and new methods
743   * can't be added to it with the `include` function.
744   */
745
746  function Point(x, y, round) {
747  	// @property x: Number; The `x` coordinate of the point
748  	this.x = (round ? Math.round(x) : x);
749  	// @property y: Number; The `y` coordinate of the point
750  	this.y = (round ? Math.round(y) : y);
751  }
752
753  var trunc = Math.trunc || function (v) {
754  	return v > 0 ? Math.floor(v) : Math.ceil(v);
755  };
756
757  Point.prototype = {
758
759  	// @method clone(): Point
760  	// Returns a copy of the current point.
761  	clone: function () {
762  		return new Point(this.x, this.y);
763  	},
764
765  	// @method add(otherPoint: Point): Point
766  	// Returns the result of addition of the current and the given points.
767  	add: function (point) {
768  		// non-destructive, returns a new point
769  		return this.clone()._add(toPoint(point));
770  	},
771
772  	_add: function (point) {
773  		// destructive, used directly for performance in situations where it's safe to modify existing point
774  		this.x += point.x;
775  		this.y += point.y;
776  		return this;
777  	},
778
779  	// @method subtract(otherPoint: Point): Point
780  	// Returns the result of subtraction of the given point from the current.
781  	subtract: function (point) {
782  		return this.clone()._subtract(toPoint(point));
783  	},
784
785  	_subtract: function (point) {
786  		this.x -= point.x;
787  		this.y -= point.y;
788  		return this;
789  	},
790
791  	// @method divideBy(num: Number): Point
792  	// Returns the result of division of the current point by the given number.
793  	divideBy: function (num) {
794  		return this.clone()._divideBy(num);
795  	},
796
797  	_divideBy: function (num) {
798  		this.x /= num;
799  		this.y /= num;
800  		return this;
801  	},
802
803  	// @method multiplyBy(num: Number): Point
804  	// Returns the result of multiplication of the current point by the given number.
805  	multiplyBy: function (num) {
806  		return this.clone()._multiplyBy(num);
807  	},
808
809  	_multiplyBy: function (num) {
810  		this.x *= num;
811  		this.y *= num;
812  		return this;
813  	},
814
815  	// @method scaleBy(scale: Point): Point
816  	// Multiply each coordinate of the current point by each coordinate of
817  	// `scale`. In linear algebra terms, multiply the point by the
818  	// [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation)
819  	// defined by `scale`.
820  	scaleBy: function (point) {
821  		return new Point(this.x * point.x, this.y * point.y);
822  	},
823
824  	// @method unscaleBy(scale: Point): Point
825  	// Inverse of `scaleBy`. Divide each coordinate of the current point by
826  	// each coordinate of `scale`.
827  	unscaleBy: function (point) {
828  		return new Point(this.x / point.x, this.y / point.y);
829  	},
830
831  	// @method round(): Point
832  	// Returns a copy of the current point with rounded coordinates.
833  	round: function () {
834  		return this.clone()._round();
835  	},
836
837  	_round: function () {
838  		this.x = Math.round(this.x);
839  		this.y = Math.round(this.y);
840  		return this;
841  	},
842
843  	// @method floor(): Point
844  	// Returns a copy of the current point with floored coordinates (rounded down).
845  	floor: function () {
846  		return this.clone()._floor();
847  	},
848
849  	_floor: function () {
850  		this.x = Math.floor(this.x);
851  		this.y = Math.floor(this.y);
852  		return this;
853  	},
854
855  	// @method ceil(): Point
856  	// Returns a copy of the current point with ceiled coordinates (rounded up).
857  	ceil: function () {
858  		return this.clone()._ceil();
859  	},
860
861  	_ceil: function () {
862  		this.x = Math.ceil(this.x);
863  		this.y = Math.ceil(this.y);
864  		return this;
865  	},
866
867  	// @method trunc(): Point
868  	// Returns a copy of the current point with truncated coordinates (rounded towards zero).
869  	trunc: function () {
870  		return this.clone()._trunc();
871  	},
872
873  	_trunc: function () {
874  		this.x = trunc(this.x);
875  		this.y = trunc(this.y);
876  		return this;
877  	},
878
879  	// @method distanceTo(otherPoint: Point): Number
880  	// Returns the cartesian distance between the current and the given points.
881  	distanceTo: function (point) {
882  		point = toPoint(point);
883
884  		var x = point.x - this.x,
885  		    y = point.y - this.y;
886
887  		return Math.sqrt(x * x + y * y);
888  	},
889
890  	// @method equals(otherPoint: Point): Boolean
891  	// Returns `true` if the given point has the same coordinates.
892  	equals: function (point) {
893  		point = toPoint(point);
894
895  		return point.x === this.x &&
896  		       point.y === this.y;
897  	},
898
899  	// @method contains(otherPoint: Point): Boolean
900  	// Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values).
901  	contains: function (point) {
902  		point = toPoint(point);
903
904  		return Math.abs(point.x) <= Math.abs(this.x) &&
905  		       Math.abs(point.y) <= Math.abs(this.y);
906  	},
907
908  	// @method toString(): String
909  	// Returns a string representation of the point for debugging purposes.
910  	toString: function () {
911  		return 'Point(' +
912  		        formatNum(this.x) + ', ' +
913  		        formatNum(this.y) + ')';
914  	}
915  };
916
917  // @factory L.point(x: Number, y: Number, round?: Boolean)
918  // Creates a Point object with the given `x` and `y` coordinates. If optional `roun
918d` is set to true, rounds the `x` and `y` values.
919
920  // @alternative
921  // @factory L.point(coords: Number[])
922  // Expects an array of the form `[x, y]` instead.
923
924  // @alternative
925  // @factory L.point(coords: Object)
926  // Expects a plain object of the form `{x: Number, y: Number}` instead.
927  function toPoint(x, y, round) {
928  	if (x instanceof Point) {
929  		return x;
930  	}
931  	if (isArray(x)) {
932  		return new Point(x[0], x[1]);
933  	}
934  	if (x === undefined || x === null) {
935  		return x;
936  	}
937  	if (typeof x === 'object' && 'x' in x && 'y' in x) {
938  		return new Point(x.x, x.y);
939  	}
940  	return new Point(x, y, round);
941  }
942
943  /*
944   * @class Bounds
945   * @aka L.Bounds
946   *
947   * Represents a rectangular area in pixel coordinates.
948   *
949   * @example
950   *
951   * ```js
952   * var p1 = L.point(10, 10),
953   * p2 = L.point(40, 60),
954   * bounds = L.bounds(p1, p2);
955   * ```
956   *
957   * All Leaflet methods that accept `Bounds` objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:
958   *
959   * ```js
960   * otherBounds.intersects([[10, 10], [40, 60]]);
961   * ```
962   *
963   * Note that `Bounds` does not inherit from Leaflet's `Class` object,
964   * which means new classes can't inherit from it, and new methods
965   * can't be added to it with the `include` function.
966   */
967
968  function Bounds(a, b) {
969  	if (!a) { return; }
970
971  	var points = b ? [a, b] : a;
972
973  	for (var i = 0, len = points.length; i < len; i++) {
974  		this.extend(points[i]);
975  	}
976  }
977
978  Bounds.prototype = {
979  	// @method extend(point: Point): this
980  	// Extends the bounds to contain the given point.
981  	extend: function (point) { // (Point)
982  		point = toPoint(point);
983
984  		// @property min: Point
985  		// The top left corner of the rectangle.
986  		// @property max: Point
987  		// The bottom right corner of the rectangle.
988  		if (!this.min && !this.max) {
989  			this.min = point.clone();
990  			this.max = point.clone();
991  		} else {
992  			this.min.x = Math.min(point.x, this.min.x);
993  			this.max.x = Math.max(point.x, this.max.x);
994  			this.min.y = Math.min(point.y, this.min.y);
995  			this.max.y = Math.max(point.y, this.max.y);
996  		}
997  		return this;
998  	},
999
1000  	// @method getCenter(round?: Boolean): Point
1001  	// Returns the center point of the bounds.
1002  	getCenter: function (round) {
1003  		return new Point(
1004  		        (this.min.x + this.max.x) / 2,
1005  		        (this.min.y + this.max.y) / 2, round);
1006  	},
1007
1008  	// @method getBottomLeft(): Point
1009  	// Returns the bottom-left point of the bounds.
1010  	getBottomLeft: function () {
1011  		return new Point(this.min.x, this.max.y);
1012  	},
1013
1014  	// @method getTopRight(): Point
1015  	// Returns the top-right point of the bounds.
1016  	getTopRight: function () { // -> Point
1017  		return new Point(this.max.x, this.min.y);
1018  	},
1019
1020  	// @method getTopLeft(): Point
1021  	// Returns the top-left point of the bounds (i.e. [`this.min`](#bounds-min)).
1022  	getTopLeft: function () {
1023  		return this.min; // left, top
1024  	},
1025
1026  	// @method getBottomRight(): Point
1027  	// Returns the bottom-right point of the bounds (i.e. [`this.max`](#bounds-max)).
1028  	getBottomRight: function () {
1029  		return this.max; // right, bottom
1030  	},
1031
1032  	// @method getSize(): Point
1033  	// Returns the size of the given bounds
1034  	getSize: function () {
1035  		return this.max.subtract(this.min);
1036  	},
1037
1038  	// @method contains(otherBounds: Bounds): Boolean
1039  	// Returns `true` if the rectangle contains the given one.
1040  	// @alternative
1041  	// @method contains(point: Point): Boolean
1042  	// Returns `true` if the rectangle contains the given point.
1043  	contains: function (obj) {
1044  		var min, max;
1045
1046  		if (typeof obj[0] === 'number' || obj instanceof Point) {
1047  			obj = toPoint(obj);
1048  		} else {
1049  			obj = toBounds(obj);
1050  		}
1051
1052  		if (obj instanceof Bounds) {
1053  			min = obj.min;
1054  			max = obj.max;
1055  		} else {
1056  			min = max = obj;
1057  		}
1058
1059  		return (min.x >= this.min.x) &&
1060  		       (max.x <= this.max.x) &&
1061  		       (min.y >= this.min.y) &&
1062  		       (max.y <= this.max.y);
1063  	},
1064
1065  	// @method intersects(otherBounds: Bounds): Boolean
1066  	// Returns `true` if the rectangle intersects the given bounds. Two bounds
1067  	// intersect if they have at least one point in common.
1068  	intersects: function (bounds) { // (Bounds) -> Boolean
1069  		bounds = toBounds(bounds);
1070
1071  		var min = this.min,
1072  		    max = this.max,
1073  		    min2 = bounds.min,
vendor: 13,614 bytes, lines 1074-1503
1074  		    max2 = bounds.max,
1075  		    xIntersects = (max2.x >= min.x) && (min2.x <= max.x),
1076  		    yIntersects = (max2.y >= min.y) && (min2.y <= max.y);
1077
1078  		return xIntersects && yIntersects;
1079  	},
1080
1081  	// @method overlaps(otherBounds: Bounds): Boolean
1082  	// Returns `true` if the rectangle overlaps the given bounds. Two bounds
1083  	// overlap if their intersection is an area.
1084  	overlaps: function (bounds) { // (Bounds) -> Boolean
1085  		bounds = toBounds(bounds);
1086
1087  		var min = this.min,
1088  		    max = this.max,
1089  		    min2 = bounds.min,
1090  		    max2 = bounds.max,
1091  		    xOverlaps = (max2.x > min.x) && (min2.x < max.x),
1092  		    yOverlaps = (max2.y > min.y) && (min2.y < max.y);
1093
1094  		return xOverlaps && yOverlaps;
1095  	},
1096
1097  	isValid: function () {
1098  		return !!(this.min && this.max);
1099  	}
1100  };
1101
1102
1103  // @factory L.bounds(corner1: Point, corner2: Point)
1104  // Creates a Bounds object from two corners coordinate pairs.
1105  // @alternative
1106  // @factory L.bounds(points: Point[])
1107  // Creates a Bounds object from the given array of points.
1108  function toBounds(a, b) {
1109  	if (!a || a instanceof Bounds) {
1110  		return a;
1111  	}
1112  	return new Bounds(a, b);
1113  }
1114
1115  /*
1116   * @class LatLngBounds
1117   * @aka L.LatLngBounds
1118   *
1119   * Represents a rectangular geographical area on a map.
1120   *
1121   * @example
1122   *
1123   * ```js
1124   * var corner1 = L.latLng(40.712, -74.227),
1125   * corner2 = L.latLng(40.774, -74.125),
1126   * bounds = L.latLngBounds(corner1, corner2);
1127   * ```
1128   *
1129   * 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:
1130   *
1131   * ```js
1132   * map.fitBounds([
1133   * 	[40.712, -74.227],
1134   * 	[40.774, -74.125]
1135   * ]);
1136   * ```
1137   *
1138   * 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.
1139   *
1140   * Note that `LatLngBounds` does not inherit from Leaflet's `Class` object,
1141   * which means new classes can't inherit from it, and new methods
1142   * can't be added to it with the `include` function.
1143   */
1144
1145  function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[])
1146  	if (!corner1) { return; }
1147
1148  	var latlngs = corner2 ? [corner1, corner2] : corner1;
1149
1150  	for (var i = 0, len = latlngs.length; i < len; i++) {
1151  		this.extend(latlngs[i]);
1152  	}
1153  }
1154
1155  LatLngBounds.prototype = {
1156
1157  	// @method extend(latlng: LatLng): this
1158  	// Extend the bounds to contain the given point
1159
1160  	// @alternative
1161  	// @method extend(otherBounds: LatLngBounds): this
1162  	// Extend the bounds to contain the given bounds
1163  	extend: function (obj) {
1164  		var sw = this._southWest,
1165  		    ne = this._northEast,
1166  		    sw2, ne2;
1167
1168  		if (obj instanceof LatLng) {
1169  			sw2 = obj;
1170  			ne2 = obj;
1171
1172  		} else if (obj instanceof LatLngBounds) {
1173  			sw2 = obj._southWest;
1174  			ne2 = obj._northEast;
1175
1176  			if (!sw2 || !ne2) { return this; }
1177
1178  		} else {
1179  			return obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this;
1180  		}
1181
1182  		if (!sw && !ne) {
1183  			this._southWest = new LatLng(sw2.lat, sw2.lng);
1184  			this._northEast = new LatLng(ne2.lat, ne2.lng);
1185  		} else {
1186  			sw.lat = Math.min(sw2.lat, sw.lat);
1187  			sw.lng = Math.min(sw2.lng, sw.lng);
1188  			ne.lat = Math.max(ne2.lat, ne.lat);
1189  			ne.lng = Math.max(ne2.lng, ne.lng);
1190  		}
1191
1192  		return this;
1193  	},
1194
1195  	// @method pad(bufferRatio: Number): LatLngBounds
1196  	// Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
1197  	// For example, a ratio of 0.5 extends the bounds by 50% in each direction.
1198  	// Negative values will retract the bounds.
1199  	pad: function (bufferRatio) {
1200  		var sw = this._southWest,
1201  		    ne = this._northEast,
1202  		    heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
1203  		    widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
1204
1205  		return new LatLngBounds(
1206  		        new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
1207  		        new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));
1208  	},
1209
1210  	// @method getCenter(): LatLng
1211  	// Returns the center point of the bounds.
1212  	getCenter: function () {
1213  		return new LatLng(
1214  		        (this._southWest.lat + this._northEast.lat) / 2,
1215  		        (this._southWest.lng + this._northEast.lng) / 2);
1216  	},
1217
1218  	// @method getSouthWest(): LatLng
1219  	// Returns the south-west point of the bounds.
1220  	getSouthWest: function () {
1221  		return this._southWest;
1222  	},
1223
1224  	// @method getNorthEast(): LatLng
1225  	// Returns the north-east point of the bounds.
1226  	getNorthEast: function () {
1227  		return this._northEast;
1228  	},
1229
1230  	// @method getNorthWest(): LatLng
1231  	// Returns the north-west point of the bounds.
1232  	getNorthWest: function () {
1233  		return new LatLng(this.getNorth(), this.getWest());
1234  	},
1235
1236  	// @method getSouthEast(): LatLng
1237  	// Returns the south-east point of the bounds.
1238  	getSouthEast: function () {
1239  		return new LatLng(this.getSouth(), this.getEast());
1240  	},
1241
1242  	// @method getWest(): Number
1243  	// Returns the west longitude of the bounds
1244  	getWest: function () {
1245  		return this._southWest.lng;
1246  	},
1247
1248  	// @method getSouth(): Number
1249  	// Returns the south latitude of the bounds
1250  	getSouth: function () {
1251  		return this._southWest.lat;
1252  	},
1253
1254  	// @method getEast(): Number
1255  	// Returns the east longitude of the bounds
1256  	getEast: function () {
1257  		return this._northEast.lng;
1258  	},
1259
1260  	// @method getNorth(): Number
1261  	// Returns the north latitude of the bounds
1262  	getNorth: function () {
1263  		return this._northEast.lat;
1264  	},
1265
1266  	// @method contains(otherBounds: LatLngBounds): Boolean
1267  	// Returns `true` if the rectangle contains the given one.
1268
1269  	// @alternative
1270  	// @method contains (latlng: LatLng): Boolean
1271  	// Returns `true` if the rectangle contains the given point.
1272  	contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean
1273  		if (typeof obj[0] === 'number' || obj instanceof LatLng || 'lat' in obj) {
1274  			obj = toLatLng(obj);
1275  		} else {
1276  			obj = toLatLngBounds(obj);
1277  		}
1278
1279  		var sw = this._southWest,
1280  		    ne = this._northEast,
1281  		    sw2, ne2;
1282
1283  		if (obj instanceof LatLngBounds) {
1284  			sw2 = obj.getSouthWest();
1285  			ne2 = obj.getNorthEast();
1286  		} else {
1287  			sw2 = ne2 = obj;
1288  		}
1289
1290  		return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&
1291  		       (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);
1292  	},
1293
1294  	// @method intersects(otherBounds: LatLngBounds): Boolean
1295  	// Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.
1296  	intersects: function (bounds) {
1297  		bounds = toLatLngBounds(bounds);
1298
1299  		var sw = this._southWest,
1300  		    ne = this._northEast,
1301  		    sw2 = bounds.getSouthWest(),
1302  		    ne2 = bounds.getNorthEast(),
1303
1304  		    latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),
1305  		    lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);
1306
1307  		return latIntersects && lngIntersects;
1308  	},
1309
1310  	// @method overlaps(otherBounds: LatLngBounds): Boolean
1311  	// Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.
1312  	overlaps: function (bounds) {
1313  		bounds = toLatLngBounds(bounds);
1314
1315  		var sw = this._southWest,
1316  		    ne = this._northEast,
1317  		    sw2 = bounds.getSouthWest(),
1318  		    ne2 = bounds.getNorthEast(),
1319
1320  		    latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat),
1321  		    lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng);
1322
1323  		return latOverlaps && lngOverlaps;
1324  	},
1325
1326  	// @method toBBoxString(): String
1327  	// 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.
1328  	toBBoxString: function () {
1329  		return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');
1330  	},
1331
1332  	// @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean
1333  	// Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds. The margin of error can be overridden by setting `maxMargin` to a small number.
1334  	equals: function (bounds, maxMargin) {
1335  		if (!bounds) { return false; }
1336
1337  		bounds = toLatLngBounds(bounds);
1338
1339  		return this._southWest.equals(bounds.getSouthWest(), maxMargin) &&
1340  		       this._northEast.equals(bounds.getNorthEast(), maxMargin);
1341  	},
1342
1343  	// @method isValid(): Boolean
1344  	// Returns `true` if the bounds are properly initialized.
1345  	isValid: function () {
1346  		return !!(this._southWest && this._northEast);
1347  	}
1348  };
1349
1350  // TODO International date line?
1351
1352  // @factory L.latLngBounds(corner1: LatLng, corner2: LatLng)
1353  // Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle.
1354
1355  // @alternative
1356  // @factory L.latLngBounds(latlngs: LatLng[])
1357  // 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).
1358  function toLatLngBounds(a, b) {
1359  	if (a instanceof LatLngBounds) {
1360  		return a;
1361  	}
1362  	return new LatLngBounds(a, b);
1363  }
1364
1365  /* @class LatLng
1366   * @aka L.LatLng
1367   *
1368   * Represents a geographical point with a certain latitude and longitude.
1369   *
1370   * @example
1371   *
1372   * ```
1373   * var latlng = L.latLng(50.5, 30.5);
1374   * ```
1375   *
1376   * All Leaflet methods that accept LatLng objects also accept them in a simple Array form and simple object form (unless noted otherwise), so these lines are equivalent:
1377   *
1378   * ```
1379   * map.panTo([50, 30]);
1380   * map.panTo({lon: 30, lat: 50});
1381   * map.panTo({lat: 50, lng: 30});
1382   * map.panTo(L.latLng(50, 30));
1383   * ```
1384   *
1385   * Note that `LatLng` does not inherit from Leaflet's `Class` object,
1386   * which means new classes can't inherit from it, and new methods
1387   * can't be added to it with the `include` function.
1388   */
1389
1390  function LatLng(lat, lng, alt) {
1391  	if (isNaN(lat) || isNaN(lng)) {
1392  		throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');
1393  	}
1394
1395  	// @property lat: Number
1396  	// Latitude in degrees
1397  	this.lat = +lat;
1398
1399  	// @property lng: Number
1400  	// Longitude in degrees
1401  	this.lng = +lng;
1402
1403  	// @property alt: Number
1404  	// Altitude in meters (optional)
1405  	if (alt !== undefined) {
1406  		this.alt = +alt;
1407  	}
1408  }
1409
1410  LatLng.prototype = {
1411  	// @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean
1412  	// Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overridden by setting `maxMargin` to a small number.
1413  	equals: function (obj, maxMargin) {
1414  		if (!obj) { return false; }
1415
1416  		obj = toLatLng(obj);
1417
1418  		var margin = Math.max(
1419  		        Math.abs(this.lat - obj.lat),
1420  		        Math.abs(this.lng - obj.lng));
1421
1422  		return margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin);
1423  	},
1424
1425  	// @method toString(): String
1426  	// Returns a string representation of the point (for debugging purposes).
1427  	toString: function (precision) {
1428  		return 'LatLng(' +
1429  		        formatNum(this.lat, precision) + ', ' +
1430  		        formatNum(this.lng, precision) + ')';
1431  	},
1432
1433  	// @method distanceTo(otherLatLng: LatLng): Number
1434  	// Returns the distance (in meters) to the given `LatLng` calculated using the [Spherical Law of Cosines](https://en.wikipedia.org/wiki/Spherical_law_of_cosines).
1435  	distanceTo: function (other) {
1436  		return Earth.distance(this, toLatLng(other));
1437  	},
1438
1439  	// @method wrap(): LatLng
1440  	// Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees.
1441  	wrap: function () {
1442  		return Earth.wrapLatLng(this);
1443  	},
1444
1445  	// @method toBounds(sizeInMeters: Number): LatLngBounds
1446  	// Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`.
1447  	toBounds: function (sizeInMeters) {
1448  		var latAccuracy = 180 * sizeInMeters / 40075017,
1449  		    lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat);
1450
1451  		return toLatLngBounds(
1452  		        [this.lat - latAccuracy, this.lng - lngAccuracy],
1453  		        [this.lat + latAccuracy, this.lng + lngAccuracy]);
1454  	},
1455
1456  	clone: function () {
1457  		return new LatLng(this.lat, this.lng, this.alt);
1458  	}
1459  };
1460
1461
1462
1463  // @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng
1464  // Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude).
1465
1466  // @alternative
1467  // @factory L.latLng(coords: Array): LatLng
1468  // Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead.
1469
1470  // @alternative
1471  // @factory L.latLng(coords: Object): LatLng
1472  // Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead.
1473
1474  function toLatLng(a, b, c) {
1475  	if (a instanceof LatLng) {
1476  		return a;
1477  	}
1478  	if (isArray(a) && typeof a[0] !== 'object') {
1479  		if (a.length === 3) {
1480  			return new LatLng(a[0], a[1], a[2]);
1481  		}
1482  		if (a.length === 2) {
1483  			return new LatLng(a[0], a[1]);
1484  		}
1485  		return null;
1486  	}
1487  	if (a === undefined || a === null) {
1488  		return a;
1489  	}
1490  	if (typeof a === 'object' && 'lat' in a) {
1491  		return new LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt);
1492  	}
1493  	if (b === undefined) {
1494  		return null;
1495  	}
1496  	return new LatLng(a, b, c);
1497  }
1498
1499  /*
1500   * @namespace CRS
1501   * @crs L.CRS.Base
1502   * Object that defines coordinate reference systems for projecting
1503   * geographical points into pixel (screen) coordinates and back (and to
1504   * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See
1505   * [spatial reference system](http://en.wikipedia.org/wiki/Coordinate_reference_system).
1506   *
1507   * Leaflet defines the most usual CRSs by default. If you want to use a
1508   * CRS not defined by default, take a look at the
1509   * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin.
1510   *
1511   * Note that the CRS instances do not inherit from Leaflet's `Class` object,
1512   * and can't be instantiated. Also, new classes can't inherit from them,
1513   * and methods can't be added to them with the `include` function.
1514   */
1515
1516  var CRS = {
1517  	// @method latLngToPoint(latlng: LatLng, zoom: Number): Point
1518  	// Projects geographical coordinates into pixel coordinates for a given zoom.
1519  	latLngToPoint: function (latlng, zoom) {
1520  		var projectedPoint = this.projection.project(latlng),
1521  		    scale = this.scale(zoom);
1522
1523  		return this.transformation._transform(projectedPoint, scale);
1524  	},
1525
1526  	// @method pointToLatLng(point: Point, zoom: Number): LatLng
1527  	// The inverse of `latLngToPoint`. Projects pixel coordinates on a given
1528  	// zoom into geographical coordinates.
1529  	pointToLatLng: function (point, zoom) {
1530  		var scale = this.scale(zoom),
1531  		    untransformedPoint = this.transformation.untransform(point, scale);
1532
1533  		return this.projection.unproject(untransformedPoint);
1534  	},
1535
1536  	// @method project(latlng: LatLng): Point
1537  	// Projects geographical coordinates into coordinates in units accepted for
1538  	// this CRS (e.g. meters for EPSG:3857, for passing it to WMS services).
1539  	project: function (latlng) {
1540  		return this.projection.project(latlng);
1541  	},
1542
1543  	// @method unproject(point: Point): LatLng
1544  	// Given a projected coordinate returns the corresponding LatLng.
1545  	// The inverse of `project`.
1546  	unproject: function (point) {
1547  		return this.projection.unproject(point);
1548  	},
1549
1550  	// @method scale(zoom: Number): Number
1551  	// Returns the scale used when transforming projected coordinates into
1552  	// pixel coordinates for a particular zoom. For example, it returns
1553  	// `256 * 2^zoom` for Mercator-based CRS.
1554  	scale: function (zoom) {
1555  		return 256 * Math.pow(2, zoom);
1556  	},
1557
1558  	// @method zoom(scale: Number): Number
1559  	// Inverse of `scale()`, returns the zoom level corresponding to a scale
1560  	// factor of `scale`.
1561  	zoom: function (scale) {
1562  		return Math.log(scale / 256) / Math.LN2;
1563  	},
1564
1565  	// @method getProjectedBounds(zoom: Number): Bounds
1566  	// Returns the projection's bounds scaled and transformed for the provided `zoom`.
1567  	getProjectedBounds: function (zoom) {
1568  		if (this.infinite) { return null; }
1569
1570  		var b = this.projection.bounds,
1571  		    s = this.scale(zoom),
1572  		    min = this.transformation.transform(b.min, s),
1573  		    max = this.transformation.transform(b.max, s);
1574
1575  		return new Bounds(min, max);
1576  	},
1577
1578  	// @method distance(latlng1: LatLng, latlng2: LatLng): Number
1579  	// Returns the distance between two geographical coordinates.
1580
1581  	// @property code: String
1582  	// Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`)
1583  	//
1584  	// @property wrapLng: Number[]
1585  	// An array of two numbers defining whether the longitude (horizontal) coordinate
1586  	// axis wraps around a given range and how. Defaults to `[-180, 180]` in most
1587  	// geographical CRSs. If `undefined`, the longitude axis does not wrap around.
1588  	//
1589  	// @property wrapLat: Number[]
1590  	// Like `wrapLng`, but for the latitude (vertical) axis.
1591
1592  	// wrapLng: [min, max],
1593  	// wrapLat: [min, max],
1594
1595  	// @property infinite: Boolean
1596  	// If true, the coordinate space will be unbounded (infinite in both axes)
1597  	infinite: false,
1598
1599  	// @method wrapLatLng(latlng: LatLng): LatLng
1600  	// Returns a `LatLng` where lat and lng has been wrapped according to the
1601  	// CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds.
1602  	wrapLatLng: function (latlng) {
1603  		var lng = this.wrapLng ? wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng,
1604  		    lat = this.wrapLat ? wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat,
1605  		    alt = latlng.alt;
1606
vendor: 13,927 bytes, lines 1607-1997
1607  		return new LatLng(lat, lng, alt);
1608  	},
1609
1610  	// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds
1611  	// Returns a `LatLngBounds` with the same size as the given one, ensuring
1612  	// that its center is within the CRS's bounds.
1613  	// Only accepts actual `L.LatLngBounds` instances, not arrays.
1614  	wrapLatLngBounds: function (bounds) {
1615  		var center = bounds.getCenter(),
1616  		    newCenter = this.wrapLatLng(center),
1617  		    latShift = center.lat - newCenter.lat,
1618  		    lngShift = center.lng - newCenter.lng;
1619
1620  		if (latShift === 0 && lngShift === 0) {
1621  			return bounds;
1622  		}
1623
1624  		var sw = bounds.getSouthWest(),
1625  		    ne = bounds.getNorthEast(),
1626  		    newSw = new LatLng(sw.lat - latShift, sw.lng - lngShift),
1627  		    newNe = new LatLng(ne.lat - latShift, ne.lng - lngShift);
1628
1629  		return new LatLngBounds(newSw, newNe);
1630  	}
1631  };
1632
1633  /*
1634   * @namespace CRS
1635   * @crs L.CRS.Earth
1636   *
1637   * Serves as the base for CRS that are global such that they cover the earth.
1638   * Can only be used as the base for other CRS and cannot be used directly,
1639   * since it does not have a `code`, `projection` or `transformation`. `distance()` returns
1640   * meters.
1641   */
1642
1643  var Earth = extend({}, CRS, {
1644  	wrapLng: [-180, 180],
1645
1646  	// Mean Earth Radius, as recommended for use by
1647  	// the International Union of Geodesy and Geophysics,
1648  	// see http://rosettacode.org/wiki/Haversine_formula
1649  	R: 6371000,
1650
1651  	// distance between two geographical points using spherical law of cosines approximation
1652  	distance: function (latlng1, latlng2) {
1653  		var rad = Math.PI / 180,
1654  		    lat1 = latlng1.lat * rad,
1655  		    lat2 = latlng2.lat * rad,
1656  		    sinDLat = Math.sin((latlng2.lat - latlng1.lat) * rad / 2),
1657  		    sinDLon = Math.sin((latlng2.lng - latlng1.lng) * rad / 2),
1658  		    a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon,
1659  		    c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
1660  		return this.R * c;
1661  	}
1662  });
1663
1664  /*
1665   * @namespace Projection
1666   * @projection L.Projection.SphericalMercator
1667   *
1668   * Spherical Mercator projection — the most common projection for online maps,
1669   * used by almost all free and commercial tile providers. Assumes that Earth is
1670   * a sphere. Used by the `EPSG:3857` CRS.
1671   */
1672
1673  var earthRadius = 6378137;
1674
1675  var SphericalMercator = {
1676
1677  	R: earthRadius,
1678  	MAX_LATITUDE: 85.0511287798,
1679
1680  	project: function (latlng) {
1681  		var d = Math.PI / 180,
1682  		    max = this.MAX_LATITUDE,
1683  		    lat = Math.max(Math.min(max, latlng.lat), -max),
1684  		    sin = Math.sin(lat * d);
1685
1686  		return new Point(
1687  			this.R * latlng.lng * d,
1688  			this.R * Math.log((1 + sin) / (1 - sin)) / 2);
1689  	},
1690
1691  	unproject: function (point) {
1692  		var d = 180 / Math.PI;
1693
1694  		return new LatLng(
1695  			(2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d,
1696  			point.x * d / this.R);
1697  	},
1698
1699  	bounds: (function () {
1700  		var d = earthRadius * Math.PI;
1701  		return new Bounds([-d, -d], [d, d]);
1702  	})()
1703  };
1704
1705  /*
1706   * @class Transformation
1707   * @aka L.Transformation
1708   *
1709   * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d`
1710   * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing
1711   * the reverse. Used by Leaflet in its projections code.
1712   *
1713   * @example
1714   *
1715   * ```js
1716   * var transformation = L.transformation(2, 5, -1, 10),
1717   * 	p = L.point(1, 2),
1718   * 	p2 = transformation.transform(p), //  L.point(7, 8)
1719   * 	p3 = transformation.untransform(p2); //  L.point(1, 2)
1720   * ```
1721   */
1722
1723
1724  // factory new L.Transformation(a: Number, b: Number, c: Number, d: Number)
1725  // Creates a `Transformation` object with the given coefficients.
1726  function Transformation(a, b, c, d) {
1727  	if (isArray(a)) {
1728  		// use array properties
1729  		this._a = a[0];
1730  		this._b = a[1];
1731  		this._c = a[2];
1732  		this._d = a[3];
1733  		return;
1734  	}
1735  	this._a = a;
1736  	this._b = b;
1737  	this._c = c;
1738  	this._d = d;
1739  }
1740
1741  Transformation.prototype = {
1742  	// @method transform(point: Point, scale?: Number): Point
1743  	// Returns a transformed point, optionally multiplied by the given scale.
1744  	// Only accepts actual `L.Point` instances, not arrays.
1745  	transform: function (point, scale) { // (Point, Number) -> Point
1746  		return this._transform(point.clone(), scale);
1747  	},
1748
1749  	// destructive transform (faster)
1750  	_transform: function (point, scale) {
1751  		scale = scale || 1;
1752  		point.x = scale * (this._a * point.x + this._b);
1753  		point.y = scale * (this._c * point.y + this._d);
1754  		return point;
1755  	},
1756
1757  	// @method untransform(point: Point, scale?: Number): Point
1758  	// Returns the reverse transformation of the given point, optionally divided
1759  	// by the given scale. Only accepts actual `L.Point` instances, not arrays.
1760  	untransform: function (point, scale) {
1761  		scale = scale || 1;
1762  		return new Point(
1763  		        (point.x / scale - this._b) / this._a,
1764  		        (point.y / scale - this._d) / this._c);
1765  	}
1766  };
1767
1768  // factory L.transformation(a: Number, b: Number, c: Number, d: Number)
1769
1770  // @factory L.transformation(a: Number, b: Number, c: Number, d: Number)
1771  // Instantiates a Transformation object with the given coefficients.
1772
1773  // @alternative
1774  // @factory L.transformation(coefficients: Array): Transformation
1775  // Expects an coefficients array of the form
1776  // `[a: Number, b: Number, c: Number, d: Number]`.
1777
1778  function toTransformation(a, b, c, d) {
1779  	return new Transformation(a, b, c, d);
1780  }
1781
1782  /*
1783   * @namespace CRS
1784   * @crs L.CRS.EPSG3857
1785   *
1786   * The most common CRS for online maps, used by almost all free and commercial
1787   * tile providers. Uses Spherical Mercator projection. Set in by default in
1788   * Map's `crs` option.
1789   */
1790
1791  var EPSG3857 = extend({}, Earth, {
1792  	code: 'EPSG:3857',
1793  	projection: SphericalMercator,
1794
1795  	transformation: (function () {
1796  		var scale = 0.5 / (Math.PI * SphericalMercator.R);
1797  		return toTransformation(scale, 0.5, -scale, 0.5);
1798  	}())
1799  });
1800
1801  var EPSG900913 = extend({}, EPSG3857, {
1802  	code: 'EPSG:900913'
1803  });
1804
1805  // @namespace SVG; @section
1806  // There are several static functions which can be called without instantiating L.SVG:
1807
1808  // @function create(name: String): SVGElement
1809  // Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement),
1810  // corresponding to the class name passed. For example, using 'line' will return
1811  // an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement).
1812  function svgCreate(name) {
1813  	return document.createElementNS('http://www.w3.org/2000/svg', name);
1814  }
1815
1816  // @function pointsToPath(rings: Point[], closed: Boolean): String
1817  // Generates a SVG path string for multiple rings, with each ring turning
1818  // into "M..L..L.." instructions
1819  function pointsToPath(rings, closed) {
1820  	var str = '',
1821  	i, j, len, len2, points, p;
1822
1823  	for (i = 0, len = rings.length; i < len; i++) {
1824  		points = rings[i];
1825
1826  		for (j = 0, len2 = points.length; j < len2; j++) {
1827  			p = points[j];
1828  			str += (j ? 'L' : 'M') + p.x + ' ' + p.y;
1829  		}
1830
1831  		// closes the ring for polygons; "x" is VML syntax
1832  		str += closed ? (svg$1 ? 'z' : 'x') : '';
1833  	}
1834
1835  	// SVG complains about empty path strings
1836  	return str || 'M0 0';
1837  }
1838
1839  /*
1840   * @namespace Browser
1841   * @aka L.Browser
1842   *
1843   * A namespace with static properties for browser/feature detection used by Leaflet internally.
1844   *
1845   * @example
1846   *
1847   * ```js
1848   * if (L.Browser.ielt9) {
1849   *   alert('Upgrade your browser, dude!');
1850   * }
1851   * ```
1852   */
1853
1854  var style = document.documentElement.style;
1855
1856  // @property ie: Boolean; `true` for all Internet Explorer versions (not Edge).
1857  var ie = 'ActiveXObject' in window;
1858
1859  // @property ielt9: Boolean; `true` for Internet Explorer versions less than 9.
1860  var ielt9 = ie && !document.addEventListener;
1861
1862  // @property edge: Boolean; `true` for the Edge web browser.
1863  var edge = 'msLaunchUri' in navigator && !('documentMode' in document);
1864
1865  // @property webkit: Boolean;
1866  // `true` for webkit-based browsers like Chrome and Safari (including mobile versions).
1867  var webkit = userAgentContains('webkit');
1868
1869  // @property android: Boolean
1870  // **Deprecated.** `true` for any browser running on an Android platform.
1871  var android = userAgentContains('android');
1872
1873  // @property android23: Boolean; **Deprecated.** `true` for browsers running on Android 2 or Android 3.
1874  var android23 = userAgentContains('android 2') || userAgentContains('android 3');
1875
1876  /* See https://stackoverflow.com/a/17961266 for details on detecting stock Android */
1877  var webkitVer = parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10); // also matches AppleWebKit
1878  // @property androidStock: Boolean; **Deprecated.** `true` for the Android stock browser (i.e. not Chrome)
1879  var androidStock = android && userAgentContains('Google') && webkitVer < 537 && !('AudioNode' in window);
1880
1881  // @property opera: Boolean; `true` for the Opera browser
1882  var opera = !!window.opera;
1883
1884  // @property chrome: Boolean; `true` for the Chrome browser.
1885  var chrome = !edge && userAgentContains('chrome');
1886
1887  // @property gecko: Boolean; `true` for gecko-based browsers like Firefox.
1888  var gecko = userAgentContains('gecko') && !webkit && !opera && !ie;
1889
1890  // @property safari: Boolean; `true` for the Safari browser.
1891  var safari = !chrome && userAgentContains('safari');
1892
1893  var phantom = userAgentContains('phantom');
1894
1895  // @property opera12: Boolean
1896  // `true` for the Opera browser supporting CSS transforms (version 12 or later).
1897  var opera12 = 'OTransition' in style;
1898
1899  // @property win: Boolean; `true` when the browser is running in a Windows platform
1900  var win = navigator.platform.indexOf('Win') === 0;
1901
1902  // @property ie3d: Boolean; `true` for all Internet Explorer versions supporting CSS transforms.
1903  var ie3d = ie && ('transition' in style);
1904
1905  // @property webkit3d: Boolean; `true` for webkit-based browsers supporting CSS transforms.
1906  var webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23;
1907
1908  // @property gecko3d: Boolean; `true` for gecko-based browsers supporting CSS transforms.
1909  var gecko3d = 'MozPerspective' in style;
1910
1911  // @property any3d: Boolean
1912  // `true` for all browsers supporting CSS transforms.
1913  var any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantom;
1914
1915  // @property mobile: Boolean; `true` for all browsers running in a mobile device.
1916  var mobile = typeof orientation !== 'undefined' || userAgentContains('mobile');
1917
1918  // @property mobileWebkit: Boolean; `true` for all webkit-based browsers in a mobile device.
1919  var mobileWebkit = mobile && webkit;
1920
1921  // @property mobileWebkit3d: Boolean
1922  // `true` for all webkit-based browsers in a mobile device supporting CSS transforms.
1923  var mobileWebkit3d = mobile && webkit3d;
1924
1925  // @property msPointer: Boolean
1926  // `true` for browsers implementing the Microsoft touch events model (notably IE10).
1927  var msPointer = !window.PointerEvent && window.MSPointerEvent;
1928
1929  // @property pointer: Boolean
1930  // `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx).
1931  var pointer = !!(window.PointerEvent || msPointer);
1932
1933  // @property touchNative: Boolean
1934  // `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).
1935  // **This does not necessarily mean** that the browser is running in a computer with
1936  // a touchscreen, it only means that the browser is capable of understanding
1937  // touch events.
1938  var touchNative = 'ontouchstart' in window || !!window.TouchEvent;
1939
1940  // @property touch: Boolean
1941  // `true` for all browsers supporting either [touch](#browser-touch) or [pointer](#browser-pointer) events.
1942  // Note: pointer events will be preferred (if available), and processed for all `touch*` listeners.
1943  var touch = !window.L_NO_TOUCH && (touchNative || pointer);
1944
1945  // @property mobileOpera: Boolean; `true` for the Opera browser in a mobile device.
1946  var mobileOpera = mobile && opera;
1947
1948  // @property mobileGecko: Boolean
1949  // `true` for gecko-based browsers running in a mobile device.
1950  var mobileGecko = mobile && gecko;
1951
1952  // @property retina: Boolean
1953  // `true` for browsers on a high-resolution "retina" screen or on any screen when browser's display zoom is more than 100%.
1954  var retina = (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1;
1955
1956  // @property passiveEvents: Boolean
1957  // `true` for browsers that support passive events.
1958  var passiveEvents = (function () {
1959  	var supportsPassiveOption = false;
1960  	try {
1961  		var opts = Object.defineProperty({}, 'passive', {
1962  			get: function () { // eslint-disable-line getter-return
1963  				supportsPassiveOption = true;
1964  			}
1965  		});
1966  		window.addEventListener('testPassiveEventSupport', falseFn, opts);
1967  		window.removeEventListener('testPassiveEventSupport', falseFn, opts);
1968  	} catch (e) {
1969  		// Errors can safely be ignored since this is only a browser support test.
1970  	}
1971  	return supportsPassiveOption;
1972  }());
1973
1974  // @property canvas: Boolean
1975  // `true` when the browser supports [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
1976  var canvas$1 = (function () {
1977  	return !!document.createElement('canvas').getContext;
1978  }());
1979
1980  // @property svg: Boolean
1981  // `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG).
1982  var svg$1 = !!(document.createElementNS && svgCreate('svg').createSVGRect);
1983
1984  // @property vml: Boolean
1985  // `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language).
1986  var vml = !svg$1 && (function () {
1987  	try {
1988  		var div = document.createElement('div');
1989  		div.innerHTML = '<v:shape adj="1"/>';
1990
1991  		var shape = div.firstChild;
1992  		shape.style.behavior = 'url(#default#VML)';
1993
1994  		return shape && (typeof shape.adj === 'object');
1995
1996  	} catch (e) {
1997  		return false;
1998  	}
1999  }());
2000
2001
2002  function userAgentContains(str) {
2003  	return navigator.userAgent.toLowerCase().indexOf(str) >= 0;
2004  }
2005
2006  var Browser = {
2007    __proto__: null,
2008    ie: ie,
2009    ielt9: ielt9,
2010    edge: edge,
2011    webkit: webkit,
2012    android: android,
2013    android23: android23,
2014    androidStock: androidStock,
2015    opera: opera,
2016    chrome: chrome,
2017    gecko: gecko,
2018    safari: safari,
2019    phantom: phantom,
2020    opera12: opera12,
2021    win: win,
2022    ie3d: ie3d,
2023    webkit3d: webkit3d,
2024    gecko3d: gecko3d,
2025    any3d: any3d,
2026    mobile: mobile,
2027    mobileWebkit: mobileWebkit,
2028    mobileWebkit3d: mobileWebkit3d,
2029    msPointer: msPointer,
2030    pointer: pointer,
2031    touchNative: touchNative,
2032    touch: touch,
2033    mobileOpera: mobileOpera,
2034    mobileGecko: mobileGecko,
2035    retina: retina,
2036    passiveEvents: passiveEvents,
2037    canvas: canvas$1,
2038    svg: svg$1,
2039    vml: vml
2040  };
2041
2042  /*
2043   * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.
2044   */
2045
2046  var POINTER_DOWN =   msPointer ? 'MSPointerDown'   : 'pointerdown';
2047  var POINTER_MOVE =   msPointer ? 'MSPointerMove'   : 'pointermove';
2048  var POINTER_UP =     msPointer ? 'MSPointerUp'     : 'pointerup';
2049  var POINTER_CANCEL = msPointer ? 'MSPointerCancel' : 'pointercancel';
2050  var pEvent = {
2051  	touchstart  : POINTER_DOWN,
2052  	touchmove   : POINTER_MOVE,
2053  	touchend    : POINTER_UP,
2054  	touchcancel : POINTER_CANCEL
2055  };
2056  var handle = {
2057  	touchstart  : _onPointerStart,
2058  	touchmove   : _handlePointer,
2059  	touchend    : _handlePointer,
2060  	touchcancel : _handlePointer
2061  };
2062  var _pointers = {};
2063  var _pointerDocListener = false;
vendor: 154,267 bytes, lines 2064-7013
2064
2065  // Provides a touch events wrapper for (ms)pointer events.
2066  // ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
2067
2068  function addPointerListener(obj, type, handler) {
2069  	if (type === 'touchstart') {
2070  		_addPointerDocListener();
2071  	}
2072  	if (!handle[type]) {
2073  		console.warn('wrong event specified:', type);
2074  		return L.Util.falseFn;
2075  	}
2076  	handler = handle[type].bind(this, handler);
2077  	obj.addEventListener(pEvent[type], handler, false);
2078  	return handler;
2079  }
2080
2081  function removePointerListener(obj, type, handler) {
2082  	if (!pEvent[type]) {
2083  		console.warn('wrong event specified:', type);
2084  		return;
2085  	}
2086  	obj.removeEventListener(pEvent[type], handler, false);
2087  }
2088
2089  function _globalPointerDown(e) {
2090  	_pointers[e.pointerId] = e;
2091  }
2092
2093  function _globalPointerMove(e) {
2094  	if (_pointers[e.pointerId]) {
2095  		_pointers[e.pointerId] = e;
2096  	}
2097  }
2098
2099  function _globalPointerUp(e) {
2100  	delete _pointers[e.pointerId];
2101  }
2102
2103  function _addPointerDocListener() {
2104  	// need to keep track of what pointers and how many are active to provide e.touches emulation
2105  	if (!_pointerDocListener) {
2106  		// we listen document as any drags that end by moving the touch off the screen get fired there
2107  		document.addEventListener(POINTER_DOWN, _globalPointerDown, true);
2108  		document.addEventListener(POINTER_MOVE, _globalPointerMove, true);
2109  		document.addEventListener(POINTER_UP, _globalPointerUp, true);
2110  		document.addEventListener(POINTER_CANCEL, _globalPointerUp, true);
2111
2112  		_pointerDocListener = true;
2113  	}
2114  }
2115
2116  function _handlePointer(handler, e) {
2117  	if (e.pointerType === (e.MSPOINTER_TYPE_MOUSE || 'mouse')) { return; }
2118
2119  	e.touches = [];
2120  	for (var i in _pointers) {
2121  		e.touches.push(_pointers[i]);
2122  	}
2123  	e.changedTouches = [e];
2124
2125  	handler(e);
2126  }
2127
2128  function _onPointerStart(handler, e) {
2129  	// IE10 specific: MsTouch needs preventDefault. See #2000
2130  	if (e.MSPOINTER_TYPE_TOUCH && e.pointerType === e.MSPOINTER_TYPE_TOUCH) {
2131  		preventDefault(e);
2132  	}
2133  	_handlePointer(handler, e);
2134  }
2135
2136  /*
2137   * Extends the event handling code with double tap support for mobile browsers.
2138   *
2139   * Note: currently most browsers fire native dblclick, with only a few exceptions
2140   * (see https://github.com/Leaflet/Leaflet/issues/7012#issuecomment-595087386)
2141   */
2142
2143  function makeDblclick(event) {
2144  	// in modern browsers `type` cannot be just overridden:
2145  	// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only
2146  	var newEvent = {},
2147  	    prop, i;
2148  	for (i in event) {
2149  		prop = event[i];
2150  		newEvent[i] = prop && prop.bind ? prop.bind(event) : prop;
2151  	}
2152  	event = newEvent;
2153  	newEvent.type = 'dblclick';
2154  	newEvent.detail = 2;
2155  	newEvent.isTrusted = false;
2156  	newEvent._simulated = true; // for debug purposes
2157  	return newEvent;
2158  }
2159
2160  var delay = 200;
2161  function addDoubleTapListener(obj, handler) {
2162  	// Most browsers handle double tap natively
2163  	obj.addEventListener('dblclick', handler);
2164
2165  	// On some platforms the browser doesn't fire native dblclicks for touch events.
2166  	// It seems that in all such cases `detail` property of `click` event is always `1`.
2167  	// So here we rely on that fact to avoid excessive 'dblclick' simulation when not needed.
2168  	var last = 0,
2169  	    detail;
2170  	function simDblclick(e) {
2171  		if (e.detail !== 1) {
2172  			detail = e.detail; // keep in sync to avoid false dblclick in some cases
2173  			return;
2174  		}
2175
2176  		if (e.pointerType === 'mouse' ||
2177  			(e.sourceCapabilities && !e.sourceCapabilities.firesTouchEvents)) {
2178
2179  			return;
2180  		}
2181
2182  		var now = Date.now();
2183  		if (now - last <= delay) {
2184  			detail++;
2185  			if (detail === 2) {
2186  				handler(makeDblclick(e));
2187  			}
2188  		} else {
2189  			detail = 1;
2190  		}
2191  		last = now;
2192  	}
2193
2194  	obj.addEventListener('click', simDblclick);
2195
2196  	return {
2197  		dblclick: handler,
2198  		simDblclick: simDblclick
2199  	};
2200  }
2201
2202  function removeDoubleTapListener(obj, handlers) {
2203  	obj.removeEventListener('dblclick', handlers.dblclick);
2204  	obj.removeEventListener('click', handlers.simDblclick);
2205  }
2206
2207  /*
2208   * @namespace DomUtil
2209   *
2210   * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)
2211   * tree, used by Leaflet internally.
2212   *
2213   * Most functions expecting or returning a `HTMLElement` also work for
2214   * SVG elements. The only difference is that classes refer to CSS classes
2215   * in HTML and SVG classes in SVG.
2216   */
2217
2218
2219  // @property TRANSFORM: String
2220  // Vendor-prefixed transform style name (e.g. `'webkitTransform'` for WebKit).
2221  var TRANSFORM = testProp(
2222  	['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
2223
2224  // webkitTransition comes first because some browser versions that drop vendor prefix don't do
2225  // the same for the transitionend event, in particular the Android 4.1 stock browser
2226
2227  // @property TRANSITION: String
2228  // Vendor-prefixed transition style name.
2229  var TRANSITION = testProp(
2230  	['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);
2231
2232  // @property TRANSITION_END: String
2233  // Vendor-prefixed transitionend event name.
2234  var TRANSITION_END =
2235  	TRANSITION === 'webkitTransition' || TRANSITION === 'OTransition' ? TRANSITION + 'End' : 'transitionend';
2236
2237
2238  // @function get(id: String|HTMLElement): HTMLElement
2239  // Returns an element given its DOM id, or returns the element itself
2240  // if it was passed directly.
2241  function get(id) {
2242  	return typeof id === 'string' ? document.getElementById(id) : id;
2243  }
2244
2245  // @function getStyle(el: HTMLElement, styleAttrib: String): String
2246  // Returns the value for a certain style attribute on an element,
2247  // including computed values or values set through CSS.
2248  function getStyle(el, style) {
2249  	var value = el.style[style] || (el.currentStyle && el.currentStyle[style]);
2250
2251  	if ((!value || value === 'auto') && document.defaultView) {
2252  		var css = document.defaultView.getComputedStyle(el, null);
2253  		value = css ? css[style] : null;
2254  	}
2255  	return value === 'auto' ? null : value;
2256  }
2257
2258  // @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement
2259  // Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element.
2260  function create$1(tagName, className, container) {
2261  	var el = document.createElement(tagName);
2262  	el.className = className || '';
2263
2264  	if (container) {
2265  		container.appendChild(el);
2266  	}
2267  	return el;
2268  }
2269
2270  // @function remove(el: HTMLElement)
2271  // Removes `el` from its parent element
2272  function remove(el) {
2273  	var parent = el.parentNode;
2274  	if (parent) {
2275  		parent.removeChild(el);
2276  	}
2277  }
2278
2279  // @function empty(el: HTMLElement)
2280  // Removes all of `el`'s children elements from `el`
2281  function empty(el) {
2282  	while (el.firstChild) {
2283  		el.removeChild(el.firstChild);
2284  	}
2285  }
2286
2287  // @function toFront(el: HTMLElement)
2288  // Makes `el` the last child of its parent, so it renders in front of the other children.
2289  function toFront(el) {
2290  	var parent = el.parentNode;
2291  	if (parent && parent.lastChild !== el) {
2292  		parent.appendChild(el);
2293  	}
2294  }
2295
2296  // @function toBack(el: HTMLElement)
2297  // Makes `el` the first child of its parent, so it renders behind the other children.
2298  function toBack(el) {
2299  	var parent = el.parentNode;
2300  	if (parent && parent.firstChild !== el) {
2301  		parent.insertBefore(el, parent.firstChild);
2302  	}
2303  }
2304
2305  // @function hasClass(el: HTMLElement, name: String): Boolean
2306  // Returns `true` if the element's class attribute contains `name`.
2307  function hasClass(el, name) {
2308  	if (el.classList !== undefined) {
2309  		return el.classList.contains(name);
2310  	}
2311  	var className = getClass(el);
2312  	return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className);
2313  }
2314
2315  // @function addClass(el: HTMLElement, name: String)
2316  // Adds `name` to the element's class attribute.
2317  function addClass(el, name) {
2318  	if (el.classList !== undefined) {
2319  		var classes = splitWords(name);
2320  		for (var i = 0, len = classes.length; i < len; i++) {
2321  			el.classList.add(classes[i]);
2322  		}
2323  	} else if (!hasClass(el, name)) {
2324  		var className = getClass(el);
2325  		setClass(el, (className ? className + ' ' : '') + name);
2326  	}
2327  }
2328
2329  // @function removeClass(el: HTMLElement, name: String)
2330  // Removes `name` from the element's class attribute.
2331  function removeClass(el, name) {
2332  	if (el.classList !== undefined) {
2333  		el.classList.remove(name);
2334  	} else {
2335  		setClass(el, trim((' ' + getClass(el) + ' ').replace(' ' + name + ' ', ' ')));
2336  	}
2337  }
2338
2339  // @function setClass(el: HTMLElement, name: String)
2340  // Sets the element's class.
2341  function setClass(el, name) {
2342  	if (el.className.baseVal === undefined) {
2343  		el.className = name;
2344  	} else {
2345  		// in case of SVG element
2346  		el.className.baseVal = name;
2347  	}
2348  }
2349
2350  // @function getClass(el: HTMLElement): String
2351  // Returns the element's class.
2352  function getClass(el) {
2353  	// Check if the element is an SVGElementInstance and use the correspondingElement instead
2354  	// (Required for linked SVG elements in IE11.)
2355  	if (el.correspondingElement) {
2356  		el = el.correspondingElement;
2357  	}
2358  	return el.className.baseVal === undefined ? el.className : el.className.baseVal;
2359  }
2360
2361  // @function setOpacity(el: HTMLElement, opacity: Number)
2362  // Set the opacity of an element (including old IE support).
2363  // `opacity` must be a number from `0` to `1`.
2364  function setOpacity(el, value) {
2365  	if ('opacity' in el.style) {
2366  		el.style.opacity = value;
2367  	} else if ('filter' in el.style) {
2368  		_setOpacityIE(el, value);
2369  	}
2370  }
2371
2372  function _setOpacityIE(el, value) {
2373  	var filter = false,
2374  	    filterName = 'DXImageTransform.Microsoft.Alpha';
2375
2376  	// filters collection throws an error if we try to retrieve a filter that doesn't exist
2377  	try {
2378  		filter = el.filters.item(filterName);
2379  	} catch (e) {
2380  		// don't set opacity to 1 if we haven't already set an opacity,
2381  		// it isn't needed and breaks transparent pngs.
2382  		if (value === 1) { return; }
2383  	}
2384
2385  	value = Math.round(value * 100);
2386
2387  	if (filter) {
2388  		filter.Enabled = (value !== 100);
2389  		filter.Opacity = value;
2390  	} else {
2391  		el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';
2392  	}
2393  }
2394
2395  // @function testProp(props: String[]): String|false
2396  // Goes through the array of style names and returns the first name
2397  // that is a valid style name for an element. If no such name is found,
2398  // it returns false. Useful for vendor-prefixed styles like `transform`.
2399  function testProp(props) {
2400  	var style = document.documentElement.style;
2401
2402  	for (var i = 0; i < props.length; i++) {
2403  		if (props[i] in style) {
2404  			return props[i];
2405  		}
2406  	}
2407  	return false;
2408  }
2409
2410  // @function setTransform(el: HTMLElement, offset: Point, scale?: Number)
2411  // Resets the 3D CSS transform of `el` so it is translated by `offset` pixels
2412  // and optionally scaled by `scale`. Does not have an effect if the
2413  // browser doesn't support 3D CSS transforms.
2414  function setTransform(el, offset, scale) {
2415  	var pos = offset || new Point(0, 0);
2416
2417  	el.style[TRANSFORM] =
2418  		(ie3d ?
2419  			'translate(' + pos.x + 'px,' + pos.y + 'px)' :
2420  			'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') +
2421  		(scale ? ' scale(' + scale + ')' : '');
2422  }
2423
2424  // @function setPosition(el: HTMLElement, position: Point)
2425  // Sets the position of `el` to coordinates specified by `position`,
2426  // using CSS translate or top/left positioning depending on the browser
2427  // (used by Leaflet internally to position its layers).
2428  function setPosition(el, point) {
2429
2430  	/*eslint-disable */
2431  	el._leaflet_pos = point;
2432  	/* eslint-enable */
2433
2434  	if (any3d) {
2435  		setTransform(el, point);
2436  	} else {
2437  		el.style.left = point.x + 'px';
2438  		el.style.top = point.y + 'px';
2439  	}
2440  }
2441
2442  // @function getPosition(el: HTMLElement): Point
2443  // Returns the coordinates of an element previously positioned with setPosition.
2444  function getPosition(el) {
2445  	// this method is only used for elements previously positioned using setPosition,
2446  	// so it's safe to cache the position for performance
2447
2448  	return el._leaflet_pos || new Point(0, 0);
2449  }
2450
2451  // @function disableTextSelection()
2452  // Prevents the user from generating `selectstart` DOM events, usually generated
2453  // when the user drags the mouse through a page with text. Used internally
2454  // by Leaflet to override the behaviour of any click-and-drag interaction on
2455  // the map. Affects drag interactions on the whole document.
2456
2457  // @function enableTextSelection()
2458  // Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection).
2459  var disableTextSelection;
2460  var enableTextSelection;
2461  var _userSelect;
2462  if ('onselectstart' in document) {
2463  	disableTextSelection = function () {
2464  		on(window, 'selectstart', preventDefault);
2465  	};
2466  	enableTextSelection = function () {
2467  		off(window, 'selectstart', preventDefault);
2468  	};
2469  } else {
2470  	var userSelectProperty = testProp(
2471  		['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
2472
2473  	disableTextSelection = function () {
2474  		if (userSelectProperty) {
2475  			var style = document.documentElement.style;
2476  			_userSelect = style[userSelectProperty];
2477  			style[userSelectProperty] = 'none';
2478  		}
2479  	};
2480  	enableTextSelection = function () {
2481  		if (userSelectProperty) {
2482  			document.documentElement.style[userSelectProperty] = _userSelect;
2483  			_userSelect = undefined;
2484  		}
2485  	};
2486  }
2487
2488  // @function disableImageDrag()
2489  // As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but
2490  // for `dragstart` DOM events, usually generated when the user drags an image.
2491  function disableImageDrag() {
2492  	on(window, 'dragstart', preventDefault);
2493  }
2494
2495  // @function enableImageDrag()
2496  // Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection).
2497  function enableImageDrag() {
2498  	off(window, 'dragstart', preventDefault);
2499  }
2500
2501  var _outlineElement, _outlineStyle;
2502  // @function preventOutline(el: HTMLElement)
2503  // Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline)
2504  // of the element `el` invisible. Used internally by Leaflet to prevent
2505  // focusable elements from displaying an outline when the user performs a
2506  // drag interaction on them.
2507  function preventOutline(element) {
2508  	while (element.tabIndex === -1) {
2509  		element = element.parentNode;
2510  	}
2511  	if (!element.style) { return; }
2512  	restoreOutline();
2513  	_outlineElement = element;
2514  	_outlineStyle = element.style.outline;
2515  	element.style.outline = 'none';
2516  	on(window, 'keydown', restoreOutline);
2517  }
2518
2519  // @function restoreOutline()
2520  // Cancels the effects of a previous [`L.DomUtil.preventOutline`]().
2521  function restoreOutline() {
2522  	if (!_outlineElement) { return; }
2523  	_outlineElement.style.outline = _outlineStyle;
2524  	_outlineElement = undefined;
2525  	_outlineStyle = undefined;
2526  	off(window, 'keydown', restoreOutline);
2527  }
2528
2529  // @function getSizedParentNode(el: HTMLElement): HTMLElement
2530  // Finds the closest parent node which size (width and height) is not null.
2531  function getSizedParentNode(element) {
2532  	do {
2533  		element = element.parentNode;
2534  	} while ((!element.offsetWidth || !element.offsetHeight) && element !== document.body);
2535  	return element;
2536  }
2537
2538  // @function getScale(el: HTMLElement): Object
2539  // Computes the CSS scale currently applied on the element.
2540  // Returns an object with `x` and `y` members as horizontal and vertical scales respectively,
2541  // and `boundingClientRect` as the result of [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect).
2542  function getScale(element) {
2543  	var rect = element.getBoundingClientRect(); // Read-only in old browsers.
2544
2545  	return {
2546  		x: rect.width / element.offsetWidth || 1,
2547  		y: rect.height / element.offsetHeight || 1,
2548  		boundingClientRect: rect
2549  	};
2550  }
2551
2552  var DomUtil = {
2553    __proto__: null,
2554    TRANSFORM: TRANSFORM,
2555    TRANSITION: TRANSITION,
2556    TRANSITION_END: TRANSITION_END,
2557    get: get,
2558    getStyle: getStyle,
2559    create: create$1,
2560    remove: remove,
2561    empty: empty,
2562    toFront: toFront,
2563    toBack: toBack,
2564    hasClass: hasClass,
2565    addClass: addClass,
2566    removeClass: removeClass,
2567    setClass: setClass,
2568    getClass: getClass,
2569    setOpacity: setOpacity,
2570    testProp: testProp,
2571    setTransform: setTransform,
2572    setPosition: setPosition,
2573    getPosition: getPosition,
2574    get disableTextSelection () { return disableTextSelection; },
2575    get enableTextSelection () { return enableTextSelection; },
2576    disableImageDrag: disableImageDrag,
2577    enableImageDrag: enableImageDrag,
2578    preventOutline: preventOutline,
2579    restoreOutline: restoreOutline,
2580    getSizedParentNode: getSizedParentNode,
2581    getScale: getScale
2582  };
2583
2584  /*
2585   * @namespace DomEvent
2586   * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally.
2587   */
2588
2589  // Inspired by John Resig, Dean Edwards and YUI addEvent implementations.
2590
2591  // @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this
2592  // Adds a listener function (`fn`) to a particular DOM event type of the
2593  // element `el`. You can optionally specify the context of the listener
2594  // (object the `this` keyword will point to). You can also pass several
2595  // space-separated types (e.g. `'click dblclick'`).
2596
2597  // @alternative
2598  // @function on(el: HTMLElement, eventMap: Object, context?: Object): this
2599  // Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
2600  function on(obj, types, fn, context) {
2601
2602  	if (types && typeof types === 'object') {
2603  		for (var type in types) {
2604  			addOne(obj, type, types[type], fn);
2605  		}
2606  	} else {
2607  		types = splitWords(types);
2608
2609  		for (var i = 0, len = types.length; i < len; i++) {
2610  			addOne(obj, types[i], fn, context);
2611  		}
2612  	}
2613
2614  	return this;
2615  }
2616
2617  var eventsKey = '_leaflet_events';
2618
2619  // @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this
2620  // Removes a previously added listener function.
2621  // Note that if you passed a custom context to on, you must pass the same
2622  // context to `off` in order to remove the listener.
2623
2624  // @alternative
2625  // @function off(el: HTMLElement, eventMap: Object, context?: Object): this
2626  // Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
2627
2628  // @alternative
2629  // @function off(el: HTMLElement, types: String): this
2630  // Removes all previously added listeners of given types.
2631
2632  // @alternative
2633  // @function off(el: HTMLElement): this
2634  // Removes all previously added listeners from given HTMLElement
2635  function off(obj, types, fn, context) {
2636
2637  	if (arguments.length === 1) {
2638  		batchRemove(obj);
2639  		delete obj[eventsKey];
2640
2641  	} else if (types && typeof types === 'object') {
2642  		for (var type in types) {
2643  			removeOne(obj, type, types[type], fn);
2644  		}
2645
2646  	} else {
2647  		types = splitWords(types);
2648
2649  		if (arguments.length === 2) {
2650  			batchRemove(obj, function (type) {
2651  				return indexOf(types, type) !== -1;
2652  			});
2653  		} else {
2654  			for (var i = 0, len = types.length; i < len; i++) {
2655  				removeOne(obj, types[i], fn, context);
2656  			}
2657  		}
2658  	}
2659
2660  	return this;
2661  }
2662
2663  function batchRemove(obj, filterFn) {
2664  	for (var id in obj[eventsKey]) {
2665  		var type = id.split(/\d/)[0];
2666  		if (!filterFn || filterFn(type)) {
2667  			removeOne(obj, type, null, null, id);
2668  		}
2669  	}
2670  }
2671
2672  var mouseSubst = {
2673  	mouseenter: 'mouseover',
2674  	mouseleave: 'mouseout',
2675  	wheel: !('onwheel' in window) && 'mousewheel'
2676  };
2677
2678  function addOne(obj, type, fn, context) {
2679  	var id = type + stamp(fn) + (context ? '_' + stamp(context) : '');
2680
2681  	if (obj[eventsKey] && obj[eventsKey][id]) { return this; }
2682
2683  	var handler = function (e) {
2684  		return fn.call(context || obj, e || window.event);
2685  	};
2686
2687  	var originalHandler = handler;
2688
2689  	if (!touchNative && pointer && type.indexOf('touch') === 0) {
2690  		// Needs DomEvent.Pointer.js
2691  		handler = addPointerListener(obj, type, handler);
2692
2693  	} else if (touch && (type === 'dblclick')) {
2694  		handler = addDoubleTapListener(obj, handler);
2695
2696  	} else if ('addEventListener' in obj) {
2697
2698  		if (type === 'touchstart' || type === 'touchmove' || type === 'wheel' ||  type === 'mousewheel') {
2699  			obj.addEventListener(mouseSubst[type] || type, handler, passiveEvents ? {passive: false} : false);
2700
2701  		} else if (type === 'mouseenter' || type === 'mouseleave') {
2702  			handler = function (e) {
2703  				e = e || window.event;
2704  				if (isExternalTarget(obj, e)) {
2705  					originalHandler(e);
2706  				}
2707  			};
2708  			obj.addEventListener(mouseSubst[type], handler, false);
2709
2710  		} else {
2711  			obj.addEventListener(type, originalHandler, false);
2712  		}
2713
2714  	} else {
2715  		obj.attachEvent('on' + type, handler);
2716  	}
2717
2718  	obj[eventsKey] = obj[eventsKey] || {};
2719  	obj[eventsKey][id] = handler;
2720  }
2721
2722  function removeOne(obj, type, fn, context, id) {
2723  	id = id || type + stamp(fn) + (context ? '_' + stamp(context) : '');
2724  	var handler = obj[eventsKey] && obj[eventsKey][id];
2725
2726  	if (!handler) { return this; }
2727
2728  	if (!touchNative && pointer && type.indexOf('touch') === 0) {
2729  		removePointerListener(obj, type, handler);
2730
2731  	} else if (touch && (type === 'dblclick')) {
2732  		removeDoubleTapListener(obj, handler);
2733
2734  	} else if ('removeEventListener' in obj) {
2735
2736  		obj.removeEventListener(mouseSubst[type] || type, handler, false);
2737
2738  	} else {
2739  		obj.detachEvent('on' + type, handler);
2740  	}
2741
2742  	obj[eventsKey][id] = null;
2743  }
2744
2745  // @function stopPropagation(ev: DOMEvent): this
2746  // Stop the given event from propagation to parent elements. Used inside the listener functions:
2747  // ```js
2748  // L.DomEvent.on(div, 'click', function (ev) {
2749  // 	L.DomEvent.stopPropagation(ev);
2750  // });
2751  // ```
2752  function stopPropagation(e) {
2753
2754  	if (e.stopPropagation) {
2755  		e.stopPropagation();
2756  	} else if (e.originalEvent) {  // In case of Leaflet event.
2757  		e.originalEvent._stopped = true;
2758  	} else {
2759  		e.cancelBubble = true;
2760  	}
2761
2762  	return this;
2763  }
2764
2765  // @function disableScrollPropagation(el: HTMLElement): this
2766  // Adds `stopPropagation` to the element's `'wheel'` events (plus browser variants).
2767  function disableScrollPropagation(el) {
2768  	addOne(el, 'wheel', stopPropagation);
2769  	return this;
2770  }
2771
2772  // @function disableClickPropagation(el: HTMLElement): this
2773  // Adds `stopPropagation` to the element's `'click'`, `'dblclick'`, `'contextmenu'`,
2774  // `'mousedown'` and `'touchstart'` events (plus browser variants).
2775  function disableClickPropagation(el) {
2776  	on(el, 'mousedown touchstart dblclick contextmenu', stopPropagation);
2777  	el['_leaflet_disable_click'] = true;
2778  	return this;
2779  }
2780
2781  // @function preventDefault(ev: DOMEvent): this
2782  // Prevents the default action of the DOM Event `ev` from happening (such as
2783  // following a link in the href of the a element, or doing a POST request
2784  // with page reload when a `<form>` is submitted).
2785  // Use it inside listener functions.
2786  function preventDefault(e) {
2787  	if (e.preventDefault) {
2788  		e.preventDefault();
2789  	} else {
2790  		e.returnValue = false;
2791  	}
2792  	return this;
2793  }
2794
2795  // @function stop(ev: DOMEvent): this
2796  // Does `stopPropagation` and `preventDefault` at the same time.
2797  function stop(e) {
2798  	preventDefault(e);
2799  	stopPropagation(e);
2800  	return this;
2801  }
2802
2803  // @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point
2804  // Gets normalized mouse position from a DOM event relative to the
2805  // `container` (border excluded) or to the whole page if not specified.
2806  function getMousePosition(e, container) {
2807  	if (!container) {
2808  		return new Point(e.clientX, e.clientY);
2809  	}
2810
2811  	var scale = getScale(container),
2812  	    offset = scale.boundingClientRect; // left and top  values are in page scale (like the event clientX/Y)
2813
2814  	return new Point(
2815  		// offset.left/top values are in page scale (like clientX/Y),
2816  		// whereas clientLeft/Top (border width) values are the original values (before CSS scale applies).
2817  		(e.clientX - offset.left) / scale.x - container.clientLeft,
2818  		(e.clientY - offset.top) / scale.y - container.clientTop
2819  	);
2820  }
2821
2822  // Chrome on Win scrolls double the pixels as in other platforms (see #4538),
2823  // and Firefox scrolls device pixels, not CSS pixels
2824  var wheelPxFactor =
2825  	(win && chrome) ? 2 * window.devicePixelRatio :
2826  	gecko ? window.devicePixelRatio : 1;
2827
2828  // @function getWheelDelta(ev: DOMEvent): Number
2829  // Gets normalized wheel delta from a wheel DOM event, in vertical
2830  // pixels scrolled (negative if scrolling down).
2831  // Events from pointing devices without precise scrolling are mapped to
2832  // a best guess of 60 pixels.
2833  function getWheelDelta(e) {
2834  	return (edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta
2835  	       (e.deltaY && e.deltaMode === 0) ? -e.deltaY / wheelPxFactor : // Pixels
2836  	       (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines
2837  	       (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages
2838  	       (e.deltaX || e.deltaZ) ? 0 :	// Skip horizontal/depth wheel events
2839  	       e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels
2840  	       (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines
2841  	       e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages
2842  	       0;
2843  }
2844
2845  // check if element really left/entered the event target (for mouseenter/mouseleave)
2846  function isExternalTarget(el, e) {
2847
2848  	var related = e.relatedTarget;
2849
2850  	if (!related) { return true; }
2851
2852  	try {
2853  		while (related && (related !== el)) {
2854  			related = related.parentNode;
2855  		}
2856  	} catch (err) {
2857  		return false;
2858  	}
2859  	return (related !== el);
2860  }
2861
2862  var DomEvent = {
2863    __proto__: null,
2864    on: on,
2865    off: off,
2866    stopPropagation: stopPropagation,
2867    disableScrollPropagation: disableScrollPropagation,
2868    disableClickPropagation: disableClickPropagation,
2869    preventDefault: preventDefault,
2870    stop: stop,
2871    getMousePosition: getMousePosition,
2872    getWheelDelta: getWheelDelta,
2873    isExternalTarget: isExternalTarget,
2874    addListener: on,
2875    removeListener: off
2876  };
2877
2878  /*
2879   * @class PosAnimation
2880   * @aka L.PosAnimation
2881   * @inherits Evented
2882   * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9.
2883   *
2884   * @example
2885   * ```js
2886   * var fx = new L.PosAnimation();
2887   * fx.run(el, [300, 500], 0.5);
2888   * ```
2889   *
2890   * @constructor L.PosAnimation()
2891   * Creates a `PosAnimation` object.
2892   *
2893   */
2894
2895  var PosAnimation = Evented.extend({
2896
2897  	// @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)
2898  	// Run an animation of a given element to a new position, optionally setting
2899  	// duration in seconds (`0.25` by default) and easing linearity factor (3rd
2900  	// argument of the [cubic bezier curve](http://cubic-bezier.com/#0,0,.5,1),
2901  	// `0.5` by default).
2902  	run: function (el, newPos, duration, easeLinearity) {
2903  		this.stop();
2904
2905  		this._el = el;
2906  		this._inProgress = true;
2907  		this._duration = duration || 0.25;
2908  		this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);
2909
2910  		this._startPos = getPosition(el);
2911  		this._offset = newPos.subtract(this._startPos);
2912  		this._startTime = +new Date();
2913
2914  		// @event start: Event
2915  		// Fired when the animation starts
2916  		this.fire('start');
2917
2918  		this._animate();
2919  	},
2920
2921  	// @method stop()
2922  	// Stops the animation (if currently running).
2923  	stop: function () {
2924  		if (!this._inProgress) { return; }
2925
2926  		this._step(true);
2927  		this._complete();
2928  	},
2929
2930  	_animate: function () {
2931  		// animation loop
2932  		this._animId = requestAnimFrame(this._animate, this);
2933  		this._step();
2934  	},
2935
2936  	_step: function (round) {
2937  		var elapsed = (+new Date()) - this._startTime,
2938  		    duration = this._duration * 1000;
2939
2940  		if (elapsed < duration) {
2941  			this._runFrame(this._easeOut(elapsed / duration), round);
2942  		} else {
2943  			this._runFrame(1);
2944  			this._complete();
2945  		}
2946  	},
2947
2948  	_runFrame: function (progress, round) {
2949  		var pos = this._startPos.add(this._offset.multiplyBy(progress));
2950  		if (round) {
2951  			pos._round();
2952  		}
2953  		setPosition(this._el, pos);
2954
2955  		// @event step: Event
2956  		// Fired continuously during the animation.
2957  		this.fire('step');
2958  	},
2959
2960  	_complete: function () {
2961  		cancelAnimFrame(this._animId);
2962
2963  		this._inProgress = false;
2964  		// @event end: Event
2965  		// Fired when the animation ends.
2966  		this.fire('end');
2967  	},
2968
2969  	_easeOut: function (t) {
2970  		return 1 - Math.pow(1 - t, this._easeOutPower);
2971  	}
2972  });
2973
2974  /*
2975   * @class Map
2976   * @aka L.Map
2977   * @inherits Evented
2978   *
2979   * The central class of the API — it is used to create a map on a page and manipulate it.
2980   *
2981   * @example
2982   *
2983   * ```js
2984   * // initialize the map on the "map" div with a given center and zoom
2985   * var map = L.map('map', {
2986   * 	center: [51.505, -0.09],
2987   * 	zoom: 13
2988   * });
2989   * ```
2990   *
2991   */
2992
2993  var Map = Evented.extend({
2994
2995  	options: {
2996  		// @section Map State Options
2997  		// @option crs: CRS = L.CRS.EPSG3857
2998  		// The [Coordinate Reference System](#crs) to use. Don't change this if you're not
2999  		// sure what it means.
3000  		crs: EPSG3857,
3001
3002  		// @option center: LatLng = undefined
3003  		// Initial geographic center of the map
3004  		center: undefined,
3005
3006  		// @option zoom: Number = undefined
3007  		// Initial map zoom level
3008  		zoom: undefined,
3009
3010  		// @option minZoom: Number = *
3011  		// Minimum zoom level of the map.
3012  		// If not specified and at least one `GridLayer` or `TileLayer` is in the map,
3013  		// the lowest of their `minZoom` options will be used instead.
3014  		minZoom: undefined,
3015
3016  		// @option maxZoom: Number = *
3017  		// Maximum zoom level of the map.
3018  		// If not specified and at least one `GridLayer` or `TileLayer` is in the map,
3019  		// the highest of their `maxZoom` options will be used instead.
3020  		maxZoom: undefined,
3021
3022  		// @option layers: Layer[] = []
3023  		// Array of layers that will be added to the map initially
3024  		layers: [],
3025
3026  		// @option maxBounds: LatLngBounds = null
3027  		// When this option is set, the map restricts the view to the given
3028  		// geographical bounds, bouncing the user back if the user tries to pan
3029  		// outside the view. To set the restriction dynamically, use
3030  		// [`setMaxBounds`](#map-setmaxbounds) method.
3031  		maxBounds: undefined,
3032
3033  		// @option renderer: Renderer = *
3034  		// The default method for drawing vector layers on the map. `L.SVG`
3035  		// or `L.Canvas` by default depending on browser support.
3036  		renderer: undefined,
3037
3038
3039  		// @section Animation Options
3040  		// @option zoomAnimation: Boolean = true
3041  		// Whether the map zoom animation is enabled. By default it's enabled
3042  		// in all browsers that support CSS3 Transitions except Android.
3043  		zoomAnimation: true,
3044
3045  		// @option zoomAnimationThreshold: Number = 4
3046  		// Won't animate zoom if the zoom difference exceeds this value.
3047  		zoomAnimationThreshold: 4,
3048
3049  		// @option fadeAnimation: Boolean = true
3050  		// Whether the tile fade animation is enabled. By default it's enabled
3051  		// in all browsers that support CSS3 Transitions except Android.
3052  		fadeAnimation: true,
3053
3054  		// @option markerZoomAnimation: Boolean = true
3055  		// Whether markers animate their zoom with the zoom animation, if disabled
3056  		// they will disappear for the length of the animation. By default it's
3057  		// enabled in all browsers that support CSS3 Transitions except Android.
3058  		markerZoomAnimation: true,
3059
3060  		// @option transform3DLimit: Number = 2^23
3061  		// Defines the maximum size of a CSS translation transform. The default
3062  		// value should not be changed unless a web browser positions layers in
3063  		// the wrong place after doing a large `panBy`.
3064  		transform3DLimit: 8388608, // Precision limit of a 32-bit float
3065
3066  		// @section Interaction Options
3067  		// @option zoomSnap: Number = 1
3068  		// Forces the map's zoom level to always be a multiple of this, particularly
3069  		// right after a [`fitBounds()`](#map-fitbounds) or a pinch-zoom.
3070  		// By default, the zoom level snaps to the nearest integer; lower values
3071  		// (e.g. `0.5` or `0.1`) allow for greater granularity. A value of `0`
3072  		// means the zoom level will not be snapped after `fitBounds` or a pinch-zoom.
3073  		zoomSnap: 1,
3074
3075  		// @option zoomDelta: Number = 1
3076  		// Controls how much the map's zoom level will change after a
3077  		// [`zoomIn()`](#map-zoomin), [`zoomOut()`](#map-zoomout), pressing `+`
3078  		// or `-` on the keyboard, or using the [zoom controls](#control-zoom).
3079  		// Values smaller than `1` (e.g. `0.5`) allow for greater granularity.
3080  		zoomDelta: 1,
3081
3082  		// @option trackResize: Boolean = true
3083  		// Whether the map automatically handles browser window resize to update itself.
3084  		trackResize: true
3085  	},
3086
3087  	initialize: function (id, options) { // (HTMLElement or String, Object)
3088  		options = setOptions(this, options);
3089
3090  		// Make sure to assign internal flags at the beginning,
3091  		// to avoid inconsistent state in some edge cases.
3092  		this._handlers = [];
3093  		this._layers = {};
3094  		this._zoomBoundLayers = {};
3095  		this._sizeChanged = true;
3096
3097  		this._initContainer(id);
3098  		this._initLayout();
3099
3100  		// hack for https://github.com/Leaflet/Leaflet/issues/1980
3101  		this._onResize = bind(this._onResize, this);
3102
3103  		this._initEvents();
3104
3105  		if (options.maxBounds) {
3106  			this.setMaxBounds(options.maxBounds);
3107  		}
3108
3109  		if (options.zoom !== undefined) {
3110  			this._zoom = this._limitZoom(options.zoom);
3111  		}
3112
3113  		if (options.center && options.zoom !== undefined) {
3114  			this.setView(toLatLng(options.center), options.zoom, {reset: true});
3115  		}
3116
3117  		this.callInitHooks();
3118
3119  		// don't animate on browsers without hardware-accelerated transitions or old Android/Opera
3120  		this._zoomAnimated = TRANSITION && any3d && !mobileOpera &&
3121  				this.options.zoomAnimation;
3122
3123  		// zoom transitions run with the same duration for all layers, so if one of transitionend events
3124  		// happens after starting zoom animation (propagating to the map pane), we know that it ended globally
3125  		if (this._zoomAnimated) {
3126  			this._createAnimProxy();
3127  			on(this._proxy, TRANSITION_END, this._catchTransitionEnd, this);
3128  		}
3129
3130  		this._addLayers(this.options.layers);
3131  	},
3132
3133
3134  	// @section Methods for modifying map state
3135
3136  	// @method setView(center: LatLng, zoom: Number, options?: Zoom/pan options): this
3137  	// Sets the view of the map (geographical center and zoom) with the given
3138  	// animation options.
3139  	setView: function (center, zoom, options) {
3140
3141  		zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
3142  		center = this._limitCenter(toLatLng(center), zoom, this.options.maxBounds);
3143  		options = options || {};
3144
3145  		this._stop();
3146
3147  		if (this._loaded && !options.reset && options !== true) {
3148
3149  			if (options.animate !== undefined) {
3150  				options.zoom = extend({animate: options.animate}, options.zoom);
3151  				options.pan = extend({animate: options.animate, duration: options.duration}, options.pan);
3152  			}
3153
3154  			// try animating pan or zoom
3155  			var moved = (this._zoom !== zoom) ?
3156  				this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :
3157  				this._tryAnimatedPan(center, options.pan);
3158
3159  			if (moved) {
3160  				// prevent resize handler call, the view will refresh after animation anyway
3161  				clearTimeout(this._sizeTimer);
3162  				return this;
3163  			}
3164  		}
3165
3166  		// animation didn't start, just reset the map view
3167  		this._resetView(center, zoom);
3168
3169  		return this;
3170  	},
3171
3172  	// @method setZoom(zoom: Number, options?: Zoom/pan options): this
3173  	// Sets the zoom of the map.
3174  	setZoom: function (zoom, options) {
3175  		if (!this._loaded) {
3176  			this._zoom = zoom;
3177  			return this;
3178  		}
3179  		return this.setView(this.getCenter(), zoom, {zoom: options});
3180  	},
3181
3182  	// @method zoomIn(delta?: Number, options?: Zoom options): this
3183  	// Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
3184  	zoomIn: function (delta, options) {
3185  		delta = delta || (any3d ? this.options.zoomDelta : 1);
3186  		return this.setZoom(this._zoom + delta, options);
3187  	},
3188
3189  	// @method zoomOut(delta?: Number, options?: Zoom options): this
3190  	// Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
3191  	zoomOut: function (delta, options) {
3192  		delta = delta || (any3d ? this.options.zoomDelta : 1);
3193  		return this.setZoom(this._zoom - delta, options);
3194  	},
3195
3196  	// @method setZoomAround(latlng: LatLng, zoom: Number, options: Zoom options): this
3197  	// Zooms the map while keeping a specified geographical point on the map
3198  	// stationary (e.g. used internally for scroll zoom and double-click zoom).
3199  	// @alternative
3200  	// @method setZoomAround(offset: Point, zoom: Number, options: Zoom options): this
3201  	// Zooms the map while keeping a specified pixel on the map (relative to the top-left corner) stationary.
3202  	setZoomAround: function (latlng, zoom, options) {
3203  		var scale = this.getZoomScale(zoom),
3204  		    viewHalf = this.getSize().divideBy(2),
3205  		    containerPoint = latlng instanceof Point ? latlng : this.latLngToContainerPoint(latlng),
3206
3207  		    centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),
3208  		    newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));
3209
3210  		return this.setView(newCenter, zoom, {zoom: options});
3211  	},
3212
3213  	_getBoundsCenterZoom: function (bounds, options) {
3214
3215  		options = options || {};
3216  		bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);
3217
3218  		var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
3219  		    paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
3220
3221  		    zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
3222
3223  		zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
3224
3225  		if (zoom === Infinity) {
3226  			return {
3227  				center: bounds.getCenter(),
3228  				zoom: zoom
3229  			};
3230  		}
3231
3232  		var paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),
3233
3234  		    swPoint = this.project(bounds.getSouthWest(), zoom),
3235  		    nePoint = this.project(bounds.getNorthEast(), zoom),
3236  		    center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);
3237
3238  		return {
3239  			center: center,
3240  			zoom: zoom
3241  		};
3242  	},
3243
3244  	// @method fitBounds(bounds: LatLngBounds, options?: fitBounds options): this
3245  	// Sets a map view that contains the given geographical bounds with the
3246  	// maximum zoom level possible.
3247  	fitBounds: function (bounds, options) {
3248
3249  		bounds = toLatLngBounds(bounds);
3250
3251  		if (!bounds.isValid()) {
3252  			throw new Error('Bounds are not valid.');
3253  		}
3254
3255  		var target = this._getBoundsCenterZoom(bounds, options);
3256  		return this.setView(target.center, target.zoom, options);
3257  	},
3258
3259  	// @method fitWorld(options?: fitBounds options): this
3260  	// Sets a map view that mostly contains the whole world with the maximum
3261  	// zoom level possible.
3262  	fitWorld: function (options) {
3263  		return this.fitBounds([[-90, -180], [90, 180]], options);
3264  	},
3265
3266  	// @method panTo(latlng: LatLng, options?: Pan options): this
3267  	// Pans the map to a given center.
3268  	panTo: function (center, options) { // (LatLng)
3269  		return this.setView(center, this._zoom, {pan: options});
3270  	},
3271
3272  	// @method panBy(offset: Point, options?: Pan options): this
3273  	// Pans the map by a given number of pixels (animated).
3274  	panBy: function (offset, options) {
3275  		offset = toPoint(offset).round();
3276  		options = options || {};
3277
3278  		if (!offset.x && !offset.y) {
3279  			return this.fire('moveend');
3280  		}
3281  		// If we pan too far, Chrome gets issues with tiles
3282  		// and makes them disappear or appear in the wrong place (slightly offset) #2602
3283  		if (options.animate !== true && !this.getSize().contains(offset)) {
3284  			this._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom());
3285  			return this;
3286  		}
3287
3288  		if (!this._panAnim) {
3289  			this._panAnim = new PosAnimation();
3290
3291  			this._panAnim.on({
3292  				'step': this._onPanTransitionStep,
3293  				'end': this._onPanTransitionEnd
3294  			}, this);
3295  		}
3296
3297  		// don't fire movestart if animating inertia
3298  		if (!options.noMoveStart) {
3299  			this.fire('movestart');
3300  		}
3301
3302  		// animate pan unless animate: false specified
3303  		if (options.animate !== false) {
3304  			addClass(this._mapPane, 'leaflet-pan-anim');
3305
3306  			var newPos = this._getMapPanePos().subtract(offset).round();
3307  			this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);
3308  		} else {
3309  			this._rawPanBy(offset);
3310  			this.fire('move').fire('moveend');
3311  		}
3312
3313  		return this;
3314  	},
3315
3316  	// @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this
3317  	// Sets the view of the map (geographical center and zoom) performing a smooth
3318  	// pan-zoom animation.
3319  	flyTo: function (targetCenter, targetZoom, options) {
3320
3321  		options = options || {};
3322  		if (options.animate === false || !any3d) {
3323  			return this.setView(targetCenter, targetZoom, options);
3324  		}
3325
3326  		this._stop();
3327
3328  		var from = this.project(this.getCenter()),
3329  		    to = this.project(targetCenter),
3330  		    size = this.getSize(),
3331  		    startZoom = this._zoom;
3332
3333  		targetCenter = toLatLng(targetCenter);
3334  		targetZoom = targetZoom === undefined ? startZoom : targetZoom;
3335
3336  		var w0 = Math.max(size.x, size.y),
3337  		    w1 = w0 * this.getZoomScale(startZoom, targetZoom),
3338  		    u1 = (to.distanceTo(from)) || 1,
3339  		    rho = 1.42,
3340  		    rho2 = rho * rho;
3341
3342  		function r(i) {
3343  			var s1 = i ? -1 : 1,
3344  			    s2 = i ? w1 : w0,
3345  			    t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1,
3346  			    b1 = 2 * s2 * rho2 * u1,
3347  			    b = t1 / b1,
3348  			    sq = Math.sqrt(b * b + 1) - b;
3349
3350  			    // workaround for floating point precision bug when sq = 0, log = -Infinite,
3351  			    // thus triggering an infinite loop in flyTo
3352  			    var log = sq < 0.000000001 ? -18 : Math.log(sq);
3353
3354  			return log;
3355  		}
3356
3357  		function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }
3358  		function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }
3359  		function tanh(n) { return sinh(n) / cosh(n); }
3360
3361  		var r0 = r(0);
3362
3363  		function w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); }
3364  		function u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; }
3365
3366  		function easeOut(t) { return 1 - Math.pow(1 - t, 1.5); }
3367
3368  		var start = Date.now(),
3369  		    S = (r(1) - r0) / rho,
3370  		    duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8;
3371
3372  		function frame() {
3373  			var t = (Date.now() - start) / duration,
3374  			    s = easeOut(t) * S;
3375
3376  			if (t <= 1) {
3377  				this._flyToFrame = requestAnimFrame(frame, this);
3378
3379  				this._move(
3380  					this.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),
3381  					this.getScaleZoom(w0 / w(s), startZoom),
3382  					{flyTo: true});
3383
3384  			} else {
3385  				this
3386  					._move(targetCenter, targetZoom)
3387  					._moveEnd(true);
3388  			}
3389  		}
3390
3391  		this._moveStart(true, options.noMoveStart);
3392
3393  		frame.call(this);
3394  		return this;
3395  	},
3396
3397  	// @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
3398  	// Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
3399  	// but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
3400  	flyToBounds: function (bounds, options) {
3401  		var target = this._getBoundsCenterZoom(bounds, options);
3402  		return this.flyTo(target.center, target.zoom, options);
3403  	},
3404
3405  	// @method setMaxBounds(bounds: LatLngBounds): this
3406  	// Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option).
3407  	setMaxBounds: function (bounds) {
3408  		bounds = toLatLngBounds(bounds);
3409
3410  		if (!bounds.isValid()) {
3411  			this.options.maxBounds = null;
3412  			return this.off('moveend', this._panInsideMaxBounds);
3413  		} else if (this.options.maxBounds) {
3414  			this.off('moveend', this._panInsideMaxBounds);
3415  		}
3416
3417  		this.options.maxBounds = bounds;
3418
3419  		if (this._loaded) {
3420  			this._panInsideMaxBounds();
3421  		}
3422
3423  		return this.on('moveend', this._panInsideMaxBounds);
3424  	},
3425
3426  	// @method setMinZoom(zoom: Number): this
3427  	// Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option).
3428  	setMinZoom: function (zoom) {
3429  		var oldZoom = this.options.minZoom;
3430  		this.options.minZoom = zoom;
3431
3432  		if (this._loaded && oldZoom !== zoom) {
3433  			this.fire('zoomlevelschange');
3434
3435  			if (this.getZoom() < this.options.minZoom) {
3436  				return this.setZoom(zoom);
3437  			}
3438  		}
3439
3440  		return this;
3441  	},
3442
3443  	// @method setMaxZoom(zoom: Number): this
3444  	// Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option).
3445  	setMaxZoom: function (zoom) {
3446  		var oldZoom = this.options.maxZoom;
3447  		this.options.maxZoom = zoom;
3448
3449  		if (this._loaded && oldZoom !== zoom) {
3450  			this.fire('zoomlevelschange');
3451
3452  			if (this.getZoom() > this.options.maxZoom) {
3453  				return this.setZoom(zoom);
3454  			}
3455  		}
3456
3457  		return this;
3458  	},
3459
3460  	// @method panInsideBounds(bounds: LatLngBounds, options?: Pan options): this
3461  	// Pans the map to the closest view that would lie inside the given bounds (if it's not already), controlling the animation using the options specific, if any.
3462  	panInsideBounds: function (bounds, options) {
3463  		this._enforcingBounds = true;
3464  		var center = this.getCenter(),
3465  		    newCenter = this._limitCenter(center, this._zoom, toLatLngBounds(bounds));
3466
3467  		if (!center.equals(newCenter)) {
3468  			this.panTo(newCenter, options);
3469  		}
3470
3471  		this._enforcingBounds = false;
3472  		return this;
3473  	},
3474
3475  	// @method panInside(latlng: LatLng, options?: padding options): this
3476  	// Pans the map the minimum amount to make the `latlng` visible. Use
3477  	// padding options to fit the display to more restricted bounds.
3478  	// If `latlng` is already within the (optionally padded) display bounds,
3479  	// the map will not be panned.
3480  	panInside: function (latlng, options) {
3481  		options = options || {};
3482
3483  		var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
3484  		    paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
3485  		    pixelCenter = this.project(this.getCenter()),
3486  		    pixelPoint = this.project(latlng),
3487  		    pixelBounds = this.getPixelBounds(),
3488  		    paddedBounds = toBounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]),
3489  		    paddedSize = paddedBounds.getSize();
3490
3491  		if (!paddedBounds.contains(pixelPoint)) {
3492  			this._enforcingBounds = true;
3493  			var centerOffset = pixelPoint.subtract(paddedBounds.getCenter());
3494  			var offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize);
3495  			pixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x;
3496  			pixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y;
3497  			this.panTo(this.unproject(pixelCenter), options);
3498  			this._enforcingBounds = false;
3499  		}
3500  		return this;
3501  	},
3502
3503  	// @method invalidateSize(options: Zoom/pan options): this
3504  	// Checks if the map container size changed and updates the map if so —
3505  	// call it after you've changed the map size dynamically, also animating
3506  	// pan by default. If `options.pan` is `false`, panning will not occur.
3507  	// If `options.debounceMoveend` is `true`, it will delay `moveend` event so
3508  	// that it doesn't happen often even if the method is called many
3509  	// times in a row.
3510
3511  	// @alternative
3512  	// @method invalidateSize(animate: Boolean): this
3513  	// Checks if the map container size changed and updates the map if so —
3514  	// call it after you've changed the map size dynamically, also animating
3515  	// pan by default.
3516  	invalidateSize: function (options) {
3517  		if (!this._loaded) { return this; }
3518
3519  		options = extend({
3520  			animate: false,
3521  			pan: true
3522  		}, options === true ? {animate: true} : options);
3523
3524  		var oldSize = this.getSize();
3525  		this._sizeChanged = true;
3526  		this._lastCenter = null;
3527
3528  		var newSize = this.getSize(),
3529  		    oldCenter = oldSize.divideBy(2).round(),
3530  		    newCenter = newSize.divideBy(2).round(),
3531  		    offset = oldCenter.subtract(newCenter);
3532
3533  		if (!offset.x && !offset.y) { return this; }
3534
3535  		if (options.animate && options.pan) {
3536  			this.panBy(offset);
3537
3538  		} else {
3539  			if (options.pan) {
3540  				this._rawPanBy(offset);
3541  			}
3542
3543  			this.fire('move');
3544
3545  			if (options.debounceMoveend) {
3546  				clearTimeout(this._sizeTimer);
3547  				this._sizeTimer = setTimeout(bind(this.fire, this, 'moveend'), 200);
3548  			} else {
3549  				this.fire('moveend');
3550  			}
3551  		}
3552
3553  		// @section Map state change events
3554  		// @event resize: ResizeEvent
3555  		// Fired when the map is resized.
3556  		return this.fire('resize', {
3557  			oldSize: oldSize,
3558  			newSize: newSize
3559  		});
3560  	},
3561
3562  	// @section Methods for modifying map state
3563  	// @method stop(): this
3564  	// Stops the currently running `panTo` or `flyTo` animation, if any.
3565  	stop: function () {
3566  		this.setZoom(this._limitZoom(this._zoom));
3567  		if (!this.options.zoomSnap) {
3568  			this.fire('viewreset');
3569  		}
3570  		return this._stop();
3571  	},
3572
3573  	// @section Geolocation methods
3574  	// @method locate(options?: Locate options): this
3575  	// Tries to locate the user using the Geolocation API, firing a [`locationfound`](#map-locationfound)
3576  	// event with location data on success or a [`locationerror`](#map-locationerror) event on failure,
3577  	// and optionally sets the map view to the user's location with respect to
3578  	// detection accuracy (or to the world view if geolocation failed).
3579  	// Note that, if your page doesn't use HTTPS, this method will fail in
3580  	// modern browsers ([Chrome 50 and newer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins))
3581  	// See `Locate options` for more details.
3582  	locate: function (options) {
3583
3584  		options = this._locateOptions = extend({
3585  			timeout: 10000,
3586  			watch: false
3587  			// setView: false
3588  			// maxZoom: <Number>
3589  			// maximumAge: 0
3590  			// enableHighAccuracy: false
3591  		}, options);
3592
3593  		if (!('geolocation' in navigator)) {
3594  			this._handleGeolocationError({
3595  				code: 0,
3596  				message: 'Geolocation not supported.'
3597  			});
3598  			return this;
3599  		}
3600
3601  		var onResponse = bind(this._handleGeolocationResponse, this),
3602  		    onError = bind(this._handleGeolocationError, this);
3603
3604  		if (options.watch) {
3605  			this._locationWatchId =
3606  			        navigator.geolocation.watchPosition(onResponse, onError, options);
3607  		} else {
3608  			navigator.geolocation.getCurrentPosition(onResponse, onError, options);
3609  		}
3610  		return this;
3611  	},
3612
3613  	// @method stopLocate(): this
3614  	// Stops watching location previously initiated by `map.locate({watch: true})`
3615  	// and aborts resetting the map view if map.locate was called with
3616  	// `{setView: true}`.
3617  	stopLocate: function () {
3618  		if (navigator.geolocation && navigator.geolocation.clearWatch) {
3619  			navigator.geolocation.clearWatch(this._locationWatchId);
3620  		}
3621  		if (this._locateOptions) {
3622  			this._locateOptions.setView = false;
3623  		}
3624  		return this;
3625  	},
3626
3627  	_handleGeolocationError: function (error) {
3628  		var c = error.code,
3629  		    message = error.message ||
3630  		            (c === 1 ? 'permission denied' :
3631  		            (c === 2 ? 'position unavailable' : 'timeout'));
3632
3633  		if (this._locateOptions.setView && !this._loaded) {
3634  			this.fitWorld();
3635  		}
3636
3637  		// @section Location events
3638  		// @event locationerror: ErrorEvent
3639  		// Fired when geolocation (using the [`locate`](#map-locate) method) failed.
3640  		this.fire('locationerror', {
3641  			code: c,
3642  			message: 'Geolocation error: ' + message + '.'
3643  		});
3644  	},
3645
3646  	_handleGeolocationResponse: function (pos) {
3647  		var lat = pos.coords.latitude,
3648  		    lng = pos.coords.longitude,
3649  		    latlng = new LatLng(lat, lng),
3650  		    bounds = latlng.toBounds(pos.coords.accuracy * 2),
3651  		    options = this._locateOptions;
3652
3653  		if (options.setView) {
3654  			var zoom = this.getBoundsZoom(bounds);
3655  			this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);
3656  		}
3657
3658  		var data = {
3659  			latlng: latlng,
3660  			bounds: bounds,
3661  			timestamp: pos.timestamp
3662  		};
3663
3664  		for (var i in pos.coords) {
3665  			if (typeof pos.coords[i] === 'number') {
3666  				data[i] = pos.coords[i];
3667  			}
3668  		}
3669
3670  		// @event locationfound: LocationEvent
3671  		// Fired when geolocation (using the [`locate`](#map-locate) method)
3672  		// went successfully.
3673  		this.fire('locationfound', data);
3674  	},
3675
3676  	// TODO Appropriate docs section?
3677  	// @section Other Methods
3678  	// @method addHandler(name: String, HandlerClass: Function): this
3679  	// Adds a new `Handler` to the map, given its name and constructor function.
3680  	addHandler: function (name, HandlerClass) {
3681  		if (!HandlerClass) { return this; }
3682
3683  		var handler = this[name] = new HandlerClass(this);
3684
3685  		this._handlers.push(handler);
3686
3687  		if (this.options[name]) {
3688  			handler.enable();
3689  		}
3690
3691  		return this;
3692  	},
3693
3694  	// @method remove(): this
3695  	// Destroys the map and clears all related event listeners.
3696  	remove: function () {
3697
3698  		this._initEvents(true);
3699  		if (this.options.maxBounds) { this.off('moveend', this._panInsideMaxBounds); }
3700
3701  		if (this._containerId !== this._container._leaflet_id) {
3702  			throw new Error('Map container is being reused by another instance');
3703  		}
3704
3705  		try {
3706  			// throws error in IE6-8
3707  			delete this._container._leaflet_id;
3708  			delete this._containerId;
3709  		} catch (e) {
3710  			/*eslint-disable */
3711  			this._container._leaflet_id = undefined;
3712  			/* eslint-enable */
3713  			this._containerId = undefined;
3714  		}
3715
3716  		if (this._locationWatchId !== undefined) {
3717  			this.stopLocate();
3718  		}
3719
3720  		this._stop();
3721
3722  		remove(this._mapPane);
3723
3724  		if (this._clearControlPos) {
3725  			this._clearControlPos();
3726  		}
3727  		if (this._resizeRequest) {
3728  			cancelAnimFrame(this._resizeRequest);
3729  			this._resizeRequest = null;
3730  		}
3731
3732  		this._clearHandlers();
3733
3734  		if (this._loaded) {
3735  			// @section Map state change events
3736  			// @event unload: Event
3737  			// Fired when the map is destroyed with [remove](#map-remove) method.
3738  			this.fire('unload');
3739  		}
3740
3741  		var i;
3742  		for (i in this._layers) {
3743  			this._layers[i].remove();
3744  		}
3745  		for (i in this._panes) {
3746  			remove(this._panes[i]);
3747  		}
3748
3749  		this._layers = [];
3750  		this._panes = [];
3751  		delete this._mapPane;
3752  		delete this._renderer;
3753
3754  		return this;
3755  	},
3756
3757  	// @section Other Methods
3758  	// @method createPane(name: String, container?: HTMLElement): HTMLElement
3759  	// Creates a new [map pane](#map-pane) with the given name if it doesn't exist already,
3760  	// then returns it. The pane is created as a child of `container`, or
3761  	// as a child of the main map pane if not set.
3762  	createPane: function (name, container) {
3763  		var className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''),
3764  		    pane = create$1('div', className, container || this._mapPane);
3765
3766  		if (name) {
3767  			this._panes[name] = pane;
3768  		}
3769  		return pane;
3770  	},
3771
3772  	// @section Methods for Getting Map State
3773
3774  	// @method getCenter(): LatLng
3775  	// Returns the geographical center of the map view
3776  	getCenter: function () {
3777  		this._checkIfLoaded();
3778
3779  		if (this._lastCenter && !this._moved()) {
3780  			return this._lastCenter;
3781  		}
3782  		return this.layerPointToLatLng(this._getCenterLayerPoint());
3783  	},
3784
3785  	// @method getZoom(): Number
3786  	// Returns the current zoom level of the map view
3787  	getZoom: function () {
3788  		return this._zoom;
3789  	},
3790
3791  	// @method getBounds(): LatLngBounds
3792  	// Returns the geographical bounds visible in the current map view
3793  	getBounds: function () {
3794  		var bounds = this.getPixelBounds(),
3795  		    sw = this.unproject(bounds.getBottomLeft()),
3796  		    ne = this.unproject(bounds.getTopRight());
3797
3798  		return new LatLngBounds(sw, ne);
3799  	},
3800
3801  	// @method getMinZoom(): Number
3802  	// Returns the minimum zoom level of the map (if set in the `minZoom` option of the map or of any layers), or `0` by default.
3803  	getMinZoom: function () {
3804  		return this.options.minZoom === undefined ? this._layersMinZoom || 0 : this.options.minZoom;
3805  	},
3806
3807  	// @method getMaxZoom(): Number
3808  	// Returns the maximum zoom level of the map (if set in the `maxZoom` option of the map or of any layers).
3809  	getMaxZoom: function () {
3810  		return this.options.maxZoom === undefined ?
3811  			(this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :
3812  			this.options.maxZoom;
3813  	},
3814
3815  	// @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean, padding?: Point): Number
3816  	// Returns the maximum zoom level on which the given bounds fit to the map
3817  	// view in its entirety. If `inside` (optional) is set to `true`, the method
3818  	// instead returns the minimum zoom level on which the map view fits into
3819  	// the given bounds in its entirety.
3820  	getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
3821  		bounds = toLatLngBounds(bounds);
3822  		padding = toPoint(padding || [0, 0]);
3823
3824  		var zoom = this.getZoom() || 0,
3825  		    min = this.getMinZoom(),
3826  		    max = this.getMaxZoom(),
3827  		    nw = bounds.getNorthWest(),
3828  		    se = bounds.getSouthEast(),
3829  		    size = this.getSize().subtract(padding),
3830  		    boundsSize = toBounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),
3831  		    snap = any3d ? this.options.zoomSnap : 1,
3832  		    scalex = size.x / boundsSize.x,
3833  		    scaley = size.y / boundsSize.y,
3834  		    scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);
3835
3836  		zoom = this.getScaleZoom(scale, zoom);
3837
3838  		if (snap) {
3839  			zoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level
3840  			zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;
3841  		}
3842
3843  		return Math.max(min, Math.min(max, zoom));
3844  	},
3845
3846  	// @method getSize(): Point
3847  	// Returns the current size of the map container (in pixels).
3848  	getSize: function () {
3849  		if (!this._size || this._sizeChanged) {
3850  			this._size = new Point(
3851  				this._container.clientWidth || 0,
3852  				this._container.clientHeight || 0);
3853
3854  			this._sizeChanged = false;
3855  		}
3856  		return this._size.clone();
3857  	},
3858
3859  	// @method getPixelBounds(): Bounds
3860  	// Returns the bounds of the current map view in projected pixel
3861  	// coordinates (sometimes useful in layer and overlay implementations).
3862  	getPixelBounds: function (center, zoom) {
3863  		var topLeftPoint = this._getTopLeftPoint(center, zoom);
3864  		return new Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
3865  	},
3866
3867  	// TODO: Check semantics - isn't the pixel origin the 0,0 coord relative to
3868  	// the map pane? "left point of the map layer" can be confusing, specially
3869  	// since there can be negative offsets.
3870  	// @method getPixelOrigin(): Point
3871  	// Returns the projected pixel coordinates of the top left point of
3872  	// the map layer (useful in custom layer and overlay implementations).
3873  	getPixelOrigin: function () {
3874  		this._checkIfLoaded();
3875  		return this._pixelOrigin;
3876  	},
3877
3878  	// @method getPixelWorldBounds(zoom?: Number): Bounds
3879  	// Returns the world's bounds in pixel coordinates for zoom level `zoom`.
3880  	// If `zoom` is omitted, the map's current zoom level is used.
3881  	getPixelWorldBounds: function (zoom) {
3882  		return this.options.crs.getProjectedBounds(zoom === undefined ? this.getZoom() : zoom);
3883  	},
3884
3885  	// @section Other Methods
3886
3887  	// @method getPane(pane: String|HTMLElement): HTMLElement
3888  	// Returns a [map pane](#map-pane), given its name or its HTML element (its identity).
3889  	getPane: function (pane) {
3890  		return typeof pane === 'string' ? this._panes[pane] : pane;
3891  	},
3892
3893  	// @method getPanes(): Object
3894  	// Returns a plain object containing the names of all [panes](#map-pane) as keys and
3895  	// the panes as values.
3896  	getPanes: function () {
3897  		return this._panes;
3898  	},
3899
3900  	// @method getContainer: HTMLElement
3901  	// Returns the HTML element that contains the map.
3902  	getContainer: function () {
3903  		return this._container;
3904  	},
3905
3906
3907  	// @section Conversion Methods
3908
3909  	// @method getZoomScale(toZoom: Number, fromZoom: Number): Number
3910  	// Returns the scale factor to be applied to a map transition from zoom level
3911  	// `fromZoom` to `toZoom`. Used internally to help with zoom animations.
3912  	getZoomScale: function (toZoom, fromZoom) {
3913  		// TODO replace with universal implementation after refactoring projections
3914  		var crs = this.options.crs;
3915  		fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
3916  		return crs.scale(toZoom) / crs.scale(fromZoom);
3917  	},
3918
3919  	// @method getScaleZoom(scale: Number, fromZoom: Number): Number
3920  	// Returns the zoom level that the map would end up at, if it is at `fromZoom`
3921  	// level and everything is scaled by a factor of `scale`. Inverse of
3922  	// [`getZoomScale`](#map-getZoomScale).
3923  	getScaleZoom: function (scale, fromZoom) {
3924  		var crs = this.options.crs;
3925  		fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
3926  		var zoom = crs.zoom(scale * crs.scale(fromZoom));
3927  		return isNaN(zoom) ? Infinity : zoom;
3928  	},
3929
3930  	// @method project(latlng: LatLng, zoom: Number): Point
3931  	// Projects a geographical coordinate `LatLng` according to the projection
3932  	// of the map's CRS, then scales it according to `zoom` and the CRS's
3933  	// `Transformation`. The result is pixel coordinate relative to
3934  	// the CRS origin.
3935  	project: function (latlng, zoom) {
3936  		zoom = zoom === undefined ? this._zoom : zoom;
3937  		return this.options.crs.latLngToPoint(toLatLng(latlng), zoom);
3938  	},
3939
3940  	// @method unproject(point: Point, zoom: Number): LatLng
3941  	// Inverse of [`project`](#map-project).
3942  	unproject: function (point, zoom) {
3943  		zoom = zoom === undefined ? this._zoom : zoom;
3944  		return this.options.crs.pointToLatLng(toPoint(point), zoom);
3945  	},
3946
3947  	// @method layerPointToLatLng(point: Point): LatLng
3948  	// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
3949  	// returns the corresponding geographical coordinate (for the current zoom level).
3950  	layerPointToLatLng: function (point) {
3951  		var projectedPoint = toPoint(point).add(this.getPixelOrigin());
3952  		return this.unproject(projectedPoint);
3953  	},
3954
3955  	// @method latLngToLayerPoint(latlng: LatLng): Point
3956  	// Given a geographical coordinate, returns the corresponding pixel coordinate
3957  	// relative to the [origin pixel](#map-getpixelorigin).
3958  	latLngToLayerPoint: function (latlng) {
3959  		var projectedPoint = this.project(toLatLng(latlng))._round();
3960  		return projectedPoint._subtract(this.getPixelOrigin());
3961  	},
3962
3963  	// @method wrapLatLng(latlng: LatLng): LatLng
3964  	// Returns a `LatLng` where `lat` and `lng` has been wrapped according to the
3965  	// map's CRS's `wrapLat` and `wrapLng` properties, if they are outside the
3966  	// CRS's bounds.
3967  	// By default this means longitude is wrapped around the dateline so its
3968  	// value is between -180 and +180 degrees.
3969  	wrapLatLng: function (latlng) {
3970  		return this.options.crs.wrapLatLng(toLatLng(latlng));
3971  	},
3972
3973  	// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds
3974  	// Returns a `LatLngBounds` with the same size as the given one, ensuring that
3975  	// its center is within the CRS's bounds.
3976  	// By default this means the center longitude is wrapped around the dateline so its
3977  	// value is between -180 and +180 degrees, and the majority of the bounds
3978  	// overlaps the CRS's bounds.
3979  	wrapLatLngBounds: function (latlng) {
3980  		return this.options.crs.wrapLatLngBounds(toLatLngBounds(latlng));
3981  	},
3982
3983  	// @method distance(latlng1: LatLng, latlng2: LatLng): Number
3984  	// Returns the distance between two geographical coordinates according to
3985  	// the map's CRS. By default this measures distance in meters.
3986  	distance: function (latlng1, latlng2) {
3987  		return this.options.crs.distance(toLatLng(latlng1), toLatLng(latlng2));
3988  	},
3989
3990  	// @method containerPointToLayerPoint(point: Point): Point
3991  	// Given a pixel coordinate relative to the map container, returns the corresponding
3992  	// pixel coordinate relative to the [origin pixel](#map-getpixelorigin).
3993  	containerPointToLayerPoint: function (point) { // (Point)
3994  		return toPoint(point).subtract(this._getMapPanePos());
3995  	},
3996
3997  	// @method layerPointToContainerPoint(point: Point): Point
3998  	// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
3999  	// returns the corresponding pixel coordinate relative to the map container.
4000  	layerPointToContainerPoint: function (point) { // (Point)
4001  		return toPoint(point).add(this._getMapPanePos());
4002  	},
4003
4004  	// @method containerPointToLatLng(point: Point): LatLng
4005  	// Given a pixel coordinate relative to the map container, returns
4006  	// the corresponding geographical coordinate (for the current zoom level).
4007  	containerPointToLatLng: function (point) {
4008  		var layerPoint = this.containerPointToLayerPoint(toPoint(point));
4009  		return this.layerPointToLatLng(layerPoint);
4010  	},
4011
4012  	// @method latLngToContainerPoint(latlng: LatLng): Point
4013  	// Given a geographical coordinate, returns the corresponding pixel coordinate
4014  	// relative to the map container.
4015  	latLngToContainerPoint: function (latlng) {
4016  		return this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng)));
4017  	},
4018
4019  	// @method mouseEventToContainerPoint(ev: MouseEvent): Point
4020  	// Given a MouseEvent object, returns the pixel coordinate relative to the
4021  	// map container where the event took place.
4022  	mouseEventToContainerPoint: function (e) {
4023  		return getMousePosition(e, this._container);
4024  	},
4025
4026  	// @method mouseEventToLayerPoint(ev: MouseEvent): Point
4027  	// Given a MouseEvent object, returns the pixel coordinate relative to
4028  	// the [origin pixel](#map-getpixelorigin) where the event took place.
4029  	mouseEventToLayerPoint: function (e) {
4030  		return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));
4031  	},
4032
4033  	// @method mouseEventToLatLng(ev: MouseEvent): LatLng
4034  	// Given a MouseEvent object, returns geographical coordinate where the
4035  	// event took place.
4036  	mouseEventToLatLng: function (e) { // (MouseEvent)
4037  		return this.layerPointToLatLng(this.mouseEventToLayerPoint(e));
4038  	},
4039
4040
4041  	// map initialization methods
4042
4043  	_initContainer: function (id) {
4044  		var container = this._container = get(id);
4045
4046  		if (!container) {
4047  			throw new Error('Map container not found.');
4048  		} else if (container._leaflet_id) {
4049  			throw new Error('Map container is already initialized.');
4050  		}
4051
4052  		on(container, 'scroll', this._onScroll, this);
4053  		this._containerId = stamp(container);
4054  	},
4055
4056  	_initLayout: function () {
4057  		var container = this._container;
4058
4059  		this._fadeAnimated = this.options.fadeAnimation && any3d;
4060
4061  		addClass(container, 'leaflet-container' +
4062  			(touch ? ' leaflet-touch' : '') +
4063  			(retina ? ' leaflet-retina' : '') +
4064  			(ielt9 ? ' leaflet-oldie' : '') +
4065  			(safari ? ' leaflet-safari' : '') +
4066  			(this._fadeAnimated ? ' leaflet-fade-anim' : ''));
4067
4068  		var position = getStyle(container, 'position');
4069
4070  		if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') {
4071  			container.style.position = 'relative';
4072  		}
4073
4074  		this._initPanes();
4075
4076  		if (this._initControlPos) {
4077  			this._initControlPos();
4078  		}
4079  	},
4080
4081  	_initPanes: function () {
4082  		var panes = this._panes = {};
4083  		this._paneRenderers = {};
4084
4085  		// @section
4086  		//
4087  		// Panes are DOM elements used to control the ordering of layers on the map. You
4088  		// can access panes with [`map.getPane`](#map-getpane) or
4089  		// [`map.getPanes`](#map-getpanes) methods. New panes can be created with the
4090  		// [`map.createPane`](#map-createpane) method.
4091  		//
4092  		// Every map has the following default panes that differ only in zIndex.
4093  		//
4094  		// @pane mapPane: HTMLElement = 'auto'
4095  		// Pane that contains all other map panes
4096
4097  		this._mapPane = this.createPane('mapPane', this._container);
4098  		setPosition(this._mapPane, new Point(0, 0));
4099
4100  		// @pane tilePane: HTMLElement = 200
4101  		// Pane for `GridLayer`s and `TileLayer`s
4102  		this.createPane('tilePane');
4103  		// @pane overlayPane: HTMLElement = 400
4104  		// Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s and `VideoOverlay`s
4105  		this.createPane('overlayPane');
4106  		// @pane shadowPane: HTMLElement = 500
4107  		// Pane for overlay shadows (e.g. `Marker` shadows)
4108  		this.createPane('shadowPane');
4109  		// @pane markerPane: HTMLElement = 600
4110  		// Pane for `Icon`s of `Marker`s
4111  		this.createPane('markerPane');
4112  		// @pane tooltipPane: HTMLElement = 650
4113  		// Pane for `Tooltip`s.
4114  		this.createPane('tooltipPane');
4115  		// @pane popupPane: HTMLElement = 700
4116  		// Pane for `Popup`s.
4117  		this.createPane('popupPane');
4118
4119  		if (!this.options.markerZoomAnimation) {
4120  			addClass(panes.markerPane, 'leaflet-zoom-hide');
4121  			addClass(panes.shadowPane, 'leaflet-zoom-hide');
4122  		}
4123  	},
4124
4125
4126  	// private methods that modify map state
4127
4128  	// @section Map state change events
4129  	_resetView: function (center, zoom) {
4130  		setPosition(this._mapPane, new Point(0, 0));
4131
4132  		var loading = !this._loaded;
4133  		this._loaded = true;
4134  		zoom = this._limitZoom(zoom);
4135
4136  		this.fire('viewprereset');
4137
4138  		var zoomChanged = this._zoom !== zoom;
4139  		this
4140  			._moveStart(zoomChanged, false)
4141  			._move(center, zoom)
4142  			._moveEnd(zoomChanged);
4143
4144  		// @event viewreset: Event
4145  		// Fired when the map needs to redraw its content (this usually happens
4146  		// on map zoom or load). Very useful for creating custom overlays.
4147  		this.fire('viewreset');
4148
4149  		// @event load: Event
4150  		// Fired when the map is initialized (when its center and zoom are set
4151  		// for the first time).
4152  		if (loading) {
4153  			this.fire('load');
4154  		}
4155  	},
4156
4157  	_moveStart: function (zoomChanged, noMoveStart) {
4158  		// @event zoomstart: Event
4159  		// Fired when the map zoom is about to change (e.g. before zoom animation).
4160  		// @event movestart: Event
4161  		// Fired when the view of the map starts changing (e.g. user starts dragging the map).
4162  		if (zoomChanged) {
4163  			this.fire('zoomstart');
4164  		}
4165  		if (!noMoveStart) {
4166  			this.fire('movestart');
4167  		}
4168  		return this;
4169  	},
4170
4171  	_move: function (center, zoom, data) {
4172  		if (zoom === undefined) {
4173  			zoom = this._zoom;
4174  		}
4175  		var zoomChanged = this._zoom !== zoom;
4176
4177  		this._zoom = zoom;
4178  		this._lastCenter = center;
4179  		this._pixelOrigin = this._getNewPixelOrigin(center);
4180
4181  		// @event zoom: Event
4182  		// Fired repeatedly during any change in zoom level,
4183  		// including zoom and fly animations.
4184  		if (zoomChanged || (data && data.pinch)) {	// Always fire 'zoom' if pinching because #3530
4185  			this.fire('zoom', data);
4186  		}
4187
4188  		// @event move: Event
4189  		// Fired repeatedly during any movement of the map,
4190  		// including pan and fly animations.
4191  		return this.fire('move', data);
4192  	},
4193
4194  	_moveEnd: function (zoomChanged) {
4195  		// @event zoomend: Event
4196  		// Fired when the map zoom changed, after any animations.
4197  		if (zoomChanged) {
4198  			this.fire('zoomend');
4199  		}
4200
4201  		// @event moveend: Event
4202  		// Fired when the center of the map stops changing
4203  		// (e.g. user stopped dragging the map or after non-centered zoom).
4204  		return this.fire('moveend');
4205  	},
4206
4207  	_stop: function () {
4208  		cancelAnimFrame(this._flyToFrame);
4209  		if (this._panAnim) {
4210  			this._panAnim.stop();
4211  		}
4212  		return this;
4213  	},
4214
4215  	_rawPanBy: function (offset) {
4216  		setPosition(this._mapPane, this._getMapPanePos().subtract(offset));
4217  	},
4218
4219  	_getZoomSpan: function () {
4220  		return this.getMaxZoom() - this.getMinZoom();
4221  	},
4222
4223  	_panInsideMaxBounds: function () {
4224  		if (!this._enforcingBounds) {
4225  			this.panInsideBounds(this.options.maxBounds);
4226  		}
4227  	},
4228
4229  	_checkIfLoaded: function () {
4230  		if (!this._loaded) {
4231  			throw new Error('Set map center and zoom first.');
4232  		}
4233  	},
4234
4235  	// DOM event handling
4236
4237  	// @section Interaction events
4238  	_initEvents: function (remove) {
4239  		this._targets = {};
4240  		this._targets[stamp(this._container)] = this;
4241
4242  		var onOff = remove ? off : on;
4243
4244  		// @event click: MouseEvent
4245  		// Fired when the user clicks (or taps) the map.
4246  		// @event dblclick: MouseEvent
4247  		// Fired when the user double-clicks (or double-taps) the map.
4248  		// @event mousedown: MouseEvent
4249  		// Fired when the user pushes the mouse button on the map.
4250  		// @event mouseup: MouseEvent
4251  		// Fired when the user releases the mouse button on the map.
4252  		// @event mouseover: MouseEvent
4253  		// Fired when the mouse enters the map.
4254  		// @event mouseout: MouseEvent
4255  		// Fired when the mouse leaves the map.
4256  		// @event mousemove: MouseEvent
4257  		// Fired while the mouse moves over the map.
4258  		// @event contextmenu: MouseEvent
4259  		// Fired when the user pushes the right mouse button on the map, prevents
4260  		// default browser context menu from showing if there are listeners on
4261  		// this event. Also fired on mobile when the user holds a single touch
4262  		// for a second (also called long press).
4263  		// @event keypress: KeyboardEvent
4264  		// Fired when the user presses a key from the keyboard that produces a character value while the map is focused.
4265  		// @event keydown: KeyboardEvent
4266  		// Fired when the user presses a key from the keyboard while the map is focused. Unlike the `keypress` event,
4267  		// the `keydown` event is fired for keys that produce a character value and for keys
4268  		// that do not produce a character value.
4269  		// @event keyup: KeyboardEvent
4270  		// Fired when the user releases a key from the keyboard while the map is focused.
4271  		onOff(this._container, 'click dblclick mousedown mouseup ' +
4272  			'mouseover mouseout mousemove contextmenu keypress keydown keyup', this._handleDOMEvent, this);
4273
4274  		if (this.options.trackResize) {
4275  			onOff(window, 'resize', this._onResize, this);
4276  		}
4277
4278  		if (any3d && this.options.transform3DLimit) {
4279  			(remove ? this.off : this.on).call(this, 'moveend', this._onMoveEnd);
4280  		}
4281  	},
4282
4283  	_onResize: function () {
4284  		cancelAnimFrame(this._resizeRequest);
4285  		this._resizeRequest = requestAnimFrame(
4286  		        function () { this.invalidateSize({debounceMoveend: true}); }, this);
4287  	},
4288
4289  	_onScroll: function () {
4290  		this._container.scrollTop  = 0;
4291  		this._container.scrollLeft = 0;
4292  	},
4293
4294  	_onMoveEnd: function () {
4295  		var pos = this._getMapPanePos();
4296  		if (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) {
4297  			// https://bugzilla.mozilla.org/show_bug.cgi?id=1203873 but Webkit also have
4298  			// a pixel offset on very high values, see: http://jsfiddle.net/dg6r5hhb/
4299  			this._resetView(this.getCenter(), this.getZoom());
4300  		}
4301  	},
4302
4303  	_findEventTargets: function (e, type) {
4304  		var targets = [],
4305  		    target,
4306  		    isHover = type === 'mouseout' || type === 'mouseover',
4307  		    src = e.target || e.srcElement,
4308  		    dragging = false;
4309
4310  		while (src) {
4311  			target = this._targets[stamp(src)];
4312  			if (target && (type === 'click' || type === 'preclick') && this._draggableMoved(target)) {
4313  				// Prevent firing click after you just dragged an object.
4314  				dragging = true;
4315  				break;
4316  			}
4317  			if (target && target.listens(type, true)) {
4318  				if (isHover && !isExternalTarget(src, e)) { break; }
4319  				targets.push(target);
4320  				if (isHover) { break; }
4321  			}
4322  			if (src === this._container) { break; }
4323  			src = src.parentNode;
4324  		}
4325  		if (!targets.length && !dragging && !isHover && isExternalTarget(src, e)) {
4326  			targets = [this];
4327  		}
4328  		return targets;
4329  	},
4330
4331  	_isClickDisabled: function (el) {
4332  		while (el !== this._container) {
4333  			if (el['_leaflet_disable_click']) { return true; }
4334  			el = el.parentNode;
4335  		}
4336  	},
4337
4338  	_handleDOMEvent: function (e) {
4339  		var el = (e.target || e.srcElement);
4340  		if (!this._loaded || el['_leaflet_disable_events'] || e.type === 'click' && this._isClickDisabled(el)) {
4341  			return;
4342  		}
4343
4344  		var type = e.type;
4345
4346  		if (type === 'mousedown') {
4347  			// prevents outline when clicking on keyboard-focusable element
4348  			preventOutline(el);
4349  		}
4350
4351  		this._fireDOMEvent(e, type);
4352  	},
4353
4354  	_mouseEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu'],
4355
4356  	_fireDOMEvent: function (e, type, canvasTargets) {
4357
4358  		if (e.type === 'click') {
4359  			// Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).
4360  			// @event preclick: MouseEvent
4361  			// Fired before mouse click on the map (sometimes useful when you
4362  			// want something to happen on click before any existing click
4363  			// handlers start running).
4364  			var synth = extend({}, e);
4365  			synth.type = 'preclick';
4366  			this._fireDOMEvent(synth, synth.type, canvasTargets);
4367  		}
4368
4369  		// Find the layer the event is propagating from and its parents.
4370  		var targets = this._findEventTargets(e, type);
4371
4372  		if (canvasTargets) {
4373  			var filtered = []; // pick only targets with listeners
4374  			for (var i = 0; i < canvasTargets.length; i++) {
4375  				if (canvasTargets[i].listens(type, true)) {
4376  					filtered.push(canvasTargets[i]);
4377  				}
4378  			}
4379  			targets = filtered.concat(targets);
4380  		}
4381
4382  		if (!targets.length) { return; }
4383
4384  		if (type === 'contextmenu') {
4385  			preventDefault(e);
4386  		}
4387
4388  		var target = targets[0];
4389  		var data = {
4390  			originalEvent: e
4391  		};
4392
4393  		if (e.type !== 'keypress' && e.type !== 'keydown' && e.type !== 'keyup') {
4394  			var isMarker = target.getLatLng && (!target._radius || target._radius <= 10);
4395  			data.containerPoint = isMarker ?
4396  				this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
4397  			data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);
4398  			data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);
4399  		}
4400
4401  		for (i = 0; i < targets.length; i++) {
4402  			targets[i].fire(type, data, true);
4403  			if (data.originalEvent._stopped ||
4404  				(targets[i].options.bubblingMouseEvents === false && indexOf(this._mouseEvents, type) !== -1)) { return; }
4405  		}
4406  	},
4407
4408  	_draggableMoved: function (obj) {
4409  		obj = obj.dragging && obj.dragging.enabled() ? obj : this;
4410  		return (obj.dragging && obj.dragging.moved()) || (this.boxZoom && this.boxZoom.moved());
4411  	},
4412
4413  	_clearHandlers: function () {
4414  		for (var i = 0, len = this._handlers.length; i < len; i++) {
4415  			this._handlers[i].disable();
4416  		}
4417  	},
4418
4419  	// @section Other Methods
4420
4421  	// @method whenReady(fn: Function, context?: Object): this
4422  	// Runs the given function `fn` when the map gets initialized with
4423  	// a view (center and zoom) and at least one layer, or immediately
4424  	// if it's already initialized, optionally passing a function context.
4425  	whenReady: function (callback, context) {
4426  		if (this._loaded) {
4427  			callback.call(context || this, {target: this});
4428  		} else {
4429  			this.on('load', callback, context);
4430  		}
4431  		return this;
4432  	},
4433
4434
4435  	// private methods for getting map state
4436
4437  	_getMapPanePos: function () {
4438  		return getPosition(this._mapPane) || new Point(0, 0);
4439  	},
4440
4441  	_moved: function () {
4442  		var pos = this._getMapPanePos();
4443  		return pos && !pos.equals([0, 0]);
4444  	},
4445
4446  	_getTopLeftPoint: function (center, zoom) {
4447  		var pixelOrigin = center && zoom !== undefined ?
4448  			this._getNewPixelOrigin(center, zoom) :
4449  			this.getPixelOrigin();
4450  		return pixelOrigin.subtract(this._getMapPanePos());
4451  	},
4452
4453  	_getNewPixelOrigin: function (center, zoom) {
4454  		var viewHalf = this.getSize()._divideBy(2);
4455  		return this.project(center, zoom)._subtract(viewHalf)._add(this._getMapPanePos())._round();
4456  	},
4457
4458  	_latLngToNewLayerPoint: function (latlng, zoom, center) {
4459  		var topLeft = this._getNewPixelOrigin(center, zoom);
4460  		return this.project(latlng, zoom)._subtract(topLeft);
4461  	},
4462
4463  	_latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) {
4464  		var topLeft = this._getNewPixelOrigin(center, zoom);
4465  		return toBounds([
4466  			this.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft),
4467  			this.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft),
4468  			this.project(latLngBounds.getSouthEast(), zoom)._subtract(topLeft),
4469  			this.project(latLngBounds.getNorthEast(), zoom)._subtract(topLeft)
4470  		]);
4471  	},
4472
4473  	// layer point of the current center
4474  	_getCenterLayerPoint: function () {
4475  		return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
4476  	},
4477
4478  	// offset of the specified place to the current center in pixels
4479  	_getCenterOffset: function (latlng) {
4480  		return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());
4481  	},
4482
4483  	// adjust center for view to get inside bounds
4484  	_limitCenter: function (center, zoom, bounds) {
4485
4486  		if (!bounds) { return center; }
4487
4488  		var centerPoint = this.project(center, zoom),
4489  		    viewHalf = this.getSize().divideBy(2),
4490  		    viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
4491  		    offset = this._getBoundsOffset(viewBounds, bounds, zoom);
4492
4493  		// If offset is less than a pixel, ignore.
4494  		// This prevents unstable projections from getting into
4495  		// an infinite loop of tiny offsets.
4496  		if (offset.round().equals([0, 0])) {
4497  			return center;
4498  		}
4499
4500  		return this.unproject(centerPoint.add(offset), zoom);
4501  	},
4502
4503  	// adjust offset for view to get inside bounds
4504  	_limitOffset: function (offset, bounds) {
4505  		if (!bounds) { return offset; }
4506
4507  		var viewBounds = this.getPixelBounds(),
4508  		    newBounds = new Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));
4509
4510  		return offset.add(this._getBoundsOffset(newBounds, bounds));
4511  	},
4512
4513  	// returns offset needed for pxBounds to get inside maxBounds at a specified zoom
4514  	_getBoundsOffset: function (pxBounds, maxBounds, zoom) {
4515  		var projectedMaxBounds = toBounds(
4516  		        this.project(maxBounds.getNorthEast(), zoom),
4517  		        this.project(maxBounds.getSouthWest(), zoom)
4518  		    ),
4519  		    minOffset = projectedMaxBounds.min.subtract(pxBounds.min),
4520  		    maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),
4521
4522  		    dx = this._rebound(minOffset.x, -maxOffset.x),
4523  		    dy = this._rebound(minOffset.y, -maxOffset.y);
4524
4525  		return new Point(dx, dy);
4526  	},
4527
4528  	_rebound: function (left, right) {
4529  		return left + right > 0 ?
4530  			Math.round(left - right) / 2 :
4531  			Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));
4532  	},
4533
4534  	_limitZoom: function (zoom) {
4535  		var min = this.getMinZoom(),
4536  		    max = this.getMaxZoom(),
4537  		    snap = any3d ? this.options.zoomSnap : 1;
4538  		if (snap) {
4539  			zoom = Math.round(zoom / snap) * snap;
4540  		}
4541  		return Math.max(min, Math.min(max, zoom));
4542  	},
4543
4544  	_onPanTransitionStep: function () {
4545  		this.fire('move');
4546  	},
4547
4548  	_onPanTransitionEnd: function () {
4549  		removeClass(this._mapPane, 'leaflet-pan-anim');
4550  		this.fire('moveend');
4551  	},
4552
4553  	_tryAnimatedPan: function (center, options) {
4554  		// difference between the new and current centers in pixels
4555  		var offset = this._getCenterOffset(center)._trunc();
4556
4557  		// don't animate too far unless animate: true specified in options
4558  		if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }
4559
4560  		this.panBy(offset, options);
4561
4562  		return true;
4563  	},
4564
4565  	_createAnimProxy: function () {
4566
4567  		var proxy = this._proxy = create$1('div', 'leaflet-proxy leaflet-zoom-animated');
4568  		this._panes.mapPane.appendChild(proxy);
4569
4570  		this.on('zoomanim', function (e) {
4571  			var prop = TRANSFORM,
4572  			    transform = this._proxy.style[prop];
4573
4574  			setTransform(this._proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));
4575
4576  			// workaround for case when transform is the same and so transitionend event is not fired
4577  			if (transform === this._proxy.style[prop] && this._animatingZoom) {
4578  				this._onZoomTransitionEnd();
4579  			}
4580  		}, this);
4581
4582  		this.on('load moveend', this._animMoveEnd, this);
4583
4584  		this._on('unload', this._destroyAnimProxy, this);
4585  	},
4586
4587  	_destroyAnimProxy: function () {
4588  		remove(this._proxy);
4589  		this.off('load moveend', this._animMoveEnd, this);
4590  		delete this._proxy;
4591  	},
4592
4593  	_animMoveEnd: function () {
4594  		var c = this.getCenter(),
4595  		    z = this.getZoom();
4596  		setTransform(this._proxy, this.project(c, z), this.getZoomScale(z, 1));
4597  	},
4598
4599  	_catchTransitionEnd: function (e) {
4600  		if (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) {
4601  			this._onZoomTransitionEnd();
4602  		}
4603  	},
4604
4605  	_nothingToAnimate: function () {
4606  		return !this._container.getElementsByClassName('leaflet-zoom-animated').length;
4607  	},
4608
4609  	_tryAnimatedZoom: function (center, zoom, options) {
4610
4611  		if (this._animatingZoom) { return true; }
4612
4613  		options = options || {};
4614
4615  		// don't animate if disabled, not supported or zoom difference is too large
4616  		if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||
4617  		        Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }
4618
4619  		// offset is the pixel coords of the zoom origin relative to the current center
4620  		var scale = this.getZoomScale(zoom),
4621  		    offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale);
4622
4623  		// don't animate if the zoom origin isn't within one screen from the current center, unless forced
4624  		if (options.animate !== true && !this.getSize().contains(offset)) { return false; }
4625
4626  		requestAnimFrame(function () {
4627  			this
4628  			    ._moveStart(true, false)
4629  			    ._animateZoom(center, zoom, true);
4630  		}, this);
4631
4632  		return true;
4633  	},
4634
4635  	_animateZoom: function (center, zoom, startAnim, noUpdate) {
4636  		if (!this._mapPane) { return; }
4637
4638  		if (startAnim) {
4639  			this._animatingZoom = true;
4640
4641  			// remember what center/zoom to set after animation
4642  			this._animateToCenter = center;
4643  			this._animateToZoom = zoom;
4644
4645  			addClass(this._mapPane, 'leaflet-zoom-anim');
4646  		}
4647
4648  		// @section Other Events
4649  		// @event zoomanim: ZoomAnimEvent
4650  		// Fired at least once per zoom animation. For continuous zoom, like pinch zooming, fired once per frame during zoom.
4651  		this.fire('zoomanim', {
4652  			center: center,
4653  			zoom: zoom,
4654  			noUpdate: noUpdate
4655  		});
4656
4657  		// Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693
4658  		setTimeout(bind(this._onZoomTransitionEnd, this), 250);
4659  	},
4660
4661  	_onZoomTransitionEnd: function () {
4662  		if (!this._animatingZoom) { return; }
4663
4664  		if (this._mapPane) {
4665  			removeClass(this._mapPane, 'leaflet-zoom-anim');
4666  		}
4667
4668  		this._animatingZoom = false;
4669
4670  		this._move(this._animateToCenter, this._animateToZoom);
4671
4672  		// This anim frame should prevent an obscure iOS webkit tile loading race condition.
4673  		requestAnimFrame(function () {
4674  			this._moveEnd(true);
4675  		}, this);
4676  	}
4677  });
4678
4679  // @section
4680
4681  // @factory L.map(id: String, options?: Map options)
4682  // Instantiates a map object given the DOM ID of a `<div>` element
4683  // and optionally an object literal with `Map options`.
4684  //
4685  // @alternative
4686  // @factory L.map(el: HTMLElement, options?: Map options)
4687  // Instantiates a map object given an instance of a `<div>` HTML element
4688  // and optionally an object literal with `Map options`.
4689  function createMap(id, options) {
4690  	return new Map(id, options);
4691  }
4692
4693  /*
4694   * @class Control
4695   * @aka L.Control
4696   * @inherits Class
4697   *
4698   * L.Control is a base class for implementing map controls. Handles positioning.
4699   * All other controls extend from this class.
4700   */
4701
4702  var Control = Class.extend({
4703  	// @section
4704  	// @aka Control Options
4705  	options: {
4706  		// @option position: String = 'topright'
4707  		// The position of the control (one of the map corners). Possible values are `'topleft'`,
4708  		// `'topright'`, `'bottomleft'` or `'bottomright'`
4709  		position: 'topright'
4710  	},
4711
4712  	initialize: function (options) {
4713  		setOptions(this, options);
4714  	},
4715
4716  	/* @section
4717  	 * Classes extending L.Control will inherit the following methods:
4718  	 *
4719  	 * @method getPosition: string
4720  	 * Returns the position of the control.
4721  	 */
4722  	getPosition: function () {
4723  		return this.options.position;
4724  	},
4725
4726  	// @method setPosition(position: string): this
4727  	// Sets the position of the control.
4728  	setPosition: function (position) {
4729  		var map = this._map;
4730
4731  		if (map) {
4732  			map.removeControl(this);
4733  		}
4734
4735  		this.options.position = position;
4736
4737  		if (map) {
4738  			map.addControl(this);
4739  		}
4740
4741  		return this;
4742  	},
4743
4744  	// @method getContainer: HTMLElement
4745  	// Returns the HTMLElement that contains the control.
4746  	getContainer: function () {
4747  		return this._container;
4748  	},
4749
4750  	// @method addTo(map: Map): this
4751  	// Adds the control to the given map.
4752  	addTo: function (map) {
4753  		this.remove();
4754  		this._map = map;
4755
4756  		var container = this._container = this.onAdd(map),
4757  		    pos = this.getPosition(),
4758  		    corner = map._controlCorners[pos];
4759
4760  		addClass(container, 'leaflet-control');
4761
4762  		if (pos.indexOf('bottom') !== -1) {
4763  			corner.insertBefore(container, corner.firstChild);
4764  		} else {
4765  			corner.appendChild(container);
4766  		}
4767
4768  		this._map.on('unload', this.remove, this);
4769
4770  		return this;
4771  	},
4772
4773  	// @method remove: this
4774  	// Removes the control from the map it is currently active on.
4775  	remove: function () {
4776  		if (!this._map) {
4777  			return this;
4778  		}
4779
4780  		remove(this._container);
4781
4782  		if (this.onRemove) {
4783  			this.onRemove(this._map);
4784  		}
4785
4786  		this._map.off('unload', this.remove, this);
4787  		this._map = null;
4788
4789  		return this;
4790  	},
4791
4792  	_refocusOnMap: function (e) {
4793  		// if map exists and event is not a keyboard event
4794  		if (this._map && e && e.screenX > 0 && e.screenY > 0) {
4795  			this._map.getContainer().focus();
4796  		}
4797  	}
4798  });
4799
4800  var control = function (options) {
4801  	return new Control(options);
4802  };
4803
4804  /* @section Extension methods
4805   * @uninheritable
4806   *
4807   * Every control should extend from `L.Control` and (re-)implement the following methods.
4808   *
4809   * @method onAdd(map: Map): HTMLElement
4810   * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo).
4811   *
4812   * @method onRemove(map: Map)
4813   * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove).
4814   */
4815
4816  /* @namespace Map
4817   * @section Methods for Layers and Controls
4818   */
4819  Map.include({
4820  	// @method addControl(control: Control): this
4821  	// Adds the given control to the map
4822  	addControl: function (control) {
4823  		control.addTo(this);
4824  		return this;
4825  	},
4826
4827  	// @method removeControl(control: Control): this
4828  	// Removes the given control from the map
4829  	removeControl: function (control) {
4830  		control.remove();
4831  		return this;
4832  	},
4833
4834  	_initControlPos: function () {
4835  		var corners = this._controlCorners = {},
4836  		    l = 'leaflet-',
4837  		    container = this._controlContainer =
4838  		            create$1('div', l + 'control-container', this._container);
4839
4840  		function createCorner(vSide, hSide) {
4841  			var className = l + vSide + ' ' + l + hSide;
4842
4843  			corners[vSide + hSide] = create$1('div', className, container);
4844  		}
4845
4846  		createCorner('top', 'left');
4847  		createCorner('top', 'right');
4848  		createCorner('bottom', 'left');
4849  		createCorner('bottom', 'right');
4850  	},
4851
4852  	_clearControlPos: function () {
4853  		for (var i in this._controlCorners) {
4854  			remove(this._controlCorners[i]);
4855  		}
4856  		remove(this._controlContainer);
4857  		delete this._controlCorners;
4858  		delete this._controlContainer;
4859  	}
4860  });
4861
4862  /*
4863   * @class Control.Layers
4864   * @aka L.Control.Layers
4865   * @inherits Control
4866   *
4867   * 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`.
4868   *
4869   * @example
4870   *
4871   * ```js
4872   * var baseLayers = {
4873   * 	"Mapbox": mapbox,
4874   * 	"OpenStreetMap": osm
4875   * };
4876   *
4877   * var overlays = {
4878   * 	"Marker": marker,
4879   * 	"Roads": roadsLayer
4880   * };
4881   *
4882   * L.control.layers(baseLayers, overlays).addTo(map);
4883   * ```
4884   *
4885   * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values:
4886   *
4887   * ```js
4888   * {
4889   *     "<someName1>": layer1,
4890   *     "<someName2>": layer2
4891   * }
4892   * ```
4893   *
4894   * The layer names can contain HTML, which allows you to add additional styling to the items:
4895   *
4896   * ```js
4897   * {"<img src='my-layer-icon' /> <span class='my-layer-item'>My Layer</span>": myLayer}
4898   * ```
4899   */
4900
4901  var Layers = Control.extend({
4902  	// @section
4903  	// @aka Control.Layers options
4904  	options: {
4905  		// @option collapsed: Boolean = true
4906  		// If `true`, the control will be collapsed into an icon and expanded on mouse hover or touch.
4907  		collapsed: true,
4908  		position: 'topright',
4909
4910  		// @option autoZIndex: Boolean = true
4911  		// 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.
4912  		autoZIndex: true,
4913
4914  		// @option hideSingleBase: Boolean = false
4915  		// If `true`, the base layers in the control will be hidden when there is only one.
4916  		hideSingleBase: false,
4917
4918  		// @option sortLayers: Boolean = false
4919  		// Whether to sort the layers. When `false`, layers will keep the order
4920  		// in which they were added to the control.
4921  		sortLayers: false,
4922
4923  		// @option sortFunction: Function = *
4924  		// A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
4925  		// that will be used for sorting the layers, when `sortLayers` is `true`.
4926  		// The function receives both the `L.Layer` instances and their names, as in
4927  		// `sortFunction(layerA, layerB, nameA, nameB)`.
4928  		// By default, it sorts layers alphabetically by their name.
4929  		sortFunction: function (layerA, layerB, nameA, nameB) {
4930  			return nameA < nameB ? -1 : (nameB < nameA ? 1 : 0);
4931  		}
4932  	},
4933
4934  	initialize: function (baseLayers, overlays, options) {
4935  		setOptions(this, options);
4936
4937  		this._layerControlInputs = [];
4938  		this._layers = [];
4939  		this._lastZIndex = 0;
4940  		this._handlingClick = false;
4941
4942  		for (var i in baseLayers) {
4943  			this._addLayer(baseLayers[i], i);
4944  		}
4945
4946  		for (i in overlays) {
4947  			this._addLayer(overlays[i], i, true);
4948  		}
4949  	},
4950
4951  	onAdd: function (map) {
4952  		this._initLayout();
4953  		this._update();
4954
4955  		this._map = map;
4956  		map.on('zoomend', this._checkDisabledLayers, this);
4957
4958  		for (var i = 0; i < this._layers.length; i++) {
4959  			this._layers[i].layer.on('add remove', this._onLayerChange, this);
4960  		}
4961
4962  		return this._container;
4963  	},
4964
4965  	addTo: function (map) {
4966  		Control.prototype.addTo.call(this, map);
4967  		// Trigger expand after Layers Control has been inserted into DOM so that is now has an actual height.
4968  		return this._expandIfNotCollapsed();
4969  	},
4970
4971  	onRemove: function () {
4972  		this._map.off('zoomend', this._checkDisabledLayers, this);
4973
4974  		for (var i = 0; i < this._layers.length; i++) {
4975  			this._layers[i].layer.off('add remove', this._onLayerChange, this);
4976  		}
4977  	},
4978
4979  	// @method addBaseLayer(layer: Layer, name: String): this
4980  	// Adds a base layer (radio button entry) with the given name to the control.
4981  	addBaseLayer: function (layer, name) {
4982  		this._addLayer(layer, name);
4983  		return (this._map) ? this._update() : this;
4984  	},
4985
4986  	// @method addOverlay(layer: Layer, name: String): this
4987  	// Adds an overlay (checkbox entry) with the given name to the control.
4988  	addOverlay: function (layer, name) {
4989  		this._addLayer(layer, name, true);
4990  		return (this._map) ? this._update() : this;
4991  	},
4992
4993  	// @method removeLayer(layer: Layer): this
4994  	// Remove the given layer from the control.
4995  	removeLayer: function (layer) {
4996  		layer.off('add remove', this._onLayerChange, this);
4997
4998  		var obj = this._getLayer(stamp(layer));
4999  		if (obj) {
5000  			this._layers.splice(this._layers.indexOf(obj), 1);
5001  		}
5002  		return (this._map) ? this._update() : this;
5003  	},
5004
5005  	// @method expand(): this
5006  	// Expand the control container if collapsed.
5007  	expand: function () {
5008  		addClass(this._container, 'leaflet-control-layers-expanded');
5009  		this._section.style.height = null;
5010  		var acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);
5011  		if (acceptableHeight < this._section.clientHeight) {
5012  			addClass(this._section, 'leaflet-control-layers-scrollbar');
5013  			this._section.style.height = acceptableHeight + 'px';
5014  		} else {
5015  			removeClass(this._section, 'leaflet-control-layers-scrollbar');
5016  		}
5017  		this._checkDisabledLayers();
5018  		return this;
5019  	},
5020
5021  	// @method collapse(): this
5022  	// Collapse the control container if expanded.
5023  	collapse: function () {
5024  		removeClass(this._container, 'leaflet-control-layers-expanded');
5025  		return this;
5026  	},
5027
5028  	_initLayout: function () {
5029  		var className = 'leaflet-control-layers',
5030  		    container = this._container = create$1('div', className),
5031  		    collapsed = this.options.collapsed;
5032
5033  		// makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released
5034  		container.setAttribute('aria-haspopup', true);
5035
5036  		disableClickPropagation(container);
5037  		disableScrollPropagation(container);
5038
5039  		var section = this._section = create$1('section', className + '-list');
5040
5041  		if (collapsed) {
5042  			this._map.on('click', this.collapse, this);
5043
5044  			on(container, {
5045  				mouseenter: function () {
5046  					on(section, 'click', preventDefault);
5047  					this.expand();
5048  					setTimeout(function () {
5049  						off(section, 'click', preventDefault);
5050  					});
5051  				},
5052  				mouseleave: this.collapse
5053  			}, this);
5054  		}
5055
5056  		var link = this._layersLink = create$1('a', className + '-toggle', container);
5057  		link.href = '#';
5058  		link.title = 'Layers';
5059
5060  		on(link, 'click', preventDefault); // prevent link function
5061  		on(link, 'focus', this.expand, this);
5062
5063  		if (!collapsed) {
5064  			this.expand();
5065  		}
5066
5067  		this._baseLayersList = create$1('div', className + '-base', section);
5068  		this._separator = create$1('div', className + '-separator', section);
5069  		this._overlaysList = create$1('div', className + '-overlays', section);
5070
5071  		container.appendChild(section);
5072  	},
5073
5074  	_getLayer: function (id) {
5075  		for (var i = 0; i < this._layers.length; i++) {
5076
5077  			if (this._layers[i] && stamp(this._layers[i].layer) === id) {
5078  				return this._layers[i];
5079  			}
5080  		}
5081  	},
5082
5083  	_addLayer: function (layer, name, overlay) {
5084  		if (this._map) {
5085  			layer.on('add remove', this._onLayerChange, this);
5086  		}
5087
5088  		this._layers.push({
5089  			layer: layer,
5090  			name: name,
5091  			overlay: overlay
5092  		});
5093
5094  		if (this.options.sortLayers) {
5095  			this._layers.sort(bind(function (a, b) {
5096  				return this.options.sortFunction(a.layer, b.layer, a.name, b.name);
5097  			}, this));
5098  		}
5099
5100  		if (this.options.autoZIndex && layer.setZIndex) {
5101  			this._lastZIndex++;
5102  			layer.setZIndex(this._lastZIndex);
5103  		}
5104
5105  		this._expandIfNotCollapsed();
5106  	},
5107
5108  	_update: function () {
5109  		if (!this._container) { return this; }
5110
5111  		empty(this._baseLayersList);
5112  		empty(this._overlaysList);
5113
5114  		this._layerControlInputs = [];
5115  		var baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;
5116
5117  		for (i = 0; i < this._layers.length; i++) {
5118  			obj = this._layers[i];
5119  			this._addItem(obj);
5120  			overlaysPresent = overlaysPresent || obj.overlay;
5121  			baseLayersPresent = baseLayersPresent || !obj.overlay;
5122  			baseLayersCount += !obj.overlay ? 1 : 0;
5123  		}
5124
5125  		// Hide base layers section if there's only one layer.
5126  		if (this.options.hideSingleBase) {
5127  			baseLayersPresent = baseLayersPresent && baseLayersCount > 1;
5128  			this._baseLayersList.style.display = baseLayersPresent ? '' : 'none';
5129  		}
5130
5131  		this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
5132
5133  		return this;
5134  	},
5135
5136  	_onLayerChange: function (e) {
5137  		if (!this._handlingClick) {
5138  			this._update();
5139  		}
5140
5141  		var obj = this._getLayer(stamp(e.target));
5142
5143  		// @namespace Map
5144  		// @section Layer events
5145  		// @event baselayerchange: LayersControlEvent
5146  		// Fired when the base layer is changed through the [layers control](#control-layers).
5147  		// @event overlayadd: LayersControlEvent
5148  		// Fired when an overlay is selected through the [layers control](#control-layers).
5149  		// @event overlayremove: LayersControlEvent
5150  		// Fired when an overlay is deselected through the [layers control](#control-layers).
5151  		// @namespace Control.Layers
5152  		var type = obj.overlay ?
5153  			(e.type === 'add' ? 'overlayadd' : 'overlayremove') :
5154  			(e.type === 'add' ? 'baselayerchange' : null);
5155
5156  		if (type) {
5157  			this._map.fire(type, obj);
5158  		}
5159  	},
5160
5161  	// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see https://stackoverflow.com/a/119079)
5162  	_createRadioElement: function (name, checked) {
5163
5164  		var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' +
5165  				name + '"' + (checked ? ' checked="checked"' : '') + '/>';
5166
5167  		var radioFragment = document.createElement('div');
5168  		radioFragment.innerHTML = radioHtml;
5169
5170  		return radioFragment.firstChild;
5171  	},
5172
5173  	_addItem: function (obj) {
5174  		var label = document.createElement('label'),
5175  		    checked = this._map.hasLayer(obj.layer),
5176  		    input;
5177
5178  		if (obj.overlay) {
5179  			input = document.createElement('input');
5180  			input.type = 'checkbox';
5181  			input.className = 'leaflet-control-layers-selector';
5182  			input.defaultChecked = checked;
5183  		} else {
5184  			input = this._createRadioElement('leaflet-base-layers_' + stamp(this), checked);
5185  		}
5186
5187  		this._layerControlInputs.push(input);
5188  		input.layerId = stamp(obj.layer);
5189
5190  		on(input, 'click', this._onInputClick, this);
5191
5192  		var name = document.createElement('span');
5193  		name.innerHTML = ' ' + obj.name;
5194
5195  		// Helps from preventing layer control flicker when checkboxes are disabled
5196  		// https://github.com/Leaflet/Leaflet/issues/2771
5197  		var holder = document.createElement('div');
5198
5199  		label.appendChild(holder);
5200  		holder.appendChild(input);
5201  		holder.appendChild(name);
5202
5203  		var container = obj.overlay ? this._overlaysList : this._baseLayersList;
5204  		container.appendChild(label);
5205
5206  		this._checkDisabledLayers();
5207  		return label;
5208  	},
5209
5210  	_onInputClick: function () {
5211  		var inputs = this._layerControlInputs,
5212  		    input, layer;
5213  		var addedLayers = [],
5214  		    removedLayers = [];
5215
5216  		this._handlingClick = true;
5217
5218  		for (var i = inputs.length - 1; i >= 0; i--) {
5219  			input = inputs[i];
5220  			layer = this._getLayer(input.layerId).layer;
5221
5222  			if (input.checked) {
5223  				addedLayers.push(layer);
5224  			} else if (!input.checked) {
5225  				removedLayers.push(layer);
5226  			}
5227  		}
5228
5229  		// Bugfix issue 2318: Should remove all old layers before readding new ones
5230  		for (i = 0; i < removedLayers.length; i++) {
5231  			if (this._map.hasLayer(removedLayers[i])) {
5232  				this._map.removeLayer(removedLayers[i]);
5233  			}
5234  		}
5235  		for (i = 0; i < addedLayers.length; i++) {
5236  			if (!this._map.hasLayer(addedLayers[i])) {
5237  				this._map.addLayer(addedLayers[i]);
5238  			}
5239  		}
5240
5241  		this._handlingClick = false;
5242
5243  		this._refocusOnMap();
5244  	},
5245
5246  	_checkDisabledLayers: function () {
5247  		var inputs = this._layerControlInputs,
5248  		    input,
5249  		    layer,
5250  		    zoom = this._map.getZoom();
5251
5252  		for (var i = inputs.length - 1; i >= 0; i--) {
5253  			input = inputs[i];
5254  			layer = this._getLayer(input.layerId).layer;
5255  			input.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) ||
5256  			                 (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom);
5257
5258  		}
5259  	},
5260
5261  	_expandIfNotCollapsed: function () {
5262  		if (this._map && !this.options.collapsed) {
5263  			this.expand();
5264  		}
5265  		return this;
5266  	}
5267
5268  });
5269
5270
5271  // @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options)
5272  // Creates a layers 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.
5273  var layers = function (baseLayers, overlays, options) {
5274  	return new Layers(baseLayers, overlays, options);
5275  };
5276
5277  /*
5278   * @class Control.Zoom
5279   * @aka L.Control.Zoom
5280   * @inherits Control
5281   *
5282   * 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`.
5283   */
5284
5285  var Zoom = Control.extend({
5286  	// @section
5287  	// @aka Control.Zoom options
5288  	options: {
5289  		position: 'topleft',
5290
5291  		// @option zoomInText: String = '+'
5292  		// The text set on the 'zoom in' button.
5293  		zoomInText: '<span aria-hidden="true">+</span>',
5294
5295  		// @option zoomInTitle: String = 'Zoom in'
5296  		// The title set on the 'zoom in' button.
5297  		zoomInTitle: 'Zoom in',
5298
5299  		// @option zoomOutText: String = '&#x2212;'
5300  		// The text set on the 'zoom out' button.
5301  		zoomOutText: '<span aria-hidden="true">&#x2212;</span>',
5302
5303  		// @option zoomOutTitle: String = 'Zoom out'
5304  		// The title set on the 'zoom out' button.
5305  		zoomOutTitle: 'Zoom out'
5306  	},
5307
5308  	onAdd: function (map) {
5309  		var zoomName = 'leaflet-control-zoom',
5310  		    container = create$1('div', zoomName + ' leaflet-bar'),
5311  		    options = this.options;
5312
5313  		this._zoomInButton  = this._createButton(options.zoomInText, options.zoomInTitle,
5314  		        zoomName + '-in',  container, this._zoomIn);
5315  		this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,
5316  		        zoomName + '-out', container, this._zoomOut);
5317
5318  		this._updateDisabled();
5319  		map.on('zoomend zoomlevelschange', this._updateDisabled, this);
5320
5321  		return container;
5322  	},
5323
5324  	onRemove: function (map) {
5325  		map.off('zoomend zoomlevelschange', this._updateDisabled, this);
5326  	},
5327
5328  	disable: function () {
5329  		this._disabled = true;
5330  		this._updateDisabled();
5331  		return this;
5332  	},
5333
5334  	enable: function () {
5335  		this._disabled = false;
5336  		this._updateDisabled();
5337  		return this;
5338  	},
5339
5340  	_zoomIn: function (e) {
5341  		if (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {
5342  			this._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
5343  		}
5344  	},
5345
5346  	_zoomOut: function (e) {
5347  		if (!this._disabled && this._map._zoom > this._map.getMinZoom()) {
5348  			this._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
5349  		}
5350  	},
5351
5352  	_createButton: function (html, title, className, container, fn) {
5353  		var link = create$1('a', className, container);
5354  		link.innerHTML = html;
5355  		link.href = '#';
5356  		link.title = title;
5357
5358  		/*
5359  		 * Will force screen readers like VoiceOver to read this as "Zoom in - button"
5360  		 */
5361  		link.setAttribute('role', 'button');
5362  		link.setAttribute('aria-label', title);
5363
5364  		disableClickPropagation(link);
5365  		on(link, 'click', stop);
5366  		on(link, 'click', fn, this);
5367  		on(link, 'click', this._refocusOnMap, this);
5368
5369  		return link;
5370  	},
5371
5372  	_updateDisabled: function () {
5373  		var map = this._map,
5374  		    className = 'leaflet-disabled';
5375
5376  		removeClass(this._zoomInButton, className);
5377  		removeClass(this._zoomOutButton, className);
5378  		this._zoomInButton.setAttribute('aria-disabled', 'false');
5379  		this._zoomOutButton.setAttribute('aria-disabled', 'false');
5380
5381  		if (this._disabled || map._zoom === map.getMinZoom()) {
5382  			addClass(this._zoomOutButton, className);
5383  			this._zoomOutButton.setAttribute('aria-disabled', 'true');
5384  		}
5385  		if (this._disabled || map._zoom === map.getMaxZoom()) {
5386  			addClass(this._zoomInButton, className);
5387  			this._zoomInButton.setAttribute('aria-disabled', 'true');
5388  		}
5389  	}
5390  });
5391
5392  // @namespace Map
5393  // @section Control options
5394  // @option zoomControl: Boolean = true
5395  // Whether a [zoom control](#control-zoom) is added to the map by default.
5396  Map.mergeOptions({
5397  	zoomControl: true
5398  });
5399
5400  Map.addInitHook(function () {
5401  	if (this.options.zoomControl) {
5402  		// @section Controls
5403  		// @property zoomControl: Control.Zoom
5404  		// The default zoom control (only available if the
5405  		// [`zoomControl` option](#map-zoomcontrol) was `true` when creating the map).
5406  		this.zoomControl = new Zoom();
5407  		this.addControl(this.zoomControl);
5408  	}
5409  });
5410
5411  // @namespace Control.Zoom
5412  // @factory L.control.zoom(options: Control.Zoom options)
5413  // Creates a zoom control
5414  var zoom = function (options) {
5415  	return new Zoom(options);
5416  };
5417
5418  /*
5419   * @class Control.Scale
5420   * @aka L.Control.Scale
5421   * @inherits Control
5422   *
5423   * 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`.
5424   *
5425   * @example
5426   *
5427   * ```js
5428   * L.control.scale().addTo(map);
5429   * ```
5430   */
5431
5432  var Scale = Control.extend({
5433  	// @section
5434  	// @aka Control.Scale options
5435  	options: {
5436  		position: 'bottomleft',
5437
5438  		// @option maxWidth: Number = 100
5439  		// Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).
5440  		maxWidth: 100,
5441
5442  		// @option metric: Boolean = True
5443  		// Whether to show the metric scale line (m/km).
5444  		metric: true,
5445
5446  		// @option imperial: Boolean = True
5447  		// Whether to show the imperial scale line (mi/ft).
5448  		imperial: true
5449
5450  		// @option updateWhenIdle: Boolean = false
5451  		// If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).
5452  	},
5453
5454  	onAdd: function (map) {
5455  		var className = 'leaflet-control-scale',
5456  		    container = create$1('div', className),
5457  		    options = this.options;
5458
5459  		this._addScales(options, className + '-line', container);
5460
5461  		map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
5462  		map.whenReady(this._update, this);
5463
5464  		return container;
5465  	},
5466
5467  	onRemove: function (map) {
5468  		map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
5469  	},
5470
5471  	_addScales: function (options, className, container) {
5472  		if (options.metric) {
5473  			this._mScale = create$1('div', className, container);
5474  		}
5475  		if (options.imperial) {
5476  			this._iScale = create$1('div', className, container);
5477  		}
5478  	},
5479
5480  	_update: function () {
5481  		var map = this._map,
5482  		    y = map.getSize().y / 2;
5483
5484  		var maxMeters = map.distance(
5485  			map.containerPointToLatLng([0, y]),
5486  			map.containerPointToLatLng([this.options.maxWidth, y]));
5487
5488  		this._updateScales(maxMeters);
5489  	},
5490
5491  	_updateScales: function (maxMeters) {
5492  		if (this.options.metric && maxMeters) {
5493  			this._updateMetric(maxMeters);
5494  		}
5495  		if (this.options.imperial && maxMeters) {
5496  			this._updateImperial(maxMeters);
5497  		}
5498  	},
5499
5500  	_updateMetric: function (maxMeters) {
5501  		var meters = this._getRoundNum(maxMeters),
5502  		    label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';
5503
5504  		this._updateScale(this._mScale, label, meters / maxMeters);
5505  	},
5506
5507  	_updateImperial: function (maxMeters) {
5508  		var maxFeet = maxMeters * 3.2808399,
5509  		    maxMiles, miles, feet;
5510
5511  		if (maxFeet > 5280) {
5512  			maxMiles = maxFeet / 5280;
5513  			miles = this._getRoundNum(maxMiles);
5514  			this._updateScale(this._iScale, miles + ' mi', miles / maxMiles);
5515
5516  		} else {
5517  			feet = this._getRoundNum(maxFeet);
5518  			this._updateScale(this._iScale, feet + ' ft', feet / maxFeet);
5519  		}
5520  	},
5521
5522  	_updateScale: function (scale, text, ratio) {
5523  		scale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';
5524  		scale.innerHTML = text;
5525  	},
5526
5527  	_getRoundNum: function (num) {
5528  		var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),
5529  		    d = num / pow10;
5530
5531  		d = d >= 10 ? 10 :
5532  		    d >= 5 ? 5 :
5533  		    d >= 3 ? 3 :
5534  		    d >= 2 ? 2 : 1;
5535
5536  		return pow10 * d;
5537  	}
5538  });
5539
5540
5541  // @factory L.control.scale(options?: Control.Scale options)
5542  // Creates an scale control with the given options.
5543  var scale = function (options) {
5544  	return new Scale(options);
5545  };
5546
5547  /*
5548   * @class Control.Attribution
5549   * @aka L.Control.Attribution
5550   * @inherits Control
5551   *
5552   * 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.
5553   */
5554
5555  var Attribution = Control.extend({
5556  	// @section
5557  	// @aka Control.Attribution options
5558  	options: {
5559  		position: 'bottomright',
5560
5561  		// @option prefix: String = 'Leaflet'
5562  		// The HTML text shown before the attributions. Pass `false` to disable.
5563  		prefix: '<a href="https://leafletjs.com" title="A JavaScript library for interactive maps">Leaflet</a>'
5564
5565  	},
5566
5567  	initialize: function (options) {
5568  		setOptions(this, options);
5569
5570  		this._attributions = {};
5571  	},
5572
5573  	onAdd: function (map) {
5574  		map.attributionControl = this;
5575  		this._container = create$1('div', 'leaflet-control-attribution');
5576  		disableClickPropagation(this._container);
5577
5578  		// TODO ugly, refactor
5579  		for (var i in map._layers) {
5580  			if (map._layers[i].getAttribution) {
5581  				this.addAttribution(map._layers[i].getAttribution());
5582  			}
5583  		}
5584
5585  		this._update();
5586
5587  		map.on('layeradd', this._addAttribution, this);
5588
5589  		return this._container;
5590  	},
5591
5592  	onRemove: function (map) {
5593  		map.off('layeradd', this._addAttribution, this);
5594  	},
5595
5596  	_addAttribution: function (ev) {
5597  		if (ev.layer.getAttribution) {
5598  			this.addAttribution(ev.layer.getAttribution());
5599  			ev.layer.once('remove', function () {
5600  				this.removeAttribution(ev.layer.getAttribution());
5601  			}, this);
5602  		}
5603  	},
5604
5605  	// @method setPrefix(prefix: String): this
5606  	// Sets the text before the attributions.
5607  	setPrefix: function (prefix) {
5608  		this.options.prefix = prefix;
5609  		this._update();
5610  		return this;
5611  	},
5612
5613  	// @method addAttribution(text: String): this
5614  	// Adds an attribution text (e.g. `'Vector data &copy; Mapbox'`).
5615  	addAttribution: function (text) {
5616  		if (!text) { return this; }
5617
5618  		if (!this._attributions[text]) {
5619  			this._attributions[text] = 0;
5620  		}
5621  		this._attributions[text]++;
5622
5623  		this._update();
5624
5625  		return this;
5626  	},
5627
5628  	// @method removeAttribution(text: String): this
5629  	// Removes an attribution text.
5630  	removeAttribution: function (text) {
5631  		if (!text) { return this; }
5632
5633  		if (this._attributions[text]) {
5634  			this._attributions[text]--;
5635  			this._update();
5636  		}
5637
5638  		return this;
5639  	},
5640
5641  	_update: function () {
5642  		if (!this._map) { return; }
5643
5644  		var attribs = [];
5645
5646  		for (var i in this._attributions) {
5647  			if (this._attributions[i]) {
5648  				attribs.push(i);
5649  			}
5650  		}
5651
5652  		var prefixAndAttribs = [];
5653
5654  		if (this.options.prefix) {
5655  			prefixAndAttribs.push(this.options.prefix);
5656  		}
5657  		if (attribs.length) {
5658  			prefixAndAttribs.push(attribs.join(', '));
5659  		}
5660
5661  		this._container.innerHTML = prefixAndAttribs.join(' | ');
5662  	}
5663  });
5664
5665  // @namespace Map
5666  // @section Control options
5667  // @option attributionControl: Boolean = true
5668  // Whether a [attribution control](#control-attribution) is added to the map by default.
5669  Map.mergeOptions({
5670  	attributionControl: true
5671  });
5672
5673  Map.addInitHook(function () {
5674  	if (this.options.attributionControl) {
5675  		new Attribution().addTo(this);
5676  	}
5677  });
5678
5679  // @namespace Control.Attribution
5680  // @factory L.control.attribution(options: Control.Attribution options)
5681  // Creates an attribution control.
5682  var attribution = function (options) {
5683  	return new Attribution(options);
5684  };
5685
5686  Control.Layers = Layers;
5687  Control.Zoom = Zoom;
5688  Control.Scale = Scale;
5689  Control.Attribution = Attribution;
5690
5691  control.layers = layers;
5692  control.zoom = zoom;
5693  control.scale = scale;
5694  control.attribution = attribution;
5695
5696  /*
5697  	L.Handler is a base class for handler classes that are used internally to inject
5698  	interaction features like dragging to classes like Map and Marker.
5699  */
5700
5701  // @class Handler
5702  // @aka L.Handler
5703  // Abstract class for map interaction handlers
5704
5705  var Handler = Class.extend({
5706  	initialize: function (map) {
5707  		this._map = map;
5708  	},
5709
5710  	// @method enable(): this
5711  	// Enables the handler
5712  	enable: function () {
5713  		if (this._enabled) { return this; }
5714
5715  		this._enabled = true;
5716  		this.addHooks();
5717  		return this;
5718  	},
5719
5720  	// @method disable(): this
5721  	// Disables the handler
5722  	disable: function () {
5723  		if (!this._enabled) { return this; }
5724
5725  		this._enabled = false;
5726  		this.removeHooks();
5727  		return this;
5728  	},
5729
5730  	// @method enabled(): Boolean
5731  	// Returns `true` if the handler is enabled
5732  	enabled: function () {
5733  		return !!this._enabled;
5734  	}
5735
5736  	// @section Extension methods
5737  	// Classes inheriting from `Handler` must implement the two following methods:
5738  	// @method addHooks()
5739  	// Called when the handler is enabled, should add event hooks.
5740  	// @method removeHooks()
5741  	// Called when the handler is disabled, should remove the event hooks added previously.
5742  });
5743
5744  // @section There is static function which can be called without instantiating L.Handler:
5745  // @function addTo(map: Map, name: String): this
5746  // Adds a new Handler to the given map with the given name.
5747  Handler.addTo = function (map, name) {
5748  	map.addHandler(name, this);
5749  	return this;
5750  };
5751
5752  var Mixin = {Events: Events};
5753
5754  /*
5755   * @class Draggable
5756   * @aka L.Draggable
5757   * @inherits Evented
5758   *
5759   * A class for making DOM elements draggable (including touch support).
5760   * Used internally for map and marker dragging. Only works for elements
5761   * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).
5762   *
5763   * @example
5764   * ```js
5765   * var draggable = new L.Draggable(elementToDrag);
5766   * draggable.enable();
5767   * ```
5768   */
5769
5770  var START = touch ? 'touchstart mousedown' : 'mousedown';
5771
5772  var Draggable = Evented.extend({
5773
5774  	options: {
5775  		// @section
5776  		// @aka Draggable options
5777  		// @option clickTolerance: Number = 3
5778  		// The max number of pixels a user can shift the mouse pointer during a click
5779  		// for it to be considered a valid click (as opposed to a mouse drag).
5780  		clickTolerance: 3
5781  	},
5782
5783  	// @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline?: Boolean, options?: Draggable options)
5784  	// Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).
5785  	initialize: function (element, dragStartTarget, preventOutline, options) {
5786  		setOptions(this, options);
5787
5788  		this._element = element;
5789  		this._dragStartTarget = dragStartTarget || element;
5790  		this._preventOutline = preventOutline;
5791  	},
5792
5793  	// @method enable()
5794  	// Enables the dragging ability
5795  	enable: function () {
5796  		if (this._enabled) { return; }
5797
5798  		on(this._dragStartTarget, START, this._onDown, this);
5799
5800  		this._enabled = true;
5801  	},
5802
5803  	// @method disable()
5804  	// Disables the dragging ability
5805  	disable: function () {
5806  		if (!this._enabled) { return; }
5807
5808  		// If we're currently dragging this draggable,
5809  		// disabling it counts as first ending the drag.
5810  		if (Draggable._dragging === this) {
5811  			this.finishDrag();
5812  		}
5813
5814  		off(this._dragStartTarget, START, this._onDown, this);
5815
5816  		this._enabled = false;
5817  		this._moved = false;
5818  	},
5819
5820  	_onDown: function (e) {
5821  		// Ignore the event if disabled; this happens in IE11
5822  		// under some circumstances, see #3666.
5823  		if (!this._enabled) { return; }
5824
5825  		this._moved = false;
5826
5827  		if (hasClass(this._element, 'leaflet-zoom-anim')) { return; }
5828
5829  		if (Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }
5830  		Draggable._dragging = this;  // Prevent dragging multiple objects at once.
5831
5832  		if (this._preventOutline) {
5833  			preventOutline(this._element);
5834  		}
5835
5836  		disableImageDrag();
5837  		disableTextSelection();
5838
5839  		if (this._moving) { return; }
5840
5841  		// @event down: Event
5842  		// Fired when a drag is about to start.
5843  		this.fire('down');
5844
5845  		var first = e.touches ? e.touches[0] : e,
5846  		    sizedParent = getSizedParentNode(this._element);
5847
5848  		this._startPoint = new Point(first.clientX, first.clientY);
5849
5850  		// Cache the scale, so that we can continuously compensate for it during drag (_onMove).
5851  		this._parentScale = getScale(sizedParent);
5852
5853  		var mouseevent = e.type === 'mousedown';
5854  		on(document, mouseevent ? 'mousemove' : 'touchmove', this._onMove, this);
5855  		on(document, mouseevent ? 'mouseup' : 'touchend touchcancel', this._onUp, this);
5856  	},
5857
5858  	_onMove: function (e) {
5859  		// Ignore the event if disabled; this happens in IE11
5860  		// under some circumstances, see #3666.
5861  		if (!this._enabled) { return; }
5862
5863  		if (e.touches && e.touches.length > 1) {
5864  			this._moved = true;
5865  			return;
5866  		}
5867
5868  		var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
5869  		    offset = new Point(first.clientX, first.clientY)._subtract(this._startPoint);
5870
5871  		if (!offset.x && !offset.y) { return; }
5872  		if (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; }
5873
5874  		// We assume that the parent container's position, border and scale do not change for the duration of the drag.
5875  		// Therefore there is no need to account for the position and border (they are eliminated by the subtraction)
5876  		// and we can use the cached value for the scale.
5877  		offset.x /= this._parentScale.x;
5878  		offset.y /= this._parentScale.y;
5879
5880  		preventDefault(e);
5881
5882  		if (!this._moved) {
5883  			// @event dragstart: Event
5884  			// Fired when a drag starts
5885  			this.fire('dragstart');
5886
5887  			this._moved = true;
5888  			this._startPos = getPosition(this._element).subtract(offset);
5889
5890  			addClass(document.body, 'leaflet-dragging');
5891
5892  			this._lastTarget = e.target || e.srcElement;
5893  			// IE and Edge do not give the <use> element, so fetch it
5894  			// if necessary
5895  			if (window.SVGElementInstance && this._lastTarget instanceof window.SVGElementInstance) {
5896  				this._lastTarget = this._lastTarget.correspondingUseElement;
5897  			}
5898  			addClass(this._lastTarget, 'leaflet-drag-target');
5899  		}
5900
5901  		this._newPos = this._startPos.add(offset);
5902  		this._moving = true;
5903
5904  		cancelAnimFrame(this._animRequest);
5905  		this._lastEvent = e;
5906  		this._animRequest = requestAnimFrame(this._updatePosition, this, true);
5907  	},
5908
5909  	_updatePosition: function () {
5910  		var e = {originalEvent: this._lastEvent};
5911
5912  		// @event predrag: Event
5913  		// Fired continuously during dragging *before* each corresponding
5914  		// update of the element's position.
5915  		this.fire('predrag', e);
5916  		setPosition(this._element, this._newPos);
5917
5918  		// @event drag: Event
5919  		// Fired continuously during dragging.
5920  		this.fire('drag', e);
5921  	},
5922
5923  	_onUp: function () {
5924  		// Ignore the event if disabled; this happens in IE11
5925  		// under some circumstances, see #3666.
5926  		if (!this._enabled) { return; }
5927  		this.finishDrag();
5928  	},
5929
5930  	finishDrag: function () {
5931  		removeClass(document.body, 'leaflet-dragging');
5932
5933  		if (this._lastTarget) {
5934  			removeClass(this._lastTarget, 'leaflet-drag-target');
5935  			this._lastTarget = null;
5936  		}
5937
5938  		off(document, 'mousemove touchmove', this._onMove, this);
5939  		off(document, 'mouseup touchend touchcancel', this._onUp, this);
5940
5941  		enableImageDrag();
5942  		enableTextSelection();
5943
5944  		if (this._moved && this._moving) {
5945  			// ensure drag is not fired after dragend
5946  			cancelAnimFrame(this._animRequest);
5947
5948  			// @event dragend: DragEndEvent
5949  			// Fired when the drag ends.
5950  			this.fire('dragend', {
5951  				distance: this._newPos.distanceTo(this._startPos)
5952  			});
5953  		}
5954
5955  		this._moving = false;
5956  		Draggable._dragging = false;
5957  	}
5958
5959  });
5960
5961  /*
5962   * @namespace LineUtil
5963   *
5964   * Various utility functions for polyline points processing, used by Leaflet internally to make polylines lightning-fast.
5965   */
5966
5967  // Simplify polyline with vertex reduction and Douglas-Peucker simplification.
5968  // Improves rendering performance dramatically by lessening the number of points to draw.
5969
5970  // @function simplify(points: Point[], tolerance: Number): Point[]
5971  // Dramatically reduces the number of points in a polyline while retaining
5972  // its shape and returns a new array of simplified points, using the
5973  // [Douglas-Peucker algorithm](http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm).
5974  // Used for a huge performance boost when processing/displaying Leaflet polylines for
5975  // each zoom level and also reducing visual noise. tolerance affects the amount of
5976  // simplification (lesser value means higher quality but slower and with more points).
5977  // Also released as a separated micro-library [Simplify.js](http://mourner.github.com/simplify-js/).
5978  function simplify(points, tolerance) {
5979  	if (!tolerance || !points.length) {
5980  		return points.slice();
5981  	}
5982
5983  	var sqTolerance = tolerance * tolerance;
5984
5985  	    // stage 1: vertex reduction
5986  	    points = _reducePoints(points, sqTolerance);
5987
5988  	    // stage 2: Douglas-Peucker simplification
5989  	    points = _simplifyDP(points, sqTolerance);
5990
5991  	return points;
5992  }
5993
5994  // @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number
5995  // Returns the distance between point `p` and segment `p1` to `p2`.
5996  function pointToSegmentDistance(p, p1, p2) {
5997  	return Math.sqrt(_sqClosestPointOnSegment(p, p1, p2, true));
5998  }
5999
6000  // @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number
6001  // Returns the closest point from a point `p` on a segment `p1` to `p2`.
6002  function closestPointOnSegment(p, p1, p2) {
6003  	return _sqClosestPointOnSegment(p, p1, p2);
6004  }
6005
6006  // Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm
6007  function _simplifyDP(points, sqTolerance) {
6008
6009  	var len = points.length,
6010  	    ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,
6011  	    markers = new ArrayConstructor(len);
6012
6013  	    markers[0] = markers[len - 1] = 1;
6014
6015  	_simplifyDPStep(points, markers, sqTolerance, 0, len - 1);
6016
6017  	var i,
6018  	    newPoints = [];
6019
6020  	for (i = 0; i < len; i++) {
6021  		if (markers[i]) {
6022  			newPoints.push(points[i]);
6023  		}
6024  	}
6025
6026  	return newPoints;
6027  }
6028
6029  function _simplifyDPStep(points, markers, sqTolerance, first, last) {
6030
6031  	var maxSqDist = 0,
6032  	index, i, sqDist;
6033
6034  	for (i = first + 1; i <= last - 1; i++) {
6035  		sqDist = _sqClosestPointOnSegment(points[i], points[first], points[last], true);
6036
6037  		if (sqDist > maxSqDist) {
6038  			index = i;
6039  			maxSqDist = sqDist;
6040  		}
6041  	}
6042
6043  	if (maxSqDist > sqTolerance) {
6044  		markers[index] = 1;
6045
6046  		_simplifyDPStep(points, markers, sqTolerance, first, index);
6047  		_simplifyDPStep(points, markers, sqTolerance, index, last);
6048  	}
6049  }
6050
6051  // reduce points that are too close to each other to a single point
6052  function _reducePoints(points, sqTolerance) {
6053  	var reducedPoints = [points[0]];
6054
6055  	for (var i = 1, prev = 0, len = points.length; i < len; i++) {
6056  		if (_sqDist(points[i], points[prev]) > sqTolerance) {
6057  			reducedPoints.push(points[i]);
6058  			prev = i;
6059  		}
6060  	}
6061  	if (prev < len - 1) {
6062  		reducedPoints.push(points[len - 1]);
6063  	}
6064  	return reducedPoints;
6065  }
6066
6067  var _lastCode;
6068
6069  // @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, round?: Boolean): Point[]|Boolean
6070  // Clips the segment a to b by rectangular bounds with the
6071  // [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm)
6072  // (modifying the segment points directly!). Used by Leaflet to only show polyline
6073  // points that are on the screen or near, increasing performance.
6074  function clipSegment(a, b, bounds, useLastCode, round) {
6075  	var codeA = useLastCode ? _lastCode : _getBitCode(a, bounds),
6076  	    codeB = _getBitCode(b, bounds),
6077
6078  	    codeOut, p, newCode;
6079
6080  	    // save 2nd code to avoid calculating it on the next segment
6081  	    _lastCode = codeB;
6082
6083  	while (true) {
6084  		// if a,b is inside the clip window (trivial accept)
6085  		if (!(codeA | codeB)) {
6086  			return [a, b];
6087  		}
6088
6089  		// if a,b is outside the clip window (trivial reject)
6090  		if (codeA & codeB) {
6091  			return false;
6092  		}
6093
6094  		// other cases
6095  		codeOut = codeA || codeB;
6096  		p = _getEdgeIntersection(a, b, codeOut, bounds, round);
6097  		newCode = _getBitCode(p, bounds);
6098
6099  		if (codeOut === codeA) {
6100  			a = p;
6101  			codeA = newCode;
6102  		} else {
6103  			b = p;
6104  			codeB = newCode;
6105  		}
6106  	}
6107  }
6108
6109  function _getEdgeIntersection(a, b, code, bounds, round) {
6110  	var dx = b.x - a.x,
6111  	    dy = b.y - a.y,
6112  	    min = bounds.min,
6113  	    max = bounds.max,
6114  	    x, y;
6115
6116  	if (code & 8) { // top
6117  		x = a.x + dx * (max.y - a.y) / dy;
6118  		y = max.y;
6119
6120  	} else if (code & 4) { // bottom
6121  		x = a.x + dx * (min.y - a.y) / dy;
6122  		y = min.y;
6123
6124  	} else if (code & 2) { // right
6125  		x = max.x;
6126  		y = a.y + dy * (max.x - a.x) / dx;
6127
6128  	} else if (code & 1) { // left
6129  		x = min.x;
6130  		y = a.y + dy * (min.x - a.x) / dx;
6131  	}
6132
6133  	return new Point(x, y, round);
6134  }
6135
6136  function _getBitCode(p, bounds) {
6137  	var code = 0;
6138
6139  	if (p.x < bounds.min.x) { // left
6140  		code |= 1;
6141  	} else if (p.x > bounds.max.x) { // right
6142  		code |= 2;
6143  	}
6144
6145  	if (p.y < bounds.min.y) { // bottom
6146  		code |= 4;
6147  	} else if (p.y > bounds.max.y) { // top
6148  		code |= 8;
6149  	}
6150
6151  	return code;
6152  }
6153
6154  // square distance (to avoid unnecessary Math.sqrt calls)
6155  function _sqDist(p1, p2) {
6156  	var dx = p2.x - p1.x,
6157  	    dy = p2.y - p1.y;
6158  	return dx * dx + dy * dy;
6159  }
6160
6161  // return closest point on segment or distance to that point
6162  function _sqClosestPointOnSegment(p, p1, p2, sqDist) {
6163  	var x = p1.x,
6164  	    y = p1.y,
6165  	    dx = p2.x - x,
6166  	    dy = p2.y - y,
6167  	    dot = dx * dx + dy * dy,
6168  	    t;
6169
6170  	if (dot > 0) {
6171  		t = ((p.x - x) * dx + (p.y - y) * dy) / dot;
6172
6173  		if (t > 1) {
6174  			x = p2.x;
6175  			y = p2.y;
6176  		} else if (t > 0) {
6177  			x += dx * t;
6178  			y += dy * t;
6179  		}
6180  	}
6181
6182  	dx = p.x - x;
6183  	dy = p.y - y;
6184
6185  	return sqDist ? dx * dx + dy * dy : new Point(x, y);
6186  }
6187
6188
6189  // @function isFlat(latlngs: LatLng[]): Boolean
6190  // Returns true if `latlngs` is a flat array, false is nested.
6191  function isFlat(latlngs) {
6192  	return !isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');
6193  }
6194
6195  function _flat(latlngs) {
6196  	console.warn('Deprecated use of _flat, please use L.LineUtil.isFlat instead.');
6197  	return isFlat(latlngs);
6198  }
6199
6200  var LineUtil = {
6201    __proto__: null,
6202    simplify: simplify,
6203    pointToSegmentDistance: pointToSegmentDistance,
6204    closestPointOnSegment: closestPointOnSegment,
6205    clipSegment: clipSegment,
6206    _getEdgeIntersection: _getEdgeIntersection,
6207    _getBitCode: _getBitCode,
6208    _sqClosestPointOnSegment: _sqClosestPointOnSegment,
6209    isFlat: isFlat,
6210    _flat: _flat
6211  };
6212
6213  /*
6214   * @namespace PolyUtil
6215   * Various utility functions for polygon geometries.
6216   */
6217
6218  /* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]
6219   * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).
6220   * Used by Leaflet to only show polygon points that are on the screen or near, increasing
6221   * performance. Note that polygon points needs different algorithm for clipping
6222   * than polyline, so there's a separate method for it.
6223   */
6224  function clipPolygon(points, bounds, round) {
6225  	var clippedPoints,
6226  	    edges = [1, 4, 2, 8],
6227  	    i, j, k,
6228  	    a, b,
6229  	    len, edge, p;
6230
6231  	for (i = 0, len = points.length; i < len; i++) {
6232  		points[i]._code = _getBitCode(points[i], bounds);
6233  	}
6234
6235  	// for each edge (left, bottom, right, top)
6236  	for (k = 0; k < 4; k++) {
6237  		edge = edges[k];
6238  		clippedPoints = [];
6239
6240  		for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
6241  			a = points[i];
6242  			b = points[j];
6243
6244  			// if a is inside the clip window
6245  			if (!(a._code & edge)) {
6246  				// if b is outside the clip window (a->b goes out of screen)
6247  				if (b._code & edge) {
6248  					p = _getEdgeIntersection(b, a, edge, bounds, round);
6249  					p._code = _getBitCode(p, bounds);
6250  					clippedPoints.push(p);
6251  				}
6252  				clippedPoints.push(a);
6253
6254  			// else if b is inside the clip window (a->b enters the screen)
6255  			} else if (!(b._code & edge)) {
6256  				p = _getEdgeIntersection(b, a, edge, bounds, round);
6257  				p._code = _getBitCode(p, bounds);
6258  				clippedPoints.push(p);
6259  			}
6260  		}
6261  		points = clippedPoints;
6262  	}
6263
6264  	return points;
6265  }
6266
6267  var PolyUtil = {
6268    __proto__: null,
6269    clipPolygon: clipPolygon
6270  };
6271
6272  /*
6273   * @namespace Projection
6274   * @section
6275   * Leaflet comes with a set of already defined Projections out of the box:
6276   *
6277   * @projection L.Projection.LonLat
6278   *
6279   * Equirectangular, or Plate Carree projection — the most simple projection,
6280   * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as
6281   * latitude. Also suitable for flat worlds, e.g. game maps. Used by the
6282   * `EPSG:4326` and `Simple` CRS.
6283   */
6284
6285  var LonLat = {
6286  	project: function (latlng) {
6287  		return new Point(latlng.lng, latlng.lat);
6288  	},
6289
6290  	unproject: function (point) {
6291  		return new LatLng(point.y, point.x);
6292  	},
6293
6294  	bounds: new Bounds([-180, -90], [180, 90])
6295  };
6296
6297  /*
6298   * @namespace Projection
6299   * @projection L.Projection.Mercator
6300   *
6301   * Elliptical Mercator projection — more complex than Spherical Mercator. Assumes that Earth is an ellipsoid. Used by the EPSG:3395 CRS.
6302   */
6303
6304  var Mercator = {
6305  	R: 6378137,
6306  	R_MINOR: 6356752.314245179,
6307
6308  	bounds: new Bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]),
6309
6310  	project: function (latlng) {
6311  		var d = Math.PI / 180,
6312  		    r = this.R,
6313  		    y = latlng.lat * d,
6314  		    tmp = this.R_MINOR / r,
6315  		    e = Math.sqrt(1 - tmp * tmp),
6316  		    con = e * Math.sin(y);
6317
6318  		var ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2);
6319  		y = -r * Math.log(Math.max(ts, 1E-10));
6320
6321  		return new Point(latlng.lng * d * r, y);
6322  	},
6323
6324  	unproject: function (point) {
6325  		var d = 180 / Math.PI,
6326  		    r = this.R,
6327  		    tmp = this.R_MINOR / r,
6328  		    e = Math.sqrt(1 - tmp * tmp),
6329  		    ts = Math.exp(-point.y / r),
6330  		    phi = Math.PI / 2 - 2 * Math.atan(ts);
6331
6332  		for (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) {
6333  			con = e * Math.sin(phi);
6334  			con = Math.pow((1 - con) / (1 + con), e / 2);
6335  			dphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi;
6336  			phi += dphi;
6337  		}
6338
6339  		return new LatLng(phi * d, point.x * d / r);
6340  	}
6341  };
6342
6343  /*
6344   * @class Projection
6345
6346   * An object with methods for projecting geographical coordinates of the world onto
6347   * a flat surface (and back). See [Map projection](http://en.wikipedia.org/wiki/Map_projection).
6348
6349   * @property bounds: Bounds
6350   * The bounds (specified in CRS units) where the projection is valid
6351
6352   * @method project(latlng: LatLng): Point
6353   * Projects geographical coordinates into a 2D point.
6354   * Only accepts actual `L.LatLng` instances, not arrays.
6355
6356   * @method unproject(point: Point): LatLng
6357   * The inverse of `project`. Projects a 2D point into a geographical location.
6358   * Only accepts actual `L.Point` instances, not arrays.
6359
6360   * Note that the projection instances do not inherit from Leaflet's `Class` object,
6361   * and can't be instantiated. Also, new classes can't inherit from them,
6362   * and methods can't be added to them with the `include` function.
6363
6364   */
6365
6366  var index = {
6367    __proto__: null,
6368    LonLat: LonLat,
6369    Mercator: Mercator,
6370    SphericalMercator: SphericalMercator
6371  };
6372
6373  /*
6374   * @namespace CRS
6375   * @crs L.CRS.EPSG3395
6376   *
6377   * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection.
6378   */
6379  var EPSG3395 = extend({}, Earth, {
6380  	code: 'EPSG:3395',
6381  	projection: Mercator,
6382
6383  	transformation: (function () {
6384  		var scale = 0.5 / (Math.PI * Mercator.R);
6385  		return toTransformation(scale, 0.5, -scale, 0.5);
6386  	}())
6387  });
6388
6389  /*
6390   * @namespace CRS
6391   * @crs L.CRS.EPSG4326
6392   *
6393   * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection.
6394   *
6395   * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic),
6396   * which is a breaking change from 0.7.x behaviour.  If you are using a `TileLayer`
6397   * with this CRS, ensure that there are two 256x256 pixel tiles covering the
6398   * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90),
6399   * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set.
6400   */
6401
6402  var EPSG4326 = extend({}, Earth, {
6403  	code: 'EPSG:4326',
6404  	projection: LonLat,
6405  	transformation: toTransformation(1 / 180, 1, -1 / 180, 0.5)
6406  });
6407
6408  /*
6409   * @namespace CRS
6410   * @crs L.CRS.Simple
6411   *
6412   * A simple CRS that maps longitude and latitude into `x` and `y` directly.
6413   * May be used for maps of flat surfaces (e.g. game maps). Note that the `y`
6414   * axis should still be inverted (going from bottom to top). `distance()` returns
6415   * simple euclidean distance.
6416   */
6417
6418  var Simple = extend({}, CRS, {
6419  	projection: LonLat,
6420  	transformation: toTransformation(1, 0, -1, 0),
6421
6422  	scale: function (zoom) {
6423  		return Math.pow(2, zoom);
6424  	},
6425
6426  	zoom: function (scale) {
6427  		return Math.log(scale) / Math.LN2;
6428  	},
6429
6430  	distance: function (latlng1, latlng2) {
6431  		var dx = latlng2.lng - latlng1.lng,
6432  		    dy = latlng2.lat - latlng1.lat;
6433
6434  		return Math.sqrt(dx * dx + dy * dy);
6435  	},
6436
6437  	infinite: true
6438  });
6439
6440  CRS.Earth = Earth;
6441  CRS.EPSG3395 = EPSG3395;
6442  CRS.EPSG3857 = EPSG3857;
6443  CRS.EPSG900913 = EPSG900913;
6444  CRS.EPSG4326 = EPSG4326;
6445  CRS.Simple = Simple;
6446
6447  /*
6448   * @class Layer
6449   * @inherits Evented
6450   * @aka L.Layer
6451   * @aka ILayer
6452   *
6453   * A set of methods from the Layer base class that all Leaflet layers use.
6454   * Inherits all methods, options and events from `L.Evented`.
6455   *
6456   * @example
6457   *
6458   * ```js
6459   * var layer = L.marker(latlng).addTo(map);
6460   * layer.addTo(map);
6461   * layer.remove();
6462   * ```
6463   *
6464   * @event add: Event
6465   * Fired after the layer is added to a map
6466   *
6467   * @event remove: Event
6468   * Fired after the layer is removed from a map
6469   */
6470
6471
6472  var Layer = Evented.extend({
6473
6474  	// Classes extending `L.Layer` will inherit the following options:
6475  	options: {
6476  		// @option pane: String = 'overlayPane'
6477  		// By default the layer will be added to the map's [overlay pane](#map-overlaypane). Overriding this option will cause the layer to be placed on another pane by default.
6478  		pane: 'overlayPane',
6479
6480  		// @option attribution: String = null
6481  		// String to be shown in the attribution control, e.g. "© OpenStreetMap contributors". It describes the layer data and is often a legal obligation towards copyright holders and tile providers.
6482  		attribution: null,
6483
6484  		bubblingMouseEvents: true
6485  	},
6486
6487  	/* @section
6488  	 * Classes extending `L.Layer` will inherit the following methods:
6489  	 *
6490  	 * @method addTo(map: Map|LayerGroup): this
6491  	 * Adds the layer to the given map or layer group.
6492  	 */
6493  	addTo: function (map) {
6494  		map.addLayer(this);
6495  		return this;
6496  	},
6497
6498  	// @method remove: this
6499  	// Removes the layer from the map it is currently active on.
6500  	remove: function () {
6501  		return this.removeFrom(this._map || this._mapToAdd);
6502  	},
6503
6504  	// @method removeFrom(map: Map): this
6505  	// Removes the layer from the given map
6506  	//
6507  	// @alternative
6508  	// @method removeFrom(group: LayerGroup): this
6509  	// Removes the layer from the given `LayerGroup`
6510  	removeFrom: function (obj) {
6511  		if (obj) {
6512  			obj.removeLayer(this);
6513  		}
6514  		return this;
6515  	},
6516
6517  	// @method getPane(name? : String): HTMLElement
6518  	// Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer.
6519  	getPane: function (name) {
6520  		return this._map.getPane(name ? (this.options[name] || name) : this.options.pane);
6521  	},
6522
6523  	addInteractiveTarget: function (targetEl) {
6524  		this._map._targets[stamp(targetEl)] = this;
6525  		return this;
6526  	},
6527
6528  	removeInteractiveTarget: function (targetEl) {
6529  		delete this._map._targets[stamp(targetEl)];
6530  		return this;
6531  	},
6532
6533  	// @method getAttribution: String
6534  	// Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution).
6535  	getAttribution: function () {
6536  		return this.options.attribution;
6537  	},
6538
6539  	_layerAdd: function (e) {
6540  		var map = e.target;
6541
6542  		// check in case layer gets added and then removed before the map is ready
6543  		if (!map.hasLayer(this)) { return; }
6544
6545  		this._map = map;
6546  		this._zoomAnimated = map._zoomAnimated;
6547
6548  		if (this.getEvents) {
6549  			var events = this.getEvents();
6550  			map.on(events, this);
6551  			this.once('remove', function () {
6552  				map.off(events, this);
6553  			}, this);
6554  		}
6555
6556  		this.onAdd(map);
6557
6558  		this.fire('add');
6559  		map.fire('layeradd', {layer: this});
6560  	}
6561  });
6562
6563  /* @section Extension methods
6564   * @uninheritable
6565   *
6566   * Every layer should extend from `L.Layer` and (re-)implement the following methods.
6567   *
6568   * @method onAdd(map: Map): this
6569   * Should contain code that creates DOM elements for the layer, adds them to `map panes` where they should belong and puts listeners on relevant map events. Called on [`map.addLayer(layer)`](#map-addlayer).
6570   *
6571   * @method onRemove(map: Map): this
6572   * Should contain all clean up code that removes the layer's elements from the DOM and removes listeners previously added in [`onAdd`](#layer-onadd). Called on [`map.removeLayer(layer)`](#map-removelayer).
6573   *
6574   * @method getEvents(): Object
6575   * This optional method should return an object like `{ viewreset: this._reset }` for [`addEventListener`](#evented-addeventlistener). The event handlers in this object will be automatically added and removed from the map with your layer.
6576   *
6577   * @method getAttribution(): String
6578   * This optional method should return a string containing HTML to be shown on the `Attribution control` whenever the layer is visible.
6579   *
6580   * @method beforeAdd(map: Map): this
6581   * Optional method. Called on [`map.addLayer(layer)`](#map-addlayer), before the layer is added to the map, before events are initialized, without waiting until the map is in a usable state. Use for early initialization only.
6582   */
6583
6584
6585  /* @namespace Map
6586   * @section Layer events
6587   *
6588   * @event layeradd: LayerEvent
6589   * Fired when a new layer is added to the map.
6590   *
6591   * @event layerremove: LayerEvent
6592   * Fired when some layer is removed from the map
6593   *
6594   * @section Methods for Layers and Controls
6595   */
6596  Map.include({
6597  	// @method addLayer(layer: Layer): this
6598  	// Adds the given layer to the map
6599  	addLayer: function (layer) {
6600  		if (!layer._layerAdd) {
6601  			throw new Error('The provided object is not a Layer.');
6602  		}
6603
6604  		var id = stamp(layer);
6605  		if (this._layers[id]) { return this; }
6606  		this._layers[id] = layer;
6607
6608  		layer._mapToAdd = this;
6609
6610  		if (layer.beforeAdd) {
6611  			layer.beforeAdd(this);
6612  		}
6613
6614  		this.whenReady(layer._layerAdd, layer);
6615
6616  		return this;
6617  	},
6618
6619  	// @method removeLayer(layer: Layer): this
6620  	// Removes the given layer from the map.
6621  	removeLayer: function (layer) {
6622  		var id = stamp(layer);
6623
6624  		if (!this._layers[id]) { return this; }
6625
6626  		if (this._loaded) {
6627  			layer.onRemove(this);
6628  		}
6629
6630  		delete this._layers[id];
6631
6632  		if (this._loaded) {
6633  			this.fire('layerremove', {layer: layer});
6634  			layer.fire('remove');
6635  		}
6636
6637  		layer._map = layer._mapToAdd = null;
6638
6639  		return this;
6640  	},
6641
6642  	// @method hasLayer(layer: Layer): Boolean
6643  	// Returns `true` if the given layer is currently added to the map
6644  	hasLayer: function (layer) {
6645  		return stamp(layer) in this._layers;
6646  	},
6647
6648  	/* @method eachLayer(fn: Function, context?: Object): this
6649  	 * Iterates over the layers of the map, optionally specifying context of the iterator function.
6650  	 * ```
6651  	 * map.eachLayer(function(layer){
6652  	 *     layer.bindPopup('Hello');
6653  	 * });
6654  	 * ```
6655  	 */
6656  	eachLayer: function (method, context) {
6657  		for (var i in this._layers) {
6658  			method.call(context, this._layers[i]);
6659  		}
6660  		return this;
6661  	},
6662
6663  	_addLayers: function (layers) {
6664  		layers = layers ? (isArray(layers) ? layers : [layers]) : [];
6665
6666  		for (var i = 0, len = layers.length; i < len; i++) {
6667  			this.addLayer(layers[i]);
6668  		}
6669  	},
6670
6671  	_addZoomLimit: function (layer) {
6672  		if (isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {
6673  			this._zoomBoundLayers[stamp(layer)] = layer;
6674  			this._updateZoomLevels();
6675  		}
6676  	},
6677
6678  	_removeZoomLimit: function (layer) {
6679  		var id = stamp(layer);
6680
6681  		if (this._zoomBoundLayers[id]) {
6682  			delete this._zoomBoundLayers[id];
6683  			this._updateZoomLevels();
6684  		}
6685  	},
6686
6687  	_updateZoomLevels: function () {
6688  		var minZoom = Infinity,
6689  		    maxZoom = -Infinity,
6690  		    oldZoomSpan = this._getZoomSpan();
6691
6692  		for (var i in this._zoomBoundLayers) {
6693  			var options = this._zoomBoundLayers[i].options;
6694
6695  			minZoom = options.minZoom === undefined ? minZoom : Math.min(minZoom, options.minZoom);
6696  			maxZoom = options.maxZoom === undefined ? maxZoom : Math.max(maxZoom, options.maxZoom);
6697  		}
6698
6699  		this._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom;
6700  		this._layersMinZoom = minZoom === Infinity ? undefined : minZoom;
6701
6702  		// @section Map state change events
6703  		// @event zoomlevelschange: Event
6704  		// Fired when the number of zoomlevels on the map is changed due
6705  		// to adding or removing a layer.
6706  		if (oldZoomSpan !== this._getZoomSpan()) {
6707  			this.fire('zoomlevelschange');
6708  		}
6709
6710  		if (this.options.maxZoom === undefined && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) {
6711  			this.setZoom(this._layersMaxZoom);
6712  		}
6713  		if (this.options.minZoom === undefined && this._layersMinZoom && this.getZoom() < this._layersMinZoom) {
6714  			this.setZoom(this._layersMinZoom);
6715  		}
6716  	}
6717  });
6718
6719  /*
6720   * @class LayerGroup
6721   * @aka L.LayerGroup
6722   * @inherits Layer
6723   *
6724   * Used to group several layers and handle them as one. If you add it to the map,
6725   * any layers added or removed from the group will be added/removed on the map as
6726   * well. Extends `Layer`.
6727   *
6728   * @example
6729   *
6730   * ```js
6731   * L.layerGroup([marker1, marker2])
6732   * 	.addLayer(polyline)
6733   * 	.addTo(map);
6734   * ```
6735   */
6736
6737  var LayerGroup = Layer.extend({
6738
6739  	initialize: function (layers, options) {
6740  		setOptions(this, options);
6741
6742  		this._layers = {};
6743
6744  		var i, len;
6745
6746  		if (layers) {
6747  			for (i = 0, len = layers.length; i < len; i++) {
6748  				this.addLayer(layers[i]);
6749  			}
6750  		}
6751  	},
6752
6753  	// @method addLayer(layer: Layer): this
6754  	// Adds the given layer to the group.
6755  	addLayer: function (layer) {
6756  		var id = this.getLayerId(layer);
6757
6758  		this._layers[id] = layer;
6759
6760  		if (this._map) {
6761  			this._map.addLayer(layer);
6762  		}
6763
6764  		return this;
6765  	},
6766
6767  	// @method removeLayer(layer: Layer): this
6768  	// Removes the given layer from the group.
6769  	// @alternative
6770  	// @method removeLayer(id: Number): this
6771  	// Removes the layer with the given internal ID from the group.
6772  	removeLayer: function (layer) {
6773  		var id = layer in this._layers ? layer : this.getLayerId(layer);
6774
6775  		if (this._map && this._layers[id]) {
6776  			this._map.removeLayer(this._layers[id]);
6777  		}
6778
6779  		delete this._layers[id];
6780
6781  		return this;
6782  	},
6783
6784  	// @method hasLayer(layer: Layer): Boolean
6785  	// Returns `true` if the given layer is currently added to the group.
6786  	// @alternative
6787  	// @method hasLayer(id: Number): Boolean
6788  	// Returns `true` if the given internal ID is currently added to the group.
6789  	hasLayer: function (layer) {
6790  		var layerId = typeof layer === 'number' ? layer : this.getLayerId(layer);
6791  		return layerId in this._layers;
6792  	},
6793
6794  	// @method clearLayers(): this
6795  	// Removes all the layers from the group.
6796  	clearLayers: function () {
6797  		return this.eachLayer(this.removeLayer, this);
6798  	},
6799
6800  	// @method invoke(methodName: String, …): this
6801  	// Calls `methodName` on every layer contained in this group, passing any
6802  	// additional parameters. Has no effect if the layers contained do not
6803  	// implement `methodName`.
6804  	invoke: function (methodName) {
6805  		var args = Array.prototype.slice.call(arguments, 1),
6806  		    i, layer;
6807
6808  		for (i in this._layers) {
6809  			layer = this._layers[i];
6810
6811  			if (layer[methodName]) {
6812  				layer[methodName].apply(layer, args);
6813  			}
6814  		}
6815
6816  		return this;
6817  	},
6818
6819  	onAdd: function (map) {
6820  		this.eachLayer(map.addLayer, map);
6821  	},
6822
6823  	onRemove: function (map) {
6824  		this.eachLayer(map.removeLayer, map);
6825  	},
6826
6827  	// @method eachLayer(fn: Function, context?: Object): this
6828  	// Iterates over the layers of the group, optionally specifying context of the iterator function.
6829  	// ```js
6830  	// group.eachLayer(function (layer) {
6831  	// 	layer.bindPopup('Hello');
6832  	// });
6833  	// ```
6834  	eachLayer: function (method, context) {
6835  		for (var i in this._layers) {
6836  			method.call(context, this._layers[i]);
6837  		}
6838  		return this;
6839  	},
6840
6841  	// @method getLayer(id: Number): Layer
6842  	// Returns the layer with the given internal ID.
6843  	getLayer: function (id) {
6844  		return this._layers[id];
6845  	},
6846
6847  	// @method getLayers(): Layer[]
6848  	// Returns an array of all the layers added to the group.
6849  	getLayers: function () {
6850  		var layers = [];
6851  		this.eachLayer(layers.push, layers);
6852  		return layers;
6853  	},
6854
6855  	// @method setZIndex(zIndex: Number): this
6856  	// Calls `setZIndex` on every layer contained in this group, passing the z-index.
6857  	setZIndex: function (zIndex) {
6858  		return this.invoke('setZIndex', zIndex);
6859  	},
6860
6861  	// @method getLayerId(layer: Layer): Number
6862  	// Returns the internal ID for a layer
6863  	getLayerId: function (layer) {
6864  		return stamp(layer);
6865  	}
6866  });
6867
6868
6869  // @factory L.layerGroup(layers?: Layer[], options?: Object)
6870  // Create a layer group, optionally given an initial set of layers and an `options` object.
6871  var layerGroup = function (layers, options) {
6872  	return new LayerGroup(layers, options);
6873  };
6874
6875  /*
6876   * @class FeatureGroup
6877   * @aka L.FeatureGroup
6878   * @inherits LayerGroup
6879   *
6880   * Extended `LayerGroup` that makes it easier to do the same thing to all its member layers:
6881   *  * [`bindPopup`](#layer-bindpopup) binds a popup to all of the layers at once (likewise with [`bindTooltip`](#layer-bindtooltip))
6882   *  * Events are propagated to the `FeatureGroup`, so if the group has an event
6883   * handler, it will handle events from any of the layers. This includes mouse events
6884   * and custom events.
6885   *  * Has `layeradd` and `layerremove` events
6886   *
6887   * @example
6888   *
6889   * ```js
6890   * L.featureGroup([marker1, marker2, polyline])
6891   * 	.bindPopup('Hello world!')
6892   * 	.on('click', function() { alert('Clicked on a member of the group!'); })
6893   * 	.addTo(map);
6894   * ```
6895   */
6896
6897  var FeatureGroup = LayerGroup.extend({
6898
6899  	addLayer: function (layer) {
6900  		if (this.hasLayer(layer)) {
6901  			return this;
6902  		}
6903
6904  		layer.addEventParent(this);
6905
6906  		LayerGroup.prototype.addLayer.call(this, layer);
6907
6908  		// @event layeradd: LayerEvent
6909  		// Fired when a layer is added to this `FeatureGroup`
6910  		return this.fire('layeradd', {layer: layer});
6911  	},
6912
6913  	removeLayer: function (layer) {
6914  		if (!this.hasLayer(layer)) {
6915  			return this;
6916  		}
6917  		if (layer in this._layers) {
6918  			layer = this._layers[layer];
6919  		}
6920
6921  		layer.removeEventParent(this);
6922
6923  		LayerGroup.prototype.removeLayer.call(this, layer);
6924
6925  		// @event layerremove: LayerEvent
6926  		// Fired when a layer is removed from this `FeatureGroup`
6927  		return this.fire('layerremove', {layer: layer});
6928  	},
6929
6930  	// @method setStyle(style: Path options): this
6931  	// Sets the given path options to each layer of the group that has a `setStyle` method.
6932  	setStyle: function (style) {
6933  		return this.invoke('setStyle', style);
6934  	},
6935
6936  	// @method bringToFront(): this
6937  	// Brings the layer group to the top of all other layers
6938  	bringToFront: function () {
6939  		return this.invoke('bringToFront');
6940  	},
6941
6942  	// @method bringToBack(): this
6943  	// Brings the layer group to the back of all other layers
6944  	bringToBack: function () {
6945  		return this.invoke('bringToBack');
6946  	},
6947
6948  	// @method getBounds(): LatLngBounds
6949  	// Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).
6950  	getBounds: function () {
6951  		var bounds = new LatLngBounds();
6952
6953  		for (var id in this._layers) {
6954  			var layer = this._layers[id];
6955  			bounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());
6956  		}
6957  		return bounds;
6958  	}
6959  });
6960
6961  // @factory L.featureGroup(layers?: Layer[], options?: Object)
6962  // Create a feature group, optionally given an initial set of layers and an `options` object.
6963  var featureGroup = function (layers, options) {
6964  	return new FeatureGroup(layers, options);
6965  };
6966
6967  /*
6968   * @class Icon
6969   * @aka L.Icon
6970   *
6971   * Represents an icon to provide when creating a marker.
6972   *
6973   * @example
6974   *
6975   * ```js
6976   * var myIcon = L.icon({
6977   *     iconUrl: 'my-icon.png',
6978   *     iconRetinaUrl: '[email protected]',
6979   *     iconSize: [38, 95],
6980   *     iconAnchor: [22, 94],
6981   *     popupAnchor: [-3, -76],
6982   *     shadowUrl: 'my-icon-shadow.png',
6983   *     shadowRetinaUrl: '[email protected]',
6984   *     shadowSize: [68, 95],
6985   *     shadowAnchor: [22, 94]
6986   * });
6987   *
6988   * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
6989   * ```
6990   *
6991   * `L.Icon.Default` extends `L.Icon` and is the blue icon Leaflet uses for markers by default.
6992   *
6993   */
6994
6995  var Icon = Class.extend({
6996
6997  	/* @section
6998  	 * @aka Icon options
6999  	 *
7000  	 * @option iconUrl: String = null
7001  	 * **(required)** The URL to the icon image (absolute or relative to your script path).
7002  	 *
7003  	 * @option iconRetinaUrl: String = null
7004  	 * The URL to a retina sized version of the icon image (absolute or relative to your
7005  	 * script path). Used for Retina screen devices.
7006  	 *
7007  	 * @option iconSize: Point = null
7008  	 * Size of the icon image in pixels.
7009  	 *
7010  	 * @option iconAnchor: Point = null
7011  	 * The coordinates of the "tip" of the icon (relative to its top left corner). The icon
7012  	 * will be aligned so that this point is at the marker's geographical location. Centered
7013  	 * by default if size is specified, also can be set in CSS with 
7013negative margins.
7014  	 *
7015  	 * @option popupAnchor: Point = [0, 0]
7016  	 * The coordinates of the point from which popups will "open", relative to the icon anchor.
7017  	 *
7018  	 * @option tooltipAnchor: Point = [0, 0]
7019  	 * The coordinates of the point from which tooltips will "open", relative to the icon anchor.
7020  	 *
7021  	 * @option shadowUrl: String = null
7022  	 * The URL to the icon shadow image. If not specified, no shadow image will be created.
7023  	 *
7024  	 * @option shadowRetinaUrl: String = null
7025  	 *
7026  	 * @option shadowSize: Point = null
7027  	 * Size of the shadow image in pixels.
7028  	 *
7029  	 * @option shadowAnchor: Point = null
7030  	 * The coordinates of the "tip" of the shadow (relative to its top left corner) (the same
7031  	 * as iconAnchor if not specified).
7032  	 *
7033  	 * @option className: String = ''
7034  	 * A custom class name to assign to both icon and shadow images. Empty by default.
7035  	 */
7036
7037  	options: {
7038  		popupAnchor: [0, 0],
7039  		tooltipAnchor: [0, 0],
7040
7041  		// @option crossOrigin: Boolean|String = false
7042  		// Whether the crossOrigin attribute will be added to the tiles.
7043  		// If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.
7044  		// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
7045  		crossOrigin: false
7046  	},
7047
7048  	initialize: function (options) {
7049  		setOptions(this, options);
7050  	},
7051
7052  	// @method createIcon(oldIcon?: HTMLElement): HTMLElement
7053  	// Called internally when the icon has to be shown, returns a `<img>` HTML element
7054  	// styled according to the options.
7055  	createIcon: function (oldIcon) {
7056  		return this._createIcon('icon', oldIcon);
7057  	},
7058
7059  	// @method createShadow(oldIcon?: HTMLElement): HTMLElement
7060  	// As `createIcon`, but for the shadow beneath it.
7061  	createShadow: function (oldIcon) {
7062  		return this._createIcon('shadow', oldIcon);
7063  	},
7064
7065  	_createIcon: function (name, oldIcon) {
7066  		var src = this._getIconUrl(name);
7067
7068  		if (!src) {
7069  			if (name === 'icon') {
7070  				throw new Error('iconUrl not set in Icon options (see the docs).');
7071  			}
7072  			return null;
7073  		}
7074
7075  		var img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null);
7076  		this._setIconStyles(img, name);
7077
7078  		if (this.options.crossOrigin || this.options.crossOrigin === '') {
7079  			img.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
7080  		}
7081
7082  		return img;
7083  	},
7084
7085  	_setIconStyles: function (img, name) {
7086  		var options = this.options;
7087  		var sizeOption = options[name + 'Size'];
7088
7089  		if (typeof sizeOption === 'number') {
7090  			sizeOption = [sizeOption, sizeOption];
7091  		}
7092
7093  		var size = toPoint(sizeOption),
7094  		    anchor = toPoint(name === 'shadow' && options.shadowAnchor || options.iconAnchor ||
7095  		            size && size.divideBy(2, true));
7096
7097  		img.className = 'leaflet-marker-' + name + ' ' + (options.className || '');
7098
7099  		if (anchor) {
7100  			img.style.marginLeft = (-anchor.x) + 'px';
7101  			img.style.marginTop  = (-anchor.y) + 'px';
7102  		}
7103
7104  		if (size) {
7105  			img.style.width  = size.x + 'px';
7106  			img.style.height = size.y + 'px';
7107  		}
7108  	},
7109
7110  	_createImg: function (src, el) {
7111  		el = el || document.createElement('img');
7112  		el.src = src;
7113  		return el;
7114  	},
7115
7116  	_getIconUrl: function (name) {
7117  		return retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url'];
7118  	}
7119  });
7120
7121
7122  // @factory L.icon(options: Icon options)
7123  // Creates an icon instance with the given options.
7124  function icon(options) {
7125  	return new Icon(options);
7126  }
7127
7128  /*
7129   * @miniclass Icon.Default (Icon)
7130   * @aka L.Icon.Default
7131   * @section
7132   *
7133   * A trivial subclass of `Icon`, represents the icon to use in `Marker`s when
7134   * no icon is specified. Points to the blue marker image distributed with Leaflet
7135   * releases.
7136   *
7137   * In order to customize the default icon, just change the properties of `L.Icon.Default.prototype.options`
7138   * (which is a set of `Icon options`).
7139   *
7140   * If you want to _completely_ replace the default icon, override the
7141   * `L.Marker.prototype.options.icon` with your own icon instead.
7142   */
7143
7144  var IconDefault = Icon.extend({
7145
7146  	options: {
7147  		iconUrl:       'marker-icon.png',
7148  		iconRetinaUrl: 'marker-icon-2x.png',
7149  		shadowUrl:     'marker-shadow.png',
7150  		iconSize:    [25, 41],
7151  		iconAnchor:  [12, 41],
7152  		popupAnchor: [1, -34],
7153  		tooltipAnchor: [16, -28],
7154  		shadowSize:  [41, 41]
7155  	},
7156
7157  	_getIconUrl: function (name) {
7158  		if (!IconDefault.imagePath) {	// Deprecated, backwards-compatibility only
7159  			IconDefault.imagePath = this._detectIconPath();
7160  		}
7161
7162  		// @option imagePath: String
7163  		// `Icon.Default` will try to auto-detect the location of the
7164  		// blue icon images. If you are placing these images in a non-standard
7165  		// way, set this option to point to the right path.
7166  		return (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name);
7167  	},
7168
7169  	_detectIconPath: function () {
7170  		var el = create$1('div',  'leaflet-default-icon-path', document.body);
7171  		var path = getStyle(el, 'background-image') ||
7172  		           getStyle(el, 'backgroundImage');	// IE8
7173
7174  		document.body.removeChild(el);
7175
7176  		if (path === null || path.indexOf('url') !== 0) {
7177  			path = '';
7178  		} else {
7179  			path = path.replace(/^url\(["']?/, '').replace(/marker-icon\.png["']?\)$/, '');
7180  		}
7181
7182  		return path;
7183  	}
7184  });
7185
7186  /*
7187   * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.
7188   */
7189
7190
7191  /* @namespace Marker
7192   * @section Interaction handlers
7193   *
7194   * Interaction handlers are properties of a marker instance that allow you to control interaction behavior in runtime, enabling or disabling certain features such as dragging (see `Handler` methods). Example:
7195   *
7196   * ```js
7197   * marker.dragging.disable();
7198   * ```
7199   *
7200   * @property dragging: Handler
7201   * Marker dragging handler (by both mouse and touch). Only valid when the marker is on the map (Otherwise set [`marker.options.draggable`](#marker-draggable)).
7202   */
7203
7204  var MarkerDrag = Handler.extend({
7205  	initialize: function (marker) {
7206  		this._marker = marker;
7207  	},
7208
7209  	addHooks: function () {
7210  		var icon = this._marker._icon;
7211
7212  		if (!this._draggable) {
7213  			this._draggable = new Draggable(icon, icon, true);
7214  		}
7215
7216  		this._draggable.on({
7217  			dragstart: this._onDragStart,
7218  			predrag: this._onPreDrag,
7219  			drag: this._onDrag,
7220  			dragend: this._onDragEnd
7221  		}, this).enable();
7222
7223  		addClass(icon, 'leaflet-marker-draggable');
7224  	},
7225
7226  	removeHooks: function () {
7227  		this._draggable.off({
7228  			dragstart: this._onDragStart,
7229  			predrag: this._onPreDrag,
7230  			drag: this._onDrag,
7231  			dragend: this._onDragEnd
7232  		}, this).disable();
7233
7234  		if (this._marker._icon) {
7235  			removeClass(this._marker._icon, 'leaflet-marker-draggable');
7236  		}
7237  	},
7238
7239  	moved: function () {
7240  		return this._draggable && this._draggable._moved;
7241  	},
7242
7243  	_adjustPan: function (e) {
7244  		var marker = this._marker,
7245  		    map = marker._map,
7246  		    speed = this._marker.options.autoPanSpeed,
7247  		    padding = this._marker.options.autoPanPadding,
7248  		    iconPos = getPosition(marker._icon),
7249  		    bounds = map.getPixelBounds(),
7250  		    origin = map.getPixelOrigin();
7251
7252  		var panBounds = toBounds(
7253  			bounds.min._subtract(origin).add(padding),
7254  			bounds.max._subtract(origin).subtract(padding)
7255  		);
7256
7257  		if (!panBounds.contains(iconPos)) {
7258  			// Compute incremental movement
7259  			var movement = toPoint(
7260  				(Math.max(panBounds.max.x, iconPos.x) - panBounds.max.x) / (bounds.max.x - panBounds.max.x) -
7261  				(Math.min(panBounds.min.x, iconPos.x) - panBounds.min.x) / (bounds.min.x - panBounds.min.x),
7262
7263  				(Math.max(panBounds.max.y, iconPos.y) - panBounds.max.y) / (bounds.max.y - panBounds.max.y) -
7264  				(Math.min(panBounds.min.y, iconPos.y) - panBounds.min.y) / (bounds.min.y - panBounds.min.y)
7265  			).multiplyBy(speed);
7266
7267  			map.panBy(movement, {animate: false});
7268
7269  			this._draggable._newPos._add(movement);
7270  			this._draggable._startPos._add(movement);
7271
7272  			setPosition(marker._icon, this._draggable._newPos);
7273  			this._onDrag(e);
7274
vendor: 11,130 bytes, lines 7275-7718
7275  			this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
7276  		}
7277  	},
7278
7279  	_onDragStart: function () {
7280  		// @section Dragging events
7281  		// @event dragstart: Event
7282  		// Fired when the user starts dragging the marker.
7283
7284  		// @event movestart: Event
7285  		// Fired when the marker starts moving (because of dragging).
7286
7287  		this._oldLatLng = this._marker.getLatLng();
7288
7289  		// When using ES6 imports it could not be set when `Popup` was not imported as well
7290  		this._marker.closePopup && this._marker.closePopup();
7291
7292  		this._marker
7293  			.fire('movestart')
7294  			.fire('dragstart');
7295  	},
7296
7297  	_onPreDrag: function (e) {
7298  		if (this._marker.options.autoPan) {
7299  			cancelAnimFrame(this._panRequest);
7300  			this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
7301  		}
7302  	},
7303
7304  	_onDrag: function (e) {
7305  		var marker = this._marker,
7306  		    shadow = marker._shadow,
7307  		    iconPos = getPosition(marker._icon),
7308  		    latlng = marker._map.layerPointToLatLng(iconPos);
7309
7310  		// update shadow position
7311  		if (shadow) {
7312  			setPosition(shadow, iconPos);
7313  		}
7314
7315  		marker._latlng = latlng;
7316  		e.latlng = latlng;
7317  		e.oldLatLng = this._oldLatLng;
7318
7319  		// @event drag: Event
7320  		// Fired repeatedly while the user drags the marker.
7321  		marker
7322  		    .fire('move', e)
7323  		    .fire('drag', e);
7324  	},
7325
7326  	_onDragEnd: function (e) {
7327  		// @event dragend: DragEndEvent
7328  		// Fired when the user stops dragging the marker.
7329
7330  		 cancelAnimFrame(this._panRequest);
7331
7332  		// @event moveend: Event
7333  		// Fired when the marker stops moving (because of dragging).
7334  		delete this._oldLatLng;
7335  		this._marker
7336  		    .fire('moveend')
7337  		    .fire('dragend', e);
7338  	}
7339  });
7340
7341  /*
7342   * @class Marker
7343   * @inherits Interactive layer
7344   * @aka L.Marker
7345   * L.Marker is used to display clickable/draggable icons on the map. Extends `Layer`.
7346   *
7347   * @example
7348   *
7349   * ```js
7350   * L.marker([50.5, 30.5]).addTo(map);
7351   * ```
7352   */
7353
7354  var Marker = Layer.extend({
7355
7356  	// @section
7357  	// @aka Marker options
7358  	options: {
7359  		// @option icon: Icon = *
7360  		// Icon instance to use for rendering the marker.
7361  		// See [Icon documentation](#L.Icon) for details on how to customize the marker icon.
7362  		// If not specified, a common instance of `L.Icon.Default` is used.
7363  		icon: new IconDefault(),
7364
7365  		// Option inherited from "Interactive layer" abstract class
7366  		interactive: true,
7367
7368  		// @option keyboard: Boolean = true
7369  		// Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.
7370  		keyboard: true,
7371
7372  		// @option title: String = ''
7373  		// Text for the browser tooltip that appear on marker hover (no tooltip by default).
7374  		title: '',
7375
7376  		// @option alt: String = ''
7377  		// Text for the `alt` attribute of the icon image (useful for accessibility).
7378  		alt: '',
7379
7380  		// @option zIndexOffset: Number = 0
7381  		// By default, marker images zIndex is set automatically based on its latitude. Use this option if you want to put the marker on top of all others (or below), specifying a high value like `1000` (or high negative value, respectively).
7382  		zIndexOffset: 0,
7383
7384  		// @option opacity: Number = 1.0
7385  		// The opacity of the marker.
7386  		opacity: 1,
7387
7388  		// @option riseOnHover: Boolean = false
7389  		// If `true`, the marker will get on top of others when you hover the mouse over it.
7390  		riseOnHover: false,
7391
7392  		// @option riseOffset: Number = 250
7393  		// The z-index offset used for the `riseOnHover` feature.
7394  		riseOffset: 250,
7395
7396  		// @option pane: String = 'markerPane'
7397  		// `Map pane` where the markers icon will be added.
7398  		pane: 'markerPane',
7399
7400  		// @option shadowPane: String = 'shadowPane'
7401  		// `Map pane` where the markers shadow will be added.
7402  		shadowPane: 'shadowPane',
7403
7404  		// @option bubblingMouseEvents: Boolean = false
7405  		// When `true`, a mouse event on this marker will trigger the same event on the map
7406  		// (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).
7407  		bubblingMouseEvents: false,
7408
7409  		// @section Draggable marker options
7410  		// @option draggable: Boolean = false
7411  		// Whether the marker is draggable with mouse/touch or not.
7412  		draggable: false,
7413
7414  		// @option autoPan: Boolean = false
7415  		// Whether to pan the map when dragging this marker near its edge or not.
7416  		autoPan: false,
7417
7418  		// @option autoPanPadding: Point = Point(50, 50)
7419  		// Distance (in pixels to the left/right and to the top/bottom) of the
7420  		// map edge to start panning the map.
7421  		autoPanPadding: [50, 50],
7422
7423  		// @option autoPanSpeed: Number = 10
7424  		// Number of pixels the map should pan by.
7425  		autoPanSpeed: 10
7426  	},
7427
7428  	/* @section
7429  	 *
7430  	 * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods:
7431  	 */
7432
7433  	initialize: function (latlng, options) {
7434  		setOptions(this, options);
7435  		this._latlng = toLatLng(latlng);
7436  	},
7437
7438  	onAdd: function (map) {
7439  		this._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation;
7440
7441  		if (this._zoomAnimated) {
7442  			map.on('zoomanim', this._animateZoom, this);
7443  		}
7444
7445  		this._initIcon();
7446  		this.update();
7447  	},
7448
7449  	onRemove: function (map) {
7450  		if (this.dragging && this.dragging.enabled()) {
7451  			this.options.draggable = true;
7452  			this.dragging.removeHooks();
7453  		}
7454  		delete this.dragging;
7455
7456  		if (this._zoomAnimated) {
7457  			map.off('zoomanim', this._animateZoom, this);
7458  		}
7459
7460  		this._removeIcon();
7461  		this._removeShadow();
7462  	},
7463
7464  	getEvents: function () {
7465  		return {
7466  			zoom: this.update,
7467  			viewreset: this.update
7468  		};
7469  	},
7470
7471  	// @method getLatLng: LatLng
7472  	// Returns the current geographical position of the marker.
7473  	getLatLng: function () {
7474  		return this._latlng;
7475  	},
7476
7477  	// @method setLatLng(latlng: LatLng): this
7478  	// Changes the marker position to the given point.
7479  	setLatLng: function (latlng) {
7480  		var oldLatLng = this._latlng;
7481  		this._latlng = toLatLng(latlng);
7482  		this.update();
7483
7484  		// @event move: Event
7485  		// Fired when the marker is moved via [`setLatLng`](#marker-setlatlng) or by [dragging](#marker-dragging). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`.
7486  		return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
7487  	},
7488
7489  	// @method setZIndexOffset(offset: Number): this
7490  	// Changes the [zIndex offset](#marker-zindexoffset) of the marker.
7491  	setZIndexOffset: function (offset) {
7492  		this.options.zIndexOffset = offset;
7493  		return this.update();
7494  	},
7495
7496  	// @method getIcon: Icon
7497  	// Returns the current icon used by the marker
7498  	getIcon: function () {
7499  		return this.options.icon;
7500  	},
7501
7502  	// @method setIcon(icon: Icon): this
7503  	// Changes the marker icon.
7504  	setIcon: function (icon) {
7505
7506  		this.options.icon = icon;
7507
7508  		if (this._map) {
7509  			this._initIcon();
7510  			this.update();
7511  		}
7512
7513  		if (this._popup) {
7514  			this.bindPopup(this._popup, this._popup.options);
7515  		}
7516
7517  		return this;
7518  	},
7519
7520  	getElement: function () {
7521  		return this._icon;
7522  	},
7523
7524  	update: function () {
7525
7526  		if (this._icon && this._map) {
7527  			var pos = this._map.latLngToLayerPoint(this._latlng).round();
7528  			this._setPos(pos);
7529  		}
7530
7531  		return this;
7532  	},
7533
7534  	_initIcon: function () {
7535  		var options = this.options,
7536  		    classToAdd = 'leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
7537
7538  		var icon = options.icon.createIcon(this._icon),
7539  		    addIcon = false;
7540
7541  		// if we're not reusing the icon, remove the old one and init new one
7542  		if (icon !== this._icon) {
7543  			if (this._icon) {
7544  				this._removeIcon();
7545  			}
7546  			addIcon = true;
7547
7548  			if (options.title) {
7549  				icon.title = options.title;
7550  			}
7551
7552  			if (icon.tagName === 'IMG') {
7553  				icon.alt = options.alt || '';
7554  			}
7555  		}
7556
7557  		addClass(icon, classToAdd);
7558
7559  		if (options.keyboard) {
7560  			icon.tabIndex = '0';
7561  		}
7562
7563  		this._icon = icon;
7564
7565  		if (options.riseOnHover) {
7566  			this.on({
7567  				mouseover: this._bringToFront,
7568  				mouseout: this._resetZIndex
7569  			});
7570  		}
7571
7572  		var newShadow = options.icon.createShadow(this._shadow),
7573  		    addShadow = false;
7574
7575  		if (newShadow !== this._shadow) {
7576  			this._removeShadow();
7577  			addShadow = true;
7578  		}
7579
7580  		if (newShadow) {
7581  			addClass(newShadow, classToAdd);
7582  			newShadow.alt = '';
7583  		}
7584  		this._shadow = newShadow;
7585
7586
7587  		if (options.opacity < 1) {
7588  			this._updateOpacity();
7589  		}
7590
7591
7592  		if (addIcon) {
7593  			this.getPane().appendChild(this._icon);
7594  		}
7595  		this._initInteraction();
7596  		if (newShadow && addShadow) {
7597  			this.getPane(options.shadowPane).appendChild(this._shadow);
7598  		}
7599  	},
7600
7601  	_removeIcon: function () {
7602  		if (this.options.riseOnHover) {
7603  			this.off({
7604  				mouseover: this._bringToFront,
7605  				mouseout: this._resetZIndex
7606  			});
7607  		}
7608
7609  		remove(this._icon);
7610  		this.removeInteractiveTarget(this._icon);
7611
7612  		this._icon = null;
7613  	},
7614
7615  	_removeShadow: function () {
7616  		if (this._shadow) {
7617  			remove(this._shadow);
7618  		}
7619  		this._shadow = null;
7620  	},
7621
7622  	_setPos: function (pos) {
7623
7624  		if (this._icon) {
7625  			setPosition(this._icon, pos);
7626  		}
7627
7628  		if (this._shadow) {
7629  			setPosition(this._shadow, pos);
7630  		}
7631
7632  		this._zIndex = pos.y + this.options.zIndexOffset;
7633
7634  		this._resetZIndex();
7635  	},
7636
7637  	_updateZIndex: function (offset) {
7638  		if (this._icon) {
7639  			this._icon.style.zIndex = this._zIndex + offset;
7640  		}
7641  	},
7642
7643  	_animateZoom: function (opt) {
7644  		var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
7645
7646  		this._setPos(pos);
7647  	},
7648
7649  	_initInteraction: function () {
7650
7651  		if (!this.options.interactive) { return; }
7652
7653  		addClass(this._icon, 'leaflet-interactive');
7654
7655  		this.addInteractiveTarget(this._icon);
7656
7657  		if (MarkerDrag) {
7658  			var draggable = this.options.draggable;
7659  			if (this.dragging) {
7660  				draggable = this.dragging.enabled();
7661  				this.dragging.disable();
7662  			}
7663
7664  			this.dragging = new MarkerDrag(this);
7665
7666  			if (draggable) {
7667  				this.dragging.enable();
7668  			}
7669  		}
7670  	},
7671
7672  	// @method setOpacity(opacity: Number): this
7673  	// Changes the opacity of the marker.
7674  	setOpacity: function (opacity) {
7675  		this.options.opacity = opacity;
7676  		if (this._map) {
7677  			this._updateOpacity();
7678  		}
7679
7680  		return this;
7681  	},
7682
7683  	_updateOpacity: function () {
7684  		var opacity = this.options.opacity;
7685
7686  		if (this._icon) {
7687  			setOpacity(this._icon, opacity);
7688  		}
7689
7690  		if (this._shadow) {
7691  			setOpacity(this._shadow, opacity);
7692  		}
7693  	},
7694
7695  	_bringToFront: function () {
7696  		this._updateZIndex(this.options.riseOffset);
7697  	},
7698
7699  	_resetZIndex: function () {
7700  		this._updateZIndex(0);
7701  	},
7702
7703  	_getPopupAnchor: function () {
7704  		return this.options.icon.options.popupAnchor;
7705  	},
7706
7707  	_getTooltipAnchor: function () {
7708  		return this.options.icon.options.tooltipAnchor;
7709  	}
7710  });
7711
7712
7713  // factory L.marker(latlng: LatLng, options? : Marker options)
7714
7715  // @factory L.marker(latlng: LatLng, options? : Marker options)
7716  // Instantiates a Marker object given a geographical point and optionally an options object.
7717  function marker(latlng, options) {
7718  	return new Marker(latlng, options);
vendor: 13,798 bytes, lines 7718-8185
7718
7719  }
7720
7721  /*
7722   * @class Path
7723   * @aka L.Path
7724   * @inherits Interactive layer
7725   *
7726   * An abstract class that contains options and constants shared between vector
7727   * overlays (Polygon, Polyline, Circle). Do not use it directly. Extends `Layer`.
7728   */
7729
7730  var Path = Layer.extend({
7731
7732  	// @section
7733  	// @aka Path options
7734  	options: {
7735  		// @option stroke: Boolean = true
7736  		// Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles.
7737  		stroke: true,
7738
7739  		// @option color: String = '#3388ff'
7740  		// Stroke color
7741  		color: '#3388ff',
7742
7743  		// @option weight: Number = 3
7744  		// Stroke width in pixels
7745  		weight: 3,
7746
7747  		// @option opacity: Number = 1.0
7748  		// Stroke opacity
7749  		opacity: 1,
7750
7751  		// @option lineCap: String= 'round'
7752  		// A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke.
7753  		lineCap: 'round',
7754
7755  		// @option lineJoin: String = 'round'
7756  		// A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke.
7757  		lineJoin: 'round',
7758
7759  		// @option dashArray: String = null
7760  		// A string that defines the stroke [dash pattern](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dasharray). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).
7761  		dashArray: null,
7762
7763  		// @option dashOffset: String = null
7764  		// A string that defines the [distance into the dash pattern to start the dash](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dashoffset). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).
7765  		dashOffset: null,
7766
7767  		// @option fill: Boolean = depends
7768  		// Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles.
7769  		fill: false,
7770
7771  		// @option fillColor: String = *
7772  		// Fill color. Defaults to the value of the [`color`](#path-color) option
7773  		fillColor: null,
7774
7775  		// @option fillOpacity: Number = 0.2
7776  		// Fill opacity.
7777  		fillOpacity: 0.2,
7778
7779  		// @option fillRule: String = 'evenodd'
7780  		// A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined.
7781  		fillRule: 'evenodd',
7782
7783  		// className: '',
7784
7785  		// Option inherited from "Interactive layer" abstract class
7786  		interactive: true,
7787
7788  		// @option bubblingMouseEvents: Boolean = true
7789  		// When `true`, a mouse event on this path will trigger the same event on the map
7790  		// (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).
7791  		bubblingMouseEvents: true
7792  	},
7793
7794  	beforeAdd: function (map) {
7795  		// Renderer is set here because we need to call renderer.getEvents
7796  		// before this.getEvents.
7797  		this._renderer = map.getRenderer(this);
7798  	},
7799
7800  	onAdd: function () {
7801  		this._renderer._initPath(this);
7802  		this._reset();
7803  		this._renderer._addPath(this);
7804  	},
7805
7806  	onRemove: function () {
7807  		this._renderer._removePath(this);
7808  	},
7809
7810  	// @method redraw(): this
7811  	// Redraws the layer. Sometimes useful after you changed the coordinates that the path uses.
7812  	redraw: function () {
7813  		if (this._map) {
7814  			this._renderer._updatePath(this);
7815  		}
7816  		return this;
7817  	},
7818
7819  	// @method setStyle(style: Path options): this
7820  	// Changes the appearance of a Path based on the options in the `Path options` object.
7821  	setStyle: function (style) {
7822  		setOptions(this, style);
7823  		if (this._renderer) {
7824  			this._renderer._updateStyle(this);
7825  			if (this.options.stroke && style && Object.prototype.hasOwnProperty.call(style, 'weight')) {
7826  				this._updateBounds();
7827  			}
7828  		}
7829  		return this;
7830  	},
7831
7832  	// @method bringToFront(): this
7833  	// Brings the layer to the top of all path layers.
7834  	bringToFront: function () {
7835  		if (this._renderer) {
7836  			this._renderer._bringToFront(this);
7837  		}
7838  		return this;
7839  	},
7840
7841  	// @method bringToBack(): this
7842  	// Brings the layer to the bottom of all path layers.
7843  	bringToBack: function () {
7844  		if (this._renderer) {
7845  			this._renderer._bringToBack(this);
7846  		}
7847  		return this;
7848  	},
7849
7850  	getElement: function () {
7851  		return this._path;
7852  	},
7853
7854  	_reset: function () {
7855  		// defined in child classes
7856  		this._project();
7857  		this._update();
7858  	},
7859
7860  	_clickTolerance: function () {
7861  		// used when doing hit detection for Canvas layers
7862  		return (this.options.stroke ? this.options.weight / 2 : 0) +
7863  		  (this._renderer.options.tolerance || 0);
7864  	}
7865  });
7866
7867  /*
7868   * @class CircleMarker
7869   * @aka L.CircleMarker
7870   * @inherits Path
7871   *
7872   * A circle of a fixed size with radius specified in pixels. Extends `Path`.
7873   */
7874
7875  var CircleMarker = Path.extend({
7876
7877  	// @section
7878  	// @aka CircleMarker options
7879  	options: {
7880  		fill: true,
7881
7882  		// @option radius: Number = 10
7883  		// Radius of the circle marker, in pixels
7884  		radius: 10
7885  	},
7886
7887  	initialize: function (latlng, options) {
7888  		setOptions(this, options);
7889  		this._latlng = toLatLng(latlng);
7890  		this._radius = this.options.radius;
7891  	},
7892
7893  	// @method setLatLng(latLng: LatLng): this
7894  	// Sets the position of a circle marker to a new location.
7895  	setLatLng: function (latlng) {
7896  		var oldLatLng = this._latlng;
7897  		this._latlng = toLatLng(latlng);
7898  		this.redraw();
7899
7900  		// @event move: Event
7901  		// Fired when the marker is moved via [`setLatLng`](#circlemarker-setlatlng). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`.
7902  		return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
7903  	},
7904
7905  	// @method getLatLng(): LatLng
7906  	// Returns the current geographical position of the circle marker
7907  	getLatLng: function () {
7908  		return this._latlng;
7909  	},
7910
7911  	// @method setRadius(radius: Number): this
7912  	// Sets the radius of a circle marker. Units are in pixels.
7913  	setRadius: function (radius) {
7914  		this.options.radius = this._radius = radius;
7915  		return this.redraw();
7916  	},
7917
7918  	// @method getRadius(): Number
7919  	// Returns the current radius of the circle
7920  	getRadius: function () {
7921  		return this._radius;
7922  	},
7923
7924  	setStyle : function (options) {
7925  		var radius = options && options.radius || this._radius;
7926  		Path.prototype.setStyle.call(this, options);
7927  		this.setRadius(radius);
7928  		return this;
7929  	},
7930
7931  	_project: function () {
7932  		this._point = this._map.latLngToLayerPoint(this._latlng);
7933  		this._updateBounds();
7934  	},
7935
7936  	_updateBounds: function () {
7937  		var r = this._radius,
7938  		    r2 = this._radiusY || r,
7939  		    w = this._clickTolerance(),
7940  		    p = [r + w, r2 + w];
7941  		this._pxBounds = new Bounds(this._point.subtract(p), this._point.add(p));
7942  	},
7943
7944  	_update: function () {
7945  		if (this._map) {
7946  			this._updatePath();
7947  		}
7948  	},
7949
7950  	_updatePath: function () {
7951  		this._renderer._updateCircle(this);
7952  	},
7953
7954  	_empty: function () {
7955  		return this._radius && !this._renderer._bounds.intersects(this._pxBounds);
7956  	},
7957
7958  	// Needed by the `Canvas` renderer for interactivity
7959  	_containsPoint: function (p) {
7960  		return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
7961  	}
7962  });
7963
7964
7965  // @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options)
7966  // Instantiates a circle marker object given a geographical point, and an optional options object.
7967  function circleMarker(latlng, options) {
7968  	return new CircleMarker(latlng, options);
7969  }
7970
7971  /*
7972   * @class Circle
7973   * @aka L.Circle
7974   * @inherits CircleMarker
7975   *
7976   * A class for drawing circle overlays on a map. Extends `CircleMarker`.
7977   *
7978   * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion).
7979   *
7980   * @example
7981   *
7982   * ```js
7983   * L.circle([50.5, 30.5], {radius: 200}).addTo(map);
7984   * ```
7985   */
7986
7987  var Circle = CircleMarker.extend({
7988
7989  	initialize: function (latlng, options, legacyOptions) {
7990  		if (typeof options === 'number') {
7991  			// Backwards compatibility with 0.7.x factory (latlng, radius, options?)
7992  			options = extend({}, legacyOptions, {radius: options});
7993  		}
7994  		setOptions(this, options);
7995  		this._latlng = toLatLng(latlng);
7996
7997  		if (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); }
7998
7999  		// @section
8000  		// @aka Circle options
8001  		// @option radius: Number; Radius of the circle, in meters.
8002  		this._mRadius = this.options.radius;
8003  	},
8004
8005  	// @method setRadius(radius: Number): this
8006  	// Sets the radius of a circle. Units are in meters.
8007  	setRadius: function (radius) {
8008  		this._mRadius = radius;
8009  		return this.redraw();
8010  	},
8011
8012  	// @method getRadius(): Number
8013  	// Returns the current radius of a circle. Units are in meters.
8014  	getRadius: function () {
8015  		return this._mRadius;
8016  	},
8017
8018  	// @method getBounds(): LatLngBounds
8019  	// Returns the `LatLngBounds` of the path.
8020  	getBounds: function () {
8021  		var half = [this._radius, this._radiusY || this._radius];
8022
8023  		return new LatLngBounds(
8024  			this._map.layerPointToLatLng(this._point.subtract(half)),
8025  			this._map.layerPointToLatLng(this._point.add(half)));
8026  	},
8027
8028  	setStyle: Path.prototype.setStyle,
8029
8030  	_project: function () {
8031
8032  		var lng = this._latlng.lng,
8033  		    lat = this._latlng.lat,
8034  		    map = this._map,
8035  		    crs = map.options.crs;
8036
8037  		if (crs.distance === Earth.distance) {
8038  			var d = Math.PI / 180,
8039  			    latR = (this._mRadius / Earth.R) / d,
8040  			    top = map.project([lat + latR, lng]),
8041  			    bottom = map.project([lat - latR, lng]),
8042  			    p = top.add(bottom).divideBy(2),
8043  			    lat2 = map.unproject(p).lat,
8044  			    lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) /
8045  			            (Math.cos(lat * d) * Math.cos(lat2 * d))) / d;
8046
8047  			if (isNaN(lngR) || lngR === 0) {
8048  				lngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425
8049  			}
8050
8051  			this._point = p.subtract(map.getPixelOrigin());
8052  			this._radius = isNaN(lngR) ? 0 : p.x - map.project([lat2, lng - lngR]).x;
8053  			this._radiusY = p.y - top.y;
8054
8055  		} else {
8056  			var latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));
8057
8058  			this._point = map.latLngToLayerPoint(this._latlng);
8059  			this._radius = this._point.x - map.latLngToLayerPoint(latlng2).x;
8060  		}
8061
8062  		this._updateBounds();
8063  	}
8064  });
8065
8066  // @factory L.circle(latlng: LatLng, options?: Circle options)
8067  // Instantiates a circle object given a geographical point, and an options object
8068  // which contains the circle radius.
8069  // @alternative
8070  // @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options)
8071  // Obsolete way of instantiating a circle, for compatibility with 0.7.x code.
8072  // Do not use in new applications or plugins.
8073  function circle(latlng, options, legacyOptions) {
8074  	return new Circle(latlng, options, legacyOptions);
8075  }
8076
8077  /*
8078   * @class Polyline
8079   * @aka L.Polyline
8080   * @inherits Path
8081   *
8082   * A class for drawing polyline overlays on a map. Extends `Path`.
8083   *
8084   * @example
8085   *
8086   * ```js
8087   * // create a red polyline from an array of LatLng points
8088   * var latlngs = [
8089   * 	[45.51, -122.68],
8090   * 	[37.77, -122.43],
8091   * 	[34.04, -118.2]
8092   * ];
8093   *
8094   * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);
8095   *
8096   * // zoom the map to the polyline
8097   * map.fitBounds(polyline.getBounds());
8098   * ```
8099   *
8100   * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:
8101   *
8102   * ```js
8103   * // create a red polyline from an array of arrays of LatLng points
8104   * var latlngs = [
8105   * 	[[45.51, -122.68],
8106   * 	 [37.77, -122.43],
8107   * 	 [34.04, -118.2]],
8108   * 	[[40.78, -73.91],
8109   * 	 [41.83, -87.62],
8110   * 	 [32.76, -96.72]]
8111   * ];
8112   * ```
8113   */
8114
8115
8116  var Polyline = Path.extend({
8117
8118  	// @section
8119  	// @aka Polyline options
8120  	options: {
8121  		// @option smoothFactor: Number = 1.0
8122  		// How much to simplify the polyline on each zoom level. More means
8123  		// better performance and smoother look, and less means more accurate representation.
8124  		smoothFactor: 1.0,
8125
8126  		// @option noClip: Boolean = false
8127  		// Disable polyline clipping.
8128  		noClip: false
8129  	},
8130
8131  	initialize: function (latlngs, options) {
8132  		setOptions(this, options);
8133  		this._setLatLngs(latlngs);
8134  	},
8135
8136  	// @method getLatLngs(): LatLng[]
8137  	// Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.
8138  	getLatLngs: function () {
8139  		return this._latlngs;
8140  	},
8141
8142  	// @method setLatLngs(latlngs: LatLng[]): this
8143  	// Replaces all the points in the polyline with the given array of geographical points.
8144  	setLatLngs: function (latlngs) {
8145  		this._setLatLngs(latlngs);
8146  		return this.redraw();
8147  	},
8148
8149  	// @method isEmpty(): Boolean
8150  	// Returns `true` if the Polyline has no LatLngs.
8151  	isEmpty: function () {
8152  		return !this._latlngs.length;
8153  	},
8154
8155  	// @method closestLayerPoint(p: Point): Point
8156  	// Returns the point closest to `p` on the Polyline.
8157  	closestLayerPoint: function (p) {
8158  		var minDistance = Infinity,
8159  		    minPoint = null,
8160  		    closest = _sqClosestPointOnSegment,
8161  		    p1, p2;
8162
8163  		for (var j = 0, jLen = this._parts.length; j < jLen; j++) {
8164  			var points = this._parts[j];
8165
8166  			for (var i = 1, len = points.length; i < len; i++) {
8167  				p1 = points[i - 1];
8168  				p2 = points[i];
8169
8170  				var sqDist = closest(p, p1, p2, true);
8171
8172  				if (sqDist < minDistance) {
8173  					minDistance = sqDist;
8174  					minPoint = closest(p, p1, p2);
8175  				}
8176  			}
8177  		}
8178  		if (minPoint) {
8179  			minPoint.distance = Math.sqrt(minDistance);
8180  		}
8181  		return minPoint;
8182  	},
8183
8184  	// @method getCenter(): LatLng
8185  	// Returns the center ([centroid](http
8185://en.wikipedia.org/wiki/Centroid)) of the polyline.
8186  	getCenter: function () {
8187  		// throws error when not yet added to map as this center calculation requires projected coordinates
8188  		if (!this._map) {
8189  			throw new Error('Must add layer to map before using getCenter()');
8190  		}
8191
8192  		var i, halfDist, segDist, dist, p1, p2, ratio,
8193  		    points = this._rings[0],
8194  		    len = points.length;
8195
8196  		if (!len) { return null; }
8197
8198  		// polyline centroid algorithm; only uses the first ring if there are multiple
8199
8200  		for (i = 0, halfDist = 0; i < len - 1; i++) {
8201  			halfDist += points[i].distanceTo(points[i + 1]) / 2;
8202  		}
8203
8204  		// The line is so small in the current view that all points are on the same pixel.
8205  		if (halfDist === 0) {
8206  			return this._map.layerPointToLatLng(points[0]);
8207  		}
8208
8209  		for (i = 0, dist = 0; i < len - 1; i++) {
8210  			p1 = points[i];
8211  			p2 = points[i + 1];
8212  			segDist = p1.distanceTo(p2);
8213  			dist += segDist;
8214
8215  			if (dist > halfDist) {
8216  				ratio = (dist - halfDist) / segDist;
8217  				return this._map.layerPointToLatLng([
8218  					p2.x - ratio * (p2.x - p1.x),
8219  					p2.y - ratio * (p2.y - p1.y)
8220  				]);
8221  			}
8222  		}
8223  	},
8224
8225  	// @method getBounds(): LatLngBounds
8226  	// Returns the `LatLngBounds` of the path.
vendor: 11,124 bytes, lines 8227-8623
8227  	getBounds: function () {
8228  		return this._bounds;
8229  	},
8230
8231  	// @method addLatLng(latlng: LatLng, latlngs?: LatLng[]): this
8232  	// Adds a given point to the polyline. By default, adds to the first ring of
8233  	// the polyline in case of a multi-polyline, but can be overridden by passing
8234  	// a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).
8235  	addLatLng: function (latlng, latlngs) {
8236  		latlngs = latlngs || this._defaultShape();
8237  		latlng = toLatLng(latlng);
8238  		latlngs.push(latlng);
8239  		this._bounds.extend(latlng);
8240  		return this.redraw();
8241  	},
8242
8243  	_setLatLngs: function (latlngs) {
8244  		this._bounds = new LatLngBounds();
8245  		this._latlngs = this._convertLatLngs(latlngs);
8246  	},
8247
8248  	_defaultShape: function () {
8249  		return isFlat(this._latlngs) ? this._latlngs : this._latlngs[0];
8250  	},
8251
8252  	// recursively convert latlngs input into actual LatLng instances; calculate bounds along the way
8253  	_convertLatLngs: function (latlngs) {
8254  		var result = [],
8255  		    flat = isFlat(latlngs);
8256
8257  		for (var i = 0, len = latlngs.length; i < len; i++) {
8258  			if (flat) {
8259  				result[i] = toLatLng(latlngs[i]);
8260  				this._bounds.extend(result[i]);
8261  			} else {
8262  				result[i] = this._convertLatLngs(latlngs[i]);
8263  			}
8264  		}
8265
8266  		return result;
8267  	},
8268
8269  	_project: function () {
8270  		var pxBounds = new Bounds();
8271  		this._rings = [];
8272  		this._projectLatlngs(this._latlngs, this._rings, pxBounds);
8273
8274  		if (this._bounds.isValid() && pxBounds.isValid()) {
8275  			this._rawPxBounds = pxBounds;
8276  			this._updateBounds();
8277  		}
8278  	},
8279
8280  	_updateBounds: function () {
8281  		var w = this._clickTolerance(),
8282  		    p = new Point(w, w);
8283
8284  		if (!this._rawPxBounds) {
8285  			return;
8286  		}
8287
8288  		this._pxBounds = new Bounds([
8289  			this._rawPxBounds.min.subtract(p),
8290  			this._rawPxBounds.max.add(p)
8291  		]);
8292  	},
8293
8294  	// recursively turns latlngs into a set of rings with projected coordinates
8295  	_projectLatlngs: function (latlngs, result, projectedBounds) {
8296  		var flat = latlngs[0] instanceof LatLng,
8297  		    len = latlngs.length,
8298  		    i, ring;
8299
8300  		if (flat) {
8301  			ring = [];
8302  			for (i = 0; i < len; i++) {
8303  				ring[i] = this._map.latLngToLayerPoint(latlngs[i]);
8304  				projectedBounds.extend(ring[i]);
8305  			}
8306  			result.push(ring);
8307  		} else {
8308  			for (i = 0; i < len; i++) {
8309  				this._projectLatlngs(latlngs[i], result, projectedBounds);
8310  			}
8311  		}
8312  	},
8313
8314  	// clip polyline by renderer bounds so that we have less to render for performance
8315  	_clipPoints: function () {
8316  		var bounds = this._renderer._bounds;
8317
8318  		this._parts = [];
8319  		if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
8320  			return;
8321  		}
8322
8323  		if (this.options.noClip) {
8324  			this._parts = this._rings;
8325  			return;
8326  		}
8327
8328  		var parts = this._parts,
8329  		    i, j, k, len, len2, segment, points;
8330
8331  		for (i = 0, k = 0, len = this._rings.length; i < len; i++) {
8332  			points = this._rings[i];
8333
8334  			for (j = 0, len2 = points.length; j < len2 - 1; j++) {
8335  				segment = clipSegment(points[j], points[j + 1], bounds, j, true);
8336
8337  				if (!segment) { continue; }
8338
8339  				parts[k] = parts[k] || [];
8340  				parts[k].push(segment[0]);
8341
8342  				// if segment goes out of screen, or it's the last one, it's the end of the line part
8343  				if ((segment[1] !== points[j + 1]) || (j === len2 - 2)) {
8344  					parts[k].push(segment[1]);
8345  					k++;
8346  				}
8347  			}
8348  		}
8349  	},
8350
8351  	// simplify each clipped part of the polyline for performance
8352  	_simplifyPoints: function () {
8353  		var parts = this._parts,
8354  		    tolerance = this.options.smoothFactor;
8355
8356  		for (var i = 0, len = parts.length; i < len; i++) {
8357  			parts[i] = simplify(parts[i], tolerance);
8358  		}
8359  	},
8360
8361  	_update: function () {
8362  		if (!this._map) { return; }
8363
8364  		this._clipPoints();
8365  		this._simplifyPoints();
8366  		this._updatePath();
8367  	},
8368
8369  	_updatePath: function () {
8370  		this._renderer._updatePoly(this);
8371  	},
8372
8373  	// Needed by the `Canvas` renderer for interactivity
8374  	_containsPoint: function (p, closed) {
8375  		var i, j, k, len, len2, part,
8376  		    w = this._clickTolerance();
8377
8378  		if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }
8379
8380  		// hit detection for polylines
8381  		for (i = 0, len = this._parts.length; i < len; i++) {
8382  			part = this._parts[i];
8383
8384  			for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
8385  				if (!closed && (j === 0)) { continue; }
8386
8387  				if (pointToSegmentDistance(p, part[k], part[j]) <= w) {
8388  					return true;
8389  				}
8390  			}
8391  		}
8392  		return false;
8393  	}
8394  });
8395
8396  // @factory L.polyline(latlngs: LatLng[], options?: Polyline options)
8397  // Instantiates a polyline object given an array of geographical points and
8398  // optionally an options object. You can create a `Polyline` object with
8399  // multiple separate lines (`MultiPolyline`) by passing an array of arrays
8400  // of geographic points.
8401  function polyline(latlngs, options) {
8402  	return new Polyline(latlngs, options);
8403  }
8404
8405  // Retrocompat. Allow plugins to support Leaflet versions before and after 1.1.
8406  Polyline._flat = _flat;
8407
8408  /*
8409   * @class Polygon
8410   * @aka L.Polygon
8411   * @inherits Polyline
8412   *
8413   * A class for drawing polygon overlays on a map. Extends `Polyline`.
8414   *
8415   * Note that points you pass when creating a polygon shouldn't have an additional last point equal to the first one — it's better to filter out such points.
8416   *
8417   *
8418   * @example
8419   *
8420   * ```js
8421   * // create a red polygon from an array of LatLng points
8422   * var latlngs = [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]];
8423   *
8424   * var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map);
8425   *
8426   * // zoom the map to the polygon
8427   * map.fitBounds(polygon.getBounds());
8428   * ```
8429   *
8430   * You can also pass an array of arrays of latlngs, with the first array representing the outer shape and the other arrays representing holes in the outer shape:
8431   *
8432   * ```js
8433   * var latlngs = [
8434   *   [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring
8435   *   [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole
8436   * ];
8437   * ```
8438   *
8439   * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape.
8440   *
8441   * ```js
8442   * var latlngs = [
8443   *   [ // first polygon
8444   *     [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring
8445   *     [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole
8446   *   ],
8447   *   [ // second polygon
8448   *     [[41, -111.03],[45, -111.04],[45, -104.05],[41, -104.05]]
8449   *   ]
8450   * ];
8451   * ```
8452   */
8453
8454  var Polygon = Polyline.extend({
8455
8456  	options: {
8457  		fill: true
8458  	},
8459
8460  	isEmpty: function () {
8461  		return !this._latlngs.length || !this._latlngs[0].length;
8462  	},
8463
8464  	getCenter: function () {
8465  		// throws error when not yet added to map as this center calculation requires projected coordinates
8466  		if (!this._map) {
8467  			throw new Error('Must add layer to map before using getCenter()');
8468  		}
8469
8470  		var i, j, p1, p2, f, area, x, y, center,
8471  		    points = this._rings[0],
8472  		    len = points.length;
8473
8474  		if (!len) { return null; }
8475
8476  		// polygon centroid algorithm; only uses the first ring if there are multiple
8477
8478  		area = x = y = 0;
8479
8480  		for (i = 0, j = len - 1; i < len; j = i++) {
8481  			p1 = points[i];
8482  			p2 = points[j];
8483
8484  			f = p1.y * p2.x - p2.y * p1.x;
8485  			x += (p1.x + p2.x) * f;
8486  			y += (p1.y + p2.y) * f;
8487  			area += f * 3;
8488  		}
8489
8490  		if (area === 0) {
8491  			// Polygon is so small that all points are on same pixel.
8492  			center = points[0];
8493  		} else {
8494  			center = [x / area, y / area];
8495  		}
8496  		return this._map.layerPointToLatLng(center);
8497  	},
8498
8499  	_convertLatLngs: function (latlngs) {
8500  		var result = Polyline.prototype._convertLatLngs.call(this, latlngs),
8501  		    len = result.length;
8502
8503  		// remove last point if it equals first one
8504  		if (len >= 2 && result[0] instanceof LatLng && result[0].equals(result[len - 1])) {
8505  			result.pop();
8506  		}
8507  		return result;
8508  	},
8509
8510  	_setLatLngs: function (latlngs) {
8511  		Polyline.prototype._setLatLngs.call(this, latlngs);
8512  		if (isFlat(this._latlngs)) {
8513  			this._latlngs = [this._latlngs];
8514  		}
8515  	},
8516
8517  	_defaultShape: function () {
8518  		return isFlat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0];
8519  	},
8520
8521  	_clipPoints: function () {
8522  		// polygons need a different clipping algorithm so we redefine that
8523
8524  		var bounds = this._renderer._bounds,
8525  		    w = this.options.weight,
8526  		    p = new Point(w, w);
8527
8528  		// increase clip padding by stroke width to avoid stroke on clip edges
8529  		bounds = new Bounds(bounds.min.subtract(p), bounds.max.add(p));
8530
8531  		this._parts = [];
8532  		if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
8533  			return;
8534  		}
8535
8536  		if (this.options.noClip) {
8537  			this._parts = this._rings;
8538  			return;
8539  		}
8540
8541  		for (var i = 0, len = this._rings.length, clipped; i < len; i++) {
8542  			clipped = clipPolygon(this._rings[i], bounds, true);
8543  			if (clipped.length) {
8544  				this._parts.push(clipped);
8545  			}
8546  		}
8547  	},
8548
8549  	_updatePath: function () {
8550  		this._renderer._updatePoly(this, true);
8551  	},
8552
8553  	// Needed by the `Canvas` renderer for interactivity
8554  	_containsPoint: function (p) {
8555  		var inside = false,
8556  		    part, p1, p2, i, j, k, len, len2;
8557
8558  		if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }
8559
8560  		// ray casting algorithm for detecting if point is in polygon
8561  		for (i = 0, len = this._parts.length; i < len; i++) {
8562  			part = this._parts[i];
8563
8564  			for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
8565  				p1 = part[j];
8566  				p2 = part[k];
8567
8568  				if (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) {
8569  					inside = !inside;
8570  				}
8571  			}
8572  		}
8573
8574  		// also check if it's on polygon stroke
8575  		return inside || Polyline.prototype._containsPoint.call(this, p, true);
8576  	}
8577
8578  });
8579
8580
8581  // @factory L.polygon(latlngs: LatLng[], options?: Polyline options)
8582  function polygon(latlngs, options) {
8583  	return new Polygon(latlngs, options);
8584  }
8585
8586  /*
8587   * @class GeoJSON
8588   * @aka L.GeoJSON
8589   * @inherits FeatureGroup
8590   *
8591   * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse
8592   * GeoJSON data and display it on the map. Extends `FeatureGroup`.
8593   *
8594   * @example
8595   *
8596   * ```js
8597   * L.geoJSON(data, {
8598   * 	style: function (feature) {
8599   * 		return {color: feature.properties.color};
8600   * 	}
8601   * }).bindPopup(function (layer) {
8602   * 	return layer.feature.properties.description;
8603   * }).addTo(map);
8604   * ```
8605   */
8606
8607  var GeoJSON = FeatureGroup.extend({
8608
8609  	/* @section
8610  	 * @aka GeoJSON options
8611  	 *
8612  	 * @option pointToLayer: Function = *
8613  	 * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally
8614  	 * called when data is added, passing the GeoJSON point feature and its `LatLng`.
8615  	 * The default is to spawn a default `Marker`:
8616  	 * ```js
8617  	 * function(geoJsonPoint, latlng) {
8618  	 * 	return L.marker(latlng);
8619  	 * }
8620  	 * ```
8621  	 *
8622  	 * @option style: Function = *
8623  	 * A `Function` defining the `Path options` for styling GeoJSON lines and polygons,
8624  	 * called internally when data is added.
8625  	 * The default value is to not override any defaults:
8626  	 * ```js
8627  	 * function (geoJsonFeature) {
8628  	 * 	return {}
8629  	 * }
8630  	 * ```
8631  	 *
8632  	 * @option onEachFeature: Function = *
8633  	 * A `Function` that will be called once for each created `Feature`, after it has
8634  	 * been created and styled. Useful for attaching events and popups to features.
8635  	 * The default is to do nothing with the newly created layers:
8636  	 * ```js
8637  	 * function (feature, layer) {}
8638  	 * ```
8639  	 *
8640  	 * @option filter: Function = *
8641  	 * A `Function` that will be used to decide whether to include a feature or not.
8642  	 * The default is to include all features:
8643  	 * ```js
8644  	 * function (geoJsonFeature) {
8645  	 * 	return true;
8646  	 * }
8647  	 * ```
8648  	 * Note: dynamically changing the `filter` option will have effect only on newly
8649  	 * added data. It will _not_ re-evaluate already included features.
8650  	 *
8651  	 * @option coordsToLatLng: Function = *
8652  	 * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s.
8653  	 * The default is the `coordsToLatLng` static method.
8654  	 *
8655  	 * @option markersInheritOptions: Boolean = false
8656  	 * Whether default Markers for "Point" type Features inherit from group options.
8657  	 */
8658
8659  	initialize: function (geojson, options) {
8660  		setOptions(this, options);
8661
8662  		this._layers = {};
8663
8664  		if (geojson) {
8665  			this.addData(geojson);
8666  		}
8667  	},
8668
8669  	// @method addData( <GeoJSON> data ): this
8670  	// Adds a GeoJSON object to the layer.
8671  	addData: function (geojson) {
8672  		var features = isArray(geojson) ? geojson : geojson.features,
8673  		    i, len, feature;
8674
8675  		if (features) {
8676  			for (i = 0, len = features.length; i < len; i++) {
8677  				// only add this if geometry or geometries are set and not null
8678  				feature = features[i];
8679  				if (feature.geometries || feature.geometry || feature.features || feature.coordinates) {
8680  					this.addData(feature);
8681  				}
8682  			}
8683  			return this;
8684  		}
8685
8686  		var options = this.options;
8687
8688  		if (options.filter && !options.filter(geojson)) { return this; }
8689
8690  		var layer = geometryToLayer(geojson, options);
8691  		if (!layer) {
8692  			return this;
8693  		}
8694  		layer.feature = asFeature(geojson);
8695
8696  		layer.defaultOptions = layer.options;
8697  		this.resetStyle(layer);
8698
8699  		if (options.onEachFeature) {
8700  			options.onEachFeature(geojson, layer);
8701  		}
8702
8703  		return this.addLayer(layer);
8704  	},
8705
8706  	// @method resetStyle( <Path> layer? ): this
8707  	// Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.
8708  	// If `layer` is omitted, the style of all features in the current layer is reset.
8709  	resetStyle: function (layer) {
8710  		if (layer === undefined) {
8711  			return this.eachLayer(this.resetStyle, this);
8712  		}
8713  		// reset any custom styles
8714  		layer.options = extend({}, layer.defaultOptions);
8715  		this._setLayerStyle(layer, this.options.style);
8716  		return this;
8717  	},
8718
8719  	// @method setStyle( <Function> style ): this
8720  	// Changes styles of GeoJSON vector layers with the given style function.
8721  	setStyle: function (style) {
8722  		return this.eachLayer(function (layer) {
8723  			this._setLayerStyle(layer, style);
8724  		}, this);
8725  	},
8726
8727  	_setLayerStyle: function (layer, style) {
8728  		if (layer.setStyle) {
8729  			if (typeof style === 'function') {
8730  				style = style(layer.feature);
8731  			}
8732  			layer.setStyle(style);
8733  		}
8734  	}
8735  });
8736
8737  // @section
8738  // There are several static functions which can be called without instantiating L.GeoJSON:
8739
8740  // @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer
8741  // Creates a `Layer` from a given GeoJSON feature. Can use a custom
8742  // [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng)
8743  // functions if provided as options.
8744  function geometryToLayer(geojson, options) {
8745
8746  	var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,
8747  	    coords = geometry ? geometry.coordinates : null,
8748  	    layers = [],
8749  	    pointToLayer = options && options.pointToLayer,
8750  	    _coordsToLatLng = options && options.coordsToLatLng || coordsToLatLng,
8751  	    latlng, latlngs, i, len;
8752
8753  	if (!coords && !geometry) {
8754  		return null;
8755  	}
8756
8757  	switch (geometry.type) {
8758  	case 'Point':
8759  		latlng = _coordsToLatLng(coords);
8760  		return _pointToLayer(pointToLayer, geojson, latlng, options);
8761
8762  	case 'MultiPoint':
vendor: 57,055 bytes, lines 8763-10655
8763  		for (i = 0, len = coords.length; i < len; i++) {
8764  			latlng = _coordsToLatLng(coords[i]);
8765  			layers.push(_pointToLayer(pointToLayer, geojson, latlng, options));
8766  		}
8767  		return new FeatureGroup(layers);
8768
8769  	case 'LineString':
8770  	case 'MultiLineString':
8771  		latlngs = coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, _coordsToLatLng);
8772  		return new Polyline(latlngs, options);
8773
8774  	case 'Polygon':
8775  	case 'MultiPolygon':
8776  		latlngs = coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, _coordsToLatLng);
8777  		return new Polygon(latlngs, options);
8778
8779  	case 'GeometryCollection':
8780  		for (i = 0, len = geometry.geometries.length; i < len; i++) {
8781  			var layer = geometryToLayer({
8782  				geometry: geometry.geometries[i],
8783  				type: 'Feature',
8784  				properties: geojson.properties
8785  			}, options);
8786
8787  			if (layer) {
8788  				layers.push(layer);
8789  			}
8790  		}
8791  		return new FeatureGroup(layers);
8792
8793  	default:
8794  		throw new Error('Invalid GeoJSON object.');
8795  	}
8796  }
8797
8798  function _pointToLayer(pointToLayerFn, geojson, latlng, options) {
8799  	return pointToLayerFn ?
8800  		pointToLayerFn(geojson, latlng) :
8801  		new Marker(latlng, options && options.markersInheritOptions && options);
8802  }
8803
8804  // @function coordsToLatLng(coords: Array): LatLng
8805  // Creates a `LatLng` object from an array of 2 numbers (longitude, latitude)
8806  // or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points.
8807  function coordsToLatLng(coords) {
8808  	return new LatLng(coords[1], coords[0], coords[2]);
8809  }
8810
8811  // @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array
8812  // Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array.
8813  // `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default).
8814  // Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function.
8815  function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) {
8816  	var latlngs = [];
8817
8818  	for (var i = 0, len = coords.length, latlng; i < len; i++) {
8819  		latlng = levelsDeep ?
8820  			coordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng) :
8821  			(_coordsToLatLng || coordsToLatLng)(coords[i]);
8822
8823  		latlngs.push(latlng);
8824  	}
8825
8826  	return latlngs;
8827  }
8828
8829  // @function latLngToCoords(latlng: LatLng, precision?: Number|false): Array
8830  // Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)
8831  // Coordinates values are rounded with [`formatNum`](#util-formatnum) function.
8832  function latLngToCoords(latlng, precision) {
8833  	return latlng.alt !== undefined ?
8834  		[formatNum(latlng.lng, precision), formatNum(latlng.lat, precision), formatNum(latlng.alt, precision)] :
8835  		[formatNum(latlng.lng, precision), formatNum(latlng.lat, precision)];
8836  }
8837
8838  // @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean, precision?: Number|false): Array
8839  // Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)
8840  // `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default.
8841  // Coordinates values are rounded with [`formatNum`](#util-formatnum) function.
8842  function latLngsToCoords(latlngs, levelsDeep, closed, precision) {
8843  	var coords = [];
8844
8845  	for (var i = 0, len = latlngs.length; i < len; i++) {
8846  		coords.push(levelsDeep ?
8847  			latLngsToCoords(latlngs[i], levelsDeep - 1, closed, precision) :
8848  			latLngToCoords(latlngs[i], precision));
8849  	}
8850
8851  	if (!levelsDeep && closed) {
8852  		coords.push(coords[0]);
8853  	}
8854
8855  	return coords;
8856  }
8857
8858  function getFeature(layer, newGeometry) {
8859  	return layer.feature ?
8860  		extend({}, layer.feature, {geometry: newGeometry}) :
8861  		asFeature(newGeometry);
8862  }
8863
8864  // @function asFeature(geojson: Object): Object
8865  // Normalize GeoJSON geometries/features into GeoJSON features.
8866  function asFeature(geojson) {
8867  	if (geojson.type === 'Feature' || geojson.type === 'FeatureCollection') {
8868  		return geojson;
8869  	}
8870
8871  	return {
8872  		type: 'Feature',
8873  		properties: {},
8874  		geometry: geojson
8875  	};
8876  }
8877
8878  var PointToGeoJSON = {
8879  	toGeoJSON: function (precision) {
8880  		return getFeature(this, {
8881  			type: 'Point',
8882  			coordinates: latLngToCoords(this.getLatLng(), precision)
8883  		});
8884  	}
8885  };
8886
8887  // @namespace Marker
8888  // @section Other methods
8889  // @method toGeoJSON(precision?: Number|false): Object
8890  // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
8891  // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).
8892  Marker.include(PointToGeoJSON);
8893
8894  // @namespace CircleMarker
8895  // @method toGeoJSON(precision?: Number|false): Object
8896  // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
8897  // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).
8898  Circle.include(PointToGeoJSON);
8899  CircleMarker.include(PointToGeoJSON);
8900
8901
8902  // @namespace Polyline
8903  // @method toGeoJSON(precision?: Number|false): Object
8904  // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
8905  // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).
8906  Polyline.include({
8907  	toGeoJSON: function (precision) {
8908  		var multi = !isFlat(this._latlngs);
8909
8910  		var coords = latLngsToCoords(this._latlngs, multi ? 1 : 0, false, precision);
8911
8912  		return getFeature(this, {
8913  			type: (multi ? 'Multi' : '') + 'LineString',
8914  			coordinates: coords
8915  		});
8916  	}
8917  });
8918
8919  // @namespace Polygon
8920  // @method toGeoJSON(precision?: Number|false): Object
8921  // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
8922  // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).
8923  Polygon.include({
8924  	toGeoJSON: function (precision) {
8925  		var holes = !isFlat(this._latlngs),
8926  		    multi = holes && !isFlat(this._latlngs[0]);
8927
8928  		var coords = latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true, precision);
8929
8930  		if (!holes) {
8931  			coords = [coords];
8932  		}
8933
8934  		return getFeature(this, {
8935  			type: (multi ? 'Multi' : '') + 'Polygon',
8936  			coordinates: coords
8937  		});
8938  	}
8939  });
8940
8941
8942  // @namespace LayerGroup
8943  LayerGroup.include({
8944  	toMultiPoint: function (precision) {
8945  		var coords = [];
8946
8947  		this.eachLayer(function (layer) {
8948  			coords.push(layer.toGeoJSON(precision).geometry.coordinates);
8949  		});
8950
8951  		return getFeature(this, {
8952  			type: 'MultiPoint',
8953  			coordinates: coords
8954  		});
8955  	},
8956
8957  	// @method toGeoJSON(precision?: Number|false): Object
8958  	// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
8959  	// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`).
8960  	toGeoJSON: function (precision) {
8961
8962  		var type = this.feature && this.feature.geometry && this.feature.geometry.type;
8963
8964  		if (type === 'MultiPoint') {
8965  			return this.toMultiPoint(precision);
8966  		}
8967
8968  		var isGeometryCollection = type === 'GeometryCollection',
8969  		    jsons = [];
8970
8971  		this.eachLayer(function (layer) {
8972  			if (layer.toGeoJSON) {
8973  				var json = layer.toGeoJSON(precision);
8974  				if (isGeometryCollection) {
8975  					jsons.push(json.geometry);
8976  				} else {
8977  					var feature = asFeature(json);
8978  					// Squash nested feature collections
8979  					if (feature.type === 'FeatureCollection') {
8980  						jsons.push.apply(jsons, feature.features);
8981  					} else {
8982  						jsons.push(feature);
8983  					}
8984  				}
8985  			}
8986  		});
8987
8988  		if (isGeometryCollection) {
8989  			return getFeature(this, {
8990  				geometries: jsons,
8991  				type: 'GeometryCollection'
8992  			});
8993  		}
8994
8995  		return {
8996  			type: 'FeatureCollection',
8997  			features: jsons
8998  		};
8999  	}
9000  });
9001
9002  // @namespace GeoJSON
9003  // @factory L.geoJSON(geojson?: Object, options?: GeoJSON options)
9004  // Creates a GeoJSON layer. Optionally accepts an object in
9005  // [GeoJSON format](https://tools.ietf.org/html/rfc7946) to display on the map
9006  // (you can alternatively add it later with `addData` method) and an `options` object.
9007  function geoJSON(geojson, options) {
9008  	return new GeoJSON(geojson, options);
9009  }
9010
9011  // Backward compatibility.
9012  var geoJson = geoJSON;
9013
9014  /*
9015   * @class ImageOverlay
9016   * @aka L.ImageOverlay
9017   * @inherits Interactive layer
9018   *
9019   * Used to load and display a single image over specific bounds of the map. Extends `Layer`.
9020   *
9021   * @example
9022   *
9023   * ```js
9024   * var imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
9025   * 	imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];
9026   * L.imageOverlay(imageUrl, imageBounds).addTo(map);
9027   * ```
9028   */
9029
9030  var ImageOverlay = Layer.extend({
9031
9032  	// @section
9033  	// @aka ImageOverlay options
9034  	options: {
9035  		// @option opacity: Number = 1.0
9036  		// The opacity of the image overlay.
9037  		opacity: 1,
9038
9039  		// @option alt: String = ''
9040  		// Text for the `alt` attribute of the image (useful for accessibility).
9041  		alt: '',
9042
9043  		// @option interactive: Boolean = false
9044  		// If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.
9045  		interactive: false,
9046
9047  		// @option crossOrigin: Boolean|String = false
9048  		// Whether the crossOrigin attribute will be added to the image.
9049  		// If a String is provided, the image will have its crossOrigin attribute set to the String provided. This is needed if you want to access image pixel data.
9050  		// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
9051  		crossOrigin: false,
9052
9053  		// @option errorOverlayUrl: String = ''
9054  		// URL to the overlay image to show in place of the overlay that failed to load.
9055  		errorOverlayUrl: '',
9056
9057  		// @option zIndex: Number = 1
9058  		// The explicit [zIndex](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index) of the overlay layer.
9059  		zIndex: 1,
9060
9061  		// @option className: String = ''
9062  		// A custom class name to assign to the image. Empty by default.
9063  		className: ''
9064  	},
9065
9066  	initialize: function (url, bounds, options) { // (String, LatLngBounds, Object)
9067  		this._url = url;
9068  		this._bounds = toLatLngBounds(bounds);
9069
9070  		setOptions(this, options);
9071  	},
9072
9073  	onAdd: function () {
9074  		if (!this._image) {
9075  			this._initImage();
9076
9077  			if (this.options.opacity < 1) {
9078  				this._updateOpacity();
9079  			}
9080  		}
9081
9082  		if (this.options.interactive) {
9083  			addClass(this._image, 'leaflet-interactive');
9084  			this.addInteractiveTarget(this._image);
9085  		}
9086
9087  		this.getPane().appendChild(this._image);
9088  		this._reset();
9089  	},
9090
9091  	onRemove: function () {
9092  		remove(this._image);
9093  		if (this.options.interactive) {
9094  			this.removeInteractiveTarget(this._image);
9095  		}
9096  	},
9097
9098  	// @method setOpacity(opacity: Number): this
9099  	// Sets the opacity of the overlay.
9100  	setOpacity: function (opacity) {
9101  		this.options.opacity = opacity;
9102
9103  		if (this._image) {
9104  			this._updateOpacity();
9105  		}
9106  		return this;
9107  	},
9108
9109  	setStyle: function (styleOpts) {
9110  		if (styleOpts.opacity) {
9111  			this.setOpacity(styleOpts.opacity);
9112  		}
9113  		return this;
9114  	},
9115
9116  	// @method bringToFront(): this
9117  	// Brings the layer to the top of all overlays.
9118  	bringToFront: function () {
9119  		if (this._map) {
9120  			toFront(this._image);
9121  		}
9122  		return this;
9123  	},
9124
9125  	// @method bringToBack(): this
9126  	// Brings the layer to the bottom of all overlays.
9127  	bringToBack: function () {
9128  		if (this._map) {
9129  			toBack(this._image);
9130  		}
9131  		return this;
9132  	},
9133
9134  	// @method setUrl(url: String): this
9135  	// Changes the URL of the image.
9136  	setUrl: function (url) {
9137  		this._url = url;
9138
9139  		if (this._image) {
9140  			this._image.src = url;
9141  		}
9142  		return this;
9143  	},
9144
9145  	// @method setBounds(bounds: LatLngBounds): this
9146  	// Update the bounds that this ImageOverlay covers
9147  	setBounds: function (bounds) {
9148  		this._bounds = toLatLngBounds(bounds);
9149
9150  		if (this._map) {
9151  			this._reset();
9152  		}
9153  		return this;
9154  	},
9155
9156  	getEvents: function () {
9157  		var events = {
9158  			zoom: this._reset,
9159  			viewreset: this._reset
9160  		};
9161
9162  		if (this._zoomAnimated) {
9163  			events.zoomanim = this._animateZoom;
9164  		}
9165
9166  		return events;
9167  	},
9168
9169  	// @method setZIndex(value: Number): this
9170  	// Changes the [zIndex](#imageoverlay-zindex) of the image overlay.
9171  	setZIndex: function (value) {
9172  		this.options.zIndex = value;
9173  		this._updateZIndex();
9174  		return this;
9175  	},
9176
9177  	// @method getBounds(): LatLngBounds
9178  	// Get the bounds that this ImageOverlay covers
9179  	getBounds: function () {
9180  		return this._bounds;
9181  	},
9182
9183  	// @method getElement(): HTMLElement
9184  	// Returns the instance of [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement)
9185  	// used by this overlay.
9186  	getElement: function () {
9187  		return this._image;
9188  	},
9189
9190  	_initImage: function () {
9191  		var wasElementSupplied = this._url.tagName === 'IMG';
9192  		var img = this._image = wasElementSupplied ? this._url : create$1('img');
9193
9194  		addClass(img, 'leaflet-image-layer');
9195  		if (this._zoomAnimated) { addClass(img, 'leaflet-zoom-animated'); }
9196  		if (this.options.className) { addClass(img, this.options.className); }
9197
9198  		img.onselectstart = falseFn;
9199  		img.onmousemove = falseFn;
9200
9201  		// @event load: Event
9202  		// Fired when the ImageOverlay layer has loaded its image
9203  		img.onload = bind(this.fire, this, 'load');
9204  		img.onerror = bind(this._overlayOnError, this, 'error');
9205
9206  		if (this.options.crossOrigin || this.options.crossOrigin === '') {
9207  			img.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
9208  		}
9209
9210  		if (this.options.zIndex) {
9211  			this._updateZIndex();
9212  		}
9213
9214  		if (wasElementSupplied) {
9215  			this._url = img.src;
9216  			return;
9217  		}
9218
9219  		img.src = this._url;
9220  		img.alt = this.options.alt;
9221  	},
9222
9223  	_animateZoom: function (e) {
9224  		var scale = this._map.getZoomScale(e.zoom),
9225  		    offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min;
9226
9227  		setTransform(this._image, offset, scale);
9228  	},
9229
9230  	_reset: function () {
9231  		var image = this._image,
9232  		    bounds = new Bounds(
9233  		        this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
9234  		        this._map.latLngToLayerPoint(this._bounds.getSouthEast())),
9235  		    size = bounds.getSize();
9236
9237  		setPosition(image, bounds.min);
9238
9239  		image.style.width  = size.x + 'px';
9240  		image.style.height = size.y + 'px';
9241  	},
9242
9243  	_updateOpacity: function () {
9244  		setOpacity(this._image, this.options.opacity);
9245  	},
9246
9247  	_updateZIndex: function () {
9248  		if (this._image && this.options.zIndex !== undefined && this.options.zIndex !== null) {
9249  			this._image.style.zIndex = this.options.zIndex;
9250  		}
9251  	},
9252
9253  	_overlayOnError: function () {
9254  		// @event error: Event
9255  		// Fired when the ImageOverlay layer fails to load its image
9256  		this.fire('error');
9257
9258  		var errorUrl = this.options.errorOverlayUrl;
9259  		if (errorUrl && this._url !== errorUrl) {
9260  			this._url = errorUrl;
9261  			this._image.src = errorUrl;
9262  		}
9263  	}
9264  });
9265
9266  // @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options)
9267  // Instantiates an image overlay object given the URL of the image and the
9268  // geographical bounds it is tied to.
9269  var imageOverlay = function (url, bounds, options) {
9270  	return new ImageOverlay(url, bounds, options);
9271  };
9272
9273  /*
9274   * @class VideoOverlay
9275   * @aka L.VideoOverlay
9276   * @inherits ImageOverlay
9277   *
9278   * Used to load and display a video player over specific bounds of the map. Extends `ImageOverlay`.
9279   *
9280   * A video overlay uses the [`<video>`](https://developer.mozilla.org/docs/Web/HTML/Element/video)
9281   * HTML5 element.
9282   *
9283   * @example
9284   *
9285   * ```js
9286   * var videoUrl = 'https://www.mapbox.com/bites/00188/patricia_nasa.webm',
9287   * 	videoBounds = [[ 32, -130], [ 13, -100]];
9288   * L.videoOverlay(videoUrl, videoBounds ).addTo(map);
9289   * ```
9290   */
9291
9292  var VideoOverlay = ImageOverlay.extend({
9293
9294  	// @section
9295  	// @aka VideoOverlay options
9296  	options: {
9297  		// @option autoplay: Boolean = true
9298  		// Whether the video starts playing automatically when loaded.
9299  		autoplay: true,
9300
9301  		// @option loop: Boolean = true
9302  		// Whether the video will loop back to the beginning when played.
9303  		loop: true,
9304
9305  		// @option keepAspectRatio: Boolean = true
9306  		// Whether the video will save aspect ratio after the projection.
9307  		// Relevant for supported browsers. See [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)
9308  		keepAspectRatio: true,
9309
9310  		// @option muted: Boolean = false
9311  		// Whether the video starts on mute when loaded.
9312  		muted: false
9313  	},
9314
9315  	_initImage: function () {
9316  		var wasElementSupplied = this._url.tagName === 'VIDEO';
9317  		var vid = this._image = wasElementSupplied ? this._url : create$1('video');
9318
9319  		addClass(vid, 'leaflet-image-layer');
9320  		if (this._zoomAnimated) { addClass(vid, 'leaflet-zoom-animated'); }
9321  		if (this.options.className) { addClass(vid, this.options.className); }
9322
9323  		vid.onselectstart = falseFn;
9324  		vid.onmousemove = falseFn;
9325
9326  		// @event load: Event
9327  		// Fired when the video has finished loading the first frame
9328  		vid.onloadeddata = bind(this.fire, this, 'load');
9329
9330  		if (wasElementSupplied) {
9331  			var sourceElements = vid.getElementsByTagName('source');
9332  			var sources = [];
9333  			for (var j = 0; j < sourceElements.length; j++) {
9334  				sources.push(sourceElements[j].src);
9335  			}
9336
9337  			this._url = (sourceElements.length > 0) ? sources : [vid.src];
9338  			return;
9339  		}
9340
9341  		if (!isArray(this._url)) { this._url = [this._url]; }
9342
9343  		if (!this.options.keepAspectRatio && Object.prototype.hasOwnProperty.call(vid.style, 'objectFit')) {
9344  			vid.style['objectFit'] = 'fill';
9345  		}
9346  		vid.autoplay = !!this.options.autoplay;
9347  		vid.loop = !!this.options.loop;
9348  		vid.muted = !!this.options.muted;
9349  		for (var i = 0; i < this._url.length; i++) {
9350  			var source = create$1('source');
9351  			source.src = this._url[i];
9352  			vid.appendChild(source);
9353  		}
9354  	}
9355
9356  	// @method getElement(): HTMLVideoElement
9357  	// Returns the instance of [`HTMLVideoElement`](https://developer.mozilla.org/docs/Web/API/HTMLVideoElement)
9358  	// used by this overlay.
9359  });
9360
9361
9362  // @factory L.videoOverlay(video: String|Array|HTMLVideoElement, bounds: LatLngBounds, options?: VideoOverlay options)
9363  // Instantiates an image overlay object given the URL of the video (or array of URLs, or even a video element) and the
9364  // geographical bounds it is tied to.
9365
9366  function videoOverlay(video, bounds, options) {
9367  	return new VideoOverlay(video, bounds, options);
9368  }
9369
9370  /*
9371   * @class SVGOverlay
9372   * @aka L.SVGOverlay
9373   * @inherits ImageOverlay
9374   *
9375   * Used to load, display and provide DOM access to an SVG file over specific bounds of the map. Extends `ImageOverlay`.
9376   *
9377   * An SVG overlay uses the [`<svg>`](https://developer.mozilla.org/docs/Web/SVG/Element/svg) element.
9378   *
9379   * @example
9380   *
9381   * ```js
9382   * var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
9383   * svgElement.setAttribute('xmlns', "http://www.w3.org/2000/svg");
9384   * svgElement.setAttribute('viewBox', "0 0 200 200");
9385   * svgElement.innerHTML = '<rect width="200" height="200"/><rect x="75" y="23" width="50" height="50" style="fill:red"/><rect x="75" y="123" width="50" height="50" style="fill:#0013ff"/>';
9386   * var svgElementBounds = [ [ 32, -130 ], [ 13, -100 ] ];
9387   * L.svgOverlay(svgElement, svgElementBounds).addTo(map);
9388   * ```
9389   */
9390
9391  var SVGOverlay = ImageOverlay.extend({
9392  	_initImage: function () {
9393  		var el = this._image = this._url;
9394
9395  		addClass(el, 'leaflet-image-layer');
9396  		if (this._zoomAnimated) { addClass(el, 'leaflet-zoom-animated'); }
9397  		if (this.options.className) { addClass(el, this.options.className); }
9398
9399  		el.onselectstart = falseFn;
9400  		el.onmousemove = falseFn;
9401  	}
9402
9403  	// @method getElement(): SVGElement
9404  	// Returns the instance of [`SVGElement`](https://developer.mozilla.org/docs/Web/API/SVGElement)
9405  	// used by this overlay.
9406  });
9407
9408
9409  // @factory L.svgOverlay(svg: String|SVGElement, bounds: LatLngBounds, options?: SVGOverlay options)
9410  // Instantiates an image overlay object given an SVG element and the geographical bounds it is tied to.
9411  // A viewBox attribute is required on the SVG element to zoom in and out properly.
9412
9413  function svgOverlay(el, bounds, options) {
9414  	return new SVGOverlay(el, bounds, options);
9415  }
9416
9417  /*
9418   * @class DivOverlay
9419   * @inherits Layer
9420   * @aka L.DivOverlay
9421   * Base model for L.Popup and L.Tooltip. Inherit from it for custom popup like plugins.
9422   */
9423
9424  // @namespace DivOverlay
9425  var DivOverlay = Layer.extend({
9426
9427  	// @section
9428  	// @aka DivOverlay options
9429  	options: {
9430  		// @option offset: Point = Point(0, 7)
9431  		// The offset of the popup position. Useful to control the anchor
9432  		// of the popup when opening it on some overlays.
9433  		offset: [0, 7],
9434
9435  		// @option className: String = ''
9436  		// A custom CSS class name to assign to the popup.
9437  		className: '',
9438
9439  		// @option pane: String = 'popupPane'
9440  		// `Map pane` where the popup will be added.
9441  		pane: 'popupPane'
9442  	},
9443
9444  	initialize: function (options, source) {
9445  		setOptions(this, options);
9446
9447  		this._source = source;
9448  	},
9449
9450  	onAdd: function (map) {
9451  		this._zoomAnimated = map._zoomAnimated;
9452
9453  		if (!this._container) {
9454  			this._initLayout();
9455  		}
9456
9457  		if (map._fadeAnimated) {
9458  			setOpacity(this._container, 0);
9459  		}
9460
9461  		clearTimeout(this._removeTimeout);
9462  		this.getPane().appendChild(this._container);
9463  		this.update();
9464
9465  		if (map._fadeAnimated) {
9466  			setOpacity(this._container, 1);
9467  		}
9468
9469  		this.bringToFront();
9470  	},
9471
9472  	onRemove: function (map) {
9473  		if (map._fadeAnimated) {
9474  			setOpacity(this._container, 0);
9475  			this._removeTimeout = setTimeout(bind(remove, undefined, this._container), 200);
9476  		} else {
9477  			remove(this._container);
9478  		}
9479  	},
9480
9481  	// @namespace Popup
9482  	// @method getLatLng: LatLng
9483  	// Returns the geographical point of popup.
9484  	getLatLng: function () {
9485  		return this._latlng;
9486  	},
9487
9488  	// @method setLatLng(latlng: LatLng): this
9489  	// Sets the geographical point where the popup will open.
9490  	setLatLng: function (latlng) {
9491  		this._latlng = toLatLng(latlng);
9492  		if (this._map) {
9493  			this._updatePosition();
9494  			this._adjustPan();
9495  		}
9496  		return this;
9497  	},
9498
9499  	// @method getContent: String|HTMLElement
9500  	// Returns the content of the popup.
9501  	getContent: function () {
9502  		return this._content;
9503  	},
9504
9505  	// @method setContent(htmlContent: String|HTMLElement|Function): this
9506  	// Sets the HTML content of the popup. If a function is passed the source layer will be passed to the function. The function should return a `String` or `HTMLElement` to be used in the popup.
9507  	setContent: function (content) {
9508  		this._content = content;
9509  		this.update();
9510  		return this;
9511  	},
9512
9513  	// @method getElement: String|HTMLElement
9514  	// Returns the HTML container of the popup.
9515  	getElement: function () {
9516  		return this._container;
9517  	},
9518
9519  	// @method update: null
9520  	// Updates the popup content, layout and position. Useful for updating the popup after something inside changed, e.g. image loaded.
9521  	update: function () {
9522  		if (!this._map) { return; }
9523
9524  		this._container.style.visibility = 'hidden';
9525
9526  		this._updateContent();
9527  		this._updateLayout();
9528  		this._updatePosition();
9529
9530  		this._container.style.visibility = '';
9531
9532  		this._adjustPan();
9533  	},
9534
9535  	getEvents: function () {
9536  		var events = {
9537  			zoom: this._updatePosition,
9538  			viewreset: this._updatePosition
9539  		};
9540
9541  		if (this._zoomAnimated) {
9542  			events.zoomanim = this._animateZoom;
9543  		}
9544  		return events;
9545  	},
9546
9547  	// @method isOpen: Boolean
9548  	// Returns `true` when the popup is visible on the map.
9549  	isOpen: function () {
9550  		return !!this._map && this._map.hasLayer(this);
9551  	},
9552
9553  	// @method bringToFront: this
9554  	// Brings this popup in front of other popups (in the same map pane).
9555  	bringToFront: function () {
9556  		if (this._map) {
9557  			toFront(this._container);
9558  		}
9559  		return this;
9560  	},
9561
9562  	// @method bringToBack: this
9563  	// Brings this popup to the back of other popups (in the same map pane).
9564  	bringToBack: function () {
9565  		if (this._map) {
9566  			toBack(this._container);
9567  		}
9568  		return this;
9569  	},
9570
9571  	// prepare bound overlay to open: update latlng pos / content source (for FeatureGroup)
9572  	_prepareOpen: function (latlng) {
9573  		var source = this._source;
9574  		if (!source._map) { return false; }
9575
9576  		if (source instanceof FeatureGroup) {
9577  			source = null;
9578  			var layers = this._source._layers;
9579  			for (var id in layers) {
9580  				if (layers[id]._map) {
9581  					source = layers[id];
9582  					break;
9583  				}
9584  			}
9585  			if (!source) { return false; } // Unable to get source layer.
9586
9587  			// set overlay source to this layer
9588  			this._source = source;
9589  		}
9590
9591  		if (!latlng) {
9592  			if (source.getCenter) {
9593  				latlng = source.getCenter();
9594  			} else if (source.getLatLng) {
9595  				latlng = source.getLatLng();
9596  			} else if (source.getBounds) {
9597  				latlng = source.getBounds().getCenter();
9598  			} else {
9599  				throw new Error('Unable to get source layer LatLng.');
9600  			}
9601  		}
9602  		this.setLatLng(latlng);
9603
9604  		if (this._map) {
9605  			// update the overlay (content, layout, etc...)
9606  			this.update();
9607  		}
9608
9609  		return true;
9610  	},
9611
9612  	_updateContent: function () {
9613  		if (!this._content) { return; }
9614
9615  		var node = this._contentNode;
9616  		var content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content;
9617
9618  		if (typeof content === 'string') {
9619  			node.innerHTML = content;
9620  		} else {
9621  			while (node.hasChildNodes()) {
9622  				node.removeChild(node.firstChild);
9623  			}
9624  			node.appendChild(content);
9625  		}
9626  		this.fire('contentupdate');
9627  	},
9628
9629  	_updatePosition: function () {
9630  		if (!this._map) { return; }
9631
9632  		var pos = this._map.latLngToLayerPoint(this._latlng),
9633  		    offset = toPoint(this.options.offset),
9634  		    anchor = this._getAnchor();
9635
9636  		if (this._zoomAnimated) {
9637  			setPosition(this._container, pos.add(anchor));
9638  		} else {
9639  			offset = offset.add(pos).add(anchor);
9640  		}
9641
9642  		var bottom = this._containerBottom = -offset.y,
9643  		    left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;
9644
9645  		// bottom position the popup in case the height of the popup changes (images loading etc)
9646  		this._container.style.bottom = bottom + 'px';
9647  		this._container.style.left = left + 'px';
9648  	},
9649
9650  	_getAnchor: function () {
9651  		return [0, 0];
9652  	}
9653
9654  });
9655
9656  /*
9657   * @class Popup
9658   * @inherits DivOverlay
9659   * @aka L.Popup
9660   * Used to open popups in certain places of the map. Use [Map.openPopup](#map-openpopup) to
9661   * open popups while making sure that only one popup is open at one time
9662   * (recommended for usability), or use [Map.addLayer](#map-addlayer) to open as many as you want.
9663   *
9664   * @example
9665   *
9666   * If you want to just bind a popup to marker click and then open it, it's really easy:
9667   *
9668   * ```js
9669   * marker.bindPopup(popupContent).openPopup();
9670   * ```
9671   * Path overlays like polylines also have a `bindPopup` method.
9672   * Here's a more complicated way to open a popup on a map:
9673   *
9674   * ```js
9675   * var popup = L.popup()
9676   * 	.setLatLng(latlng)
9677   * 	.setContent('<p>Hello world!<br />This is a nice popup.</p>')
9678   * 	.openOn(map);
9679   * ```
9680   */
9681
9682
9683  // @namespace Popup
9684  var Popup = DivOverlay.extend({
9685
9686  	// @section
9687  	// @aka Popup options
9688  	options: {
9689  		// @option maxWidth: Number = 300
9690  		// Max width of the popup, in pixels.
9691  		maxWidth: 300,
9692
9693  		// @option minWidth: Number = 50
9694  		// Min width of the popup, in pixels.
9695  		minWidth: 50,
9696
9697  		// @option maxHeight: Number = null
9698  		// If set, creates a scrollable container of the given height
9699  		// inside a popup if its content exceeds it.
9700  		maxHeight: null,
9701
9702  		// @option autoPan: Boolean = true
9703  		// Set it to `false` if you don't want the map to do panning animation
9704  		// to fit the opened popup.
9705  		autoPan: true,
9706
9707  		// @option autoPanPaddingTopLeft: Point = null
9708  		// The margin between the popup and the top left corner of the map
9709  		// view after autopanning was performed.
9710  		autoPanPaddingTopLeft: null,
9711
9712  		// @option autoPanPaddingBottomRight: Point = null
9713  		// The margin between the popup and the bottom right corner of the map
9714  		// view after autopanning was performed.
9715  		autoPanPaddingBottomRight: null,
9716
9717  		// @option autoPanPadding: Point = Point(5, 5)
9718  		// Equivalent of setting both top left and bottom right autopan padding to the same value.
9719  		autoPanPadding: [5, 5],
9720
9721  		// @option keepInView: Boolean = false
9722  		// Set it to `true` if you want to prevent users from panning the popup
9723  		// off of the screen while it is open.
9724  		keepInView: false,
9725
9726  		// @option closeButton: Boolean = true
9727  		// Controls the presence of a close button in the popup.
9728  		closeButton: true,
9729
9730  		// @option autoClose: Boolean = true
9731  		// Set it to `false` if you want to override the default behavior of
9732  		// the popup closing when another popup is opened.
9733  		autoClose: true,
9734
9735  		// @option closeOnEscapeKey: Boolean = true
9736  		// Set it to `false` if you want to override the default behavior of
9737  		// the ESC key for closing of the popup.
9738  		closeOnEscapeKey: true,
9739
9740  		// @option closeOnClick: Boolean = *
9741  		// Set it if you want to override the default behavior of the popup closing when user clicks
9742  		// on the map. Defaults to the map's [`closePopupOnClick`](#map-closepopuponclick) option.
9743
9744  		// @option className: String = ''
9745  		// A custom CSS class name to assign to the popup.
9746  		className: ''
9747  	},
9748
9749  	// @namespace Popup
9750  	// @method openOn(map: Map): this
9751  	// Adds the popup to the map and closes the previous one. The same as `map.openPopup(popup)`.
9752  	openOn: function (map) {
9753  		map.openPopup(this);
9754  		return this;
9755  	},
9756
9757  	onAdd: function (map) {
9758  		DivOverlay.prototype.onAdd.call(this, map);
9759
9760  		// @namespace Map
9761  		// @section Popup events
9762  		// @event popupopen: PopupEvent
9763  		// Fired when a popup is opened in the map
9764  		map.fire('popupopen', {popup: this});
9765
9766  		if (this._source) {
9767  			// @namespace Layer
9768  			// @section Popup events
9769  			// @event popupopen: PopupEvent
9770  			// Fired when a popup bound to this layer is opened
9771  			this._source.fire('popupopen', {popup: this}, true);
9772  			// For non-path layers, we toggle the popup when clicking
9773  			// again the layer, so prevent the map to reopen it.
9774  			if (!(this._source instanceof Path)) {
9775  				this._source.on('preclick', stopPropagation);
9776  			}
9777  		}
9778  	},
9779
9780  	onRemove: function (map) {
9781  		DivOverlay.prototype.onRemove.call(this, map);
9782
9783  		// @namespace Map
9784  		// @section Popup events
9785  		// @event popupclose: PopupEvent
9786  		// Fired when a popup in the map is closed
9787  		map.fire('popupclose', {popup: this});
9788
9789  		if (this._source) {
9790  			// @namespace Layer
9791  			// @section Popup events
9792  			// @event popupclose: PopupEvent
9793  			// Fired when a popup bound to this layer is closed
9794  			this._source.fire('popupclose', {popup: this}, true);
9795  			if (!(this._source instanceof Path)) {
9796  				this._source.off('preclick', stopPropagation);
9797  			}
9798  		}
9799  	},
9800
9801  	getEvents: function () {
9802  		var events = DivOverlay.prototype.getEvents.call(this);
9803
9804  		if (this.options.closeOnClick !== undefined ? this.options.closeOnClick : this._map.options.closePopupOnClick) {
9805  			events.preclick = this._close;
9806  		}
9807
9808  		if (this.options.keepInView) {
9809  			events.moveend = this._adjustPan;
9810  		}
9811
9812  		return events;
9813  	},
9814
9815  	_close: function () {
9816  		if (this._map) {
9817  			this._map.closePopup(this);
9818  		}
9819  	},
9820
9821  	_initLayout: function () {
9822  		var prefix = 'leaflet-popup',
9823  		    container = this._container = create$1('div',
9824  			prefix + ' ' + (this.options.className || '') +
9825  			' leaflet-zoom-animated');
9826
9827  		var wrapper = this._wrapper = create$1('div', prefix + '-content-wrapper', container);
9828  		this._contentNode = create$1('div', prefix + '-content', wrapper);
9829
9830  		disableClickPropagation(container);
9831  		disableScrollPropagation(this._contentNode);
9832  		on(container, 'contextmenu', stopPropagation);
9833
9834  		this._tipContainer = create$1('div', prefix + '-tip-container', container);
9835  		this._tip = create$1('div', prefix + '-tip', this._tipContainer);
9836
9837  		if (this.options.closeButton) {
9838  			var closeButton = this._closeButton = create$1('a', prefix + '-close-button', container);
9839  			closeButton.setAttribute('role', 'button'); // overrides the implicit role=link of <a> elements #7399
9840  			closeButton.setAttribute('aria-label', 'Close popup');
9841  			closeButton.href = '#close';
9842  			closeButton.innerHTML = '<span aria-hidden="true">&#215;</span>';
9843
9844  			on(closeButton, 'click', this._close, this);
9845  		}
9846  	},
9847
9848  	_updateLayout: function () {
9849  		var container = this._contentNode,
9850  		    style = container.style;
9851
9852  		style.width = '';
9853  		style.whiteSpace = 'nowrap';
9854
9855  		var width = container.offsetWidth;
9856  		width = Math.min(width, this.options.maxWidth);
9857  		width = Math.max(width, this.options.minWidth);
9858
9859  		style.width = (width + 1) + 'px';
9860  		style.whiteSpace = '';
9861
9862  		style.height = '';
9863
9864  		var height = container.offsetHeight,
9865  		    maxHeight = this.options.maxHeight,
9866  		    scrolledClass = 'leaflet-popup-scrolled';
9867
9868  		if (maxHeight && height > maxHeight) {
9869  			style.height = maxHeight + 'px';
9870  			addClass(container, scrolledClass);
9871  		} else {
9872  			removeClass(container, scrolledClass);
9873  		}
9874
9875  		this._containerWidth = this._container.offsetWidth;
9876  	},
9877
9878  	_animateZoom: function (e) {
9879  		var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center),
9880  		    anchor = this._getAnchor();
9881  		setPosition(this._container, pos.add(anchor));
9882  	},
9883
9884  	_adjustPan: function (e) {
9885  		if (!this.options.autoPan) { return; }
9886  		if (this._map._panAnim) { this._map._panAnim.stop(); }
9887
9888  		var map = this._map,
9889  		    marginBottom = parseInt(getStyle(this._container, 'marginBottom'), 10) || 0,
9890  		    containerHeight = this._container.offsetHeight + marginBottom,
9891  		    containerWidth = this._containerWidth,
9892  		    layerPos = new Point(this._containerLeft, -containerHeight - this._containerBottom);
9893
9894  		layerPos._add(getPosition(this._container));
9895
9896  		var containerPos = map.layerPointToContainerPoint(layerPos),
9897  		    padding = toPoint(this.options.autoPanPadding),
9898  		    paddingTL = toPoint(this.options.autoPanPaddingTopLeft || padding),
9899  		    paddingBR = toPoint(this.options.autoPanPaddingBottomRight || padding),
9900  		    size = map.getSize(),
9901  		    dx = 0,
9902  		    dy = 0;
9903
9904  		if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right
9905  			dx = containerPos.x + containerWidth - size.x + paddingBR.x;
9906  		}
9907  		if (containerPos.x - dx - paddingTL.x < 0) { // left
9908  			dx = containerPos.x - paddingTL.x;
9909  		}
9910  		if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom
9911  			dy = containerPos.y + containerHeight - size.y + paddingBR.y;
9912  		}
9913  		if (containerPos.y - dy - paddingTL.y < 0) { // top
9914  			dy = containerPos.y - paddingTL.y;
9915  		}
9916
9917  		// @namespace Map
9918  		// @section Popup events
9919  		// @event autopanstart: Event
9920  		// Fired when the map starts autopanning when opening a popup.
9921  		if (dx || dy) {
9922  			map
9923  			    .fire('autopanstart')
9924  			    .panBy([dx, dy], {animate: e && e.type === 'moveend'});
9925  		}
9926  	},
9927
9928  	_getAnchor: function () {
9929  		// Where should we anchor the popup on the source layer?
9930  		return toPoint(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]);
9931  	}
9932
9933  });
9934
9935  // @namespace Popup
9936  // @factory L.popup(options?: Popup options, source?: Layer)
9937  // Instantiates a `Popup` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the popup with a reference to the Layer to which it refers.
9938  var popup = function (options, source) {
9939  	return new Popup(options, source);
9940  };
9941
9942
9943  /* @namespace Map
9944   * @section Interaction Options
9945   * @option closePopupOnClick: Boolean = true
9946   * Set it to `false` if you don't want popups to close when user clicks the map.
9947   */
9948  Map.mergeOptions({
9949  	closePopupOnClick: true
9950  });
9951
9952
9953  // @namespace Map
9954  // @section Methods for Layers and Controls
9955  Map.include({
9956  	// @method openPopup(popup: Popup): this
9957  	// Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability).
9958  	// @alternative
9959  	// @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this
9960  	// Creates a popup with the specified content and options and opens it in the given point on a map.
9961  	openPopup: function (popup, latlng, options) {
9962  		if (!(popup instanceof Popup)) {
9963  			popup = new Popup(options).setContent(popup);
9964  		}
9965
9966  		if (latlng) {
9967  			popup.setLatLng(latlng);
9968  		}
9969
9970  		if (this.hasLayer(popup)) {
9971  			return this;
9972  		}
9973
9974  		if (this._popup && this._popup.options.autoClose) {
9975  			this.closePopup();
9976  		}
9977
9978  		this._popup = popup;
9979  		return this.addLayer(popup);
9980  	},
9981
9982  	// @method closePopup(popup?: Popup): this
9983  	// Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one).
9984  	closePopup: function (popup) {
9985  		if (!popup || popup === this._popup) {
9986  			popup = this._popup;
9987  			this._popup = null;
9988  		}
9989  		if (popup) {
9990  			this.removeLayer(popup);
9991  		}
9992  		return this;
9993  	}
9994  });
9995
9996  /*
9997   * @namespace Layer
9998   * @section Popup methods example
9999   *
10000   * All layers share a set of methods convenient for binding popups to it.
10001   *
10002   * ```js
10003   * var layer = L.Polygon(latlngs).bindPopup('Hi There!').addTo(map);
10004   * layer.openPopup();
10005   * layer.closePopup();
10006   * ```
10007   *
10008   * Popups will also be automatically opened when the layer is clicked on and closed when the layer is removed from the map or another popup is opened.
10009   */
10010
10011  // @section Popup methods
10012  Layer.include({
10013
10014  	// @method bindPopup(content: String|HTMLElement|Function|Popup, options?: Popup options): this
10015  	// Binds a popup to the layer with the passed `content` and sets up the
10016  	// necessary event listeners. If a `Function` is passed it will receive
10017  	// the layer as the first argument and should return a `String` or `HTMLElement`.
10018  	bindPopup: function (content, options) {
10019
10020  		if (content instanceof Popup) {
10021  			setOptions(content, options);
10022  			this._popup = content;
10023  			content._source = this;
10024  		} else {
10025  			if (!this._popup || options) {
10026  				this._popup = new Popup(options, this);
10027  			}
10028  			this._popup.setContent(content);
10029  		}
10030
10031  		if (!this._popupHandlersAdded) {
10032  			this.on({
10033  				click: this._openPopup,
10034  				keypress: this._onKeyPress,
10035  				remove: this.closePopup,
10036  				move: this._movePopup
10037  			});
10038  			this._popupHandlersAdded = true;
10039  		}
10040
10041  		return this;
10042  	},
10043
10044  	// @method unbindPopup(): this
10045  	// Removes the popup previously bound with `bindPopup`.
10046  	unbindPopup: function () {
10047  		if (this._popup) {
10048  			this.off({
10049  				click: this._openPopup,
10050  				keypress: this._onKeyPress,
10051  				remove: this.closePopup,
10052  				move: this._movePopup
10053  			});
10054  			this._popupHandlersAdded = false;
10055  			this._popup = null;
10056  		}
10057  		return this;
10058  	},
10059
10060  	// @method openPopup(latlng?: LatLng): this
10061  	// Opens the bound popup at the specified `latlng` or at the default popup anchor if no `latlng` is passed.
10062  	openPopup: function (latlng) {
10063  		if (this._popup && this._popup._prepareOpen(latlng)) {
10064  			// open the popup on the map
10065  			this._map.openPopup(this._popup, latlng);
10066  		}
10067
10068  		return this;
10069  	},
10070
10071  	// @method closePopup(): this
10072  	// Closes the popup bound to this layer if it is open.
10073  	closePopup: function () {
10074  		if (this._popup) {
10075  			this._popup._close();
10076  		}
10077  		return this;
10078  	},
10079
10080  	// @method togglePopup(): this
10081  	// Opens or closes the popup bound to this layer depending on its current state.
10082  	togglePopup: function () {
10083  		if (this._popup) {
10084  			if (this._popup._map) {
10085  				this.closePopup();
10086  			} else {
10087  				this.openPopup();
10088  			}
10089  		}
10090  		return this;
10091  	},
10092
10093  	// @method isPopupOpen(): boolean
10094  	// Returns `true` if the popup bound to this layer is currently open.
10095  	isPopupOpen: function () {
10096  		return (this._popup ? this._popup.isOpen() : false);
10097  	},
10098
10099  	// @method setPopupContent(content: String|HTMLElement|Popup): this
10100  	// Sets the content of the popup bound to this layer.
10101  	setPopupContent: function (content) {
10102  		if (this._popup) {
10103  			this._popup.setContent(content);
10104  		}
10105  		return this;
10106  	},
10107
10108  	// @method getPopup(): Popup
10109  	// Returns the popup bound to this layer.
10110  	getPopup: function () {
10111  		return this._popup;
10112  	},
10113
10114  	_openPopup: function (e) {
10115  		if (!this._popup || !this._map) {
10116  			return;
10117  		}
10118  		// prevent map click
10119  		stop(e);
10120
10121  		var target = e.layer || e.target;
10122  		if (this._popup._source === target && !(target instanceof Path)) {
10123  			// treat it like a marker and figure out
10124  			// if we should toggle it open/closed
10125  			if (this._map.hasLayer(this._popup)) {
10126  				this.closePopup();
10127  			} else {
10128  				this.openPopup(e.latlng);
10129  			}
10130  			return;
10131  		}
10132  		this._popup._source = target;
10133  		this.openPopup(e.latlng);
10134  	},
10135
10136  	_movePopup: function (e) {
10137  		this._popup.setLatLng(e.latlng);
10138  	},
10139
10140  	_onKeyPress: function (e) {
10141  		if (e.originalEvent.keyCode === 13) {
10142  			this._openPopup(e);
10143  		}
10144  	}
10145  });
10146
10147  /*
10148   * @class Tooltip
10149   * @inherits DivOverlay
10150   * @aka L.Tooltip
10151   * Used to display small texts on top of map layers.
10152   *
10153   * @example
10154   *
10155   * ```js
10156   * marker.bindTooltip("my tooltip text").openTooltip();
10157   * ```
10158   * Note about tooltip offset. Leaflet takes two options in consideration
10159   * for computing tooltip offsetting:
10160   * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.
10161   *   Add a positive x offset to move the tooltip to the right, and a positive y offset to
10162   *   move it to the bottom. Negatives will move to the left and top.
10163   * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You
10164   *   should adapt this value if you use a custom icon.
10165   */
10166
10167
10168  // @namespace Tooltip
10169  var Tooltip = DivOverlay.extend({
10170
10171  	// @section
10172  	// @aka Tooltip options
10173  	options: {
10174  		// @option pane: String = 'tooltipPane'
10175  		// `Map pane` where the tooltip will be added.
10176  		pane: 'tooltipPane',
10177
10178  		// @option offset: Point = Point(0, 0)
10179  		// Optional offset of the tooltip position.
10180  		offset: [0, 0],
10181
10182  		// @option direction: String = 'auto'
10183  		// Direction where to open the tooltip. Possible values are: `right`, `left`,
10184  		// `top`, `bottom`, `center`, `auto`.
10185  		// `auto` will dynamically switch between `right` and `left` according to the tooltip
10186  		// position on the map.
10187  		direction: 'auto',
10188
10189  		// @option permanent: Boolean = false
10190  		// Whether to open the tooltip permanently or only on mouseover.
10191  		permanent: false,
10192
10193  		// @option sticky: Boolean = false
10194  		// If true, the tooltip will follow the mouse instead of being fixed at the feature center.
10195  		sticky: false,
10196
10197  		// @option interactive: Boolean = false
10198  		// If true, the tooltip will listen to the feature events.
10199  		interactive: false,
10200
10201  		// @option opacity: Number = 0.9
10202  		// Tooltip container opacity.
10203  		opacity: 0.9
10204  	},
10205
10206  	onAdd: function (map) {
10207  		DivOverlay.prototype.onAdd.call(this, map);
10208  		this.setOpacity(this.options.opacity);
10209
10210  		if (this.options.interactive) {
10211  			addClass(this._container, 'leaflet-interactive');
10212  			if (this._source) {
10213  				this._source.addInteractiveTarget(this._container);
10214  			}
10215  		}
10216
10217  		// @namespace Map
10218  		// @section Tooltip events
10219  		// @event tooltipopen: TooltipEvent
10220  		// Fired when a tooltip is opened in the map.
10221  		map.fire('tooltipopen', {tooltip: this});
10222
10223  		if (this._source) {
10224  			// @namespace Layer
10225  			// @section Tooltip events
10226  			// @event tooltipopen: TooltipEvent
10227  			// Fired when a tooltip bound to this layer is opened.
10228  			this._source.fire('tooltipopen', {tooltip: this}, true);
10229  		}
10230  	},
10231
10232  	onRemove: function (map) {
10233  		DivOverlay.prototype.onRemove.call(this, map);
10234
10235  		if (this.options.interactive) {
10236  			removeClass(this._container, 'leaflet-interactive');
10237  			if (this._source) {
10238  				this._source.removeInteractiveTarget(this._container);
10239  			}
10240  		}
10241
10242  		// @namespace Map
10243  		// @section Tooltip events
10244  		// @event tooltipclose: TooltipEvent
10245  		// Fired when a tooltip in the map is closed.
10246  		map.fire('tooltipclose', {tooltip: this});
10247
10248  		if (this._source) {
10249  			// @namespace Layer
10250  			// @section Tooltip events
10251  			// @event tooltipclose: TooltipEvent
10252  			// Fired when a tooltip bound to this layer is closed.
10253  			this._source.fire('tooltipclose', {tooltip: this}, true);
10254  		}
10255  	},
10256
10257  	getEvents: function () {
10258  		var events = DivOverlay.prototype.getEvents.call(this);
10259
10260  		if (!this.options.permanent) {
10261  			events.preclick = this._close;
10262  		}
10263
10264  		return events;
10265  	},
10266
10267  	_close: function () {
10268  		if (this._map) {
10269  			this._map.closeTooltip(this);
10270  		}
10271  	},
10272
10273  	_initLayout: function () {
10274  		var prefix = 'leaflet-tooltip',
10275  		    className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
10276
10277  		this._contentNode = this._container = create$1('div', className);
10278  	},
10279
10280  	_updateLayout: function () {},
10281
10282  	_adjustPan: function () {},
10283
10284  	_setPosition: function (pos) {
10285  		var subX, subY,
10286  		    map = this._map,
10287  		    container = this._container,
10288  		    centerPoint = map.latLngToContainerPoint(map.getCenter()),
10289  		    tooltipPoint = map.layerPointToContainerPoint(pos),
10290  		    direction = this.options.direction,
10291  		    tooltipWidth = container.offsetWidth,
10292  		    tooltipHeight = container.offsetHeight,
10293  		    offset = toPoint(this.options.offset),
10294  		    anchor = this._getAnchor();
10295
10296  		if (direction === 'top') {
10297  			subX = tooltipWidth / 2;
10298  			subY = tooltipHeight;
10299  		} else if (direction === 'bottom') {
10300  			subX = tooltipWidth / 2;
10301  			subY = 0;
10302  		} else if (direction === 'center') {
10303  			subX = tooltipWidth / 2;
10304  			subY = tooltipHeight / 2;
10305  		} else if (direction === 'right') {
10306  			subX = 0;
10307  			subY = tooltipHeight / 2;
10308  		} else if (direction === 'left') {
10309  			subX = tooltipWidth;
10310  			subY = tooltipHeight / 2;
10311  		} else if (tooltipPoint.x < centerPoint.x) {
10312  			direction = 'right';
10313  			subX = 0;
10314  			subY = tooltipHeight / 2;
10315  		} else {
10316  			direction = 'left';
10317  			subX = tooltipWidth + (offset.x + anchor.x) * 2;
10318  			subY = tooltipHeight / 2;
10319  		}
10320
10321  		pos = pos.subtract(toPoint(subX, subY, true)).add(offset).add(anchor);
10322
10323  		removeClass(container, 'leaflet-tooltip-right');
10324  		removeClass(container, 'leaflet-tooltip-left');
10325  		removeClass(container, 'leaflet-tooltip-top');
10326  		removeClass(container, 'leaflet-tooltip-bottom');
10327  		addClass(container, 'leaflet-tooltip-' + direction);
10328  		setPosition(container, pos);
10329  	},
10330
10331  	_updatePosition: function () {
10332  		var pos = this._map.latLngToLayerPoint(this._latlng);
10333  		this._setPosition(pos);
10334  	},
10335
10336  	setOpacity: function (opacity) {
10337  		this.options.opacity = opacity;
10338
10339  		if (this._container) {
10340  			setOpacity(this._container, opacity);
10341  		}
10342  	},
10343
10344  	_animateZoom: function (e) {
10345  		var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
10346  		this._setPosition(pos);
10347  	},
10348
10349  	_getAnchor: function () {
10350  		// Where should we anchor the tooltip on the source layer?
10351  		return toPoint(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);
10352  	}
10353
10354  });
10355
10356  // @namespace Tooltip
10357  // @factory L.tooltip(options?: Tooltip options, source?: Layer)
10358  // Instantiates a Tooltip object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers.
10359  var tooltip = function (options, source) {
10360  	return new Tooltip(options, source);
10361  };
10362
10363  // @namespace Map
10364  // @section Methods for Layers and Controls
10365  Map.include({
10366
10367  	// @method openTooltip(tooltip: Tooltip): this
10368  	// Opens the specified tooltip.
10369  	// @alternative
10370  	// @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this
10371  	// Creates a tooltip with the specified content and options and open it.
10372  	openTooltip: function (tooltip, latlng, options) {
10373  		if (!(tooltip instanceof Tooltip)) {
10374  			tooltip = new Tooltip(options).setContent(tooltip);
10375  		}
10376
10377  		if (latlng) {
10378  			tooltip.setLatLng(latlng);
10379  		}
10380
10381  		if (this.hasLayer(tooltip)) {
10382  			return this;
10383  		}
10384
10385  		return this.addLayer(tooltip);
10386  	},
10387
10388  	// @method closeTooltip(tooltip: Tooltip): this
10389  	// Closes the tooltip given as parameter.
10390  	closeTooltip: function (tooltip) {
10391  		return this.removeLayer(tooltip);
10392  	}
10393
10394  });
10395
10396  /*
10397   * @namespace Layer
10398   * @section Tooltip methods example
10399   *
10400   * All layers share a set of methods convenient for binding tooltips to it.
10401   *
10402   * ```js
10403   * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);
10404   * layer.openTooltip();
10405   * layer.closeTooltip();
10406   * ```
10407   */
10408
10409  // @section Tooltip methods
10410  Layer.include({
10411
10412  	// @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this
10413  	// Binds a tooltip to the layer with the passed `content` and sets up the
10414  	// necessary event listeners. If a `Function` is passed it will receive
10415  	// the layer as the first argument and should return a `String` or `HTMLElement`.
10416  	bindTooltip: function (content, options) {
10417
10418  		if (content instanceof Tooltip) {
10419  			setOptions(content, options);
10420  			this._tooltip = content;
10421  			content._source = this;
10422  		} else {
10423  			if (!this._tooltip || options) {
10424  				this._tooltip = new Tooltip(options, this);
10425  			}
10426  			this._tooltip.setContent(content);
10427
10428  		}
10429
10430  		this._initTooltipInteractions();
10431
10432  		if (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {
10433  			this.openTooltip();
10434  		}
10435
10436  		return this;
10437  	},
10438
10439  	// @method unbindTooltip(): this
10440  	// Removes the tooltip previously bound with `bindTooltip`.
10441  	unbindTooltip: function () {
10442  		if (this._tooltip) {
10443  			this._initTooltipInteractions(true);
10444  			this.closeTooltip();
10445  			this._tooltip = null;
10446  		}
10447  		return this;
10448  	},
10449
10450  	_initTooltipInteractions: function (remove) {
10451  		if (!remove && this._tooltipHandlersAdded) { return; }
10452  		var onOff = remove ? 'off' : 'on',
10453  		    events = {
10454  			remove: this.closeTooltip,
10455  			move: this._moveTooltip
10456  		    };
10457  		if (!this._tooltip.options.permanent) {
10458  			events.mouseover = this._openTooltip;
10459  			events.mouseout = this.closeTooltip;
10460  			if (this._tooltip.options.sticky) {
10461  				events.mousemove = this._moveTooltip;
10462  			}
10463  			events.click = this._openTooltip;
10464  		} else {
10465  			events.add = this._openTooltip;
10466  		}
10467  		this[onOff](events);
10468  		this._tooltipHandlersAdded = !remove;
10469  	},
10470
10471  	// @method openTooltip(latlng?: LatLng): this
10472  	// Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed.
10473  	openTooltip: function (latlng) {
10474  		if (this._tooltip && this._tooltip._prepareOpen(latlng)) {
10475  			// open the tooltip on the map
10476  			this._map.openTooltip(this._tooltip, latlng);
10477  		}
10478
10479  		return this;
10480  	},
10481
10482  	// @method closeTooltip(): this
10483  	// Closes the tooltip bound to this layer if it is open.
10484  	closeTooltip: function () {
10485  		if (this._tooltip) {
10486  			this._tooltip._close();
10487  		}
10488  		return this;
10489  	},
10490
10491  	// @method toggleTooltip(): this
10492  	// Opens or closes the tooltip bound to this layer depending on its current state.
10493  	toggleTooltip: function () {
10494  		if (this._tooltip) {
10495  			if (this._tooltip._map) {
10496  				this.closeTooltip();
10497  			} else {
10498  				this.openTooltip();
10499  			}
10500  		}
10501  		return this;
10502  	},
10503
10504  	// @method isTooltipOpen(): boolean
10505  	// Returns `true` if the tooltip bound to this layer is currently open.
10506  	isTooltipOpen: function () {
10507  		return this._tooltip.isOpen();
10508  	},
10509
10510  	// @method setTooltipContent(content: String|HTMLElement|Tooltip): this
10511  	// Sets the content of the tooltip bound to this layer.
10512  	setTooltipContent: function (content) {
10513  		if (this._tooltip) {
10514  			this._tooltip.setContent(content);
10515  		}
10516  		return this;
10517  	},
10518
10519  	// @method getTooltip(): Tooltip
10520  	// Returns the tooltip bound to this layer.
10521  	getTooltip: function () {
10522  		return this._tooltip;
10523  	},
10524
10525  	_openTooltip: function (e) {
10526  		if (!this._tooltip || !this._map) {
10527  			return;
10528  		}
10529  		this._tooltip._source = e.layer || e.target;
10530
10531  		this.openTooltip(this._tooltip.options.sticky ? e.latlng : undefined);
10532  	},
10533
10534  	_moveTooltip: function (e) {
10535  		var latlng = e.latlng, containerPoint, layerPoint;
10536  		if (this._tooltip.options.sticky && e.originalEvent) {
10537  			containerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);
10538  			layerPoint = this._map.containerPointToLayerPoint(containerPoint);
10539  			latlng = this._map.layerPointToLatLng(layerPoint);
10540  		}
10541  		this._tooltip.setLatLng(latlng);
10542  	}
10543  });
10544
10545  /*
10546   * @class DivIcon
10547   * @aka L.DivIcon
10548   * @inherits Icon
10549   *
10550   * Represents a lightweight icon for markers that uses a simple `<div>`
10551   * element instead of an image. Inherits from `Icon` but ignores the `iconUrl` and shadow options.
10552   *
10553   * @example
10554   * ```js
10555   * var myIcon = L.divIcon({className: 'my-div-icon'});
10556   * // you can set .my-div-icon styles in CSS
10557   *
10558   * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
10559   * ```
10560   *
10561   * By default, it has a 'leaflet-div-icon' CSS class and is styled as a little white square with a shadow.
10562   */
10563
10564  var DivIcon = Icon.extend({
10565  	options: {
10566  		// @section
10567  		// @aka DivIcon options
10568  		iconSize: [12, 12], // also can be set through CSS
10569
10570  		// iconAnchor: (Point),
10571  		// popupAnchor: (Point),
10572
10573  		// @option html: String|HTMLElement = ''
10574  		// Custom HTML code to put inside the div element, empty by default. Alternatively,
10575  		// an instance of `HTMLElement`.
10576  		html: false,
10577
10578  		// @option bgPos: Point = [0, 0]
10579  		// Optional relative position of the background, in pixels
10580  		bgPos: null,
10581
10582  		className: 'leaflet-div-icon'
10583  	},
10584
10585  	createIcon: function (oldIcon) {
10586  		var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),
10587  		    options = this.options;
10588
10589  		if (options.html instanceof Element) {
10590  			empty(div);
10591  			div.appendChild(options.html);
10592  		} else {
10593  			div.innerHTML = options.html !== false ? options.html : '';
10594  		}
10595
10596  		if (options.bgPos) {
10597  			var bgPos = toPoint(options.bgPos);
10598  			div.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px';
10599  		}
10600  		this._setIconStyles(div, 'icon');
10601
10602  		return div;
10603  	},
10604
10605  	createShadow: function () {
10606  		return null;
10607  	}
10608  });
10609
10610  // @factory L.divIcon(options: DivIcon options)
10611  // Creates a `DivIcon` instance with the given options.
10612  function divIcon(options) {
10613  	return new DivIcon(options);
10614  }
10615
10616  Icon.Default = IconDefault;
10617
10618  /*
10619   * @class GridLayer
10620   * @inherits Layer
10621   * @aka L.GridLayer
10622   *
10623   * Generic class for handling a tiled grid of HTML elements. This is the base class for all tile layers and replaces `TileLayer.Canvas`.
10624   * GridLayer can be extended to create a tiled grid of HTML elements like `<canvas>`, `<img>` or `<div>`. GridLayer will handle creating and animating these DOM elements for you.
10625   *
10626   *
10627   * @section Synchronous usage
10628   * @example
10629   *
10630   * To create a custom layer, extend GridLayer and implement the `createTile()` method, which will be passed a `Point` object with the `x`, `y`, and `z` (zoom level) coordinates to draw your tile.
10631   *
10632   * ```js
10633   * var CanvasLayer = L.GridLayer.extend({
10634   *     createTile: function(coords){
10635   *         // create a <canvas> element for drawing
10636   *         var tile = L.DomUtil.create('canvas', 'leaflet-tile');
10637   *
10638   *         // setup tile width and height according to the options
10639   *         var size = this.getTileSize();
10640   *         tile.width = size.x;
10641   *         tile.height = size.y;
10642   *
10643   *         // get a canvas context and draw something on it using coords.x, coords.y and coords.z
10644   *         var ctx = tile.getContext('2d');
10645   *
10646   *         // return the tile so it can be rendered on screen
10647   *         return tile;
10648   *     }
10649   * });
10650   * ```
10651   *
10652   * @section Asynchronous usage
10653   * @example
10654   *
10655   * Tile creation can also be asynchronous, this is useful when using a third-party drawing library. O
10655nce the tile is finished drawing it can be passed to the `done()` callback.
10656   *
10657   * ```js
10658   * var CanvasLayer = L.GridLayer.extend({
10659   *     createTile: function(coords, done){
10660   *         var error;
10661   *
10662   *         // create a <canvas> element for drawing
10663   *         var tile = L.DomUtil.create('canvas', 'leaflet-tile');
10664   *
10665   *         // setup tile width and height according to the options
10666   *         var size = this.getTileSize();
10667   *         tile.width = size.x;
10668   *         tile.height = size.y;
10669   *
10670   *         // draw something asynchronously and pass the tile to the done() callback
10671   *         setTimeout(function() {
10672   *             done(error, tile);
10673   *         }, 1000);
10674   *
10675   *         return tile;
10676   *     }
10677   * });
10678   * ```
10679   *
10680   * @section
10681   */
10682
10683
10684  var GridLayer = Layer.extend({
10685
10686  	// @section
10687  	// @aka GridLayer options
10688  	options: {
10689  		// @option tileSize: Number|Point = 256
10690  		// Width and height of tiles in the grid. Use a number if width and height are equal, or `L.point(width, height)` otherwise.
10691  		tileSize: 256,
10692
10693  		// @option opacity: Number = 1.0
10694  		// Opacity of the tiles. Can be used in the `createTile()` function.
10695  		opacity: 1,
10696
10697  		// @option updateWhenIdle: Boolean = (depends)
10698  		// Load new tiles only when panning ends.
10699  		// `true` by default on mobile browsers, in order to avoid too many requests and keep smooth navigation.
10700  		// `false` otherwise in order to display new tiles _during_ panning, since it is easy to pan outside the
10701  		// [`keepBuffer`](#gridlayer-keepbuffer) option in desktop browsers.
10702  		updateWhenIdle: mobile,
10703
10704  		// @option updateWhenZooming: Boolean = true
10705  		// By default, a smooth zoom animation (during a [touch zoom](#map-touchzoom) or a [`flyTo()`](#map-flyto)) will update grid layers every integer zoom level. Setting this option to `false` will update the grid layer only when the smooth animation ends.
10706  		updateWhenZooming: true,
10707
10708  		// @option updateInterval: Number = 200
10709  		// Tiles will not update more than once every `updateInterval` milliseconds when panning.
10710  		updateInterval: 200,
10711
10712  		// @option zIndex: Number = 1
10713  		// The explicit zIndex of the tile layer.
10714  		zIndex: 1,
10715
10716  		// @option bounds: LatLngBounds = undefined
10717  		// If set, tiles will only be loaded inside the set `LatLngBounds`.
10718  		bounds: null,
10719
10720  		// @option minZoom: Number = 0
10721  		// The minimum zoom level down to which this layer will be displayed (inclusive).
10722  		minZoom: 0,
10723
10724  		// @option maxZoom: Number = undefined
10725  		// The maximum zoom level up to which this layer will be displayed (inclusive).
10726  		maxZoom: undefined,
10727
10728  		// @option maxNativeZoom: Number = undefined
10729  		// Maximum zoom number the tile source has available. If it is specified,
10730  		// the tiles on all zoom levels higher than `maxNativeZoom` will be loaded
10731  		// from `maxNativeZoom` level and auto-scaled.
10732  		maxNativeZoom: undefined,
10733
10734  		// @option minNativeZoom: Number = undefined
10735  		// Minimum zoom number the tile source has available. If it is specified,
10736  		// the tiles on all zoom levels lower than `minNativeZoom` will be loaded
10737  		// from `minNativeZoom` level and auto-scaled.
10738  		minNativeZoom: undefined,
10739
10740  		// @option noWrap: Boolean = false
10741  		// Whether the layer is wrapped around the antimeridian. If `true`, the
10742  		// GridLayer will only be displayed once at low zoom levels. Has no
10743  		// effect when the [map CRS](#map-crs) doesn't wrap around. Can be used
10744  		// in combination with [`bounds`](#gridlayer-bounds) to prevent requesting
10745  		// tiles outside the CRS limits.
10746  		noWrap: false,
10747
10748  		// @option pane: String = 'tilePane'
10749  		// `Map pane` where the grid layer will be added.
10750  		pane: 'tilePane',
10751
10752  		// @option className: String = ''
10753  		// A custom class name to assign to the tile layer. Empty by default.
10754  		className: '',
10755
10756  		// @option keepBuffer: Number = 2
10757  		// When panning the map, keep this many rows and columns of tiles before unloading them.
10758  		keepBuffer: 2
10759  	},
10760
10761  	initialize: function (options) {
10762  		setOptions(this, options);
10763  	},
10764
10765  	onAdd: function () {
10766  		this._initContainer();
10767
10768  		this._levels = {};
10769  		this._tiles = {};
10770
10771  		this._resetView(); // implicit _update() call
10772  	},
10773
10774  	beforeAdd: function (map) {
vendor: 4,257 bytes, lines 10775-10923
10775  		map._addZoomLimit(this);
10776  	},
10777
10778  	onRemove: function (map) {
10779  		this._removeAllTiles();
10780  		remove(this._container);
10781  		map._removeZoomLimit(this);
10782  		this._container = null;
10783  		this._tileZoom = undefined;
10784  	},
10785
10786  	// @method bringToFront: this
10787  	// Brings the tile layer to the top of all tile layers.
10788  	bringToFront: function () {
10789  		if (this._map) {
10790  			toFront(this._container);
10791  			this._setAutoZIndex(Math.max);
10792  		}
10793  		return this;
10794  	},
10795
10796  	// @method bringToBack: this
10797  	// Brings the tile layer to the bottom of all tile layers.
10798  	bringToBack: function () {
10799  		if (this._map) {
10800  			toBack(this._container);
10801  			this._setAutoZIndex(Math.min);
10802  		}
10803  		return this;
10804  	},
10805
10806  	// @method getContainer: HTMLElement
10807  	// Returns the HTML element that contains the tiles for this layer.
10808  	getContainer: function () {
10809  		return this._container;
10810  	},
10811
10812  	// @method setOpacity(opacity: Number): this
10813  	// Changes the [opacity](#gridlayer-opacity) of the grid layer.
10814  	setOpacity: function (opacity) {
10815  		this.options.opacity = opacity;
10816  		this._updateOpacity();
10817  		return this;
10818  	},
10819
10820  	// @method setZIndex(zIndex: Number): this
10821  	// Changes the [zIndex](#gridlayer-zindex) of the grid layer.
10822  	setZIndex: function (zIndex) {
10823  		this.options.zIndex = zIndex;
10824  		this._updateZIndex();
10825
10826  		return this;
10827  	},
10828
10829  	// @method isLoading: Boolean
10830  	// Returns `true` if any tile in the grid layer has not finished loading.
10831  	isLoading: function () {
10832  		return this._loading;
10833  	},
10834
10835  	// @method redraw: this
10836  	// Causes the layer to clear all the tiles and request them again.
10837  	redraw: function () {
10838  		if (this._map) {
10839  			this._removeAllTiles();
10840  			var tileZoom = this._clampZoom(this._map.getZoom());
10841  			if (tileZoom !== this._tileZoom) {
10842  				this._tileZoom = tileZoom;
10843  				this._updateLevels();
10844  			}
10845  			this._update();
10846  		}
10847  		return this;
10848  	},
10849
10850  	getEvents: function () {
10851  		var events = {
10852  			viewprereset: this._invalidateAll,
10853  			viewreset: this._resetView,
10854  			zoom: this._resetView,
10855  			moveend: this._onMoveEnd
10856  		};
10857
10858  		if (!this.options.updateWhenIdle) {
10859  			// update tiles on move, but not more often than once per given interval
10860  			if (!this._onMove) {
10861  				this._onMove = throttle(this._onMoveEnd, this.options.updateInterval, this);
10862  			}
10863
10864  			events.move = this._onMove;
10865  		}
10866
10867  		if (this._zoomAnimated) {
10868  			events.zoomanim = this._animateZoom;
10869  		}
10870
10871  		return events;
10872  	},
10873
10874  	// @section Extension methods
10875  	// Layers extending `GridLayer` shall reimplement the following method.
10876  	// @method createTile(coords: Object, done?: Function): HTMLElement
10877  	// Called only internally, must be overridden by classes extending `GridLayer`.
10878  	// Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback
10879  	// is specified, it must be called when the tile has finished loading and drawing.
10880  	createTile: function () {
10881  		return document.createElement('div');
10882  	},
10883
10884  	// @section
10885  	// @method getTileSize: Point
10886  	// Normalizes the [tileSize option](#gridlayer-tilesize) into a point. Used by the `createTile()` method.
10887  	getTileSize: function () {
10888  		var s = this.options.tileSize;
10889  		return s instanceof Point ? s : new Point(s, s);
10890  	},
10891
10892  	_updateZIndex: function () {
10893  		if (this._container && this.options.zIndex !== undefined && this.options.zIndex !== null) {
10894  			this._container.style.zIndex = this.options.zIndex;
10895  		}
10896  	},
10897
10898  	_setAutoZIndex: function (compare) {
10899  		// go through all other layers of the same pane, set zIndex to max + 1 (front) or min - 1 (back)
10900
10901  		var layers = this.getPane().children,
10902  		    edgeZIndex = -compare(-Infinity, Infinity); // -Infinity for max, Infinity for min
10903
10904  		for (var i = 0, len = layers.length, zIndex; i < len; i++) {
10905
10906  			zIndex = layers[i].style.zIndex;
10907
10908  			if (layers[i] !== this._container && zIndex) {
10909  				edgeZIndex = compare(edgeZIndex, +zIndex);
10910  			}
10911  		}
10912
10913  		if (isFinite(edgeZIndex)) {
10914  			this.options.zIndex = edgeZIndex + compare(-1, 1);
10915  			this._updateZIndex();
10916  		}
10917  	},
10918
10919  	_updateOpacity: function () {
10920  		if (!this._map) { return; }
10921
10922  		// IE doesn't inherit filter opacity properly, so we're forced to set it on tiles
10923  		if (
vendor: 6,720 bytes, lines 10923-11209
10923ielt9) { return; }
10924
10925  		setOpacity(this._container, this.options.opacity);
10926
10927  		var now = +new Date(),
10928  		    nextFrame = false,
10929  		    willPrune = false;
10930
10931  		for (var key in this._tiles) {
10932  			var tile = this._tiles[key];
10933  			if (!tile.current || !tile.loaded) { continue; }
10934
10935  			var fade = Math.min(1, (now - tile.loaded) / 200);
10936
10937  			setOpacity(tile.el, fade);
10938  			if (fade < 1) {
10939  				nextFrame = true;
10940  			} else {
10941  				if (tile.active) {
10942  					willPrune = true;
10943  				} else {
10944  					this._onOpaqueTile(tile);
10945  				}
10946  				tile.active = true;
10947  			}
10948  		}
10949
10950  		if (willPrune && !this._noPrune) { this._pruneTiles(); }
10951
10952  		if (nextFrame) {
10953  			cancelAnimFrame(this._fadeFrame);
10954  			this._fadeFrame = requestAnimFrame(this._updateOpacity, this);
10955  		}
10956  	},
10957
10958  	_onOpaqueTile: falseFn,
10959
10960  	_initContainer: function () {
10961  		if (this._container) { return; }
10962
10963  		this._container = create$1('div', 'leaflet-layer ' + (this.options.className || ''));
10964  		this._updateZIndex();
10965
10966  		if (this.options.opacity < 1) {
10967  			this._updateOpacity();
10968  		}
10969
10970  		this.getPane().appendChild(this._container);
10971  	},
10972
10973  	_updateLevels: function () {
10974
10975  		var zoom = this._tileZoom,
10976  		    maxZoom = this.options.maxZoom;
10977
10978  		if (zoom === undefined) { return undefined; }
10979
10980  		for (var z in this._levels) {
10981  			z = Number(z);
10982  			if (this._levels[z].el.children.length || z === zoom) {
10983  				this._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z);
10984  				this._onUpdateLevel(z);
10985  			} else {
10986  				remove(this._levels[z].el);
10987  				this._removeTilesAtZoom(z);
10988  				this._onRemoveLevel(z);
10989  				delete this._levels[z];
10990  			}
10991  		}
10992
10993  		var level = this._levels[zoom],
10994  		    map = this._map;
10995
10996  		if (!level) {
10997  			level = this._levels[zoom] = {};
10998
10999  			level.el = create$1('div', 'leaflet-tile-container leaflet-zoom-animated', this._container);
11000  			level.el.style.zIndex = maxZoom;
11001
11002  			level.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round();
11003  			level.zoom = zoom;
11004
11005  			this._setZoomTransform(level, map.getCenter(), map.getZoom());
11006
11007  			// force the browser to consider the newly added element for transition
11008  			falseFn(level.el.offsetWidth);
11009
11010  			this._onCreateLevel(level);
11011  		}
11012
11013  		this._level = level;
11014
11015  		return level;
11016  	},
11017
11018  	_onUpdateLevel: falseFn,
11019
11020  	_onRemoveLevel: falseFn,
11021
11022  	_onCreateLevel: falseFn,
11023
11024  	_pruneTiles: function () {
11025  		if (!this._map) {
11026  			return;
11027  		}
11028
11029  		var key, tile;
11030
11031  		var zoom = this._map.getZoom();
11032  		if (zoom > this.options.maxZoom ||
11033  			zoom < this.options.minZoom) {
11034  			this._removeAllTiles();
11035  			return;
11036  		}
11037
11038  		for (key in this._tiles) {
11039  			tile = this._tiles[key];
11040  			tile.retain = tile.current;
11041  		}
11042
11043  		for (key in this._tiles) {
11044  			tile = this._tiles[key];
11045  			if (tile.current && !tile.active) {
11046  				var coords = tile.coords;
11047  				if (!this._retainParent(coords.x, coords.y, coords.z, coords.z - 5)) {
11048  					this._retainChildren(coords.x, coords.y, coords.z, coords.z + 2);
11049  				}
11050  			}
11051  		}
11052
11053  		for (key in this._tiles) {
11054  			if (!this._tiles[key].retain) {
11055  				this._removeTile(key);
11056  			}
11057  		}
11058  	},
11059
11060  	_removeTilesAtZoom: function (zoom) {
11061  		for (var key in this._tiles) {
11062  			if (this._tiles[key].coords.z !== zoom) {
11063  				continue;
11064  			}
11065  			this._removeTile(key);
11066  		}
11067  	},
11068
11069  	_removeAllTiles: function () {
11070  		for (var key in this._tiles) {
11071  			this._removeTile(key);
11072  		}
11073  	},
11074
11075  	_invalidateAll: function () {
11076  		for (var z in this._levels) {
11077  			remove(this._levels[z].el);
11078  			this._onRemoveLevel(Number(z));
11079  			delete this._levels[z];
11080  		}
11081  		this._removeAllTiles();
11082
11083  		this._tileZoom = undefined;
11084  	},
11085
11086  	_retainParent: function (x, y, z, minZoom) {
11087  		var x2 = Math.floor(x / 2),
11088  		    y2 = Math.floor(y / 2),
11089  		    z2 = z - 1,
11090  		    coords2 = new Point(+x2, +y2);
11091  		coords2.z = +z2;
11092
11093  		var key = this._tileCoordsToKey(coords2),
11094  		    tile = this._tiles[key];
11095
11096  		if (tile && tile.active) {
11097  			tile.retain = true;
11098  			return true;
11099
11100  		} else if (tile && tile.loaded) {
11101  			tile.retain = true;
11102  		}
11103
11104  		if (z2 > minZoom) {
11105  			return this._retainParent(x2, y2, z2, minZoom);
11106  		}
11107
11108  		return false;
11109  	},
11110
11111  	_retainChildren: function (x, y, z, maxZoom) {
11112
11113  		for (var i = 2 * x; i < 2 * x + 2; i++) {
11114  			for (var j = 2 * y; j < 2 * y + 2; j++) {
11115
11116  				var coords = new Point(i, j);
11117  				coords.z = z + 1;
11118
11119  				var key = this._tileCoordsToKey(coords),
11120  				    tile = this._tiles[key];
11121
11122  				if (tile && tile.active) {
11123  					tile.retain = true;
11124  					continue;
11125
11126  				} else if (tile && tile.loaded) {
11127  					tile.retain = true;
11128  				}
11129
11130  				if (z + 1 < maxZoom) {
11131  					this._retainChildren(i, j, z + 1, maxZoom);
11132  				}
11133  			}
11134  		}
11135  	},
11136
11137  	_resetView: function (e) {
11138  		var animating = e && (e.pinch || e.flyTo);
11139  		this._setView(this._map.getCenter(), this._map.getZoom(), animating, animating);
11140  	},
11141
11142  	_animateZoom: function (e) {
11143  		this._setView(e.center, e.zoom, true, e.noUpdate);
11144  	},
11145
11146  	_clampZoom: function (zoom) {
11147  		var options = this.options;
11148
11149  		if (undefined !== options.minNativeZoom && zoom < options.minNativeZoom) {
11150  			return options.minNativeZoom;
11151  		}
11152
11153  		if (undefined !== options.maxNativeZoom && options.maxNativeZoom < zoom) {
11154  			return options.maxNativeZoom;
11155  		}
11156
11157  		return zoom;
11158  	},
11159
11160  	_setView: function (center, zoom, noPrune, noUpdate) {
11161  		var tileZoom = Math.round(zoom);
11162  		if ((this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) ||
11163  		    (this.options.minZoom !== undefined && tileZoom < this.options.minZoom)) {
11164  			tileZoom = undefined;
11165  		} else {
11166  			tileZoom = this._clampZoom(tileZoom);
11167  		}
11168
11169  		var tileZoomChanged = this.options.updateWhenZooming && (tileZoom !== this._tileZoom);
11170
11171  		if (!noUpdate || tileZoomChanged) {
11172
11173  			this._tileZoom = tileZoom;
11174
11175  			if (this._abortLoading) {
11176  				this._abortLoading();
11177  			}
11178
11179  			this._updateLevels();
11180  			this._resetGrid();
11181
11182  			if (tileZoom !== undefined) {
11183  				this._update(center);
11184  			}
11185
11186  			if (!noPrune) {
11187  				this._pruneTiles();
11188  			}
11189
11190  			// Flag to prevent _updateOpacity from pruning tiles during
11191  			// a zoom anim or a pinch gesture
11192  			this._noPrune = !!noPrune;
11193  		}
11194
11195  		this._setZoomTransforms(center, zoom);
11196  	},
11197
11198  	_setZoomTransforms: function (center, zoom) {
11199  		for (var i in this._levels) {
11200  			this._setZoomTransform(this._levels[i], center, zoom);
11201  		}
11202  	},
11203
11204  	_setZoomTransform: function (level, center, zoom) {
11205  		var scale = this._map.getZoomScale(zoom, level.zoom),
11206  		    translate = level.origin.multiplyBy(scale)
11207  		        .subtract(this._map._getNewPixelOrigin(center, zoom)).round();
11208
11209  		if (
vendor: 11,680 bytes, lines 11209-11579
11209any3d) {
11210  			setTransform(level.el, translate, scale);
11211  		} else {
11212  			setPosition(level.el, translate);
11213  		}
11214  	},
11215
11216  	_resetGrid: function () {
11217  		var map = this._map,
11218  		    crs = map.options.crs,
11219  		    tileSize = this._tileSize = this.getTileSize(),
11220  		    tileZoom = this._tileZoom;
11221
11222  		var bounds = this._map.getPixelWorldBounds(this._tileZoom);
11223  		if (bounds) {
11224  			this._globalTileRange = this._pxBoundsToTileRange(bounds);
11225  		}
11226
11227  		this._wrapX = crs.wrapLng && !this.options.noWrap && [
11228  			Math.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x),
11229  			Math.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y)
11230  		];
11231  		this._wrapY = crs.wrapLat && !this.options.noWrap && [
11232  			Math.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x),
11233  			Math.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y)
11234  		];
11235  	},
11236
11237  	_onMoveEnd: function () {
11238  		if (!this._map || this._map._animatingZoom) { return; }
11239
11240  		this._update();
11241  	},
11242
11243  	_getTiledPixelBounds: function (center) {
11244  		var map = this._map,
11245  		    mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),
11246  		    scale = map.getZoomScale(mapZoom, this._tileZoom),
11247  		    pixelCenter = map.project(center, this._tileZoom).floor(),
11248  		    halfSize = map.getSize().divideBy(scale * 2);
11249
11250  		return new Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
11251  	},
11252
11253  	// Private method to load tiles in the grid's active zoom level according to map bounds
11254  	_update: function (center) {
11255  		var map = this._map;
11256  		if (!map) { return; }
11257  		var zoom = this._clampZoom(map.getZoom());
11258
11259  		if (center === undefined) { center = map.getCenter(); }
11260  		if (this._tileZoom === undefined) { return; }	// if out of minzoom/maxzoom
11261
11262  		var pixelBounds = this._getTiledPixelBounds(center),
11263  		    tileRange = this._pxBoundsToTileRange(pixelBounds),
11264  		    tileCenter = tileRange.getCenter(),
11265  		    queue = [],
11266  		    margin = this.options.keepBuffer,
11267  		    noPruneRange = new Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),
11268  		                              tileRange.getTopRight().add([margin, -margin]));
11269
11270  		// Sanity check: panic if the tile range contains Infinity somewhere.
11271  		if (!(isFinite(tileRange.min.x) &&
11272  		      isFinite(tileRange.min.y) &&
11273  		      isFinite(tileRange.max.x) &&
11274  		      isFinite(tileRange.max.y))) { throw new Error('Attempted to load an infinite number of tiles'); }
11275
11276  		for (var key in this._tiles) {
11277  			var c = this._tiles[key].coords;
11278  			if (c.z !== this._tileZoom || !noPruneRange.contains(new Point(c.x, c.y))) {
11279  				this._tiles[key].current = false;
11280  			}
11281  		}
11282
11283  		// _update just loads more tiles. If the tile zoom level differs too much
11284  		// from the map's, let _setView reset levels and prune old tiles.
11285  		if (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }
11286
11287  		// create a queue of coordinates to load tiles from
11288  		for (var j = tileRange.min.y; j <= tileRange.max.y; j++) {
11289  			for (var i = tileRange.min.x; i <= tileRange.max.x; i++) {
11290  				var coords = new Point(i, j);
11291  				coords.z = this._tileZoom;
11292
11293  				if (!this._isValidTile(coords)) { continue; }
11294
11295  				var tile = this._tiles[this._tileCoordsToKey(coords)];
11296  				if (tile) {
11297  					tile.current = true;
11298  				} else {
11299  					queue.push(coords);
11300  				}
11301  			}
11302  		}
11303
11304  		// sort tile queue to load tiles in order of their distance to center
11305  		queue.sort(function (a, b) {
11306  			return a.distanceTo(tileCenter) - b.distanceTo(tileCenter);
11307  		});
11308
11309  		if (queue.length !== 0) {
11310  			// if it's the first batch of tiles to load
11311  			if (!this._loading) {
11312  				this._loading = true;
11313  				// @event loading: Event
11314  				// Fired when the grid layer starts loading tiles.
11315  				this.fire('loading');
11316  			}
11317
11318  			// create DOM fragment to append tiles in one batch
11319  			var fragment = document.createDocumentFragment();
11320
11321  			for (i = 0; i < queue.length; i++) {
11322  				this._addTile(queue[i], fragment);
11323  			}
11324
11325  			this._level.el.appendChild(fragment);
11326  		}
11327  	},
11328
11329  	_isValidTile: function (coords) {
11330  		var crs = this._map.options.crs;
11331
11332  		if (!crs.infinite) {
11333  			// don't load tile if it's out of bounds and not wrapped
11334  			var bounds = this._globalTileRange;
11335  			if ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||
11336  			    (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }
11337  		}
11338
11339  		if (!this.options.bounds) { return true; }
11340
11341  		// don't load tile if it doesn't intersect the bounds in options
11342  		var tileBounds = this._tileCoordsToBounds(coords);
11343  		return toLatLngBounds(this.options.bounds).overlaps(tileBounds);
11344  	},
11345
11346  	_keyToBounds: function (key) {
11347  		return this._tileCoordsToBounds(this._keyToTileCoords(key));
11348  	},
11349
11350  	_tileCoordsToNwSe: function (coords) {
11351  		var map = this._map,
11352  		    tileSize = this.getTileSize(),
11353  		    nwPoint = coords.scaleBy(tileSize),
11354  		    sePoint = nwPoint.add(tileSize),
11355  		    nw = map.unproject(nwPoint, coords.z),
11356  		    se = map.unproject(sePoint, coords.z);
11357  		return [nw, se];
11358  	},
11359
11360  	// converts tile coordinates to its geographical bounds
11361  	_tileCoordsToBounds: function (coords) {
11362  		var bp = this._tileCoordsToNwSe(coords),
11363  		    bounds = new LatLngBounds(bp[0], bp[1]);
11364
11365  		if (!this.options.noWrap) {
11366  			bounds = this._map.wrapLatLngBounds(bounds);
11367  		}
11368  		return bounds;
11369  	},
11370  	// converts tile coordinates to key for the tile cache
11371  	_tileCoordsToKey: function (coords) {
11372  		return coords.x + ':' + coords.y + ':' + coords.z;
11373  	},
11374
11375  	// converts tile cache key to coordinates
11376  	_keyToTileCoords: function (key) {
11377  		var k = key.split(':'),
11378  		    coords = new Point(+k[0], +k[1]);
11379  		coords.z = +k[2];
11380  		return coords;
11381  	},
11382
11383  	_removeTile: function (key) {
11384  		var tile = this._tiles[key];
11385  		if (!tile) { return; }
11386
11387  		remove(tile.el);
11388
11389  		delete this._tiles[key];
11390
11391  		// @event tileunload: TileEvent
11392  		// Fired when a tile is removed (e.g. when a tile goes off the screen).
11393  		this.fire('tileunload', {
11394  			tile: tile.el,
11395  			coords: this._keyToTileCoords(key)
11396  		});
11397  	},
11398
11399  	_initTile: function (tile) {
11400  		addClass(tile, 'leaflet-tile');
11401
11402  		var tileSize = this.getTileSize();
11403  		tile.style.width = tileSize.x + 'px';
11404  		tile.style.height = tileSize.y + 'px';
11405
11406  		tile.onselectstart = falseFn;
11407  		tile.onmousemove = falseFn;
11408
11409  		// update opacity on tiles in IE7-8 because of filter inheritance problems
11410  		if (ielt9 && this.options.opacity < 1) {
11411  			setOpacity(tile, this.options.opacity);
11412  		}
11413  	},
11414
11415  	_addTile: function (coords, container) {
11416  		var tilePos = this._getTilePos(coords),
11417  		    key = this._tileCoordsToKey(coords);
11418
11419  		var tile = this.createTile(this._wrapCoords(coords), bind(this._tileReady, this, coords));
11420
11421  		this._initTile(tile);
11422
11423  		// if createTile is defined with a second argument ("done" callback),
11424  		// we know that tile is async and will be ready later; otherwise
11425  		if (this.createTile.length < 2) {
11426  			// mark tile as ready, but delay one frame for opacity animation to happen
11427  			requestAnimFrame(bind(this._tileReady, this, coords, null, tile));
11428  		}
11429
11430  		setPosition(tile, tilePos);
11431
11432  		// save tile in cache
11433  		this._tiles[key] = {
11434  			el: tile,
11435  			coords: coords,
11436  			current: true
11437  		};
11438
11439  		container.appendChild(tile);
11440  		// @event tileloadstart: TileEvent
11441  		// Fired when a tile is requested and starts loading.
11442  		this.fire('tileloadstart', {
11443  			tile: tile,
11444  			coords: coords
11445  		});
11446  	},
11447
11448  	_tileReady: function (coords, err, tile) {
11449  		if (err) {
11450  			// @event tileerror: TileErrorEvent
11451  			// Fired when there is an error loading a tile.
11452  			this.fire('tileerror', {
11453  				error: err,
11454  				tile: tile,
11455  				coords: coords
11456  			});
11457  		}
11458
11459  		var key = this._tileCoordsToKey(coords);
11460
11461  		tile = this._tiles[key];
11462  		if (!tile) { return; }
11463
11464  		tile.loaded = +new Date();
11465  		if (this._map._fadeAnimated) {
11466  			setOpacity(tile.el, 0);
11467  			cancelAnimFrame(this._fadeFrame);
11468  			this._fadeFrame = requestAnimFrame(this._updateOpacity, this);
11469  		} else {
11470  			tile.active = true;
11471  			this._pruneTiles();
11472  		}
11473
11474  		if (!err) {
11475  			addClass(tile.el, 'leaflet-tile-loaded');
11476
11477  			// @event tileload: TileEvent
11478  			// Fired when a tile loads.
11479  			this.fire('tileload', {
11480  				tile: tile.el,
11481  				coords: coords
11482  			});
11483  		}
11484
11485  		if (this._noTilesToLoad()) {
11486  			this._loading = false;
11487  			// @event load: Event
11488  			// Fired when the grid layer loaded all visible tiles.
11489  			this.fire('load');
11490
11491  			if (ielt9 || !this._map._fadeAnimated) {
11492  				requestAnimFrame(this._pruneTiles, this);
11493  			} else {
11494  				// Wait a bit more than 0.2 secs (the duration of the tile fade-in)
11495  				// to trigger a pruning.
11496  				setTimeout(bind(this._pruneTiles, this), 250);
11497  			}
11498  		}
11499  	},
11500
11501  	_getTilePos: function (coords) {
11502  		return coords.scaleBy(this.getTileSize()).subtract(this._level.origin);
11503  	},
11504
11505  	_wrapCoords: function (coords) {
11506  		var newCoords = new Point(
11507  			this._wrapX ? wrapNum(coords.x, this._wrapX) : coords.x,
11508  			this._wrapY ? wrapNum(coords.y, this._wrapY) : coords.y);
11509  		newCoords.z = coords.z;
11510  		return newCoords;
11511  	},
11512
11513  	_pxBoundsToTileRange: function (bounds) {
11514  		var tileSize = this.getTileSize();
11515  		return new Bounds(
11516  			bounds.min.unscaleBy(tileSize).floor(),
11517  			bounds.max.unscaleBy(tileSize).ceil().subtract([1, 1]));
11518  	},
11519
11520  	_noTilesToLoad: function () {
11521  		for (var key in this._tiles) {
11522  			if (!this._tiles[key].loaded) { return false; }
11523  		}
11524  		return true;
11525  	}
11526  });
11527
11528  // @factory L.gridLayer(options?: GridLayer options)
11529  // Creates a new instance of GridLayer with the supplied options.
11530  function gridLayer(options) {
11531  	return new GridLayer(options);
11532  }
11533
11534  /*
11535   * @class TileLayer
11536   * @inherits GridLayer
11537   * @aka L.TileLayer
11538   * Used to load and display tile layers on the map. Note that most tile servers require attribution, which you can set under `Layer`. Extends `GridLayer`.
11539   *
11540   * @example
11541   *
11542   * ```js
11543   * L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar', attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'}).addTo(map);
11544   * ```
11545   *
11546   * @section URL template
11547   * @example
11548   *
11549   * A string of the following form:
11550   *
11551   * ```
11552   * 'http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'
11553   * ```
11554   *
11555   * `{s}` means one of the available subdomains (used sequentially to help with browser parallel requests per domain limitation; subdomain values are specified in options; `a`, `b` or `c` by default, can be omitted), `{z}` — zoom level, `{x}` and `{y}` — tile coordinates. `{r}` can be used to add "&commat;2x" to the URL to load retina tiles.
11556   *
11557   * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:
11558   *
11559   * ```
11560   * L.tileLayer('http://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});
11561   * ```
11562   */
11563
11564
11565  var TileLayer = GridLayer.extend({
11566
11567  	// @section
11568  	// @aka TileLayer options
11569  	options: {
11570  		// @option minZoom: Number = 0
11571  		// The minimum zoom level down to which this layer will be displayed (inclusive).
11572  		minZoom: 0,
11573
11574  		// @option maxZoom: Number = 18
11575  		// The maximum zoom level up to which this layer will be displayed (inclusive).
11576  		maxZoom: 18,
11577
11578  		// @option subdomains: String|String[] = 'abc'
11579  		// Subdomains of the tile service. Can be passed in the form of one string (where each letter is a subdomain name) or an array of str
11579ings.
11580  		subdomains: 'abc',
11581
11582  		// @option errorTileUrl: String = ''
11583  		// URL to the tile image to show in place of the tile that failed to load.
11584  		errorTileUrl: '',
11585
11586  		// @option zoomOffset: Number = 0
11587  		// The zoom number used in tile URLs will be offset with this value.
11588  		zoomOffset: 0,
11589
11590  		// @option tms: Boolean = false
11591  		// If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).
11592  		tms: false,
11593
11594  		// @option zoomReverse: Boolean = false
11595  		// If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)
11596  		zoomReverse: false,
11597
11598  		// @option detectRetina: Boolean = false
11599  		// If `true` and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution.
11600  		detectRetina: false,
11601
11602  		// @option crossOrigin: Boolean|String = false
11603  		// Whether the crossOrigin attribute will be added to the tiles.
11604  		// If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.
11605  		// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
11606  		crossOrigin: false
11607  	},
11608
11609  	initialize: function (url, options) {
11610
11611  		this._url = url;
11612
11613  		options = setOptions(this, options);
11614
11615  		// detecting retina displays, adjusting tileSize and zoom levels
11616  		if (options.detectRetina && retina && options.maxZoom > 0) {
11617
11618  			options.tileSize = Math.floor(options.tileSize / 2);
11619
11620  			if (!options.zoomReverse) {
11621  				options.zoomOffset++;
11622  				options.maxZoom--;
11623  			} else {
11624  				options.zoomOffset--;
11625  				options.minZoom++;
11626  			}
11627
11628  			options.minZoom = Math.max(0, options.minZoom);
11629  		}
11630
11631  		if (typeof options.subdomains === 'string') {
11632  			options.subdomains = options.subdomains.split('');
11633  		}
11634
11635  		this.on('tileunload', this._onTileRemove);
11636  	},
11637
11638  	// @method setUrl(url: String, noRedraw?: Boolean): this
11639  	// Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).
11640  	// If the URL does not change, the layer will not be redrawn unless
11641  	// the noRedraw parameter is set to false.
11642  	setUrl: function (url, noRedraw) {
11643  		if (this._url === url && noRedraw === undefined) {
11644  			noRedraw = true;
11645  		}
11646
11647  		this._url = url;
11648
11649  		if (!noRedraw) {
11650  			this.redraw();
11651  		}
11652  		return this;
11653  	},
11654
11655  	// @method createTile(coords: Object, done?: Function): HTMLElement
11656  	// Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)
11657  	// to return an `<img>` HTML element with the appropriate image URL given `coords`. The `done`
11658  	// callback is called when the tile has been loaded.
11659  	createTile: function (coords, done) {
11660  		var tile = document.createElement('img');
11661
11662  		on(tile, 'load', bind(this._tileOnLoad, this, done, tile));
11663  		on(tile, 'error', bind(this._tileOnError, this, done, tile));
11664
11665  		if (this.options.crossOrigin || this.options.crossOrigin === '') {
11666  			tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
11667  		}
11668
11669  		/*
11670  		 Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons
11671  		 http://www.w3.org/TR/WCAG20-TECHS/H67
11672  		*/
11673  		tile.alt = '';
11674
11675  		/*
11676  		 Set role="presentation" to force screen readers to ignore this
11677  		 https://www.w3.org/TR/wai-aria/roles#textalternativecomputation
11678  		*/
11679  		tile.setAttribute('role', 'presentation');
11680
11681  		tile.src = this.getTileUrl(coords);
11682
11683  		return tile;
11684  	},
11685
11686  	// @section Extension methods
11687  	// @uninheritable
11688  	// Layers extending `TileLayer` might reimplement the following method.
11689  	// @method getTileUrl(coords: Object): String
11690  	// Called only internally, returns the URL for a tile given its coordinates.
11691  	// Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.
11692  	getTileUrl: function (coords) {
11693  		var data = {
11694  			r: retina ? '@2x' : '',
11695  			s: this._getSubdomain(coords),
11696  			x: coords.x,
11697  			y: coords.y,
11698  			z: this._getZoomForUrl()
11699  		};
11700  		if (this._map && !this._map.options.crs.infinite) {
11701  			var invertedY = this._globalTileRange.max.y - coords.y;
11702  			if (this.options.tms) {
11703  				data['y'] = invertedY;
11704  			}
vendor: 13,334 bytes, lines 11705-12177
11705  			data['-y'] = invertedY;
11706  		}
11707
11708  		return template(this._url, extend(data, this.options));
11709  	},
11710
11711  	_tileOnLoad: function (done, tile) {
11712  		// For https://github.com/Leaflet/Leaflet/issues/3332
11713  		if (ielt9) {
11714  			setTimeout(bind(done, this, null, tile), 0);
11715  		} else {
11716  			done(null, tile);
11717  		}
11718  	},
11719
11720  	_tileOnError: function (done, tile, e) {
11721  		var errorUrl = this.options.errorTileUrl;
11722  		if (errorUrl && tile.getAttribute('src') !== errorUrl) {
11723  			tile.src = errorUrl;
11724  		}
11725  		done(e, tile);
11726  	},
11727
11728  	_onTileRemove: function (e) {
11729  		e.tile.onload = null;
11730  	},
11731
11732  	_getZoomForUrl: function () {
11733  		var zoom = this._tileZoom,
11734  		maxZoom = this.options.maxZoom,
11735  		zoomReverse = this.options.zoomReverse,
11736  		zoomOffset = this.options.zoomOffset;
11737
11738  		if (zoomReverse) {
11739  			zoom = maxZoom - zoom;
11740  		}
11741
11742  		return zoom + zoomOffset;
11743  	},
11744
11745  	_getSubdomain: function (tilePoint) {
11746  		var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;
11747  		return this.options.subdomains[index];
11748  	},
11749
11750  	// stops loading all tiles in the background layer
11751  	_abortLoading: function () {
11752  		var i, tile;
11753  		for (i in this._tiles) {
11754  			if (this._tiles[i].coords.z !== this._tileZoom) {
11755  				tile = this._tiles[i].el;
11756
11757  				tile.onload = falseFn;
11758  				tile.onerror = falseFn;
11759
11760  				if (!tile.complete) {
11761  					tile.src = emptyImageUrl;
11762  					var coords = this._tiles[i].coords;
11763  					remove(tile);
11764  					delete this._tiles[i];
11765  					// @event tileabort: TileEvent
11766  					// Fired when a tile was loading but is now not wanted.
11767  					this.fire('tileabort', {
11768  						tile: tile,
11769  						coords: coords
11770  					});
11771  				}
11772  			}
11773  		}
11774  	},
11775
11776  	_removeTile: function (key) {
11777  		var tile = this._tiles[key];
11778  		if (!tile) { return; }
11779
11780  		// Cancels any pending http requests associated with the tile
11781  		tile.el.setAttribute('src', emptyImageUrl);
11782
11783  		return GridLayer.prototype._removeTile.call(this, key);
11784  	},
11785
11786  	_tileReady: function (coords, err, tile) {
11787  		if (!this._map || (tile && tile.getAttribute('src') === emptyImageUrl)) {
11788  			return;
11789  		}
11790
11791  		return GridLayer.prototype._tileReady.call(this, coords, err, tile);
11792  	}
11793  });
11794
11795
11796  // @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)
11797  // Instantiates a tile layer object given a `URL template` and optionally an options object.
11798
11799  function tileLayer(url, options) {
11800  	return new TileLayer(url, options);
11801  }
11802
11803  /*
11804   * @class TileLayer.WMS
11805   * @inherits TileLayer
11806   * @aka L.TileLayer.WMS
11807   * Used to display [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services as tile layers on the map. Extends `TileLayer`.
11808   *
11809   * @example
11810   *
11811   * ```js
11812   * var nexrad = L.tileLayer.wms("http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", {
11813   * 	layers: 'nexrad-n0r-900913',
11814   * 	format: 'image/png',
11815   * 	transparent: true,
11816   * 	attribution: "Weather data © 2012 IEM Nexrad"
11817   * });
11818   * ```
11819   */
11820
11821  var TileLayerWMS = TileLayer.extend({
11822
11823  	// @section
11824  	// @aka TileLayer.WMS options
11825  	// If any custom options not documented here are used, they will be sent to the
11826  	// WMS server as extra parameters in each request URL. This can be useful for
11827  	// [non-standard vendor WMS parameters](http://docs.geoserver.org/stable/en/user/services/wms/vendor.html).
11828  	defaultWmsParams: {
11829  		service: 'WMS',
11830  		request: 'GetMap',
11831
11832  		// @option layers: String = ''
11833  		// **(required)** Comma-separated list of WMS layers to show.
11834  		layers: '',
11835
11836  		// @option styles: String = ''
11837  		// Comma-separated list of WMS styles.
11838  		styles: '',
11839
11840  		// @option format: String = 'image/jpeg'
11841  		// WMS image format (use `'image/png'` for layers with transparency).
11842  		format: 'image/jpeg',
11843
11844  		// @option transparent: Boolean = false
11845  		// If `true`, the WMS service will return images with transparency.
11846  		transparent: false,
11847
11848  		// @option version: String = '1.1.1'
11849  		// Version of the WMS service to use
11850  		version: '1.1.1'
11851  	},
11852
11853  	options: {
11854  		// @option crs: CRS = null
11855  		// Coordinate Reference System to use for the WMS requests, defaults to
11856  		// map CRS. Don't change this if you're not sure what it means.
11857  		crs: null,
11858
11859  		// @option uppercase: Boolean = false
11860  		// If `true`, WMS request parameter keys will be uppercase.
11861  		uppercase: false
11862  	},
11863
11864  	initialize: function (url, options) {
11865
11866  		this._url = url;
11867
11868  		var wmsParams = extend({}, this.defaultWmsParams);
11869
11870  		// all keys that are not TileLayer options go to WMS params
11871  		for (var i in options) {
11872  			if (!(i in this.options)) {
11873  				wmsParams[i] = options[i];
11874  			}
11875  		}
11876
11877  		options = setOptions(this, options);
11878
11879  		var realRetina = options.detectRetina && retina ? 2 : 1;
11880  		var tileSize = this.getTileSize();
11881  		wmsParams.width = tileSize.x * realRetina;
11882  		wmsParams.height = tileSize.y * realRetina;
11883
11884  		this.wmsParams = wmsParams;
11885  	},
11886
11887  	onAdd: function (map) {
11888
11889  		this._crs = this.options.crs || map.options.crs;
11890  		this._wmsVersion = parseFloat(this.wmsParams.version);
11891
11892  		var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';
11893  		this.wmsParams[projectionKey] = this._crs.code;
11894
11895  		TileLayer.prototype.onAdd.call(this, map);
11896  	},
11897
11898  	getTileUrl: function (coords) {
11899
11900  		var tileBounds = this._tileCoordsToNwSe(coords),
11901  		    crs = this._crs,
11902  		    bounds = toBounds(crs.project(tileBounds[0]), crs.project(tileBounds[1])),
11903  		    min = bounds.min,
11904  		    max = bounds.max,
11905  		    bbox = (this._wmsVersion >= 1.3 && this._crs === EPSG4326 ?
11906  		    [min.y, min.x, max.y, max.x] :
11907  		    [min.x, min.y, max.x, max.y]).join(','),
11908  		    url = TileLayer.prototype.getTileUrl.call(this, coords);
11909  		return url +
11910  			getParamString(this.wmsParams, url, this.options.uppercase) +
11911  			(this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;
11912  	},
11913
11914  	// @method setParams(params: Object, noRedraw?: Boolean): this
11915  	// Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true).
11916  	setParams: function (params, noRedraw) {
11917
11918  		extend(this.wmsParams, params);
11919
11920  		if (!noRedraw) {
11921  			this.redraw();
11922  		}
11923
11924  		return this;
11925  	}
11926  });
11927
11928
11929  // @factory L.tileLayer.wms(baseUrl: String, options: TileLayer.WMS options)
11930  // Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS parameters/options object.
11931  function tileLayerWMS(url, options) {
11932  	return new TileLayerWMS(url, options);
11933  }
11934
11935  TileLayer.WMS = TileLayerWMS;
11936  tileLayer.wms = tileLayerWMS;
11937
11938  /*
11939   * @class Renderer
11940   * @inherits Layer
11941   * @aka L.Renderer
11942   *
11943   * Base class for vector renderer implementations (`SVG`, `Canvas`). Handles the
11944   * DOM container of the renderer, its bounds, and its zoom animation.
11945   *
11946   * A `Renderer` works as an implicit layer group for all `Path`s - the renderer
11947   * itself can be added or removed to the map. All paths use a renderer, which can
11948   * be implicit (the map will decide the type of renderer and use it automatically)
11949   * or explicit (using the [`renderer`](#path-renderer) option of the path).
11950   *
11951   * Do not use this class directly, use `SVG` and `Canvas` instead.
11952   *
11953   * @event update: Event
11954   * Fired when the renderer updates its bounds, center and zoom, for example when
11955   * its map has moved
11956   */
11957
11958  var Renderer = Layer.extend({
11959
11960  	// @section
11961  	// @aka Renderer options
11962  	options: {
11963  		// @option padding: Number = 0.1
11964  		// How much to extend the clip area around the map view (relative to its size)
11965  		// e.g. 0.1 would be 10% of map view in each direction
11966  		padding: 0.1
11967  	},
11968
11969  	initialize: function (options) {
11970  		setOptions(this, options);
11971  		stamp(this);
11972  		this._layers = this._layers || {};
11973  	},
11974
11975  	onAdd: function () {
11976  		if (!this._container) {
11977  			this._initContainer(); // defined by renderer implementations
11978
11979  			if (this._zoomAnimated) {
11980  				addClass(this._container, 'leaflet-zoom-animated');
11981  			}
11982  		}
11983
11984  		this.getPane().appendChild(this._container);
11985  		this._update();
11986  		this.on('update', this._updatePaths, this);
11987  	},
11988
11989  	onRemove: function () {
11990  		this.off('update', this._updatePaths, this);
11991  		this._destroyContainer();
11992  	},
11993
11994  	getEvents: function () {
11995  		var events = {
11996  			viewreset: this._reset,
11997  			zoom: this._onZoom,
11998  			moveend: this._update,
11999  			zoomend: this._onZoomEnd
12000  		};
12001  		if (this._zoomAnimated) {
12002  			events.zoomanim = this._onAnimZoom;
12003  		}
12004  		return events;
12005  	},
12006
12007  	_onAnimZoom: function (ev) {
12008  		this._updateTransform(ev.center, ev.zoom);
12009  	},
12010
12011  	_onZoom: function () {
12012  		this._updateTransform(this._map.getCenter(), this._map.getZoom());
12013  	},
12014
12015  	_updateTransform: function (center, zoom) {
12016  		var scale = this._map.getZoomScale(zoom, this._zoom),
12017  		    position = getPosition(this._container),
12018  		    viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding),
12019  		    currentCenterPoint = this._map.project(this._center, zoom),
12020  		    destCenterPoint = this._map.project(center, zoom),
12021  		    centerOffset = destCenterPoint.subtract(currentCenterPoint),
12022
12023  		    topLeftOffset = viewHalf.multiplyBy(-scale).add(position).add(viewHalf).subtract(centerOffset);
12024
12025  		if (any3d) {
12026  			setTransform(this._container, topLeftOffset, scale);
12027  		} else {
12028  			setPosition(this._container, topLeftOffset);
12029  		}
12030  	},
12031
12032  	_reset: function () {
12033  		this._update();
12034  		this._updateTransform(this._center, this._zoom);
12035
12036  		for (var id in this._layers) {
12037  			this._layers[id]._reset();
12038  		}
12039  	},
12040
12041  	_onZoomEnd: function () {
12042  		for (var id in this._layers) {
12043  			this._layers[id]._project();
12044  		}
12045  	},
12046
12047  	_updatePaths: function () {
12048  		for (var id in this._layers) {
12049  			this._layers[id]._update();
12050  		}
12051  	},
12052
12053  	_update: function () {
12054  		// Update pixel bounds of renderer container (for positioning/sizing/clipping later)
12055  		// Subclasses are responsible of firing the 'update' event.
12056  		var p = this.options.padding,
12057  		    size = this._map.getSize(),
12058  		    min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();
12059
12060  		this._bounds = new Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round());
12061
12062  		this._center = this._map.getCenter();
12063  		this._zoom = this._map.getZoom();
12064  	}
12065  });
12066
12067  /*
12068   * @class Canvas
12069   * @inherits Renderer
12070   * @aka L.Canvas
12071   *
12072   * Allows vector layers to be displayed with [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
12073   * Inherits `Renderer`.
12074   *
12075   * Due to [technical limitations](http://caniuse.com/#search=canvas), Canvas is not
12076   * available in all web browsers, notably IE8, and overlapping geometries might
12077   * not display properly in some edge cases.
12078   *
12079   * @example
12080   *
12081   * Use Canvas by default for all paths in the map:
12082   *
12083   * ```js
12084   * var map = L.map('map', {
12085   * 	renderer: L.canvas()
12086   * });
12087   * ```
12088   *
12089   * Use a Canvas renderer with extra padding for specific vector geometries:
12090   *
12091   * ```js
12092   * var map = L.map('map');
12093   * var myRenderer = L.canvas({ padding: 0.5 });
12094   * var line = L.polyline( coordinates, { renderer: myRenderer } );
12095   * var circle = L.circle( center, { renderer: myRenderer } );
12096   * ```
12097   */
12098
12099  var Canvas = Renderer.extend({
12100
12101  	// @section
12102  	// @aka Canvas options
12103  	options: {
12104  		// @option tolerance: Number = 0
12105  		// How much to extend the click tolerance around a path/object on the map.
12106  		tolerance: 0
12107  	},
12108
12109  	getEvents: function () {
12110  		var events = Renderer.prototype.getEvents.call(this);
12111  		events.viewprereset = this._onViewPreReset;
12112  		return events;
12113  	},
12114
12115  	_onViewPreReset: function () {
12116  		// Set a flag so that a viewprereset+moveend+viewreset only updates&redraws once
12117  		this._postponeUpdatePaths = true;
12118  	},
12119
12120  	onAdd: function () {
12121  		Renderer.prototype.onAdd.call(this);
12122
12123  		// Redraw vectors since canvas is cleared upon removal,
12124  		// in case of removing the renderer itself from the map.
12125  		this._draw();
12126  	},
12127
12128  	_initContainer: function () {
12129  		var container = this._container = document.createElement('canvas');
12130
12131  		on(container, 'mousemove', this._onMouseMove, this);
12132  		on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this);
12133  		on(container, 'mouseout', this._handleMouseOut, this);
12134  		container['_leaflet_disable_events'] = true;
12135
12136  		this._ctx = container.getContext('2d');
12137  	},
12138
12139  	_destroyContainer: function () {
12140  		cancelAnimFrame(this._redrawRequest);
12141  		delete this._ctx;
12142  		remove(this._container);
12143  		off(this._container);
12144  		delete this._container;
12145  	},
12146
12147  	_updatePaths: function () {
12148  		if (this._postponeUpdatePaths) { return; }
12149
12150  		var layer;
12151  		this._redrawBounds = null;
12152  		for (var id in this._layers) {
12153  			layer = this._layers[id];
12154  			layer._update();
12155  		}
12156  		this._redraw();
12157  	},
12158
12159  	_update: function () {
12160  		if (this._map._animatingZoom && this._bounds) { return; }
12161
12162  		Renderer.prototype._update.call(this);
12163
12164  		var b = this._bounds,
12165  		    container = this._container,
12166  		    size = b.getSize(),
12167  		    m = retina ? 2 : 1;
12168
12169  		setPosition(container, b.min);
12170
12171  		// set canvas size (also clearing it); use double size on retina
12172  		container.width = m * size.x;
12173  		container.height = m * size.y;
12174  		container.style.width = size.x + 'px';
12175  		container.style.height = size.y + 'px';
12176
12177  		if (
vendor: 9,280 bytes, lines 12177-12550
12177retina) {
12178  			this._ctx.scale(2, 2);
12179  		}
12180
12181  		// translate so we use the same path coordinates after canvas element moves
12182  		this._ctx.translate(-b.min.x, -b.min.y);
12183
12184  		// Tell paths to redraw themselves
12185  		this.fire('update');
12186  	},
12187
12188  	_reset: function () {
12189  		Renderer.prototype._reset.call(this);
12190
12191  		if (this._postponeUpdatePaths) {
12192  			this._postponeUpdatePaths = false;
12193  			this._updatePaths();
12194  		}
12195  	},
12196
12197  	_initPath: function (layer) {
12198  		this._updateDashArray(layer);
12199  		this._layers[stamp(layer)] = layer;
12200
12201  		var order = layer._order = {
12202  			layer: layer,
12203  			prev: this._drawLast,
12204  			next: null
12205  		};
12206  		if (this._drawLast) { this._drawLast.next = order; }
12207  		this._drawLast = order;
12208  		this._drawFirst = this._drawFirst || this._drawLast;
12209  	},
12210
12211  	_addPath: function (layer) {
12212  		this._requestRedraw(layer);
12213  	},
12214
12215  	_removePath: function (layer) {
12216  		var order = layer._order;
12217  		var next = order.next;
12218  		var prev = order.prev;
12219
12220  		if (next) {
12221  			next.prev = prev;
12222  		} else {
12223  			this._drawLast = prev;
12224  		}
12225  		if (prev) {
12226  			prev.next = next;
12227  		} else {
12228  			this._drawFirst = next;
12229  		}
12230
12231  		delete layer._order;
12232
12233  		delete this._layers[stamp(layer)];
12234
12235  		this._requestRedraw(layer);
12236  	},
12237
12238  	_updatePath: function (layer) {
12239  		// Redraw the union of the layer's old pixel
12240  		// bounds and the new pixel bounds.
12241  		this._extendRedrawBounds(layer);
12242  		layer._project();
12243  		layer._update();
12244  		// The redraw will extend the redraw bounds
12245  		// with the new pixel bounds.
12246  		this._requestRedraw(layer);
12247  	},
12248
12249  	_updateStyle: function (layer) {
12250  		this._updateDashArray(layer);
12251  		this._requestRedraw(layer);
12252  	},
12253
12254  	_updateDashArray: function (layer) {
12255  		if (typeof layer.options.dashArray === 'string') {
12256  			var parts = layer.options.dashArray.split(/[, ]+/),
12257  			    dashArray = [],
12258  			    dashValue,
12259  			    i;
12260  			for (i = 0; i < parts.length; i++) {
12261  				dashValue = Number(parts[i]);
12262  				// Ignore dash array containing invalid lengths
12263  				if (isNaN(dashValue)) { return; }
12264  				dashArray.push(dashValue);
12265  			}
12266  			layer.options._dashArray = dashArray;
12267  		} else {
12268  			layer.options._dashArray = layer.options.dashArray;
12269  		}
12270  	},
12271
12272  	_requestRedraw: function (layer) {
12273  		if (!this._map) { return; }
12274
12275  		this._extendRedrawBounds(layer);
12276  		this._redrawRequest = this._redrawRequest || requestAnimFrame(this._redraw, this);
12277  	},
12278
12279  	_extendRedrawBounds: function (layer) {
12280  		if (layer._pxBounds) {
12281  			var padding = (layer.options.weight || 0) + 1;
12282  			this._redrawBounds = this._redrawBounds || new Bounds();
12283  			this._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding]));
12284  			this._redrawBounds.extend(layer._pxBounds.max.add([padding, padding]));
12285  		}
12286  	},
12287
12288  	_redraw: function () {
12289  		this._redrawRequest = null;
12290
12291  		if (this._redrawBounds) {
12292  			this._redrawBounds.min._floor();
12293  			this._redrawBounds.max._ceil();
12294  		}
12295
12296  		this._clear(); // clear layers in redraw bounds
12297  		this._draw(); // draw layers
12298
12299  		this._redrawBounds = null;
12300  	},
12301
12302  	_clear: function () {
12303  		var bounds = this._redrawBounds;
12304  		if (bounds) {
12305  			var size = bounds.getSize();
12306  			this._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y);
12307  		} else {
12308  			this._ctx.save();
12309  			this._ctx.setTransform(1, 0, 0, 1, 0, 0);
12310  			this._ctx.clearRect(0, 0, this._container.width, this._container.height);
12311  			this._ctx.restore();
12312  		}
12313  	},
12314
12315  	_draw: function () {
12316  		var layer, bounds = this._redrawBounds;
12317  		this._ctx.save();
12318  		if (bounds) {
12319  			var size = bounds.getSize();
12320  			this._ctx.beginPath();
12321  			this._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y);
12322  			this._ctx.clip();
12323  		}
12324
12325  		this._drawing = true;
12326
12327  		for (var order = this._drawFirst; order; order = order.next) {
12328  			layer = order.layer;
12329  			if (!bounds || (layer._pxBounds && layer._pxBounds.intersects(bounds))) {
12330  				layer._updatePath();
12331  			}
12332  		}
12333
12334  		this._drawing = false;
12335
12336  		this._ctx.restore();  // Restore state before clipping.
12337  	},
12338
12339  	_updatePoly: function (layer, closed) {
12340  		if (!this._drawing) { return; }
12341
12342  		var i, j, len2, p,
12343  		    parts = layer._parts,
12344  		    len = parts.length,
12345  		    ctx = this._ctx;
12346
12347  		if (!len) { return; }
12348
12349  		ctx.beginPath();
12350
12351  		for (i = 0; i < len; i++) {
12352  			for (j = 0, len2 = parts[i].length; j < len2; j++) {
12353  				p = parts[i][j];
12354  				ctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);
12355  			}
12356  			if (closed) {
12357  				ctx.closePath();
12358  			}
12359  		}
12360
12361  		this._fillStroke(ctx, layer);
12362
12363  		// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
12364  	},
12365
12366  	_updateCircle: function (layer) {
12367
12368  		if (!this._drawing || layer._empty()) { return; }
12369
12370  		var p = layer._point,
12371  		    ctx = this._ctx,
12372  		    r = Math.max(Math.round(layer._radius), 1),
12373  		    s = (Math.max(Math.round(layer._radiusY), 1) || r) / r;
12374
12375  		if (s !== 1) {
12376  			ctx.save();
12377  			ctx.scale(1, s);
12378  		}
12379
12380  		ctx.beginPath();
12381  		ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);
12382
12383  		if (s !== 1) {
12384  			ctx.restore();
12385  		}
12386
12387  		this._fillStroke(ctx, layer);
12388  	},
12389
12390  	_fillStroke: function (ctx, layer) {
12391  		var options = layer.options;
12392
12393  		if (options.fill) {
12394  			ctx.globalAlpha = options.fillOpacity;
12395  			ctx.fillStyle = options.fillColor || options.color;
12396  			ctx.fill(options.fillRule || 'evenodd');
12397  		}
12398
12399  		if (options.stroke && options.weight !== 0) {
12400  			if (ctx.setLineDash) {
12401  				ctx.setLineDash(layer.options && layer.options._dashArray || []);
12402  			}
12403  			ctx.globalAlpha = options.opacity;
12404  			ctx.lineWidth = options.weight;
12405  			ctx.strokeStyle = options.color;
12406  			ctx.lineCap = options.lineCap;
12407  			ctx.lineJoin = options.lineJoin;
12408  			ctx.stroke();
12409  		}
12410  	},
12411
12412  	// Canvas obviously doesn't have mouse events for individual drawn objects,
12413  	// so we emulate that by calculating what's under the mouse on mousemove/click manually
12414
12415  	_onClick: function (e) {
12416  		var point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer;
12417
12418  		for (var order = this._drawFirst; order; order = order.next) {
12419  			layer = order.layer;
12420  			if (layer.options.interactive && layer._containsPoint(point)) {
12421  				if (!(e.type === 'click' || e.type === 'preclick') || !this._map._draggableMoved(layer)) {
12422  					clickedLayer = layer;
12423  				}
12424  			}
12425  		}
12426  		this._fireEvent(clickedLayer ? [clickedLayer] : false, e);
12427  	},
12428
12429  	_onMouseMove: function (e) {
12430  		if (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; }
12431
12432  		var point = this._map.mouseEventToLayerPoint(e);
12433  		this._handleMouseHover(e, point);
12434  	},
12435
12436
12437  	_handleMouseOut: function (e) {
12438  		var layer = this._hoveredLayer;
12439  		if (layer) {
12440  			// if we're leaving the layer, fire mouseout
12441  			removeClass(this._container, 'leaflet-interactive');
12442  			this._fireEvent([layer], e, 'mouseout');
12443  			this._hoveredLayer = null;
12444  			this._mouseHoverThrottled = false;
12445  		}
12446  	},
12447
12448  	_handleMouseHover: function (e, point) {
12449  		if (this._mouseHoverThrottled) {
12450  			return;
12451  		}
12452
12453  		var layer, candidateHoveredLayer;
12454
12455  		for (var order = this._drawFirst; order; order = order.next) {
12456  			layer = order.layer;
12457  			if (layer.options.interactive && layer._containsPoint(point)) {
12458  				candidateHoveredLayer = layer;
12459  			}
12460  		}
12461
12462  		if (candidateHoveredLayer !== this._hoveredLayer) {
12463  			this._handleMouseOut(e);
12464
12465  			if (candidateHoveredLayer) {
12466  				addClass(this._container, 'leaflet-interactive'); // change cursor
12467  				this._fireEvent([candidateHoveredLayer], e, 'mouseover');
12468  				this._hoveredLayer = candidateHoveredLayer;
12469  			}
12470  		}
12471
12472  		this._fireEvent(this._hoveredLayer ? [this._hoveredLayer] : false, e);
12473
12474  		this._mouseHoverThrottled = true;
12475  		setTimeout(bind(function () {
12476  			this._mouseHoverThrottled = false;
12477  		}, this), 32);
12478  	},
12479
12480  	_fireEvent: function (layers, e, type) {
12481  		this._map._fireDOMEvent(e, type || e.type, layers);
12482  	},
12483
12484  	_bringToFront: function (layer) {
12485  		var order = layer._order;
12486
12487  		if (!order) { return; }
12488
12489  		var next = order.next;
12490  		var prev = order.prev;
12491
12492  		if (next) {
12493  			next.prev = prev;
12494  		} else {
12495  			// Already last
12496  			return;
12497  		}
12498  		if (prev) {
12499  			prev.next = next;
12500  		} else if (next) {
12501  			// Update first entry unless this is the
12502  			// single entry
12503  			this._drawFirst = next;
12504  		}
12505
12506  		order.prev = this._drawLast;
12507  		this._drawLast.next = order;
12508
12509  		order.next = null;
12510  		this._drawLast = order;
12511
12512  		this._requestRedraw(layer);
12513  	},
12514
12515  	_bringToBack: function (layer) {
12516  		var order = layer._order;
12517
12518  		if (!order) { return; }
12519
12520  		var next = order.next;
12521  		var prev = order.prev;
12522
12523  		if (prev) {
12524  			prev.next = next;
12525  		} else {
12526  			// Already first
12527  			return;
12528  		}
12529  		if (next) {
12530  			next.prev = prev;
12531  		} else if (prev) {
12532  			// Update last entry unless this is the
12533  			// single entry
12534  			this._drawLast = prev;
12535  		}
12536
12537  		order.prev = null;
12538
12539  		order.next = this._drawFirst;
12540  		this._drawFirst.prev = order;
12541  		this._drawFirst = order;
12542
12543  		this._requestRedraw(layer);
12544  	}
12545  });
12546
12547  // @factory L.canvas(options?: Renderer options)
12548  // Creates a Canvas renderer with the given options.
12549  function canvas(options) {
12550  	return 
vendor: 9,649 bytes, lines 12550-12903
12550canvas$1 ? new Canvas(options) : null;
12551  }
12552
12553  /*
12554   * Thanks to Dmitry Baranovsky and his Raphael library for inspiration!
12555   */
12556
12557
12558  var vmlCreate = (function () {
12559  	try {
12560  		document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');
12561  		return function (name) {
12562  			return document.createElement('<lvml:' + name + ' class="lvml">');
12563  		};
12564  	} catch (e) {
12565  		// Do not return fn from catch block so `e` can be garbage collected
12566  		// See https://github.com/Leaflet/Leaflet/pull/7279
12567  	}
12568  	return function (name) {
12569  		return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
12570  	};
12571  })();
12572
12573
12574  /*
12575   * @class SVG
12576   *
12577   *
12578   * VML was deprecated in 2012, which means VML functionality exists only for backwards compatibility
12579   * with old versions of Internet Explorer.
12580   */
12581
12582  // mixin to redefine some SVG methods to handle VML syntax which is similar but with some differences
12583  var vmlMixin = {
12584
12585  	_initContainer: function () {
12586  		this._container = create$1('div', 'leaflet-vml-container');
12587  	},
12588
12589  	_update: function () {
12590  		if (this._map._animatingZoom) { return; }
12591  		Renderer.prototype._update.call(this);
12592  		this.fire('update');
12593  	},
12594
12595  	_initPath: function (layer) {
12596  		var container = layer._container = vmlCreate('shape');
12597
12598  		addClass(container, 'leaflet-vml-shape ' + (this.options.className || ''));
12599
12600  		container.coordsize = '1 1';
12601
12602  		layer._path = vmlCreate('path');
12603  		container.appendChild(layer._path);
12604
12605  		this._updateStyle(layer);
12606  		this._layers[stamp(layer)] = layer;
12607  	},
12608
12609  	_addPath: function (layer) {
12610  		var container = layer._container;
12611  		this._container.appendChild(container);
12612
12613  		if (layer.options.interactive) {
12614  			layer.addInteractiveTarget(container);
12615  		}
12616  	},
12617
12618  	_removePath: function (layer) {
12619  		var container = layer._container;
12620  		remove(container);
12621  		layer.removeInteractiveTarget(container);
12622  		delete this._layers[stamp(layer)];
12623  	},
12624
12625  	_updateStyle: function (layer) {
12626  		var stroke = layer._stroke,
12627  		    fill = layer._fill,
12628  		    options = layer.options,
12629  		    container = layer._container;
12630
12631  		container.stroked = !!options.stroke;
12632  		container.filled = !!options.fill;
12633
12634  		if (options.stroke) {
12635  			if (!stroke) {
12636  				stroke = layer._stroke = vmlCreate('stroke');
12637  			}
12638  			container.appendChild(stroke);
12639  			stroke.weight = options.weight + 'px';
12640  			stroke.color = options.color;
12641  			stroke.opacity = options.opacity;
12642
12643  			if (options.dashArray) {
12644  				stroke.dashStyle = isArray(options.dashArray) ?
12645  				    options.dashArray.join(' ') :
12646  				    options.dashArray.replace(/( *, *)/g, ' ');
12647  			} else {
12648  				stroke.dashStyle = '';
12649  			}
12650  			stroke.endcap = options.lineCap.replace('butt', 'flat');
12651  			stroke.joinstyle = options.lineJoin;
12652
12653  		} else if (stroke) {
12654  			container.removeChild(stroke);
12655  			layer._stroke = null;
12656  		}
12657
12658  		if (options.fill) {
12659  			if (!fill) {
12660  				fill = layer._fill = vmlCreate('fill');
12661  			}
12662  			container.appendChild(fill);
12663  			fill.color = options.fillColor || options.color;
12664  			fill.opacity = options.fillOpacity;
12665
12666  		} else if (fill) {
12667  			container.removeChild(fill);
12668  			layer._fill = null;
12669  		}
12670  	},
12671
12672  	_updateCircle: function (layer) {
12673  		var p = layer._point.round(),
12674  		    r = Math.round(layer._radius),
12675  		    r2 = Math.round(layer._radiusY || r);
12676
12677  		this._setPath(layer, layer._empty() ? 'M0 0' :
12678  			'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360));
12679  	},
12680
12681  	_setPath: function (layer, path) {
12682  		layer._path.v = path;
12683  	},
12684
12685  	_bringToFront: function (layer) {
12686  		toFront(layer._container);
12687  	},
12688
12689  	_bringToBack: function (layer) {
12690  		toBack(layer._container);
12691  	}
12692  };
12693
12694  var create = vml ? vmlCreate : svgCreate;
12695
12696  /*
12697   * @class SVG
12698   * @inherits Renderer
12699   * @aka L.SVG
12700   *
12701   * Allows vector layers to be displayed with [SVG](https://developer.mozilla.org/docs/Web/SVG).
12702   * Inherits `Renderer`.
12703   *
12704   * Due to [technical limitations](http://caniuse.com/#search=svg), SVG is not
12705   * available in all web browsers, notably Android 2.x and 3.x.
12706   *
12707   * Although SVG is not available on IE7 and IE8, these browsers support
12708   * [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language)
12709   * (a now deprecated technology), and the SVG renderer will fall back to VML in
12710   * this case.
12711   *
12712   * @example
12713   *
12714   * Use SVG by default for all paths in the map:
12715   *
12716   * ```js
12717   * var map = L.map('map', {
12718   * 	renderer: L.svg()
12719   * });
12720   * ```
12721   *
12722   * Use a SVG renderer with extra padding for specific vector geometries:
12723   *
12724   * ```js
12725   * var map = L.map('map');
12726   * var myRenderer = L.svg({ padding: 0.5 });
12727   * var line = L.polyline( coordinates, { renderer: myRenderer } );
12728   * var circle = L.circle( center, { renderer: myRenderer } );
12729   * ```
12730   */
12731
12732  var SVG = Renderer.extend({
12733
12734  	getEvents: function () {
12735  		var events = Renderer.prototype.getEvents.call(this);
12736  		events.zoomstart = this._onZoomStart;
12737  		return events;
12738  	},
12739
12740  	_initContainer: function () {
12741  		this._container = create('svg');
12742
12743  		// makes it possible to click through svg root; we'll reset it back in individual paths
12744  		this._container.setAttribute('pointer-events', 'none');
12745
12746  		this._rootGroup = create('g');
12747  		this._container.appendChild(this._rootGroup);
12748  	},
12749
12750  	_destroyContainer: function () {
12751  		remove(this._container);
12752  		off(this._container);
12753  		delete this._container;
12754  		delete this._rootGroup;
12755  		delete this._svgSize;
12756  	},
12757
12758  	_onZoomStart: function () {
12759  		// Drag-then-pinch interactions might mess up the center and zoom.
12760  		// In this case, the easiest way to prevent this is re-do the renderer
12761  		//   bounds and padding when the zooming starts.
12762  		this._update();
12763  	},
12764
12765  	_update: function () {
12766  		if (this._map._animatingZoom && this._bounds) { return; }
12767
12768  		Renderer.prototype._update.call(this);
12769
12770  		var b = this._bounds,
12771  		    size = b.getSize(),
12772  		    container = this._container;
12773
12774  		// set size of svg-container if changed
12775  		if (!this._svgSize || !this._svgSize.equals(size)) {
12776  			this._svgSize = size;
12777  			container.setAttribute('width', size.x);
12778  			container.setAttribute('height', size.y);
12779  		}
12780
12781  		// movement: update container viewBox so that we don't have to change coordinates of individual layers
12782  		setPosition(container, b.min);
12783  		container.setAttribute('viewBox', [b.min.x, b.min.y, size.x, size.y].join(' '));
12784
12785  		this.fire('update');
12786  	},
12787
12788  	// methods below are called by vector layers implementations
12789
12790  	_initPath: function (layer) {
12791  		var path = layer._path = create('path');
12792
12793  		// @namespace Path
12794  		// @option className: String = null
12795  		// Custom class name set on an element. Only for SVG renderer.
12796  		if (layer.options.className) {
12797  			addClass(path, layer.options.className);
12798  		}
12799
12800  		if (layer.options.interactive) {
12801  			addClass(path, 'leaflet-interactive');
12802  		}
12803
12804  		this._updateStyle(layer);
12805  		this._layers[stamp(layer)] = layer;
12806  	},
12807
12808  	_addPath: function (layer) {
12809  		if (!this._rootGroup) { this._initContainer(); }
12810  		this._rootGroup.appendChild(layer._path);
12811  		layer.addInteractiveTarget(layer._path);
12812  	},
12813
12814  	_removePath: function (layer) {
12815  		remove(layer._path);
12816  		layer.removeInteractiveTarget(layer._path);
12817  		delete this._layers[stamp(layer)];
12818  	},
12819
12820  	_updatePath: function (layer) {
12821  		layer._project();
12822  		layer._update();
12823  	},
12824
12825  	_updateStyle: function (layer) {
12826  		var path = layer._path,
12827  		    options = layer.options;
12828
12829  		if (!path) { return; }
12830
12831  		if (options.stroke) {
12832  			path.setAttribute('stroke', options.color);
12833  			path.setAttribute('stroke-opacity', options.opacity);
12834  			path.setAttribute('stroke-width', options.weight);
12835  			path.setAttribute('stroke-linecap', options.lineCap);
12836  			path.setAttribute('stroke-linejoin', options.lineJoin);
12837
12838  			if (options.dashArray) {
12839  				path.setAttribute('stroke-dasharray', options.dashArray);
12840  			} else {
12841  				path.removeAttribute('stroke-dasharray');
12842  			}
12843
12844  			if (options.dashOffset) {
12845  				path.setAttribute('stroke-dashoffset', options.dashOffset);
12846  			} else {
12847  				path.removeAttribute('stroke-dashoffset');
12848  			}
12849  		} else {
12850  			path.setAttribute('stroke', 'none');
12851  		}
12852
12853  		if (options.fill) {
12854  			path.setAttribute('fill', options.fillColor || options.color);
12855  			path.setAttribute('fill-opacity', options.fillOpacity);
12856  			path.setAttribute('fill-rule', options.fillRule || 'evenodd');
12857  		} else {
12858  			path.setAttribute('fill', 'none');
12859  		}
12860  	},
12861
12862  	_updatePoly: function (layer, closed) {
12863  		this._setPath(layer, pointsToPath(layer._parts, closed));
12864  	},
12865
12866  	_updateCircle: function (layer) {
12867  		var p = layer._point,
12868  		    r = Math.max(Math.round(layer._radius), 1),
12869  		    r2 = Math.max(Math.round(layer._radiusY), 1) || r,
12870  		    arc = 'a' + r + ',' + r2 + ' 0 1,0 ';
12871
12872  		// drawing a circle with two half-arcs
12873  		var d = layer._empty() ? 'M0 0' :
12874  			'M' + (p.x - r) + ',' + p.y +
12875  			arc + (r * 2) + ',0 ' +
12876  			arc + (-r * 2) + ',0 ';
12877
12878  		this._setPath(layer, d);
12879  	},
12880
12881  	_setPath: function (layer, path) {
12882  		layer._path.setAttribute('d', path);
12883  	},
12884
12885  	// SVG does not have the concept of zIndex so we resort to changing the DOM order of elements
12886  	_bringToFront: function (layer) {
12887  		toFront(layer._path);
12888  	},
12889
12890  	_bringToBack: function (layer) {
12891  		toBack(layer._path);
12892  	}
12893  });
12894
12895  if (vml) {
12896  	SVG.include(vmlMixin);
12897  }
12898
12899  // @namespace SVG
12900  // @factory L.svg(options?: Renderer options)
12901  // Creates a SVG renderer with the given options.
12902  function svg(options) {
12903  	return svg$1 || 
vendor: 8,853 bytes, lines 12903-13220
12903vml ? new SVG(options) : null;
12904  }
12905
12906  Map.include({
12907  	// @namespace Map; @method getRenderer(layer: Path): Renderer
12908  	// Returns the instance of `Renderer` that should be used to render the given
12909  	// `Path`. It will ensure that the `renderer` options of the map and paths
12910  	// are respected, and that the renderers do exist on the map.
12911  	getRenderer: function (layer) {
12912  		// @namespace Path; @option renderer: Renderer
12913  		// Use this specific instance of `Renderer` for this path. Takes
12914  		// precedence over the map's [default renderer](#map-renderer).
12915  		var renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;
12916
12917  		if (!renderer) {
12918  			renderer = this._renderer = this._createRenderer();
12919  		}
12920
12921  		if (!this.hasLayer(renderer)) {
12922  			this.addLayer(renderer);
12923  		}
12924  		return renderer;
12925  	},
12926
12927  	_getPaneRenderer: function (name) {
12928  		if (name === 'overlayPane' || name === undefined) {
12929  			return false;
12930  		}
12931
12932  		var renderer = this._paneRenderers[name];
12933  		if (renderer === undefined) {
12934  			renderer = this._createRenderer({pane: name});
12935  			this._paneRenderers[name] = renderer;
12936  		}
12937  		return renderer;
12938  	},
12939
12940  	_createRenderer: function (options) {
12941  		// @namespace Map; @option preferCanvas: Boolean = false
12942  		// Whether `Path`s should be rendered on a `Canvas` renderer.
12943  		// By default, all `Path`s are rendered in a `SVG` renderer.
12944  		return (this.options.preferCanvas && canvas(options)) || svg(options);
12945  	}
12946  });
12947
12948  /*
12949   * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object.
12950   */
12951
12952  /*
12953   * @class Rectangle
12954   * @aka L.Rectangle
12955   * @inherits Polygon
12956   *
12957   * A class for drawing rectangle overlays on a map. Extends `Polygon`.
12958   *
12959   * @example
12960   *
12961   * ```js
12962   * // define rectangle geographical bounds
12963   * var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];
12964   *
12965   * // create an orange rectangle
12966   * L.rectangle(bounds, {color: "#ff7800", weight: 1}).addTo(map);
12967   *
12968   * // zoom the map to the rectangle bounds
12969   * map.fitBounds(bounds);
12970   * ```
12971   *
12972   */
12973
12974
12975  var Rectangle = Polygon.extend({
12976  	initialize: function (latLngBounds, options) {
12977  		Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);
12978  	},
12979
12980  	// @method setBounds(latLngBounds: LatLngBounds): this
12981  	// Redraws the rectangle with the passed bounds.
12982  	setBounds: function (latLngBounds) {
12983  		return this.setLatLngs(this._boundsToLatLngs(latLngBounds));
12984  	},
12985
12986  	_boundsToLatLngs: function (latLngBounds) {
12987  		latLngBounds = toLatLngBounds(latLngBounds);
12988  		return [
12989  			latLngBounds.getSouthWest(),
12990  			latLngBounds.getNorthWest(),
12991  			latLngBounds.getNorthEast(),
12992  			latLngBounds.getSouthEast()
12993  		];
12994  	}
12995  });
12996
12997
12998  // @factory L.rectangle(latLngBounds: LatLngBounds, options?: Polyline options)
12999  function rectangle(latLngBounds, options) {
13000  	return new Rectangle(latLngBounds, options);
13001  }
13002
13003  SVG.create = create;
13004  SVG.pointsToPath = pointsToPath;
13005
13006  GeoJSON.geometryToLayer = geometryToLayer;
13007  GeoJSON.coordsToLatLng = coordsToLatLng;
13008  GeoJSON.coordsToLatLngs = coordsToLatLngs;
13009  GeoJSON.latLngToCoords = latLngToCoords;
13010  GeoJSON.latLngsToCoords = latLngsToCoords;
13011  GeoJSON.getFeature = getFeature;
13012  GeoJSON.asFeature = asFeature;
13013
13014  /*
13015   * L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map
13016   * (zoom to a selected bounding box), enabled by default.
13017   */
13018
13019  // @namespace Map
13020  // @section Interaction Options
13021  Map.mergeOptions({
13022  	// @option boxZoom: Boolean = true
13023  	// Whether the map can be zoomed to a rectangular area specified by
13024  	// dragging the mouse while pressing the shift key.
13025  	boxZoom: true
13026  });
13027
13028  var BoxZoom = Handler.extend({
13029  	initialize: function (map) {
13030  		this._map = map;
13031  		this._container = map._container;
13032  		this._pane = map._panes.overlayPane;
13033  		this._resetStateTimeout = 0;
13034  		map.on('unload', this._destroy, this);
13035  	},
13036
13037  	addHooks: function () {
13038  		on(this._container, 'mousedown', this._onMouseDown, this);
13039  	},
13040
13041  	removeHooks: function () {
13042  		off(this._container, 'mousedown', this._onMouseDown, this);
13043  	},
13044
13045  	moved: function () {
13046  		return this._moved;
13047  	},
13048
13049  	_destroy: function () {
13050  		remove(this._pane);
13051  		delete this._pane;
13052  	},
13053
13054  	_resetState: function () {
13055  		this._resetStateTimeout = 0;
13056  		this._moved = false;
13057  	},
13058
13059  	_clearDeferredResetState: function () {
13060  		if (this._resetStateTimeout !== 0) {
13061  			clearTimeout(this._resetStateTimeout);
13062  			this._resetStateTimeout = 0;
13063  		}
13064  	},
13065
13066  	_onMouseDown: function (e) {
13067  		if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
13068
13069  		// Clear the deferred resetState if it hasn't executed yet, otherwise it
13070  		// will interrupt the interaction and orphan a box element in the container.
13071  		this._clearDeferredResetState();
13072  		this._resetState();
13073
13074  		disableTextSelection();
13075  		disableImageDrag();
13076
13077  		this._startPoint = this._map.mouseEventToContainerPoint(e);
13078
13079  		on(document, {
13080  			contextmenu: stop,
13081  			mousemove: this._onMouseMove,
13082  			mouseup: this._onMouseUp,
13083  			keydown: this._onKeyDown
13084  		}, this);
13085  	},
13086
13087  	_onMouseMove: function (e) {
13088  		if (!this._moved) {
13089  			this._moved = true;
13090
13091  			this._box = create$1('div', 'leaflet-zoom-box', this._container);
13092  			addClass(this._container, 'leaflet-crosshair');
13093
13094  			this._map.fire('boxzoomstart');
13095  		}
13096
13097  		this._point = this._map.mouseEventToContainerPoint(e);
13098
13099  		var bounds = new Bounds(this._point, this._startPoint),
13100  		    size = bounds.getSize();
13101
13102  		setPosition(this._box, bounds.min);
13103
13104  		this._box.style.width  = size.x + 'px';
13105  		this._box.style.height = size.y + 'px';
13106  	},
13107
13108  	_finish: function () {
13109  		if (this._moved) {
13110  			remove(this._box);
13111  			removeClass(this._container, 'leaflet-crosshair');
13112  		}
13113
13114  		enableTextSelection();
13115  		enableImageDrag();
13116
13117  		off(document, {
13118  			contextmenu: stop,
13119  			mousemove: this._onMouseMove,
13120  			mouseup: this._onMouseUp,
13121  			keydown: this._onKeyDown
13122  		}, this);
13123  	},
13124
13125  	_onMouseUp: function (e) {
13126  		if ((e.which !== 1) && (e.button !== 1)) { return; }
13127
13128  		this._finish();
13129
13130  		if (!this._moved) { return; }
13131  		// Postpone to next JS tick so internal click event handling
13132  		// still see it as "moved".
13133  		this._clearDeferredResetState();
13134  		this._resetStateTimeout = setTimeout(bind(this._resetState, this), 0);
13135
13136  		var bounds = new LatLngBounds(
13137  		        this._map.containerPointToLatLng(this._startPoint),
13138  		        this._map.containerPointToLatLng(this._point));
13139
13140  		this._map
13141  			.fitBounds(bounds)
13142  			.fire('boxzoomend', {boxZoomBounds: bounds});
13143  	},
13144
13145  	_onKeyDown: function (e) {
13146  		if (e.keyCode === 27) {
13147  			this._finish();
13148  			this._clearDeferredResetState();
13149  			this._resetState();
13150  		}
13151  	}
13152  });
13153
13154  // @section Handlers
13155  // @property boxZoom: Handler
13156  // Box (shift-drag with mouse) zoom handler.
13157  Map.addInitHook('addHandler', 'boxZoom', BoxZoom);
13158
13159  /*
13160   * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default.
13161   */
13162
13163  // @namespace Map
13164  // @section Interaction Options
13165
13166  Map.mergeOptions({
13167  	// @option doubleClickZoom: Boolean|String = true
13168  	// Whether the map can be zoomed in by double clicking on it and
13169  	// zoomed out by double clicking while holding shift. If passed
13170  	// `'center'`, double-click zoom will zoom to the center of the
13171  	//  view regardless of where the mouse was.
13172  	doubleClickZoom: true
13173  });
13174
13175  var DoubleClickZoom = Handler.extend({
13176  	addHooks: function () {
13177  		this._map.on('dblclick', this._onDoubleClick, this);
13178  	},
13179
13180  	removeHooks: function () {
13181  		this._map.off('dblclick', this._onDoubleClick, this);
13182  	},
13183
13184  	_onDoubleClick: function (e) {
13185  		var map = this._map,
13186  		    oldZoom = map.getZoom(),
13187  		    delta = map.options.zoomDelta,
13188  		    zoom = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta;
13189
13190  		if (map.options.doubleClickZoom === 'center') {
13191  			map.setZoom(zoom);
13192  		} else {
13193  			map.setZoomAround(e.containerPoint, zoom);
13194  		}
13195  	}
13196  });
13197
13198  // @section Handlers
13199  //
13200  // Map properties include interaction handlers that allow you to control
13201  // interaction behavior in runtime, enabling or disabling certain features such
13202  // as dragging or touch zoom (see `Handler` methods). For example:
13203  //
13204  // ```js
13205  // map.doubleClickZoom.disable();
13206  // ```
13207  //
13208  // @property doubleClickZoom: Handler
13209  // Double click zoom handler.
13210  Map.addInitHook('addHandler', 'doubleClickZoom', DoubleClickZoom);
13211
13212  /*
13213   * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default.
13214   */
13215
13216  // @namespace Map
13217  // @section Interaction Options
13218  Map.mergeOptions({
13219  	// @option dragging: Boolean = true
13220  	// Whether the map 
13220be draggable with mouse/touch or not.
13221  	dragging: true,
13222
13223  	// @section Panning Inertia Options
13224  	// @option inertia: Boolean = *
13225  	// If enabled, panning of the map will have an inertia effect where
13226  	// the map builds momentum while dragging and continues moving in
13227  	// the same direction for some time. Feels especially nice on touch
13228  	// devices. Enabled by default.
13229  	inertia: true,
13230
13231  	// @option inertiaDeceleration: Number = 3000
13232  	// The rate with which the inertial movement slows down, in pixels/second².
13233  	inertiaDeceleration: 3400, // px/s^2
13234
13235  	// @option inertiaMaxSpeed: Number = Infinity
13236  	// Max speed of the inertial movement, in pixels/second.
13237  	inertiaMaxSpeed: Infinity, // px/s
13238
13239  	// @option easeLinearity: Number = 0.2
13240  	easeLinearity: 0.2,
13241
13242  	// TODO refactor, move to CRS
13243  	// @option worldCopyJump: Boolean = false
13244  	// With this option enabled, the map tracks when you pan to another "copy"
13245  	// of the world and seamlessly jumps to the original one so that all overlays
13246  	// like markers and vector layers are still visible.
vendor: 20,306 bytes, lines 13247-13944
13247  	worldCopyJump: false,
13248
13249  	// @option maxBoundsViscosity: Number = 0.0
13250  	// If `maxBounds` is set, this option will control how solid the bounds
13251  	// are when dragging the map around. The default value of `0.0` allows the
13252  	// user to drag outside the bounds at normal speed, higher values will
13253  	// slow down map dragging outside bounds, and `1.0` makes the bounds fully
13254  	// solid, preventing the user from dragging outside the bounds.
13255  	maxBoundsViscosity: 0.0
13256  });
13257
13258  var Drag = Handler.extend({
13259  	addHooks: function () {
13260  		if (!this._draggable) {
13261  			var map = this._map;
13262
13263  			this._draggable = new Draggable(map._mapPane, map._container);
13264
13265  			this._draggable.on({
13266  				dragstart: this._onDragStart,
13267  				drag: this._onDrag,
13268  				dragend: this._onDragEnd
13269  			}, this);
13270
13271  			this._draggable.on('predrag', this._onPreDragLimit, this);
13272  			if (map.options.worldCopyJump) {
13273  				this._draggable.on('predrag', this._onPreDragWrap, this);
13274  				map.on('zoomend', this._onZoomEnd, this);
13275
13276  				map.whenReady(this._onZoomEnd, this);
13277  			}
13278  		}
13279  		addClass(this._map._container, 'leaflet-grab leaflet-touch-drag');
13280  		this._draggable.enable();
13281  		this._positions = [];
13282  		this._times = [];
13283  	},
13284
13285  	removeHooks: function () {
13286  		removeClass(this._map._container, 'leaflet-grab');
13287  		removeClass(this._map._container, 'leaflet-touch-drag');
13288  		this._draggable.disable();
13289  	},
13290
13291  	moved: function () {
13292  		return this._draggable && this._draggable._moved;
13293  	},
13294
13295  	moving: function () {
13296  		return this._draggable && this._draggable._moving;
13297  	},
13298
13299  	_onDragStart: function () {
13300  		var map = this._map;
13301
13302  		map._stop();
13303  		if (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) {
13304  			var bounds = toLatLngBounds(this._map.options.maxBounds);
13305
13306  			this._offsetLimit = toBounds(
13307  				this._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),
13308  				this._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1)
13309  					.add(this._map.getSize()));
13310
13311  			this._viscosity = Math.min(1.0, Math.max(0.0, this._map.options.maxBoundsViscosity));
13312  		} else {
13313  			this._offsetLimit = null;
13314  		}
13315
13316  		map
13317  		    .fire('movestart')
13318  		    .fire('dragstart');
13319
13320  		if (map.options.inertia) {
13321  			this._positions = [];
13322  			this._times = [];
13323  		}
13324  	},
13325
13326  	_onDrag: function (e) {
13327  		if (this._map.options.inertia) {
13328  			var time = this._lastTime = +new Date(),
13329  			    pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;
13330
13331  			this._positions.push(pos);
13332  			this._times.push(time);
13333
13334  			this._prunePositions(time);
13335  		}
13336
13337  		this._map
13338  		    .fire('move', e)
13339  		    .fire('drag', e);
13340  	},
13341
13342  	_prunePositions: function (time) {
13343  		while (this._positions.length > 1 && time - this._times[0] > 50) {
13344  			this._positions.shift();
13345  			this._times.shift();
13346  		}
13347  	},
13348
13349  	_onZoomEnd: function () {
13350  		var pxCenter = this._map.getSize().divideBy(2),
13351  		    pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);
13352
13353  		this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;
13354  		this._worldWidth = this._map.getPixelWorldBounds().getSize().x;
13355  	},
13356
13357  	_viscousLimit: function (value, threshold) {
13358  		return value - (value - threshold) * this._viscosity;
13359  	},
13360
13361  	_onPreDragLimit: function () {
13362  		if (!this._viscosity || !this._offsetLimit) { return; }
13363
13364  		var offset = this._draggable._newPos.subtract(this._draggable._startPos);
13365
13366  		var limit = this._offsetLimit;
13367  		if (offset.x < limit.min.x) { offset.x = this._viscousLimit(offset.x, limit.min.x); }
13368  		if (offset.y < limit.min.y) { offset.y = this._viscousLimit(offset.y, limit.min.y); }
13369  		if (offset.x > limit.max.x) { offset.x = this._viscousLimit(offset.x, limit.max.x); }
13370  		if (offset.y > limit.max.y) { offset.y = this._viscousLimit(offset.y, limit.max.y); }
13371
13372  		this._draggable._newPos = this._draggable._startPos.add(offset);
13373  	},
13374
13375  	_onPreDragWrap: function () {
13376  		// TODO refactor to be able to adjust map pane position after zoom
13377  		var worldWidth = this._worldWidth,
13378  		    halfWidth = Math.round(worldWidth / 2),
13379  		    dx = this._initialWorldOffset,
13380  		    x = this._draggable._newPos.x,
13381  		    newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx,
13382  		    newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx,
13383  		    newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;
13384
13385  		this._draggable._absPos = this._draggable._newPos.clone();
13386  		this._draggable._newPos.x = newX;
13387  	},
13388
13389  	_onDragEnd: function (e) {
13390  		var map = this._map,
13391  		    options = map.options,
13392
13393  		    noInertia = !options.inertia || this._times.length < 2;
13394
13395  		map.fire('dragend', e);
13396
13397  		if (noInertia) {
13398  			map.fire('moveend');
13399
13400  		} else {
13401  			this._prunePositions(+new Date());
13402
13403  			var direction = this._lastPos.subtract(this._positions[0]),
13404  			    duration = (this._lastTime - this._times[0]) / 1000,
13405  			    ease = options.easeLinearity,
13406
13407  			    speedVector = direction.multiplyBy(ease / duration),
13408  			    speed = speedVector.distanceTo([0, 0]),
13409
13410  			    limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),
13411  			    limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),
13412
13413  			    decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease),
13414  			    offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();
13415
13416  			if (!offset.x && !offset.y) {
13417  				map.fire('moveend');
13418
13419  			} else {
13420  				offset = map._limitOffset(offset, map.options.maxBounds);
13421
13422  				requestAnimFrame(function () {
13423  					map.panBy(offset, {
13424  						duration: decelerationDuration,
13425  						easeLinearity: ease,
13426  						noMoveStart: true,
13427  						animate: true
13428  					});
13429  				});
13430  			}
13431  		}
13432  	}
13433  });
13434
13435  // @section Handlers
13436  // @property dragging: Handler
13437  // Map dragging handler (by both mouse and touch).
13438  Map.addInitHook('addHandler', 'dragging', Drag);
13439
13440  /*
13441   * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default.
13442   */
13443
13444  // @namespace Map
13445  // @section Keyboard Navigation Options
13446  Map.mergeOptions({
13447  	// @option keyboard: Boolean = true
13448  	// Makes the map focusable and allows users to navigate the map with keyboard
13449  	// arrows and `+`/`-` keys.
13450  	keyboard: true,
13451
13452  	// @option keyboardPanDelta: Number = 80
13453  	// Amount of pixels to pan when pressing an arrow key.
13454  	keyboardPanDelta: 80
13455  });
13456
13457  var Keyboard = Handler.extend({
13458
13459  	keyCodes: {
13460  		left:    [37],
13461  		right:   [39],
13462  		down:    [40],
13463  		up:      [38],
13464  		zoomIn:  [187, 107, 61, 171],
13465  		zoomOut: [189, 109, 54, 173]
13466  	},
13467
13468  	initialize: function (map) {
13469  		this._map = map;
13470
13471  		this._setPanDelta(map.options.keyboardPanDelta);
13472  		this._setZoomDelta(map.options.zoomDelta);
13473  	},
13474
13475  	addHooks: function () {
13476  		var container = this._map._container;
13477
13478  		// make the container focusable by tabbing
13479  		if (container.tabIndex <= 0) {
13480  			container.tabIndex = '0';
13481  		}
13482
13483  		on(container, {
13484  			focus: this._onFocus,
13485  			blur: this._onBlur,
13486  			mousedown: this._onMouseDown
13487  		}, this);
13488
13489  		this._map.on({
13490  			focus: this._addHooks,
13491  			blur: this._removeHooks
13492  		}, this);
13493  	},
13494
13495  	removeHooks: function () {
13496  		this._removeHooks();
13497
13498  		off(this._map._container, {
13499  			focus: this._onFocus,
13500  			blur: this._onBlur,
13501  			mousedown: this._onMouseDown
13502  		}, this);
13503
13504  		this._map.off({
13505  			focus: this._addHooks,
13506  			blur: this._removeHooks
13507  		}, this);
13508  	},
13509
13510  	_onMouseDown: function () {
13511  		if (this._focused) { return; }
13512
13513  		var body = document.body,
13514  		    docEl = document.documentElement,
13515  		    top = body.scrollTop || docEl.scrollTop,
13516  		    left = body.scrollLeft || docEl.scrollLeft;
13517
13518  		this._map._container.focus();
13519
13520  		window.scrollTo(left, top);
13521  	},
13522
13523  	_onFocus: function () {
13524  		this._focused = true;
13525  		this._map.fire('focus');
13526  	},
13527
13528  	_onBlur: function () {
13529  		this._focused = false;
13530  		this._map.fire('blur');
13531  	},
13532
13533  	_setPanDelta: function (panDelta) {
13534  		var keys = this._panKeys = {},
13535  		    codes = this.keyCodes,
13536  		    i, len;
13537
13538  		for (i = 0, len = codes.left.length; i < len; i++) {
13539  			keys[codes.left[i]] = [-1 * panDelta, 0];
13540  		}
13541  		for (i = 0, len = codes.right.length; i < len; i++) {
13542  			keys[codes.right[i]] = [panDelta, 0];
13543  		}
13544  		for (i = 0, len = codes.down.length; i < len; i++) {
13545  			keys[codes.down[i]] = [0, panDelta];
13546  		}
13547  		for (i = 0, len = codes.up.length; i < len; i++) {
13548  			keys[codes.up[i]] = [0, -1 * panDelta];
13549  		}
13550  	},
13551
13552  	_setZoomDelta: function (zoomDelta) {
13553  		var keys = this._zoomKeys = {},
13554  		    codes = this.keyCodes,
13555  		    i, len;
13556
13557  		for (i = 0, len = codes.zoomIn.length; i < len; i++) {
13558  			keys[codes.zoomIn[i]] = zoomDelta;
13559  		}
13560  		for (i = 0, len = codes.zoomOut.length; i < len; i++) {
13561  			keys[codes.zoomOut[i]] = -zoomDelta;
13562  		}
13563  	},
13564
13565  	_addHooks: function () {
13566  		on(document, 'keydown', this._onKeyDown, this);
13567  	},
13568
13569  	_removeHooks: function () {
13570  		off(document, 'keydown', this._onKeyDown, this);
13571  	},
13572
13573  	_onKeyDown: function (e) {
13574  		if (e.altKey || e.ctrlKey || e.metaKey) { return; }
13575
13576  		var key = e.keyCode,
13577  		    map = this._map,
13578  		    offset;
13579
13580  		if (key in this._panKeys) {
13581  			if (!map._panAnim || !map._panAnim._inProgress) {
13582  				offset = this._panKeys[key];
13583  				if (e.shiftKey) {
13584  					offset = toPoint(offset).multiplyBy(3);
13585  				}
13586
13587  				map.panBy(offset);
13588
13589  				if (map.options.maxBounds) {
13590  					map.panInsideBounds(map.options.maxBounds);
13591  				}
13592  			}
13593  		} else if (key in this._zoomKeys) {
13594  			map.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);
13595
13596  		} else if (key === 27 && map._popup && map._popup.options.closeOnEscapeKey) {
13597  			map.closePopup();
13598
13599  		} else {
13600  			return;
13601  		}
13602
13603  		stop(e);
13604  	}
13605  });
13606
13607  // @section Handlers
13608  // @section Handlers
13609  // @property keyboard: Handler
13610  // Keyboard navigation handler.
13611  Map.addInitHook('addHandler', 'keyboard', Keyboard);
13612
13613  /*
13614   * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map.
13615   */
13616
13617  // @namespace Map
13618  // @section Interaction Options
13619  Map.mergeOptions({
13620  	// @section Mouse wheel options
13621  	// @option scrollWheelZoom: Boolean|String = true
13622  	// Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,
13623  	// it will zoom to the center of the view regardless of where the mouse was.
13624  	scrollWheelZoom: true,
13625
13626  	// @option wheelDebounceTime: Number = 40
13627  	// Limits the rate at which a wheel can fire (in milliseconds). By default
13628  	// user can't zoom via wheel more often than once per 40 ms.
13629  	wheelDebounceTime: 40,
13630
13631  	// @option wheelPxPerZoomLevel: Number = 60
13632  	// How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta))
13633  	// mean a change of one full zoom level. Smaller values will make wheel-zooming
13634  	// faster (and vice versa).
13635  	wheelPxPerZoomLevel: 60
13636  });
13637
13638  var ScrollWheelZoom = Handler.extend({
13639  	addHooks: function () {
13640  		on(this._map._container, 'wheel', this._onWheelScroll, this);
13641
13642  		this._delta = 0;
13643  	},
13644
13645  	removeHooks: function () {
13646  		off(this._map._container, 'wheel', this._onWheelScroll, this);
13647  	},
13648
13649  	_onWheelScroll: function (e) {
13650  		var delta = getWheelDelta(e);
13651
13652  		var debounce = this._map.options.wheelDebounceTime;
13653
13654  		this._delta += delta;
13655  		this._lastMousePos = this._map.mouseEventToContainerPoint(e);
13656
13657  		if (!this._startTime) {
13658  			this._startTime = +new Date();
13659  		}
13660
13661  		var left = Math.max(debounce - (+new Date() - this._startTime), 0);
13662
13663  		clearTimeout(this._timer);
13664  		this._timer = setTimeout(bind(this._performZoom, this), left);
13665
13666  		stop(e);
13667  	},
13668
13669  	_performZoom: function () {
13670  		var map = this._map,
13671  		    zoom = map.getZoom(),
13672  		    snap = this._map.options.zoomSnap || 0;
13673
13674  		map._stop(); // stop panning and fly animations if any
13675
13676  		// map the delta with a sigmoid function to -4..4 range leaning on -1..1
13677  		var d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),
13678  		    d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,
13679  		    d4 = snap ? Math.ceil(d3 / snap) * snap : d3,
13680  		    delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;
13681
13682  		this._delta = 0;
13683  		this._startTime = null;
13684
13685  		if (!delta) { return; }
13686
13687  		if (map.options.scrollWheelZoom === 'center') {
13688  			map.setZoom(zoom + delta);
13689  		} else {
13690  			map.setZoomAround(this._lastMousePos, zoom + delta);
13691  		}
13692  	}
13693  });
13694
13695  // @section Handlers
13696  // @property scrollWheelZoom: Handler
13697  // Scroll wheel zoom handler.
13698  Map.addInitHook('addHandler', 'scrollWheelZoom', ScrollWheelZoom);
13699
13700  /*
13701   * L.Map.TapHold is used to simulate `contextmenu` event on long hold,
13702   * which otherwise is not fired by mobile Safari.
13703   */
13704
13705  var tapHoldDelay = 600;
13706
13707  // @namespace Map
13708  // @section Interaction Options
13709  Map.mergeOptions({
13710  	// @section Touch interaction options
13711  	// @option tapHold: Boolean
13712  	// Enables simulation of `contextmenu` event, default is `true` for mobile Safari.
13713  	tapHold: touchNative && safari && mobile,
13714
13715  	// @option tapTolerance: Number = 15
13716  	// The max number of pixels a user can shift his finger during touch
13717  	// for it to be considered a valid tap.
13718  	tapTolerance: 15
13719  });
13720
13721  var TapHold = Handler.extend({
13722  	addHooks: function () {
13723  		on(this._map._container, 'touchstart', this._onDown, this);
13724  	},
13725
13726  	removeHooks: function () {
13727  		off(this._map._container, 'touchstart', this._onDown, this);
13728  	},
13729
13730  	_onDown: function (e) {
13731  		clearTimeout(this._holdTimeout);
13732  		if (e.touches.length !== 1) { return; }
13733
13734  		var first = e.touches[0];
13735  		this._startPos = this._newPos = new Point(first.clientX, first.clientY);
13736
13737  		this._holdTimeout = setTimeout(bind(function () {
13738  			this._cancel();
13739  			if (!this._isTapValid()) { return; }
13740
13741  			// prevent simulated mouse events https://w3c.github.io/touch-events/#mouse-events
13742  			on(document, 'touchend', preventDefault);
13743  			on(document, 'touchend touchcancel', this._cancelClickPrevent);
13744  			this._simulateEvent('contextmenu', first);
13745  		}, this), tapHoldDelay);
13746
13747  		on(document, 'touchend touchcancel contextmenu', this._cancel, this);
13748  		on(document, 'touchmove', this._onMove, this);
13749  	},
13750
13751  	_cancelClickPrevent: function cancelClickPrevent() {
13752  		off(document, 'touchend', preventDefault);
13753  		off(document, 'touchend touchcancel', cancelClickPrevent);
13754  	},
13755
13756  	_cancel: function () {
13757  		clearTimeout(this._holdTimeout);
13758  		off(document, 'touchend touchcancel contextmenu', this._cancel, this);
13759  		off(document, 'touchmove', this._onMove, this);
13760  	},
13761
13762  	_onMove: function (e) {
13763  		var first = e.touches[0];
13764  		this._newPos = new Point(first.clientX, first.clientY);
13765  	},
13766
13767  	_isTapValid: function () {
13768  		return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;
13769  	},
13770
13771  	_simulateEvent: function (type, e) {
13772  		var simulatedEvent = new MouseEvent(type, {
13773  			bubbles: true,
13774  			cancelable: true,
13775  			view: window,
13776  			// detail: 1,
13777  			screenX: e.screenX,
13778  			screenY: e.screenY,
13779  			clientX: e.clientX,
13780  			clientY: e.clientY,
13781  			// button: 2,
13782  			// buttons: 2
13783  		});
13784
13785  		simulatedEvent._simulated = true;
13786
13787  		e.target.dispatchEvent(simulatedEvent);
13788  	}
13789  });
13790
13791  // @section Handlers
13792  // @property tapHold: Handler
13793  // Long tap handler to simulate `contextmenu` event (useful in mobile Safari).
13794  Map.addInitHook('addHandler', 'tapHold', TapHold);
13795
13796  /*
13797   * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.
13798   */
13799
13800  // @namespace Map
13801  // @section Interaction Options
13802  Map.mergeOptions({
13803  	// @section Touch interaction options
13804  	// @option touchZoom: Boolean|String = *
13805  	// Whether the map can be zoomed by touch-dragging with two fingers. If
13806  	// passed `'center'`, it will zoom to the center of the view regardless of
13807  	// where the touch events (fingers) were. Enabled for touch-capable web
13808  	// browsers.
13809  	touchZoom: touch,
13810
13811  	// @option bounceAtZoomLimits: Boolean = true
13812  	// Set it to false if you don't want the map to zoom beyond min/max zoom
13813  	// and then bounce back when pinch-zooming.
13814  	bounceAtZoomLimits: true
13815  });
13816
13817  var TouchZoom = Handler.extend({
13818  	addHooks: function () {
13819  		addClass(this._map._container, 'leaflet-touch-zoom');
13820  		on(this._map._container, 'touchstart', this._onTouchStart, this);
13821  	},
13822
13823  	removeHooks: function () {
13824  		removeClass(this._map._container, 'leaflet-touch-zoom');
13825  		off(this._map._container, 'touchstart', this._onTouchStart, this);
13826  	},
13827
13828  	_onTouchStart: function (e) {
13829  		var map = this._map;
13830  		if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; }
13831
13832  		var p1 = map.mouseEventToContainerPoint(e.touches[0]),
13833  		    p2 = map.mouseEventToContainerPoint(e.touches[1]);
13834
13835  		this._centerPoint = map.getSize()._divideBy(2);
13836  		this._startLatLng = map.containerPointToLatLng(this._centerPoint);
13837  		if (map.options.touchZoom !== 'center') {
13838  			this._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));
13839  		}
13840
13841  		this._startDist = p1.distanceTo(p2);
13842  		this._startZoom = map.getZoom();
13843
13844  		this._moved = false;
13845  		this._zooming = true;
13846
13847  		map._stop();
13848
13849  		on(document, 'touchmove', this._onTouchMove, this);
13850  		on(document, 'touchend touchcancel', this._onTouchEnd, this);
13851
13852  		preventDefault(e);
13853  	},
13854
13855  	_onTouchMove: function (e) {
13856  		if (!e.touches || e.touches.length !== 2 || !this._zooming) { return; }
13857
13858  		var map = this._map,
13859  		    p1 = map.mouseEventToContainerPoint(e.touches[0]),
13860  		    p2 = map.mouseEventToContainerPoint(e.touches[1]),
13861  		    scale = p1.distanceTo(p2) / this._startDist;
13862
13863  		this._zoom = map.getScaleZoom(scale, this._startZoom);
13864
13865  		if (!map.options.bounceAtZoomLimits && (
13866  			(this._zoom < map.getMinZoom() && scale < 1) ||
13867  			(this._zoom > map.getMaxZoom() && scale > 1))) {
13868  			this._zoom = map._limitZoom(this._zoom);
13869  		}
13870
13871  		if (map.options.touchZoom === 'center') {
13872  			this._center = this._startLatLng;
13873  			if (scale === 1) { return; }
13874  		} else {
13875  			// Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng
13876  			var delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);
13877  			if (scale === 1 && delta.x === 0 && delta.y === 0) { return; }
13878  			this._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom);
13879  		}
13880
13881  		if (!this._moved) {
13882  			map._moveStart(true, false);
13883  			this._moved = true;
13884  		}
13885
13886  		cancelAnimFrame(this._animRequest);
13887
13888  		var moveFn = bind(map._move, map, this._center, this._zoom, {pinch: true, round: false});
13889  		this._animRequest = requestAnimFrame(moveFn, this, true);
13890
13891  		preventDefault(e);
13892  	},
13893
13894  	_onTouchEnd: function () {
13895  		if (!this._moved || !this._zooming) {
13896  			this._zooming = false;
13897  			return;
13898  		}
13899
13900  		this._zooming = false;
13901  		cancelAnimFrame(this._animRequest);
13902
13903  		off(document, 'touchmove', this._onTouchMove, this);
13904  		off(document, 'touchend touchcancel', this._onTouchEnd, this);
13905
13906  		// Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.
13907  		if (this._map.options.zoomAnimation) {
13908  			this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);
13909  		} else {
13910  			this._map._resetView(this._center, this._map._limitZoom(this._zoom));
13911  		}
13912  	}
13913  });
13914
13915  // @section Handlers
13916  // @property touchZoom: Handler
13917  // Touch zoom handler.
13918  Map.addInitHook('addHandler', 'touchZoom', TouchZoom);
13919
13920  Map.BoxZoom = BoxZoom;
13921  Map.DoubleClickZoom = DoubleClickZoom;
13922  Map.Drag = Drag;
13923  Map.Keyboard = Keyboard;
13924  Map.ScrollWheelZoom = ScrollWheelZoom;
13925  Map.TapHold = TapHold;
13926  Map.TouchZoom = TouchZoom;
13927
13928  exports.Bounds = Bounds;
13929  exports.Browser = Browser;
13930  exports.CRS = CRS;
13931  exports.Canvas = Canvas;
13932  exports.Circle = Circle;
13933  exports.CircleMarker = CircleMarker;
13934  exports.Class = Class;
13935  exports.Control = Control;
13936  exports.DivIcon = DivIcon;
13937  exports.DivOverlay = DivOverlay;
13938  exports.DomEvent = DomEvent;
13939  exports.DomUtil = DomUtil;
13940  exports.Draggable = Draggable;
13941  exports.Evented = Evented;
13942  exports.FeatureGroup = FeatureGroup;
13943  exports.GeoJSON = GeoJSON;
13944  exports.GridLayer = GridLayer;
13945  exports.Handler = Handler;
13946  exports.Icon = Icon;
13947  exports.ImageOverlay = ImageOverlay;
13948  exports.LatLng = LatLng;
13949  exports.LatLngBounds = LatLngBounds;
13950  exports.Layer = Layer;
13951  exports.LayerGroup = LayerGroup;
13952  exports.LineUtil = LineUtil;
13953  exports.Map = Map;
13954  exports.Marker = Marker;
13955  exports.Mixin = Mixin;
13956  exports.Path = Path;
13957  exports.Point = Point;
13958  exports.PolyUtil = PolyUtil;
13959  exports.Polygon = Polygon;
13960  exports.Polyline = Polyline;
13961  exports.Popup = Popup;
13962  exports.PosAnimation = PosAnimation;
13963  exports.Projection = index;
13964  exports.Rectangle = Rectangle;
13965  exports.Renderer = Renderer;
13966  exports.SVG = SVG;
13967  exports.SVGOverlay = SVGOverlay;
13968  exports.TileLayer = TileLayer;
13969  exports.Tooltip = Tooltip;
13970  exports.Transformation = Transformation;
13971  exports.Util = Util;
13972  exports.VideoOverlay = VideoOverlay;
13973  exports.bind = bind;
13974  exports.bounds = toBounds;
13975  exports.canvas = canvas;
13976  exports.circle = circle;
13977  exports.circleMarker = circleMarker;
13978  exports.control = control;
13979  exports.divIcon = divIcon;
13980  exports.extend = extend;
13981  exports.featureGroup = featureGroup;
13982  exports.geoJSON = geoJSON;
13983  exports.geoJson = geoJson;
13984  exports.gridLayer = gridLayer;
13985  exports.icon = icon;
13986  exports.imageOverlay = imageOverlay;
13987  exports.latLng = toLatLng;
13988  exports.latLngBounds = toLatLngBounds;
13989  exports.layerGroup = layerGroup;
13990  exports.map = createMap;
13991  exports.marker = marker;
13992  exports.point = toPoint;
13993  exports.polygon = polygon;
13994  exports.polyline = polyline;
13995  exports.popup = popup;
13996  exports.rectangle = rectangle;
13997  exports.setOptions = setOptions;
13998  exports.stamp = stamp;
13999  exports.svg = svg;
14000  exports.svgOverlay = svgOverlay;
14001  exports.tileLayer = tileLayer;
14002  exports.tooltip = tooltip;
14003  exports.transformation = toTransformation;
14004  exports.version = version;
14005  exports.videoOverlay = videoOverlay;
14006
14007  var oldL = window.L;
14008  exports.noConflict = function() {
14009  	window.L = oldL;
14010  	return this;
14011  }
14012
14013  // Always export us to window global (see #2364)
14014  window.L = exports;
14015
14016}));
14017//# sourceMappingURL=leaflet-src.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.