PageSourceSearch

https://tianjara.net/javascript/leaflet/leaflet.js

js tianjara.net collected 2026-10-04 00:19:16 UTC 431,329 bytes, 14,069 lines download raw bytes

vendor: 2,390 bytes, lines 1-73
1/* @preserve
2 * Leaflet 1.6.0, a JS library for interactive maps. http://leafletjs.com
3 * (c) 2010-2019 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.6.0";
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  	/*eslint-disable */
69  	obj._leaflet_id = obj._leaflet_id || ++lastId;
70  	return obj._leaflet_id;
71  	/* eslint-enable */
72  }
73
vendor: 11,050 bytes, lines 74-395
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, digits?: Number): Number
125  // Returns the number `num` rounded to `digits` decimals, or to 6 decimals by default.
126  function formatNum(num, digits) {
127  	var pow = Math.pow(10, (digits === undefined ? 6 : digits));
128  	return Math.round(num * pow) / pow;
129  }
130
131  // @function trim(str: String): String
132  // Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)
133  function trim(str) {
134  	return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
135  }
136
137  // @function splitWords(str: String): String[]
138  // Trims and splits the string on whitespace and returns the array of parts.
139  function splitWords(str) {
140  	return trim(str).split(/\s+/);
141  }
142
143  // @function setOptions(obj: Object, options: Object): Object
144  // Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut.
145  function setOptions(obj, options) {
146  	if (!Object.prototype.hasOwnProperty.call(obj, 'options')) {
147  		obj.options = obj.options ? create$2(obj.options) : {};
148  	}
149  	for (var i in options) {
150  		obj.options[i] = options[i];
151  	}
152  	return obj.options;
153  }
154
155  // @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String
156  // Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}`
157  // translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will
158  // be appended at the end. If `uppercase` is `true`, the parameter names will
159  // be uppercased (e.g. `'?A=foo&B=bar'`)
160  function getParamString(obj, existingUrl, uppercase) {
161  	var params = [];
162  	for (var i in obj) {
163  		params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
164  	}
165  	return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
166  }
167
168  var templateRe = /\{ *([\w_-]+) *\}/g;
169
170  // @function template(str: String, data: Object): String
171  // Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`
172  // and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string
173  // `('Hello foo, bar')`. You can also specify functions instead of strings for
174  // data values — they will be evaluated passing `data` as an argument.
175  function template(str, data) {
176  	return str.replace(templateRe, function (str, key) {
177  		var value = data[key];
178
179  		if (value === undefined) {
180  			throw new Error('No value provided for variable ' + str);
181
182  		} else if (typeof value === 'function') {
183  			value = value(data);
184  		}
185  		return value;
186  	});
187  }
188
189  // @function isArray(obj): Boolean
190  // Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)
191  var isArray = Array.isArray || function (obj) {
192  	return (Object.prototype.toString.call(obj) === '[object Array]');
193  };
194
195  // @function indexOf(array: Array, el: Object): Number
196  // Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)
197  function indexOf(array, el) {
198  	for (var i = 0; i < array.length; i++) {
199  		if (array[i] === el) { return i; }
200  	}
201  	return -1;
202  }
203
204  // @property emptyImageUrl: String
205  // Data URI string containing a base64-encoded empty GIF image.
206  // Used as a hack to free memory from unused images on WebKit-powered
207  // mobile devices (by setting image `src` to this string).
208  var emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
209
210  // inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/
211
212  function getPrefixed(name) {
213  	return window['webkit' + name] || window['moz' + name] || window['ms' + name];
214  }
215
216  var lastTime = 0;
217
218  // fallback for IE 7-8
219  function timeoutDefer(fn) {
220  	var time = +new Date(),
221  	    timeToCall = Math.max(0, 16 - (time - lastTime));
222
223  	lastTime = time + timeToCall;
224  	return window.setTimeout(fn, timeToCall);
225  }
226
227  var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer;
228  var cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') ||
229  		getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); };
230
231  // @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number
232  // Schedules `fn` to be executed when the browser repaints. `fn` is bound to
233  // `context` if given. When `immediate` is set, `fn` is called immediately if
234  // the browser doesn't have native support for
235  // [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame),
236  // otherwise it's delayed. Returns a request ID that can be used to cancel the request.
237  function requestAnimFrame(fn, context, immediate) {
238  	if (immediate && requestFn === timeoutDefer) {
239  		fn.call(context);
240  	} else {
241  		return requestFn.call(window, bind(fn, context));
242  	}
243  }
244
245  // @function cancelAnimFrame(id: Number): undefined
246  // Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame).
247  function cancelAnimFrame(id) {
248  	if (id) {
249  		cancelFn.call(window, id);
250  	}
251  }
252
253  var Util = {
254    __proto__: null,
255    extend: extend,
256    create: create$2,
257    bind: bind,
258    get lastId () { return lastId; },
259    stamp: stamp,
260    throttle: throttle,
261    wrapNum: wrapNum,
262    falseFn: falseFn,
263    formatNum: formatNum,
264    trim: trim,
265    splitWords: splitWords,
266    setOptions: setOptions,
267    getParamString: getParamString,
268    template: template,
269    isArray: isArray,
270    indexOf: indexOf,
271    emptyImageUrl: emptyImageUrl,
272    requestFn: requestFn,
273    cancelFn: cancelFn,
274    requestAnimFrame: requestAnimFrame,
275    cancelAnimFrame: cancelAnimFrame
276  };
277
278  // @class Class
279  // @aka L.Class
280
281  // @section
282  // @uninheritable
283
284  // Thanks to John Resig and Dean Edwards for inspiration!
285
286  function Class() {}
287
288  Class.extend = function (props) {
289
290  	// @function extend(props: Object): Function
291  	// [Extends the current class](#class-inheritance) given the properties to be included.
292  	// Returns a Javascript function that is a class constructor (to be called with `new`).
293  	var NewClass = function () {
294
295  		// call the constructor
296  		if (this.initialize) {
297  			this.initialize.apply(this, arguments);
298  		}
299
300  		// call all constructor hooks
301  		this.callInitHooks();
302  	};
303
304  	var parentProto = NewClass.__super__ = this.prototype;
305
306  	var proto = create$2(parentProto);
307  	proto.constructor = NewClass;
308
309  	NewClass.prototype = proto;
310
311  	// inherit parent's statics
312  	for (var i in this) {
313  		if (Object.prototype.hasOwnProperty.call(this, i) && i !== 'prototype' && i !== '__super__') {
314  			NewClass[i] = this[i];
315  		}
316  	}
317
318  	// mix static properties into the class
319  	if (props.statics) {
320  		extend(NewClass, props.statics);
321  		delete props.statics;
322  	}
323
324  	// mix includes into the prototype
325  	if (props.includes) {
326  		checkDeprecatedMixinEvents(props.includes);
327  		extend.apply(null, [proto].concat(props.includes));
328  		delete props.includes;
329  	}
330
331  	// merge options
332  	if (proto.options) {
333  		props.options = extend(create$2(proto.options), props.options);
334  	}
335
336  	// mix given properties into the prototype
337  	extend(proto, props);
338
339  	proto._initHooks = [];
340
341  	// add method for calling all hooks
342  	proto.callInitHooks = function () {
343
344  		if (this._initHooksCalled) { return; }
345
346  		if (parentProto.callInitHooks) {
347  			parentProto.callInitHooks.call(this);
348  		}
349
350  		this._initHooksCalled = true;
351
352  		for (var i = 0, len = proto._initHooks.length; i < len; i++) {
353  			proto._initHooks[i].call(this);
354  		}
355  	};
356
357  	return NewClass;
358  };
359
360
361  // @function include(properties: Object): this
362  // [Includes a mixin](#class-includes) into the current class.
363  Class.include = function (props) {
364  	extend(this.prototype, props);
365  	return this;
366  };
367
368  // @function mergeOptions(options: Object): this
369  // [Merges `options`](#class-options) into the defaults of the class.
370  Class.mergeOptions = function (options) {
371  	extend(this.prototype.options, options);
372  	return this;
373  };
374
375  // @function addInitHook(fn: Function): this
376  // Adds a [constructor hook](#class-constructor-hooks) to the class.
377  Class.addInitHook = function (fn) { // (Function) || (String, args...)
378  	var args = Array.prototype.slice.call(arguments, 1);
379
380  	var init = typeof fn === 'function' ? fn : function () {
381  		this[fn].apply(this, args);
382  	};
383
384  	this.prototype._initHooks = this.prototype._initHooks || [];
385  	this.prototype._initHooks.push(init);
386  	return this;
387  };
388
389  function checkDeprecatedMixinEvents(includes) {
390  	if (typeof L === 'undefined' || !L || !L.Mixin) { return; }
391
392  	includes = isArray(includes) ? includes : [includes];
393
394  	for (var i = 0; i < includes.length; i++) {
395  		if (includes[i] === L.Mixin.Events) {
396  			console.warn('Deprecated include of L.Mixin.Events: ' +
397  				'this property will be removed in future releases, ' +
398  				'please inherit from L.Evented instead.', new Error().stack);
399  		}
400  	}
401  }
402
403  /*
404   * @class Evented
405   * @aka L.Evented
406   * @inherits Class
407   *
408   * 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).
409   *
410   * @example
411   *
412   * ```js
413   * map.on('click', function(e) {
414   * 	alert(e.latlng);
415   * } );
416   * ```
417   *
418   * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function:
419   *
420   * ```js
421   * function onClick(e) { ... }
422   *
423   * map.on('click', onClick);
424   * map.off('click', onClick);
425   * ```
426   */
427
428  var Events = {
429  	/* @method on(type: String, fn: Function, context?: Object): this
430  	 * 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'`).
431  	 *
432  	 * @alternative
433  	 * @method on(eventMap: Object): this
434  	 * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
435  	 */
436  	on: function (types, fn, context) {
437
438  		// types can be a map of types/handlers
439  		if (typeof types === 'object') {
440  			for (var type in types) {
441  				// we don't process space-separated events here for performance;
442  				// it's a hot path since Layer uses the on(obj) syntax
443  				this._on(type, types[type], fn);
444  			}
445
446  		} else {
447  			// types can be a string of space-separated words
448  			types = splitWords(types);
449
450  			for (var i = 0, len = types.length; i < len; i++) {
451  				this._on(types[i], fn, context);
452  			}
453  		}
454
455  		return this;
456  	},
457
458  	/* @method off(type: String, fn?: Function, context?: Object): this
459  	 * 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.
460  	 *
461  	 * @alternative
462  	 * @method off(eventMap: Object): this
463  	 * Removes a set of type/listener pairs.
464  	 *
465  	 * @alternative
466  	 * @method off: this
467  	 * Removes all listeners to all events on the object. This includes implicitly attached events.
468  	 */
469  	off: function (types, fn, context) {
470
471  		if (!types) {
472  			// clear all listeners if called without arguments
473  			delete this._events;
474
475  		} else if (typeof types === 'object') {
476  			for (var type in types) {
477  				this._off(type, types[type], fn);
478  			}
479
480  		} else {
481  			types = splitWords(types);
482
483  			for (var i = 0, len = types.length; i < len; i++) {
484  				this._off(types[i], fn, context);
485  			}
486  		}
487
488  		return this;
489  	},
490
491  	// attach listener (without syntactic sugar now)
492  	_on: function (type, fn, context) {
493  		this._events = this._events || {};
494
495  		/* get/init listeners for type */
496  		var typeListeners = this._events[type];
497  		if (!typeListeners) {
498  			typeListeners = [];
499  			this._events[type] = typeListeners;
500  		}
501
502  		if (context === this) {
503  			// Less memory footprint.
504  			context = undefined;
505  		}
506  		var newListener = {fn: fn, ctx: context},
507  		    listeners = typeListeners;
508
509  		// check if fn already there
510  		for (var i = 0, len = listeners.length; i < len; i++) {
511  			if (listeners[i].fn === fn && listeners[i].ctx === context) {
512  				return;
513  			}
514  		}
515
516  		listeners.push(newListener);
517  	},
518
519  	_off: function (type, fn, context) {
520  		var listeners,
521  		    i,
522  		    len;
523
524  		if (!this._events) { return; }
525
526  		listeners = this._events[type];
527
528  		if (!listeners) {
529  			return;
530  		}
531
532  		if (!fn) {
533  			// Set all removed listeners to noop so they are not called if remove happens in fire
534  			for (i = 0, len = listeners.length; i < len; i++) {
535  				listeners[i].fn = falseFn;
536  			}
537  			// clear all listeners for a type if function isn't specified
538  			delete this._events[type];
539  			return;
540  		}
541
542  		if (context === this) {
543  			context = undefined;
544  		}
545
546  		if (listeners) {
547
548  			// find fn and remove it
549  			for (i = 0, len = listeners.length; i < len; i++) {
550  				var l = listeners[i];
551  				if (l.ctx !== context) { continue; }
552  				if (l.fn === fn) {
553
554  					// set the removed listener to noop so that's not called if remove happens in fire
555  					l.fn = falseFn;
556
557  					if (this._firingCount) {
558  						/* copy array in case events are being fired */
559  						this._events[type] = listeners = listeners.slice();
560  					}
561  					listeners.splice(i, 1);
562
563  					return;
564  				}
565  			}
566  		}
567  	},
568
569  	// @method fire(type: String, data?: Object, propagate?: Boolean): this
570  	// Fires an event of the specified type. You can optionally provide an data
571  	// object — the first argument of the listener function will contain its
572  	// properties. The event can optionally be propagated to event parents.
573  	fire: function (type, data, propagate) {
574  		if (!this.listens(type, propagate)) { return this; }
575
576  		var event = extend({}, data, {
577  			type: type,
578  			target: this,
579  			sourceTarget: data && data.sourceTarget || this
580  		});
581
582  		if (this._events) {
583  			var listeners = this._events[type];
584
585  			if (listeners) {
586  				this._firingCount = (this._firingCount + 1) || 1;
587  				for (var i = 0, len = listeners.length; i < len; i++) {
588  					var l = listeners[i];
589  					l.fn.call(l.ctx || this, event);
590  				}
591
592  				this._firingCount--;
593  			}
594  		}
595
596  		if (propagate) {
597  			// propagate the event to parents (set with addEventParent)
598  			this._propagateEvent(event);
599  		}
600
601  		return this;
602  	},
603
604  	// @method listens(type: String): Boolean
605  	// Returns `true` if a particular event type has any listeners attached to it.
606  	listens: function (type, propagate) {
607  		var listeners = this._events && this._events[type];
608  		if (listeners && listeners.length) { return true; }
609
610  		if (propagate) {
611  			// also check parents for listeners if event propagates
612  			for (var id in this._eventParents) {
613  				if (this._eventParents[id].listens(type, propagate)) { return true; }
614  			}
615  		}
616  		return false;
617  	},
618
619  	// @method once(…): this
620  	// Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed.
621  	once: function (types, fn, context) {
622
623  		if (typeof types === 'object') {
624  			for (var type in types) {
625  				this.once(type, types[type], fn);
626  			}
627  			return this;
628  		}
629
630  		var handler = bind(function () {
631  			this
632  			    .off(types, fn, context)
633  			    .off(types, handler, context);
634  		}, this);
635
636  		// add a listener that's executed once and removed after that
637  		return this
638  		    .on(types, fn, context)
639  		    .on(types, handler, context)
vendor: 9,158 bytes, lines 639-954
639;
640  	},
641
642  	// @method addEventParent(obj: Evented): this
643  	// Adds an event parent - an `Evented` that will receive propagated events
644  	addEventParent: function (obj) {
645  		this._eventParents = this._eventParents || {};
646  		this._eventParents[stamp(obj)] = obj;
647  		return this;
648  	},
649
650  	// @method removeEventParent(obj: Evented): this
651  	// Removes an event parent, so it will stop receiving propagated events
652  	removeEventParent: function (obj) {
653  		if (this._eventParents) {
654  			delete this._eventParents[stamp(obj)];
655  		}
656  		return this;
657  	},
658
659  	_propagateEvent: function (e) {
660  		for (var id in this._eventParents) {
661  			this._eventParents[id].fire(e.type, extend({
662  				layer: e.target,
663  				propagatedFrom: e.target
664  			}, e), true);
665  		}
666  	}
667  };
668
669  // aliases; we should ditch those eventually
670
671  // @method addEventListener(…): this
672  // Alias to [`on(…)`](#evented-on)
673  Events.addEventListener = Events.on;
674
675  // @method removeEventListener(…): this
676  // Alias to [`off(…)`](#evented-off)
677
678  // @method clearAllEventListeners(…): this
679  // Alias to [`off()`](#evented-off)
680  Events.removeEventListener = Events.clearAllEventListeners = Events.off;
681
682  // @method addOneTimeEventListener(…): this
683  // Alias to [`once(…)`](#evented-once)
684  Events.addOneTimeEventListener = Events.once;
685
686  // @method fireEvent(…): this
687  // Alias to [`fire(…)`](#evented-fire)
688  Events.fireEvent = Events.fire;
689
690  // @method hasEventListeners(…): Boolean
691  // Alias to [`listens(…)`](#evented-listens)
692  Events.hasEventListeners = Events.listens;
693
694  var Evented = Class.extend(Events);
695
696  /*
697   * @class Point
698   * @aka L.Point
699   *
700   * Represents a point with `x` and `y` coordinates in pixels.
701   *
702   * @example
703   *
704   * ```js
705   * var point = L.point(200, 300);
706   * ```
707   *
708   * 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:
709   *
710   * ```js
711   * map.panBy([200, 300]);
712   * map.panBy(L.point(200, 300));
713   * ```
714   *
715   * Note that `Point` does not inherit from Leaflet's `Class` object,
716   * which means new classes can't inherit from it, and new methods
717   * can't be added to it with the `include` function.
718   */
719
720  function Point(x, y, round) {
721  	// @property x: Number; The `x` coordinate of the point
722  	this.x = (round ? Math.round(x) : x);
723  	// @property y: Number; The `y` coordinate of the point
724  	this.y = (round ? Math.round(y) : y);
725  }
726
727  var trunc = Math.trunc || function (v) {
728  	return v > 0 ? Math.floor(v) : Math.ceil(v);
729  };
730
731  Point.prototype = {
732
733  	// @method clone(): Point
734  	// Returns a copy of the current point.
735  	clone: function () {
736  		return new Point(this.x, this.y);
737  	},
738
739  	// @method add(otherPoint: Point): Point
740  	// Returns the result of addition of the current and the given points.
741  	add: function (point) {
742  		// non-destructive, returns a new point
743  		return this.clone()._add(toPoint(point));
744  	},
745
746  	_add: function (point) {
747  		// destructive, used directly for performance in situations where it's safe to modify existing point
748  		this.x += point.x;
749  		this.y += point.y;
750  		return this;
751  	},
752
753  	// @method subtract(otherPoint: Point): Point
754  	// Returns the result of subtraction of the given point from the current.
755  	subtract: function (point) {
756  		return this.clone()._subtract(toPoint(point));
757  	},
758
759  	_subtract: function (point) {
760  		this.x -= point.x;
761  		this.y -= point.y;
762  		return this;
763  	},
764
765  	// @method divideBy(num: Number): Point
766  	// Returns the result of division of the current point by the given number.
767  	divideBy: function (num) {
768  		return this.clone()._divideBy(num);
769  	},
770
771  	_divideBy: function (num) {
772  		this.x /= num;
773  		this.y /= num;
774  		return this;
775  	},
776
777  	// @method multiplyBy(num: Number): Point
778  	// Returns the result of multiplication of the current point by the given number.
779  	multiplyBy: function (num) {
780  		return this.clone()._multiplyBy(num);
781  	},
782
783  	_multiplyBy: function (num) {
784  		this.x *= num;
785  		this.y *= num;
786  		return this;
787  	},
788
789  	// @method scaleBy(scale: Point): Point
790  	// Multiply each coordinate of the current point by each coordinate of
791  	// `scale`. In linear algebra terms, multiply the point by the
792  	// [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation)
793  	// defined by `scale`.
794  	scaleBy: function (point) {
795  		return new Point(this.x * point.x, this.y * point.y);
796  	},
797
798  	// @method unscaleBy(scale: Point): Point
799  	// Inverse of `scaleBy`. Divide each coordinate of the current point by
800  	// each coordinate of `scale`.
801  	unscaleBy: function (point) {
802  		return new Point(this.x / point.x, this.y / point.y);
803  	},
804
805  	// @method round(): Point
806  	// Returns a copy of the current point with rounded coordinates.
807  	round: function () {
808  		return this.clone()._round();
809  	},
810
811  	_round: function () {
812  		this.x = Math.round(this.x);
813  		this.y = Math.round(this.y);
814  		return this;
815  	},
816
817  	// @method floor(): Point
818  	// Returns a copy of the current point with floored coordinates (rounded down).
819  	floor: function () {
820  		return this.clone()._floor();
821  	},
822
823  	_floor: function () {
824  		this.x = Math.floor(this.x);
825  		this.y = Math.floor(this.y);
826  		return this;
827  	},
828
829  	// @method ceil(): Point
830  	// Returns a copy of the current point with ceiled coordinates (rounded up).
831  	ceil: function () {
832  		return this.clone()._ceil();
833  	},
834
835  	_ceil: function () {
836  		this.x = Math.ceil(this.x);
837  		this.y = Math.ceil(this.y);
838  		return this;
839  	},
840
841  	// @method trunc(): Point
842  	// Returns a copy of the current point with truncated coordinates (rounded towards zero).
843  	trunc: function () {
844  		return this.clone()._trunc();
845  	},
846
847  	_trunc: function () {
848  		this.x = trunc(this.x);
849  		this.y = trunc(this.y);
850  		return this;
851  	},
852
853  	// @method distanceTo(otherPoint: Point): Number
854  	// Returns the cartesian distance between the current and the given points.
855  	distanceTo: function (point) {
856  		point = toPoint(point);
857
858  		var x = point.x - this.x,
859  		    y = point.y - this.y;
860
861  		return Math.sqrt(x * x + y * y);
862  	},
863
864  	// @method equals(otherPoint: Point): Boolean
865  	// Returns `true` if the given point has the same coordinates.
866  	equals: function (point) {
867  		point = toPoint(point);
868
869  		return point.x === this.x &&
870  		       point.y === this.y;
871  	},
872
873  	// @method contains(otherPoint: Point): Boolean
874  	// Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values).
875  	contains: function (point) {
876  		point = toPoint(point);
877
878  		return Math.abs(point.x) <= Math.abs(this.x) &&
879  		       Math.abs(point.y) <= Math.abs(this.y);
880  	},
881
882  	// @method toString(): String
883  	// Returns a string representation of the point for debugging purposes.
884  	toString: function () {
885  		return 'Point(' +
886  		        formatNum(this.x) + ', ' +
887  		        formatNum(this.y) + ')';
888  	}
889  };
890
891  // @factory L.point(x: Number, y: Number, round?: Boolean)
892  // Creates a Point object with the given `x` and `y` coordinates. If optional `round` is set to true, rounds the `x` and `y` values.
893
894  // @alternative
895  // @factory L.point(coords: Number[])
896  // Expects an array of the form `[x, y]` instead.
897
898  // @alternative
899  // @factory L.point(coords: Object)
900  // Expects a plain object of the form `{x: Number, y: Number}` instead.
901  function toPoint(x, y, round) {
902  	if (x instanceof Point) {
903  		return x;
904  	}
905  	if (isArray(x)) {
906  		return new Point(x[0], x[1]);
907  	}
908  	if (x === undefined || x === null) {
909  		return x;
910  	}
911  	if (typeof x === 'object' && 'x' in x && 'y' in x) {
912  		return new Point(x.x, x.y);
913  	}
914  	return new Point(x, y, round);
915  }
916
917  /*
918   * @class Bounds
919   * @aka L.Bounds
920   *
921   * Represents a rectangular area in pixel coordinates.
922   *
923   * @example
924   *
925   * ```js
926   * var p1 = L.point(10, 10),
927   * p2 = L.point(40, 60),
928   * bounds = L.bounds(p1, p2);
929   * ```
930   *
931   * 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:
932   *
933   * ```js
934   * otherBounds.intersects([[10, 10], [40, 60]]);
935   * ```
936   *
937   * Note that `Bounds` does not inherit from Leaflet's `Class` object,
938   * which means new classes can't inherit from it, and new methods
939   * can't be added to it with the `include` function.
940   */
941
942  function Bounds(a, b) {
943  	if (!a) { return; }
944
945  	var points = b ? [a, b] : a;
946
947  	for (var i = 0, len = points.length; i < len; i++) {
948  		this.extend(points[i]);
949  	}
950  }
951
952  Bounds.prototype = {
953  	// @method extend(point: Point): this
954  	// Extends the bounds to contain the given point.
vendor: 3,646 bytes, lines 955-1073
955  	extend: function (point) { // (Point)
956  		point = toPoint(point);
957
958  		// @property min: Point
959  		// The top left corner of the rectangle.
960  		// @property max: Point
961  		// The bottom right corner of the rectangle.
962  		if (!this.min && !this.max) {
963  			this.min = point.clone();
964  			this.max = point.clone();
965  		} else {
966  			this.min.x = Math.min(point.x, this.min.x);
967  			this.max.x = Math.max(point.x, this.max.x);
968  			this.min.y = Math.min(point.y, this.min.y);
969  			this.max.y = Math.max(point.y, this.max.y);
970  		}
971  		return this;
972  	},
973
974  	// @method getCenter(round?: Boolean): Point
975  	// Returns the center point of the bounds.
976  	getCenter: function (round) {
977  		return new Point(
978  		        (this.min.x + this.max.x) / 2,
979  		        (this.min.y + this.max.y) / 2, round);
980  	},
981
982  	// @method getBottomLeft(): Point
983  	// Returns the bottom-left point of the bounds.
984  	getBottomLeft: function () {
985  		return new Point(this.min.x, this.max.y);
986  	},
987
988  	// @method getTopRight(): Point
989  	// Returns the top-right point of the bounds.
990  	getTopRight: function () { // -> Point
991  		return new Point(this.max.x, this.min.y);
992  	},
993
994  	// @method getTopLeft(): Point
995  	// Returns the top-left point of the bounds (i.e. [`this.min`](#bounds-min)).
996  	getTopLeft: function () {
997  		return this.min; // left, top
998  	},
999
1000  	// @method getBottomRight(): Point
1001  	// Returns the bottom-right point of the bounds (i.e. [`this.max`](#bounds-max)).
1002  	getBottomRight: function () {
1003  		return this.max; // right, bottom
1004  	},
1005
1006  	// @method getSize(): Point
1007  	// Returns the size of the given bounds
1008  	getSize: function () {
1009  		return this.max.subtract(this.min);
1010  	},
1011
1012  	// @method contains(otherBounds: Bounds): Boolean
1013  	// Returns `true` if the rectangle contains the given one.
1014  	// @alternative
1015  	// @method contains(point: Point): Boolean
1016  	// Returns `true` if the rectangle contains the given point.
1017  	contains: function (obj) {
1018  		var min, max;
1019
1020  		if (typeof obj[0] === 'number' || obj instanceof Point) {
1021  			obj = toPoint(obj);
1022  		} else {
1023  			obj = toBounds(obj);
1024  		}
1025
1026  		if (obj instanceof Bounds) {
1027  			min = obj.min;
1028  			max = obj.max;
1029  		} else {
1030  			min = max = obj;
1031  		}
1032
1033  		return (min.x >= this.min.x) &&
1034  		       (max.x <= this.max.x) &&
1035  		       (min.y >= this.min.y) &&
1036  		       (max.y <= this.max.y);
1037  	},
1038
1039  	// @method intersects(otherBounds: Bounds): Boolean
1040  	// Returns `true` if the rectangle intersects the given bounds. Two bounds
1041  	// intersect if they have at least one point in common.
1042  	intersects: function (bounds) { // (Bounds) -> Boolean
1043  		bounds = toBounds(bounds);
1044
1045  		var min = this.min,
1046  		    max = this.max,
1047  		    min2 = bounds.min,
1048  		    max2 = bounds.max,
1049  		    xIntersects = (max2.x >= min.x) && (min2.x <= max.x),
1050  		    yIntersects = (max2.y >= min.y) && (min2.y <= max.y);
1051
1052  		return xIntersects && yIntersects;
1053  	},
1054
1055  	// @method overlaps(otherBounds: Bounds): Boolean
1056  	// Returns `true` if the rectangle overlaps the given bounds. Two bounds
1057  	// overlap if their intersection is an area.
1058  	overlaps: function (bounds) { // (Bounds) -> Boolean
1059  		bounds = toBounds(bounds);
1060
1061  		var min = this.min,
1062  		    max = this.max,
1063  		    min2 = bounds.min,
1064  		    max2 = bounds.max,
1065  		    xOverlaps = (max2.x > min.x) && (min2.x < max.x),
1066  		    yOverlaps = (max2.y > min.y) && (min2.y < max.y);
1067
1068  		return xOverlaps && yOverlaps;
1069  	},
1070
1071  	isValid: function () {
1072  		return !!(this.min && this.max);
1073  	}
vendor: 13,363 bytes, lines 1073-1479
1073
1074  };
1075
1076
1077  // @factory L.bounds(corner1: Point, corner2: Point)
1078  // Creates a Bounds object from two corners coordinate pairs.
1079  // @alternative
1080  // @factory L.bounds(points: Point[])
1081  // Creates a Bounds object from the given array of points.
1082  function toBounds(a, b) {
1083  	if (!a || a instanceof Bounds) {
1084  		return a;
1085  	}
1086  	return new Bounds(a, b);
1087  }
1088
1089  /*
1090   * @class LatLngBounds
1091   * @aka L.LatLngBounds
1092   *
1093   * Represents a rectangular geographical area on a map.
1094   *
1095   * @example
1096   *
1097   * ```js
1098   * var corner1 = L.latLng(40.712, -74.227),
1099   * corner2 = L.latLng(40.774, -74.125),
1100   * bounds = L.latLngBounds(corner1, corner2);
1101   * ```
1102   *
1103   * 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:
1104   *
1105   * ```js
1106   * map.fitBounds([
1107   * 	[40.712, -74.227],
1108   * 	[40.774, -74.125]
1109   * ]);
1110   * ```
1111   *
1112   * 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.
1113   *
1114   * Note that `LatLngBounds` does not inherit from Leaflet's `Class` object,
1115   * which means new classes can't inherit from it, and new methods
1116   * can't be added to it with the `include` function.
1117   */
1118
1119  function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[])
1120  	if (!corner1) { return; }
1121
1122  	var latlngs = corner2 ? [corner1, corner2] : corner1;
1123
1124  	for (var i = 0, len = latlngs.length; i < len; i++) {
1125  		this.extend(latlngs[i]);
1126  	}
1127  }
1128
1129  LatLngBounds.prototype = {
1130
1131  	// @method extend(latlng: LatLng): this
1132  	// Extend the bounds to contain the given point
1133
1134  	// @alternative
1135  	// @method extend(otherBounds: LatLngBounds): this
1136  	// Extend the bounds to contain the given bounds
1137  	extend: function (obj) {
1138  		var sw = this._southWest,
1139  		    ne = this._northEast,
1140  		    sw2, ne2;
1141
1142  		if (obj instanceof LatLng) {
1143  			sw2 = obj;
1144  			ne2 = obj;
1145
1146  		} else if (obj instanceof LatLngBounds) {
1147  			sw2 = obj._southWest;
1148  			ne2 = obj._northEast;
1149
1150  			if (!sw2 || !ne2) { return this; }
1151
1152  		} else {
1153  			return obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this;
1154  		}
1155
1156  		if (!sw && !ne) {
1157  			this._southWest = new LatLng(sw2.lat, sw2.lng);
1158  			this._northEast = new LatLng(ne2.lat, ne2.lng);
1159  		} else {
1160  			sw.lat = Math.min(sw2.lat, sw.lat);
1161  			sw.lng = Math.min(sw2.lng, sw.lng);
1162  			ne.lat = Math.max(ne2.lat, ne.lat);
1163  			ne.lng = Math.max(ne2.lng, ne.lng);
1164  		}
1165
1166  		return this;
1167  	},
1168
1169  	// @method pad(bufferRatio: Number): LatLngBounds
1170  	// Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
1171  	// For example, a ratio of 0.5 extends the bounds by 50% in each direction.
1172  	// Negative values will retract the bounds.
1173  	pad: function (bufferRatio) {
1174  		var sw = this._southWest,
1175  		    ne = this._northEast,
1176  		    heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
1177  		    widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
1178
1179  		return new LatLngBounds(
1180  		        new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
1181  		        new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));
1182  	},
1183
1184  	// @method getCenter(): LatLng
1185  	// Returns the center point of the bounds.
1186  	getCenter: function () {
1187  		return new LatLng(
1188  		        (this._southWest.lat + this._northEast.lat) / 2,
1189  		        (this._southWest.lng + this._northEast.lng) / 2);
1190  	},
1191
1192  	// @method getSouthWest(): LatLng
1193  	// Returns the south-west point of the bounds.
1194  	getSouthWest: function () {
1195  		return this._southWest;
1196  	},
1197
1198  	// @method getNorthEast(): LatLng
1199  	// Returns the north-east point of the bounds.
1200  	getNorthEast: function () {
1201  		return this._northEast;
1202  	},
1203
1204  	// @method getNorthWest(): LatLng
1205  	// Returns the north-west point of the bounds.
1206  	getNorthWest: function () {
1207  		return new LatLng(this.getNorth(), this.getWest());
1208  	},
1209
1210  	// @method getSouthEast(): LatLng
1211  	// Returns the south-east point of the bounds.
1212  	getSouthEast: function () {
1213  		return new LatLng(this.getSouth(), this.getEast());
1214  	},
1215
1216  	// @method getWest(): Number
1217  	// Returns the west longitude of the bounds
1218  	getWest: function () {
1219  		return this._southWest.lng;
1220  	},
1221
1222  	// @method getSouth(): Number
1223  	// Returns the south latitude of the bounds
1224  	getSouth: function () {
1225  		return this._southWest.lat;
1226  	},
1227
1228  	// @method getEast(): Number
1229  	// Returns the east longitude of the bounds
1230  	getEast: function () {
1231  		return this._northEast.lng;
1232  	},
1233
1234  	// @method getNorth(): Number
1235  	// Returns the north latitude of the bounds
1236  	getNorth: function () {
1237  		return this._northEast.lat;
1238  	},
1239
1240  	// @method contains(otherBounds: LatLngBounds): Boolean
1241  	// Returns `true` if the rectangle contains the given one.
1242
1243  	// @alternative
1244  	// @method contains (latlng: LatLng): Boolean
1245  	// Returns `true` if the rectangle contains the given point.
1246  	contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean
1247  		if (typeof obj[0] === 'number' || obj instanceof LatLng || 'lat' in obj) {
1248  			obj = toLatLng(obj);
1249  		} else {
1250  			obj = toLatLngBounds(obj);
1251  		}
1252
1253  		var sw = this._southWest,
1254  		    ne = this._northEast,
1255  		    sw2, ne2;
1256
1257  		if (obj instanceof LatLngBounds) {
1258  			sw2 = obj.getSouthWest();
1259  			ne2 = obj.getNorthEast();
1260  		} else {
1261  			sw2 = ne2 = obj;
1262  		}
1263
1264  		return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&
1265  		       (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);
1266  	},
1267
1268  	// @method intersects(otherBounds: LatLngBounds): Boolean
1269  	// Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.
1270  	intersects: function (bounds) {
1271  		bounds = toLatLngBounds(bounds);
1272
1273  		var sw = this._southWest,
1274  		    ne = this._northEast,
1275  		    sw2 = bounds.getSouthWest(),
1276  		    ne2 = bounds.getNorthEast(),
1277
1278  		    latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),
1279  		    lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);
1280
1281  		return latIntersects && lngIntersects;
1282  	},
1283
1284  	// @method overlaps(otherBounds: LatLngBounds): Boolean
1285  	// Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.
1286  	overlaps: function (bounds) {
1287  		bounds = toLatLngBounds(bounds);
1288
1289  		var sw = this._southWest,
1290  		    ne = this._northEast,
1291  		    sw2 = bounds.getSouthWest(),
1292  		    ne2 = bounds.getNorthEast(),
1293
1294  		    latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat),
1295  		    lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng);
1296
1297  		return latOverlaps && lngOverlaps;
1298  	},
1299
1300  	// @method toBBoxString(): String
1301  	// 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.
1302  	toBBoxString: function () {
1303  		return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');
1304  	},
1305
1306  	// @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean
1307  	// 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.
1308  	equals: function (bounds, maxMargin) {
1309  		if (!bounds) { return false; }
1310
1311  		bounds = toLatLngBounds(bounds);
1312
1313  		return this._southWest.equals(bounds.getSouthWest(), maxMargin) &&
1314  		       this._northEast.equals(bounds.getNorthEast(), maxMargin);
1315  	},
1316
1317  	// @method isValid(): Boolean
1318  	// Returns `true` if the bounds are properly initialized.
1319  	isValid: function () {
1320  		return !!(this._southWest && this._northEast);
1321  	}
1322  };
1323
1324  // TODO International date line?
1325
1326  // @factory L.latLngBounds(corner1: LatLng, corner2: LatLng)
1327  // Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle.
1328
1329  // @alternative
1330  // @factory L.latLngBounds(latlngs: LatLng[])
1331  // 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).
1332  function toLatLngBounds(a, b) {
1333  	if (a instanceof LatLngBounds) {
1334  		return a;
1335  	}
1336  	return new LatLngBounds(a, b);
1337  }
1338
1339  /* @class LatLng
1340   * @aka L.LatLng
1341   *
1342   * Represents a geographical point with a certain latitude and longitude.
1343   *
1344   * @example
1345   *
1346   * ```
1347   * var latlng = L.latLng(50.5, 30.5);
1348   * ```
1349   *
1350   * 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:
1351   *
1352   * ```
1353   * map.panTo([50, 30]);
1354   * map.panTo({lon: 30, lat: 50});
1355   * map.panTo({lat: 50, lng: 30});
1356   * map.panTo(L.latLng(50, 30));
1357   * ```
1358   *
1359   * Note that `LatLng` does not inherit from Leaflet's `Class` object,
1360   * which means new classes can't inherit from it, and new methods
1361   * can't be added to it with the `include` function.
1362   */
1363
1364  function LatLng(lat, lng, alt) {
1365  	if (isNaN(lat) || isNaN(lng)) {
1366  		throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');
1367  	}
1368
1369  	// @property lat: Number
1370  	// Latitude in degrees
1371  	this.lat = +lat;
1372
1373  	// @property lng: Number
1374  	// Longitude in degrees
1375  	this.lng = +lng;
1376
1377  	// @property alt: Number
1378  	// Altitude in meters (optional)
1379  	if (alt !== undefined) {
1380  		this.alt = +alt;
1381  	}
1382  }
1383
1384  LatLng.prototype = {
1385  	// @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean
1386  	// 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.
1387  	equals: function (obj, maxMargin) {
1388  		if (!obj) { return false; }
1389
1390  		obj = toLatLng(obj);
1391
1392  		var margin = Math.max(
1393  		        Math.abs(this.lat - obj.lat),
1394  		        Math.abs(this.lng - obj.lng));
1395
1396  		return margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin);
1397  	},
1398
1399  	// @method toString(): String
1400  	// Returns a string representation of the point (for debugging purposes).
1401  	toString: function (precision) {
1402  		return 'LatLng(' +
1403  		        formatNum(this.lat, precision) + ', ' +
1404  		        formatNum(this.lng, precision) + ')';
1405  	},
1406
1407  	// @method distanceTo(otherLatLng: LatLng): Number
1408  	// 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).
1409  	distanceTo: function (other) {
1410  		return Earth.distance(this, toLatLng(other));
1411  	},
1412
1413  	// @method wrap(): LatLng
1414  	// Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees.
1415  	wrap: function () {
1416  		return Earth.wrapLatLng(this);
1417  	},
1418
1419  	// @method toBounds(sizeInMeters: Number): LatLngBounds
1420  	// Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`.
1421  	toBounds: function (sizeInMeters) {
1422  		var latAccuracy = 180 * sizeInMeters / 40075017,
1423  		    lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat);
1424
1425  		return toLatLngBounds(
1426  		        [this.lat - latAccuracy, this.lng - lngAccuracy],
1427  		        [this.lat + latAccuracy, this.lng + lngAccuracy]);
1428  	},
1429
1430  	clone: function () {
1431  		return new LatLng(this.lat, this.lng, this.alt);
1432  	}
1433  };
1434
1435
1436
1437  // @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng
1438  // Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude).
1439
1440  // @alternative
1441  // @factory L.latLng(coords: Array): LatLng
1442  // Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead.
1443
1444  // @alternative
1445  // @factory L.latLng(coords: Object): LatLng
1446  // Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead.
1447
1448  function toLatLng(a, b, c) {
1449  	if (a instanceof LatLng) {
1450  		return a;
1451  	}
1452  	if (isArray(a) && typeof a[0] !== 'object') {
1453  		if (a.length === 3) {
1454  			return new LatLng(a[0], a[1], a[2]);
1455  		}
1456  		if (a.length === 2) {
1457  			return new LatLng(a[0], a[1]);
1458  		}
1459  		return null;
1460  	}
1461  	if (a === undefined || a === null) {
1462  		return a;
1463  	}
1464  	if (typeof a === 'object' && 'lat' in a) {
1465  		return new LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt);
1466  	}
1467  	if (b === undefined) {
1468  		return null;
1469  	}
1470  	return new LatLng(a, b, c);
1471  }
1472
1473  /*
1474   * @namespace CRS
1475   * @crs L.CRS.Base
1476   * Object that defines coordinate reference systems for projecting
1477   * geographical points into pixel (screen) coordinates and back (and to
1478   * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See
1479   * [spatial reference system](http
1479://en.wikipedia.org/wiki/Coordinate_reference_system).
1480   *
1481   * Leaflet defines the most usual CRSs by default. If you want to use a
1482   * CRS not defined by default, take a look at the
1483   * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin.
1484   *
1485   * Note that the CRS instances do not inherit from Leaflet's `Class` object,
1486   * and can't be instantiated. Also, new classes can't inherit from them,
1487   * and methods can't be added to them with the `include` function.
1488   */
1489
1490  var CRS = {
1491  	// @method latLngToPoint(latlng: LatLng, zoom: Number): Point
1492  	// Projects geographical coordinates into pixel coordinates for a given zoom.
1493  	latLngToPoint: function (latlng, zoom) {
1494  		var projectedPoint = this.projection.project(latlng),
1495  		    scale = this.scale(zoom);
1496
1497  		return this.transformation._transform(projectedPoint, scale);
1498  	},
1499
1500  	// @method pointToLatLng(point: Point, zoom: Number): LatLng
1501  	// The inverse of `latLngToPoint`. Projects pixel coordinates on a given
1502  	// zoom into geographical coordinates.
1503  	pointToLatLng: function (point, zoom) {
1504  		var scale = this.scale(zoom),
1505  		    untransformedPoint = this.transformation.untransform(point, scale);
1506
1507  		return this.projection.unproject(untransformedPoint);
1508  	},
1509
1510  	// @method project(latlng: LatLng): Point
1511  	// Projects geographical coordinates into coordinates in units accepted for
1512  	// this CRS (e.g. meters for EPSG:3857, for passing it to WMS services).
1513  	project: function (latlng) {
1514  		return this.projection.project(latlng);
1515  	},
1516
1517  	// @method unproject(point: Point): LatLng
1518  	// Given a projected coordinate returns the corresponding LatLng.
1519  	// The inverse of `project`.
1520  	unproject: function (point) {
1521  		return this.projection.unproject(point);
1522  	},
1523
1524  	// @method scale(zoom: Number): Number
1525  	// Returns the scale used when transforming projected coordinates into
1526  	// pixel coordinates for a particular zoom. For example, it returns
1527  	// `256 * 2^zoom` for Mercator-based CRS.
1528  	scale: function (zoom) {
1529  		return 256 * Math.pow(2, zoom);
1530  	},
1531
1532  	// @method zoom(scale: Number): Number
1533  	// Inverse of `scale()`, returns the zoom level corresponding to a scale
1534  	// factor of `scale`.
1535  	zoom: function (scale) {
1536  		return Math.log(scale / 256) / Math.LN2;
1537  	},
1538
1539  	// @method getProjectedBounds(zoom: Number): Bounds
1540  	// Returns the projection's bounds scaled and transformed for the provided `zoom`.
1541  	getProjectedBounds: function (zoom) {
1542  		if (this.infinite) { return null; }
1543
1544  		var b = this.projection.bounds,
1545  		    s = this.scale(zoom),
1546  		    min = this.transformation.transform(b.min, s),
1547  		    max = this.transformation.transform(b.max, s);
1548
1549  		return new Bounds(min, max);
1550  	},
1551
1552  	// @method distance(latlng1: LatLng, latlng2: LatLng): Number
1553  	// Returns the distance between two geographical coordinates.
1554
1555  	// @property code: String
1556  	// Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`)
1557  	//
1558  	// @property wrapLng: Number[]
1559  	// An array of two numbers defining whether the longitude (horizontal) coordinate
1560  	// axis wraps around a given range and how. Defaults to `[-180, 180]` in most
1561  	// geographical CRSs. If `undefined`, the longitude axis does not wrap around.
1562  	//
1563  	// @property wrapLat: Number[]
1564  	// Like `wrapLng`, but for the latitude (vertical) axis.
1565
1566  	// wrapLng: [min, max],
1567  	// wrapLat: [min, max],
1568
1569  	// @property infinite: Boolean
1570  	// If true, the coordinate space will be unbounded (infinite in both axes)
1571  	infinite: false,
1572
1573  	// @method wrapLatLng(latlng: LatLng): LatLng
1574  	// Returns a `LatLng` where lat and lng has been wrapped according to the
1575  	// CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds.
1576  	wrapLatLng: function (latlng) {
1577  		var lng = this.wrapLng ? wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng,
1578  		    lat = this.wrapLat ? wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat,
1579  		    alt = latlng.alt;
1580
vendor: 14,570 bytes, lines 1581-1998
1581  		return new LatLng(lat, lng, alt);
1582  	},
1583
1584  	// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds
1585  	// Returns a `LatLngBounds` with the same size as the given one, ensuring
1586  	// that its center is within the CRS's bounds.
1587  	// Only accepts actual `L.LatLngBounds` instances, not arrays.
1588  	wrapLatLngBounds: function (bounds) {
1589  		var center = bounds.getCenter(),
1590  		    newCenter = this.wrapLatLng(center),
1591  		    latShift = center.lat - newCenter.lat,
1592  		    lngShift = center.lng - newCenter.lng;
1593
1594  		if (latShift === 0 && lngShift === 0) {
1595  			return bounds;
1596  		}
1597
1598  		var sw = bounds.getSouthWest(),
1599  		    ne = bounds.getNorthEast(),
1600  		    newSw = new LatLng(sw.lat - latShift, sw.lng - lngShift),
1601  		    newNe = new LatLng(ne.lat - latShift, ne.lng - lngShift);
1602
1603  		return new LatLngBounds(newSw, newNe);
1604  	}
1605  };
1606
1607  /*
1608   * @namespace CRS
1609   * @crs L.CRS.Earth
1610   *
1611   * Serves as the base for CRS that are global such that they cover the earth.
1612   * Can only be used as the base for other CRS and cannot be used directly,
1613   * since it does not have a `code`, `projection` or `transformation`. `distance()` returns
1614   * meters.
1615   */
1616
1617  var Earth = extend({}, CRS, {
1618  	wrapLng: [-180, 180],
1619
1620  	// Mean Earth Radius, as recommended for use by
1621  	// the International Union of Geodesy and Geophysics,
1622  	// see http://rosettacode.org/wiki/Haversine_formula
1623  	R: 6371000,
1624
1625  	// distance between two geographical points using spherical law of cosines approximation
1626  	distance: function (latlng1, latlng2) {
1627  		var rad = Math.PI / 180,
1628  		    lat1 = latlng1.lat * rad,
1629  		    lat2 = latlng2.lat * rad,
1630  		    sinDLat = Math.sin((latlng2.lat - latlng1.lat) * rad / 2),
1631  		    sinDLon = Math.sin((latlng2.lng - latlng1.lng) * rad / 2),
1632  		    a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon,
1633  		    c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
1634  		return this.R * c;
1635  	}
1636  });
1637
1638  /*
1639   * @namespace Projection
1640   * @projection L.Projection.SphericalMercator
1641   *
1642   * Spherical Mercator projection — the most common projection for online maps,
1643   * used by almost all free and commercial tile providers. Assumes that Earth is
1644   * a sphere. Used by the `EPSG:3857` CRS.
1645   */
1646
1647  var earthRadius = 6378137;
1648
1649  var SphericalMercator = {
1650
1651  	R: earthRadius,
1652  	MAX_LATITUDE: 85.0511287798,
1653
1654  	project: function (latlng) {
1655  		var d = Math.PI / 180,
1656  		    max = this.MAX_LATITUDE,
1657  		    lat = Math.max(Math.min(max, latlng.lat), -max),
1658  		    sin = Math.sin(lat * d);
1659
1660  		return new Point(
1661  			this.R * latlng.lng * d,
1662  			this.R * Math.log((1 + sin) / (1 - sin)) / 2);
1663  	},
1664
1665  	unproject: function (point) {
1666  		var d = 180 / Math.PI;
1667
1668  		return new LatLng(
1669  			(2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d,
1670  			point.x * d / this.R);
1671  	},
1672
1673  	bounds: (function () {
1674  		var d = earthRadius * Math.PI;
1675  		return new Bounds([-d, -d], [d, d]);
1676  	})()
1677  };
1678
1679  /*
1680   * @class Transformation
1681   * @aka L.Transformation
1682   *
1683   * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d`
1684   * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing
1685   * the reverse. Used by Leaflet in its projections code.
1686   *
1687   * @example
1688   *
1689   * ```js
1690   * var transformation = L.transformation(2, 5, -1, 10),
1691   * 	p = L.point(1, 2),
1692   * 	p2 = transformation.transform(p), //  L.point(7, 8)
1693   * 	p3 = transformation.untransform(p2); //  L.point(1, 2)
1694   * ```
1695   */
1696
1697
1698  // factory new L.Transformation(a: Number, b: Number, c: Number, d: Number)
1699  // Creates a `Transformation` object with the given coefficients.
1700  function Transformation(a, b, c, d) {
1701  	if (isArray(a)) {
1702  		// use array properties
1703  		this._a = a[0];
1704  		this._b = a[1];
1705  		this._c = a[2];
1706  		this._d = a[3];
1707  		return;
1708  	}
1709  	this._a = a;
1710  	this._b = b;
1711  	this._c = c;
1712  	this._d = d;
1713  }
1714
1715  Transformation.prototype = {
1716  	// @method transform(point: Point, scale?: Number): Point
1717  	// Returns a transformed point, optionally multiplied by the given scale.
1718  	// Only accepts actual `L.Point` instances, not arrays.
1719  	transform: function (point, scale) { // (Point, Number) -> Point
1720  		return this._transform(point.clone(), scale);
1721  	},
1722
1723  	// destructive transform (faster)
1724  	_transform: function (point, scale) {
1725  		scale = scale || 1;
1726  		point.x = scale * (this._a * point.x + this._b);
1727  		point.y = scale * (this._c * point.y + this._d);
1728  		return point;
1729  	},
1730
1731  	// @method untransform(point: Point, scale?: Number): Point
1732  	// Returns the reverse transformation of the given point, optionally divided
1733  	// by the given scale. Only accepts actual `L.Point` instances, not arrays.
1734  	untransform: function (point, scale) {
1735  		scale = scale || 1;
1736  		return new Point(
1737  		        (point.x / scale - this._b) / this._a,
1738  		        (point.y / scale - this._d) / this._c);
1739  	}
1740  };
1741
1742  // factory L.transformation(a: Number, b: Number, c: Number, d: Number)
1743
1744  // @factory L.transformation(a: Number, b: Number, c: Number, d: Number)
1745  // Instantiates a Transformation object with the given coefficients.
1746
1747  // @alternative
1748  // @factory L.transformation(coefficients: Array): Transformation
1749  // Expects an coefficients array of the form
1750  // `[a: Number, b: Number, c: Number, d: Number]`.
1751
1752  function toTransformation(a, b, c, d) {
1753  	return new Transformation(a, b, c, d);
1754  }
1755
1756  /*
1757   * @namespace CRS
1758   * @crs L.CRS.EPSG3857
1759   *
1760   * The most common CRS for online maps, used by almost all free and commercial
1761   * tile providers. Uses Spherical Mercator projection. Set in by default in
1762   * Map's `crs` option.
1763   */
1764
1765  var EPSG3857 = extend({}, Earth, {
1766  	code: 'EPSG:3857',
1767  	projection: SphericalMercator,
1768
1769  	transformation: (function () {
1770  		var scale = 0.5 / (Math.PI * SphericalMercator.R);
1771  		return toTransformation(scale, 0.5, -scale, 0.5);
1772  	}())
1773  });
1774
1775  var EPSG900913 = extend({}, EPSG3857, {
1776  	code: 'EPSG:900913'
1777  });
1778
1779  // @namespace SVG; @section
1780  // There are several static functions which can be called without instantiating L.SVG:
1781
1782  // @function create(name: String): SVGElement
1783  // Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement),
1784  // corresponding to the class name passed. For example, using 'line' will return
1785  // an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement).
1786  function svgCreate(name) {
1787  	return document.createElementNS('http://www.w3.org/2000/svg', name);
1788  }
1789
1790  // @function pointsToPath(rings: Point[], closed: Boolean): String
1791  // Generates a SVG path string for multiple rings, with each ring turning
1792  // into "M..L..L.." instructions
1793  function pointsToPath(rings, closed) {
1794  	var str = '',
1795  	i, j, len, len2, points, p;
1796
1797  	for (i = 0, len = rings.length; i < len; i++) {
1798  		points = rings[i];
1799
1800  		for (j = 0, len2 = points.length; j < len2; j++) {
1801  			p = points[j];
1802  			str += (j ? 'L' : 'M') + p.x + ' ' + p.y;
1803  		}
1804
1805  		// closes the ring for polygons; "x" is VML syntax
1806  		str += closed ? (svg$1 ? 'z' : 'x') : '';
1807  	}
1808
1809  	// SVG complains about empty path strings
1810  	return str || 'M0 0';
1811  }
1812
1813  /*
1814   * @namespace Browser
1815   * @aka L.Browser
1816   *
1817   * A namespace with static properties for browser/feature detection used by Leaflet internally.
1818   *
1819   * @example
1820   *
1821   * ```js
1822   * if (L.Browser.ielt9) {
1823   *   alert('Upgrade your browser, dude!');
1824   * }
1825   * ```
1826   */
1827
1828  var style = document.documentElement.style;
1829
1830  // @property ie: Boolean; `true` for all Internet Explorer versions (not Edge).
1831  var ie = 'ActiveXObject' in window;
1832
1833  // @property ielt9: Boolean; `true` for Internet Explorer versions less than 9.
1834  var ielt9 = ie && !document.addEventListener;
1835
1836  // @property edge: Boolean; `true` for the Edge web browser.
1837  var edge = 'msLaunchUri' in navigator && !('documentMode' in document);
1838
1839  // @property webkit: Boolean;
1840  // `true` for webkit-based browsers like Chrome and Safari (including mobile versions).
1841  var webkit = userAgentContains('webkit');
1842
1843  // @property android: Boolean
1844  // `true` for any browser running on an Android platform.
1845  var android = userAgentContains('android');
1846
1847  // @property android23: Boolean; `true` for browsers running on Android 2 or Android 3.
1848  var android23 = userAgentContains('android 2') || userAgentContains('android 3');
1849
1850  /* See https://stackoverflow.com/a/17961266 for details on detecting stock Android */
1851  var webkitVer = parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10); // also matches AppleWebKit
1852  // @property androidStock: Boolean; `true` for the Android stock browser (i.e. not Chrome)
1853  var androidStock = android && userAgentContains('Google') && webkitVer < 537 && !('AudioNode' in window);
1854
1855  // @property opera: Boolean; `true` for the Opera browser
1856  var opera = !!window.opera;
1857
1858  // @property chrome: Boolean; `true` for the Chrome browser.
1859  var chrome = !edge && userAgentContains('chrome');
1860
1861  // @property gecko: Boolean; `true` for gecko-based browsers like Firefox.
1862  var gecko = userAgentContains('gecko') && !webkit && !opera && !ie;
1863
1864  // @property safari: Boolean; `true` for the Safari browser.
1865  var safari = !chrome && userAgentContains('safari');
1866
1867  var phantom = userAgentContains('phantom');
1868
1869  // @property opera12: Boolean
1870  // `true` for the Opera browser supporting CSS transforms (version 12 or later).
1871  var opera12 = 'OTransition' in style;
1872
1873  // @property win: Boolean; `true` when the browser is running in a Windows platform
1874  var win = navigator.platform.indexOf('Win') === 0;
1875
1876  // @property ie3d: Boolean; `true` for all Internet Explorer versions supporting CSS transforms.
1877  var ie3d = ie && ('transition' in style);
1878
1879  // @property webkit3d: Boolean; `true` for webkit-based browsers supporting CSS transforms.
1880  var webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23;
1881
1882  // @property gecko3d: Boolean; `true` for gecko-based browsers supporting CSS transforms.
1883  var gecko3d = 'MozPerspective' in style;
1884
1885  // @property any3d: Boolean
1886  // `true` for all browsers supporting CSS transforms.
1887  var any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantom;
1888
1889  // @property mobile: Boolean; `true` for all browsers running in a mobile device.
1890  var mobile = typeof orientation !== 'undefined' || userAgentContains('mobile');
1891
1892  // @property mobileWebkit: Boolean; `true` for all webkit-based browsers in a mobile device.
1893  var mobileWebkit = mobile && webkit;
1894
1895  // @property mobileWebkit3d: Boolean
1896  // `true` for all webkit-based browsers in a mobile device supporting CSS transforms.
1897  var mobileWebkit3d = mobile && webkit3d;
1898
1899  // @property msPointer: Boolean
1900  // `true` for browsers implementing the Microsoft touch events model (notably IE10).
1901  var msPointer = !window.PointerEvent && window.MSPointerEvent;
1902
1903  // @property pointer: Boolean
1904  // `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx).
1905  var pointer = !!(window.PointerEvent || msPointer);
1906
1907  // @property touch: Boolean
1908  // `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).
1909  // This does not necessarily mean that the browser is running in a computer with
1910  // a touchscreen, it only means that the browser is capable of understanding
1911  // touch events.
1912  var touch = !window.L_NO_TOUCH && (pointer || 'ontouchstart' in window ||
1913  		(window.DocumentTouch && document instanceof window.DocumentTouch));
1914
1915  // @property mobileOpera: Boolean; `true` for the Opera browser in a mobile device.
1916  var mobileOpera = mobile && opera;
1917
1918  // @property mobileGecko: Boolean
1919  // `true` for gecko-based browsers running in a mobile device.
1920  var mobileGecko = mobile && gecko;
1921
1922  // @property retina: Boolean
1923  // `true` for browsers on a high-resolution "retina" screen or on any screen when browser's display zoom is more than 100%.
1924  var retina = (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1;
1925
1926  // @property passiveEvents: Boolean
1927  // `true` for browsers that support passive events.
1928  var passiveEvents = (function () {
1929  	var supportsPassiveOption = false;
1930  	try {
1931  		var opts = Object.defineProperty({}, 'passive', {
1932  			get: function () { // eslint-disable-line getter-return
1933  				supportsPassiveOption = true;
1934  			}
1935  		});
1936  		window.addEventListener('testPassiveEventSupport', falseFn, opts);
1937  		window.removeEventListener('testPassiveEventSupport', falseFn, opts);
1938  	} catch (e) {
1939  		// Errors can safely be ignored since this is only a browser support test.
1940  	}
1941  	return supportsPassiveOption;
1942  }());
1943
1944  // @property canvas: Boolean
1945  // `true` when the browser supports [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
1946  var canvas$1 = (function () {
1947  	return !!document.createElement('canvas').getContext;
1948  }());
1949
1950  // @property svg: Boolean
1951  // `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG).
1952  var svg$1 = !!(document.createElementNS && svgCreate('svg').createSVGRect);
1953
1954  // @property vml: Boolean
1955  // `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language).
1956  var vml = !svg$1 && (function () {
1957  	try {
1958  		var div = document.createElement('div');
1959  		div.innerHTML = '<v:shape adj="1"/>';
1960
1961  		var shape = div.firstChild;
1962  		shape.style.behavior = 'url(#default#VML)';
1963
1964  		return shape && (typeof shape.adj === 'object');
1965
1966  	} catch (e) {
1967  		return false;
1968  	}
1969  }());
1970
1971
1972  function userAgentContains(str) {
1973  	return navigator.userAgent.toLowerCase().indexOf(str) >= 0;
1974  }
1975
1976  var Browser = {
1977    __proto__: null,
1978    ie: ie,
1979    ielt9: ielt9,
1980    edge: edge,
1981    webkit: webkit,
1982    android: android,
1983    android23: android23,
1984    androidStock: androidStock,
1985    opera: opera,
1986    chrome: chrome,
1987    gecko: gecko,
1988    safari: safari,
1989    phantom: phantom,
1990    opera12: opera12,
1991    win: win,
1992    ie3d: ie3d,
1993    webkit3d: webkit3d,
1994    gecko3d: gecko3d,
1995    any3d: any3d,
1996    mobile: mobile,
1997    mobileWebkit: mobileWebkit,
1998    mobileWebkit3d: mobileWebkit3d,
1999    msPointer: msPointer,
2000    pointer: pointer,
2001    touch: touch,
2002    mobileOpera: mobileOpera,
2003    mobileGecko: mobileGecko,
2004    retina: retina,
2005    passiveEvents: passiveEvents,
2006    canvas: canvas$1,
2007    svg: svg$1,
2008    vml: vml
2009  };
2010
2011  /*
2012   * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.
2013   */
2014
2015
2016  var POINTER_DOWN =   msPointer ? 'MSPointerDown'   : 'pointerdown';
2017  var POINTER_MOVE =   msPointer ? 'MSPointerMove'   : 'pointermove';
2018  var POINTER_UP =     msPointer ? 'MSPointerUp'     : 'pointerup';
2019  var POINTER_CANCEL = msPointer ? 'MSPointerCancel' : 'pointercancel';
2020
2021  var _pointers = {};
2022  var _pointerDocListener = false;
2023
2024  // Provides a touch events wrapper for (ms)pointer events.
2025  // ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
2026
2027  function addPointerListener(obj, type, handler, id) {
2028  	if (type === 'touchstart') {
2029  		_addPointerStart(obj, handler, id);
2030
2031  	} else if (type === 'touchmove') {
2032  		_addPointerMove(obj, handler, id);
2033
2034  	} else if (type === 'touchend') {
2035  		_addPointerEnd(obj, handler, id);
2036  	}
2037
2038  	return this;
2039  }
2040
2041  function removePointerListener(obj, type, id) {
2042  	var handler = obj['_leaflet_' + type + id];
2043
2044  	if (type === 'touchstart') {
2045  		obj.removeEventListener(POINTER_DOWN, handler, false);
2046
2047  	} else if (type === 'touchmove') {
2048  		obj.removeEventListener(POINTER_MOVE, handler, false);
2049
2050  	} else if (type === 'touchend') {
2051  		obj.removeEventListener(POINTER_UP, handler, false);
2052  		obj.removeEventListener(POINTER_CANCEL, handler, false);
2053  	}
2054
2055  	return this;
2056  }
2057
2058  function _addPointerStart(obj, handler, id) {
2059  	var onDown = bind(function (e) {
2060  		// IE10 specific: MsTouch needs preventDefault. See #2000
2061  		if (e.MSPOINTER_TYPE_TOUCH && e.pointerType === e.MSPOINTER_TYPE_TOUCH) {
2062  			preventDefault(e);
2063  		}
2064
2065  		_handlePointer(e, handler);
2066  	});
2067
2068  	obj['_leaflet_touchstart' + id] = onDown;
2069  	obj.addEventListener(POINTER_DOWN, onDown, false);
2070
2071  	// need to keep track of what pointers and how many are active to provide e.touches emulation
2072  	if (!_pointerDocListener) {
2073  		// we listen document as any drags that end by moving the touch off the screen get fired there
2074  		document.addEventListener(POINTER_DOWN, _globalPointerDown, true);
2075  		document.addEventListener(POINTER_MOVE, _globalPointerMove, true);
2076  		document.addEventListener(POINTER_UP, _globalPointerUp, true);
2077  		document.addEventListener(POINTER_CANCEL, _globalPointerUp, true);
2078
2079  		_pointerDocListener = true;
2080  	}
2081  }
2082
2083  function _globalPointerDown(e) {
2084  	_pointers[e.pointerId] = e;
2085  }
2086
2087  function _globalPointerMove(e) {
2088  	if (_pointers[e.pointerId]) {
2089  		_pointers[e.pointerId] = e;
2090  	}
2091  }
2092
2093  function _globalPointerUp(e) {
2094  	delete _pointers[e.pointerId];
2095  }
2096
2097  function _handlePointer(e, handler) {
2098  	e.touches = [];
2099  	for (var i in _pointers) {
2100  		e.touches.push(_pointers[i]);
2101  	}
2102  	e.changedTouches = [e];
2103
2104  	handler(e);
2105  }
2106
2107  function _addPointerMove(obj, handler, id) {
2108  	var onMove = function (e) {
2109  		// don't fire touch moves when mouse isn't down
2110  		if ((e.pointerType === (e.MSPOINTER_TYPE_MOUSE || 'mouse')) && e.buttons === 0) {
2111  			return;
2112  		}
2113
2114  		_handlePointer(e, handler);
2115  	};
2116
2117  	obj['_leaflet_touchmove' + id] = onMove;
2118  	obj.addEventListener(POINTER_MOVE, onMove, false);
2119  }
2120
2121  function _addPointerEnd(obj, handler, id) {
2122  	var onUp = function (e) {
2123  		_handlePointer(e, handler);
2124  	};
2125
2126  	obj['_leaflet_touchend' + id] = onUp;
2127  	obj.addEventListener(POINTER_UP, onUp, false);
2128  	obj.addEventListener(POINTER_CANCEL, onUp, false);
2129  }
2130
2131  /*
2132   * Extends the event handling code with double tap support for mobile browsers.
2133   */
2134
2135  var _touchstart = msPointer ? 'MSPointerDown' : pointer ? 'pointerdown' : 'touchstart';
2136  var _touchend = msPointer ? 'MSPointerUp' : pointer ? 'pointerup' : 'touchend';
2137  var _pre = '_leaflet_';
2138
2139  // inspired by Zepto touch code by Thomas Fuchs
2140  function addDoubleTapListener(obj, handler, id) {
2141  	var last, touch,
2142  	    doubleTap = false,
2143  	    delay = 250;
2144
2145  	function onTouchStart(e) {
2146
2147  		if (pointer) {
2148  			if (!e.isPrimary) { return; }
2149  			if (e.pointerType === 'mouse') { return; } // mouse fires native dblclick
2150  		} else if (e.touches.length > 1) {
2151  			return;
2152  		}
2153
2154  		var now = Date.now(),
2155  		    delta = now - (last || now);
2156
2157  		touch = e.touches ? e.touches[0] : e;
2158  		doubleTap = (delta > 0 && delta <= delay);
2159  		last = now;
2160  	}
2161
2162  	function onTouchEnd(e) {
2163  		if (doubleTap && !touch.cancelBubble) {
2164  			if (pointer) {
2165  				if (e.pointerType === 'mouse') { return; }
2166  				// work around .type being readonly with MSPointer* events
2167  				var newTouch = {},
2168  				    prop, i;
2169
2170  				for (i in touch) {
2171  					prop = touch[i];
2172  					newTouch[i] = prop && prop.bind ? prop.bind(touch) : prop;
2173  				}
2174  				touch = newTouch;
2175  			}
2176  			touch.type = 'dblclick';
2177  			touch.button = 0;
2178  			handler(touch);
2179  			last = null;
2180  		}
2181  	}
2182
2183  	obj[_pre + _touchstart + id] = onTouchStart;
2184  	obj[_pre + _touchend + id] = onTouchEnd;
2185  	obj[_pre + 'dblclick' + id] = handler;
2186
2187  	obj.addEventListener(_touchstart, onTouchStart, passiveEvents ? {passive: false} : false);
2188  	obj.addEventListener(_touchend, onTouchEnd, passiveEvents ? {passive: false} : false);
2189
2190  	// On some platforms (notably, chrome<55 on win10 + touchscreen + mouse),
2191  	// the browser doesn't fire touchend/pointerup events but does fire
2192  	// native dblclicks. See #4127.
2193  	// Edge 14 also fires native dblclicks, but only for pointerType mouse, see #5180.
2194  	obj.addEventListener('dblclick', handler, false);
2195
2196  	return this;
2197  }
2198
2199  function removeDoubleTapListener(obj, id) {
2200  	var touchstart = obj[_pre + _touchstart + id],
2201  	    touchend = obj[_pre + _touchend + id],
2202  	    dblclick = obj[_pre + 'dblclick' + id];
2203
2204  	obj.removeEventListener(_touchstart, touchstart, passiveEvents ? {passive: false} : false);
2205  	obj.removeEventListener(_touchend, touchend, passiveEvents ? {passive: false} : false);
2206  	obj.removeEventListener('dblclick', dblclick, false);
2207
2208  	return this;
2209  }
2210
2211  /*
2212   * @namespace DomUtil
2213   *
2214   * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)
2215   * tree, used by Leaflet internally.
2216   *
2217   * Most functions expecting or returning a `HTMLElement` also work for
2218   * SVG elements. The only difference is that classes refer to CSS classes
2219   * in HTML and SVG classes in SVG.
2220   */
2221
2222
2223  // @property TRANSFORM: String
2224  // Vendor-prefixed transform style name (e.g. `'webkitTransform'` for WebKit).
2225  var TRANSFORM = testProp(
2226  	['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
2227
2228  // webkitTransition comes first because some browser versions that drop vendor prefix don't do
2229  // the same for the transitionend event, in particular the Android 4.1 stock browser
2230
2231  // @property TRANSITION: String
2232  // Vendor-prefixed transition style name.
2233  var TRANSITION = testProp(
2234  	['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);
2235
2236  // @property TRANSITION_END: String
2237  // Vendor-prefixed transitionend event name.
2238  var TRANSITION_END =
2239  	TRANSITION === 'webkitTransition' || TRANSITION === 'OTransition' ? TRANSITION + 'End' : 'transitionend';
2240
2241
2242  // @function get(id: String|HTMLElement): HTMLElement
2243  // Returns an element given its DOM id, or returns the element itself
2244  // if it was passed directly.
2245  function get(id) {
2246  	return typeof id === 'string' ? document.getElementById(id) : id;
2247  }
2248
2249  // @function getStyle(el: HTMLElement, styleAttrib: String): String
2250  // Returns the value for a certain style attribute on an element,
2251  // including computed values or values set through CSS.
2252  function getStyle(el, style) {
2253  	var value = el.style[style] || (el.currentStyle && el.currentStyle[style]);
2254
2255  	if ((!value || value === 'auto') && document.defaultView) {
2256  		var css = document.defaultView.getComputedStyle(el, null);
2257  		value = css ? css[style] : null;
2258  	}
2259  	return value === 'auto' ? null : value;
2260  }
2261
2262  // @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement
2263  // Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element.
2264  function create$1(tagName, className, container) {
2265  	var el = document.createElement(tagName);
2266  	el.className = className || '';
2267
2268  	if (container) {
2269  		container.appendChild(el);
2270  	}
2271  	return el;
2272  }
2273
2274  // @function remove(el: HTMLElement)
2275  // Removes `el` from its parent element
2276  function remove(el) {
2277  	var parent = el.parentNode;
2278  	if (parent) {
2279  		parent.removeChild(el);
2280  	}
2281  }
2282
2283  // @function empty(el: HTMLElement)
2284  // Removes all of `el`'s children elements from `el`
2285  function empty(el) {
2286  	while (el.firstChild) {
2287  		el.removeChild(el.firstChild);
2288  	}
2289  }
2290
2291  // @function toFront(el: HTMLElement)
2292  // Makes `el` the last child of its parent, so it renders in front of the other children.
2293  function toFront(el) {
2294  	var parent = el.parentNode;
2295  	if (parent && parent.lastChild !== el) {
2296  		parent.appendChild(el);
2297  	}
2298  }
2299
2300  // @function toBack(el: HTMLElement)
2301  // Makes `el` the first child of its parent, so it renders behind the other children.
2302  function toBack(el) {
2303  	var parent = el.parentNode;
2304  	if (parent && parent.firstChild !== el) {
2305  		parent.insertBefore(el, parent.firstChild);
2306  	}
2307  }
2308
2309  // @function hasClass(el: HTMLElement, name: String): Boolean
2310  // Returns `true` if the element's class attribute contains `name`.
2311  function hasClass(el, name) {
2312  	if (el.classList !== undefined) {
2313  		return el.classList.contains(name);
2314  	}
2315  	var className = getClass(el);
2316  	return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className);
2317  }
2318
2319  // @function addClass(el: HTMLElement, name: String)
2320  // Adds `name` to the element's class attribute.
2321  function addClass(el, name) {
2322  	if (el.classList !== undefined) {
2323  		var classes = splitWords(name);
2324  		for (var i = 0, len = classes.length; i < len; i++) {
2325  			el.classList.add(classes[i]);
2326  		}
2327  	} else if (!hasClass(el, name)) {
2328  		var className = getClass(el);
2329  		setClass(el, (className ? className + ' ' : '') + name);
2330  	}
2331  }
2332
2333  // @function removeClass(el: HTMLElement, name: String)
2334  // Removes `name` from the element's class attribute.
2335  function removeClass(el, name) {
2336  	if (el.classList !== undefined) {
2337  		el.classList.remove(name);
2338  	} else {
2339  		setClass(el, trim((' ' + getClass(el) + ' ').replace(' ' + name + ' ', ' ')));
2340  	}
2341  }
2342
2343  // @function setClass(el: HTMLElement, name: String)
2344  // Sets the element's class.
2345  function setClass(el, name) {
2346  	if (el.className.baseVal === undefined) {
2347  		el.className = name;
2348  	} else {
2349  		// in case of SVG element
2350  		el.className.baseVal = name;
2351  	}
2352  }
2353
2354  // @function getClass(el: HTMLElement): String
2355  // Returns the element's class.
2356  function getClass(el) {
2357  	// Check if the element is an SVGElementInstance and use the correspondingElement instead
2358  	// (Required for linked SVG elements in IE11.)
2359  	if (el.correspondingElement) {
2360  		el = el.correspondingElement;
2361  	}
2362  	return el.className.baseVal === undefined ? el.className : el.className.baseVal;
2363  }
2364
2365  // @function setOpacity(el: HTMLElement, opacity: Number)
2366  // Set the opacity of an element (including old IE support).
2367  // `opacity` must be a number from `0` to `1`.
2368  function setOpacity(el, value) {
2369  	if ('opacity' in el.style) {
2370  		el.style.opacity = value;
2371  	} else if ('filter' in el.style) {
2372  		_setOpacityIE(el, value);
2373  	}
2374  }
2375
2376  function _setOpacityIE(el, value) {
2377  	var filter = false,
2378  	    filterName = 'DXImageTransform.Microsoft.Alpha';
2379
2380  	// filters collection throws an error if we try to retrieve a filter that doesn't exist
2381  	try {
2382  		filter = el.filters.item(filterName);
2383  	} catch (e) {
2384  		// don't set opacity to 1 if we haven't already set an opacity,
2385  		// it isn't needed and breaks transparent pngs.
2386  		if (value === 1) { return; }
2387  	}
2388
2389  	value = Math.round(value * 100);
2390
2391  	if (filter) {
2392  		filter.Enabled = (value !== 100);
2393  		filter.Opacity = value;
2394  	} else {
2395  		el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';
2396  	}
2397  }
2398
2399  // @function testProp(props: String[]): String|false
2400  // Goes through the array of style names and returns the first name
2401  // that is a valid style name for an element. If no such name is found,
2402  // it returns false. Useful for vendor-prefixed styles like `transform`.
2403  function testProp(props) {
2404  	var style = document.documentElement.style;
2405
2406  	for (var i = 0; i < props.length; i++) {
2407  		if (props[i] in style) {
2408  			return props[i];
2409  		}
2410  	}
2411  	return false;
2412  }
2413
2414  // @function setTransform(el: HTMLElement, offset: Point, scale?: Number)
2415  // Resets the 3D CSS transform of `el` so it is translated by `offset` pixels
2416  // and optionally scaled by `scale`. Does not have an effect if the
2417  // browser doesn't support 3D CSS transforms.
2418  function setTransform(el, offset, scale) {
2419  	var pos = offset || new Point(0, 0);
2420
2421  	el.style[TRANSFORM] =
2422  		(ie3d ?
2423  			'translate(' + pos.x + 'px,' + pos.y + 'px)' :
2424  			'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') +
2425  		(scale ? ' scale(' + scale + ')' : '');
2426  }
2427
2428  // @function setPosition(el: HTMLElement, position: Point)
2429  // Sets the position of `el` to coordinates specified by `position`,
2430  // using CSS translate or top/left positioning depending on the browser
vendor: 8,125 bytes, lines 2431-2671
2431  // (used by Leaflet internally to position its layers).
2432  function setPosition(el, point) {
2433
2434  	/*eslint-disable */
2435  	el._leaflet_pos = point;
2436  	/* eslint-enable */
2437
2438  	if (any3d) {
2439  		setTransform(el, point);
2440  	} else {
2441  		el.style.left = point.x + 'px';
2442  		el.style.top = point.y + 'px';
2443  	}
2444  }
2445
2446  // @function getPosition(el: HTMLElement): Point
2447  // Returns the coordinates of an element previously positioned with setPosition.
2448  function getPosition(el) {
2449  	// this method is only used for elements previously positioned using setPosition,
2450  	// so it's safe to cache the position for performance
2451
2452  	return el._leaflet_pos || new Point(0, 0);
2453  }
2454
2455  // @function disableTextSelection()
2456  // Prevents the user from generating `selectstart` DOM events, usually generated
2457  // when the user drags the mouse through a page with text. Used internally
2458  // by Leaflet to override the behaviour of any click-and-drag interaction on
2459  // the map. Affects drag interactions on the whole document.
2460
2461  // @function enableTextSelection()
2462  // Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection).
2463  var disableTextSelection;
2464  var enableTextSelection;
2465  var _userSelect;
2466  if ('onselectstart' in document) {
2467  	disableTextSelection = function () {
2468  		on(window, 'selectstart', preventDefault);
2469  	};
2470  	enableTextSelection = function () {
2471  		off(window, 'selectstart', preventDefault);
2472  	};
2473  } else {
2474  	var userSelectProperty = testProp(
2475  		['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
2476
2477  	disableTextSelection = function () {
2478  		if (userSelectProperty) {
2479  			var style = document.documentElement.style;
2480  			_userSelect = style[userSelectProperty];
2481  			style[userSelectProperty] = 'none';
2482  		}
2483  	};
2484  	enableTextSelection = function () {
2485  		if (userSelectProperty) {
2486  			document.documentElement.style[userSelectProperty] = _userSelect;
2487  			_userSelect = undefined;
2488  		}
2489  	};
2490  }
2491
2492  // @function disableImageDrag()
2493  // As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but
2494  // for `dragstart` DOM events, usually generated when the user drags an image.
2495  function disableImageDrag() {
2496  	on(window, 'dragstart', preventDefault);
2497  }
2498
2499  // @function enableImageDrag()
2500  // Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection).
2501  function enableImageDrag() {
2502  	off(window, 'dragstart', preventDefault);
2503  }
2504
2505  var _outlineElement, _outlineStyle;
2506  // @function preventOutline(el: HTMLElement)
2507  // Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline)
2508  // of the element `el` invisible. Used internally by Leaflet to prevent
2509  // focusable elements from displaying an outline when the user performs a
2510  // drag interaction on them.
2511  function preventOutline(element) {
2512  	while (element.tabIndex === -1) {
2513  		element = element.parentNode;
2514  	}
2515  	if (!element.style) { return; }
2516  	restoreOutline();
2517  	_outlineElement = element;
2518  	_outlineStyle = element.style.outline;
2519  	element.style.outline = 'none';
2520  	on(window, 'keydown', restoreOutline);
2521  }
2522
2523  // @function restoreOutline()
2524  // Cancels the effects of a previous [`L.DomUtil.preventOutline`]().
2525  function restoreOutline() {
2526  	if (!_outlineElement) { return; }
2527  	_outlineElement.style.outline = _outlineStyle;
2528  	_outlineElement = undefined;
2529  	_outlineStyle = undefined;
2530  	off(window, 'keydown', restoreOutline);
2531  }
2532
2533  // @function getSizedParentNode(el: HTMLElement): HTMLElement
2534  // Finds the closest parent node which size (width and height) is not null.
2535  function getSizedParentNode(element) {
2536  	do {
2537  		element = element.parentNode;
2538  	} while ((!element.offsetWidth || !element.offsetHeight) && element !== document.body);
2539  	return element;
2540  }
2541
2542  // @function getScale(el: HTMLElement): Object
2543  // Computes the CSS scale currently applied on the element.
2544  // Returns an object with `x` and `y` members as horizontal and vertical scales respectively,
2545  // and `boundingClientRect` as the result of [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect).
2546  function getScale(element) {
2547  	var rect = element.getBoundingClientRect(); // Read-only in old browsers.
2548
2549  	return {
2550  		x: rect.width / element.offsetWidth || 1,
2551  		y: rect.height / element.offsetHeight || 1,
2552  		boundingClientRect: rect
2553  	};
2554  }
2555
2556  var DomUtil = {
2557    __proto__: null,
2558    TRANSFORM: TRANSFORM,
2559    TRANSITION: TRANSITION,
2560    TRANSITION_END: TRANSITION_END,
2561    get: get,
2562    getStyle: getStyle,
2563    create: create$1,
2564    remove: remove,
2565    empty: empty,
2566    toFront: toFront,
2567    toBack: toBack,
2568    hasClass: hasClass,
2569    addClass: addClass,
2570    removeClass: removeClass,
2571    setClass: setClass,
2572    getClass: getClass,
2573    setOpacity: setOpacity,
2574    testProp: testProp,
2575    setTransform: setTransform,
2576    setPosition: setPosition,
2577    getPosition: getPosition,
2578    get disableTextSelection () { return disableTextSelection; },
2579    get enableTextSelection () { return enableTextSelection; },
2580    disableImageDrag: disableImageDrag,
2581    enableImageDrag: enableImageDrag,
2582    preventOutline: preventOutline,
2583    restoreOutline: restoreOutline,
2584    getSizedParentNode: getSizedParentNode,
2585    getScale: getScale
2586  };
2587
2588  /*
2589   * @namespace DomEvent
2590   * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally.
2591   */
2592
2593  // Inspired by John Resig, Dean Edwards and YUI addEvent implementations.
2594
2595  // @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this
2596  // Adds a listener function (`fn`) to a particular DOM event type of the
2597  // element `el`. You can optionally specify the context of the listener
2598  // (object the `this` keyword will point to). You can also pass several
2599  // space-separated types (e.g. `'click dblclick'`).
2600
2601  // @alternative
2602  // @function on(el: HTMLElement, eventMap: Object, context?: Object): this
2603  // Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
2604  function on(obj, types, fn, context) {
2605
2606  	if (typeof types === 'object') {
2607  		for (var type in types) {
2608  			addOne(obj, type, types[type], fn);
2609  		}
2610  	} else {
2611  		types = splitWords(types);
2612
2613  		for (var i = 0, len = types.length; i < len; i++) {
2614  			addOne(obj, types[i], fn, context);
2615  		}
2616  	}
2617
2618  	return this;
2619  }
2620
2621  var eventsKey = '_leaflet_events';
2622
2623  // @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this
2624  // Removes a previously added listener function.
2625  // Note that if you passed a custom context to on, you must pass the same
2626  // context to `off` in order to remove the listener.
2627
2628  // @alternative
2629  // @function off(el: HTMLElement, eventMap: Object, context?: Object): this
2630  // Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
2631  function off(obj, types, fn, context) {
2632
2633  	if (typeof types === 'object') {
2634  		for (var type in types) {
2635  			removeOne(obj, type, types[type], fn);
2636  		}
2637  	} else if (types) {
2638  		types = splitWords(types);
2639
2640  		for (var i = 0, len = types.length; i < len; i++) {
2641  			removeOne(obj, types[i], fn, context);
2642  		}
2643  	} else {
2644  		for (var j in obj[eventsKey]) {
2645  			removeOne(obj, j, obj[eventsKey][j]);
2646  		}
2647  		delete obj[eventsKey];
2648  	}
2649
2650  	return this;
2651  }
2652
2653  function browserFiresNativeDblClick() {
2654  	// See https://github.com/w3c/pointerevents/issues/171
2655  	if (pointer) {
2656  		return !(edge || safari);
2657  	}
2658  }
2659
2660  var mouseSubst = {
2661  	mouseenter: 'mouseover',
2662  	mouseleave: 'mouseout',
2663  	wheel: !('onwheel' in window) && 'mousewheel'
2664  };
2665
2666  function addOne(obj, type, fn, context) {
2667  	var id = type + stamp(fn) + (context ? '_' + stamp(context) : '');
2668
2669  	if (obj[eventsKey] && obj[eventsKey][id]) { return this; }
2670
2671  	var handler = function (e) {
2672  		return fn.call(context || obj, e || window.event);
2673  	};
2674
2675  	var originalHandler = handler;
2676
2677  	if (pointer && type.indexOf('touch') === 0) {
2678  		// Needs DomEvent.Pointer.js
2679  		addPointerListener(obj, type, handler, id);
2680
2681  	} else if (touch && (type === 'dblclick') && !browserFiresNativeDblClick()) {
2682  		addDoubleTapListener(obj, handler, id);
2683
2684  	} else if ('addEventListener' in obj) {
2685
2686  		if (type === 'touchstart' || type === 'touchmove' || type === 'wheel' ||  type === 'mousewheel') {
2687  			obj.addEventListener(mouseSubst[type] || type, handler, passiveEvents ? {passive: false} : false);
2688
2689  		} else if (type === 'mouseenter' || type === 'mouseleave') {
2690  			handler = function (e) {
2691  				e = e || window.event;
2692  				if (isExternalTarget(obj, e)) {
2693  					originalHandler(e);
2694  				}
2695  			};
2696  			obj.addEventListener(mouseSubst[type], handler, false);
2697
2698  		} else {
2699  			obj.addEventListener(type, originalHandler, false);
2700  		}
2701
2702  	} else if ('attachEvent' in obj) {
2703  		obj.attachEvent('on' + type, handler);
2704  	}
2705
2706  	obj[eventsKey] = obj[eventsKey] || {};
2707  	obj[eventsKey][id] = handler;
2708  }
2709
2710  function removeOne(obj, type, fn, context) {
2711
2712  	var id = type + stamp(fn) + (context ? '_' + stamp(context) : ''),
2713  	    handler = obj[eventsKey] && obj[eventsKey][id];
2714
2715  	if (!handler) { return this; }
2716
2717  	if (pointer && type.indexOf('touch') === 0) {
2718  		removePointerListener(obj, type, id);
2719
2720  	} else if (touch && (type === 'dblclick') && !browserFiresNativeDblClick()) {
2721  		removeDoubleTapListener(obj, id);
2722
2723  	} else if ('removeEventListener' in obj) {
2724
2725  		obj.removeEventListener(mouseSubst[type] || type, handler, false);
2726
2727  	} else if ('detachEvent' in obj) {
2728  		obj.detachEvent('on' + type, handler);
2729  	}
2730
2731  	obj[eventsKey][id] = null;
2732  }
2733
2734  // @function stopPropagation(ev: DOMEvent): this
2735  // Stop the given event from propagation to parent elements. Used inside the listener functions:
2736  // ```js
2737  // L.DomEvent.on(div, 'click', function (ev) {
2738  // 	L.DomEvent.stopPropagation(ev);
2739  // });
2740  // ```
2741  function stopPropagation(e) {
2742
2743  	if (e.stopPropagation) {
2744  		e.stopPropagation();
2745  	} else if (e.originalEvent) {  // In case of Leaflet event.
2746  		e.originalEvent._stopped = true;
2747  	} else {
2748  		e.cancelBubble = true;
2749  	}
2750  	skipped(e);
2751
2752  	return this;
2753  }
2754
2755  // @function disableScrollPropagation(el: HTMLElement): this
2756  // Adds `stopPropagation` to the element's `'wheel'` events (plus browser variants).
2757  function disableScrollPropagation(el) {
2758  	addOne(el, 'wheel', stopPropagation);
2759  	return this;
2760  }
2761
2762  // @function disableClickPropagation(el: HTMLElement): this
2763  // Adds `stopPropagation` to the element's `'click'`, `'doubleclick'`,
2764  // `'mousedown'` and `'touchstart'` events (plus browser variants).
2765  function disableClickPropagation(el) {
2766  	on(el, 'mousedown touchstart dblclick', stopPropagation);
2767  	addOne(el, 'click', fakeStop);
2768  	return this;
2769  }
2770
2771  // @function preventDefault(ev: DOMEvent): this
2772  // Prevents the default action of the DOM Event `ev` from happening (such as
2773  // following a link in the href of the a element, or doing a POST request
2774  // with page reload when a `<form>` is submitted).
2775  // Use it inside listener functions.
2776  function preventDefault(e) {
2777  	if (e.preventDefault) {
2778  		e.preventDefault();
2779  	} else {
2780  		e.returnValue = false;
2781  	}
2782  	return this;
2783  }
2784
2785  // @function stop(ev: DOMEvent): this
2786  // Does `stopPropagation` and `preventDefault` at the same time.
2787  function stop(e) {
2788  	preventDefault(e);
2789  	stopPropagation(e);
2790  	return this;
2791  }
2792
2793  // @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point
2794  // Gets normalized mouse position from a DOM event relative to the
2795  // `container` (border excluded) or to the whole page if not specified.
2796  function getMousePosition(e, container) {
2797  	if (!container) {
2798  		return new Point(e.clientX, e.clientY);
2799  	}
2800
2801  	var scale = getScale(container),
2802  	    offset = scale.boundingClientRect; // left and top  values are in page scale (like the event clientX/Y)
2803
2804  	return new Point(
2805  		// offset.left/top values are in page scale (like clientX/Y),
2806  		// whereas clientLeft/Top (border width) values are the original values (before CSS scale applies).
2807  		(e.clientX - offset.left) / scale.x - container.clientLeft,
2808  		(e.clientY - offset.top) / scale.y - container.clientTop
2809  	);
2810  }
2811
2812  // Chrome on Win scrolls double the pixels as in other platforms (see #4538),
2813  // and Firefox scrolls device pixels, not CSS pixels
2814  var wheelPxFactor =
2815  	(win && chrome) ? 2 * window.devicePixelRatio :
2816  	gecko ? window.devicePixelRatio : 1;
2817
2818  // @function getWheelDelta(ev: DOMEvent): Number
2819  // Gets normalized wheel delta from a wheel DOM event, in vertical
2820  // pixels scrolled (negative if scrolling down).
2821  // Events from pointing devices without precise scrolling are mapped to
2822  // a best guess of 60 pixels.
2823  function getWheelDelta(e) {
2824  	return (edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta
2825  	       (e.deltaY && e.deltaMode === 0) ? -e.deltaY / wheelPxFactor : // Pixels
2826  	       (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines
2827  	       (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages
2828  	       (e.deltaX || e.deltaZ) ? 0 :	// Skip horizontal/depth wheel events
vendor: 18,424 bytes, lines 2829-3382
2829  	       e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels
2830  	       (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines
2831  	       e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages
2832  	       0;
2833  }
2834
2835  var skipEvents = {};
2836
2837  function fakeStop(e) {
2838  	// fakes stopPropagation by setting a special event flag, checked/reset with skipped(e)
2839  	skipEvents[e.type] = true;
2840  }
2841
2842  function skipped(e) {
2843  	var events = skipEvents[e.type];
2844  	// reset when checking, as it's only used in map container and propagates outside of the map
2845  	skipEvents[e.type] = false;
2846  	return events;
2847  }
2848
2849  // check if element really left/entered the event target (for mouseenter/mouseleave)
2850  function isExternalTarget(el, e) {
2851
2852  	var related = e.relatedTarget;
2853
2854  	if (!related) { return true; }
2855
2856  	try {
2857  		while (related && (related !== el)) {
2858  			related = related.parentNode;
2859  		}
2860  	} catch (err) {
2861  		return false;
2862  	}
2863  	return (related !== el);
2864  }
2865
2866  var DomEvent = {
2867    __proto__: null,
2868    on: on,
2869    off: off,
2870    stopPropagation: stopPropagation,
2871    disableScrollPropagation: disableScrollPropagation,
2872    disableClickPropagation: disableClickPropagation,
2873    preventDefault: preventDefault,
2874    stop: stop,
2875    getMousePosition: getMousePosition,
2876    getWheelDelta: getWheelDelta,
2877    fakeStop: fakeStop,
2878    skipped: skipped,
2879    isExternalTarget: isExternalTarget,
2880    addListener: on,
2881    removeListener: off
2882  };
2883
2884  /*
2885   * @class PosAnimation
2886   * @aka L.PosAnimation
2887   * @inherits Evented
2888   * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9.
2889   *
2890   * @example
2891   * ```js
2892   * var fx = new L.PosAnimation();
2893   * fx.run(el, [300, 500], 0.5);
2894   * ```
2895   *
2896   * @constructor L.PosAnimation()
2897   * Creates a `PosAnimation` object.
2898   *
2899   */
2900
2901  var PosAnimation = Evented.extend({
2902
2903  	// @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)
2904  	// Run an animation of a given element to a new position, optionally setting
2905  	// duration in seconds (`0.25` by default) and easing linearity factor (3rd
2906  	// argument of the [cubic bezier curve](http://cubic-bezier.com/#0,0,.5,1),
2907  	// `0.5` by default).
2908  	run: function (el, newPos, duration, easeLinearity) {
2909  		this.stop();
2910
2911  		this._el = el;
2912  		this._inProgress = true;
2913  		this._duration = duration || 0.25;
2914  		this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);
2915
2916  		this._startPos = getPosition(el);
2917  		this._offset = newPos.subtract(this._startPos);
2918  		this._startTime = +new Date();
2919
2920  		// @event start: Event
2921  		// Fired when the animation starts
2922  		this.fire('start');
2923
2924  		this._animate();
2925  	},
2926
2927  	// @method stop()
2928  	// Stops the animation (if currently running).
2929  	stop: function () {
2930  		if (!this._inProgress) { return; }
2931
2932  		this._step(true);
2933  		this._complete();
2934  	},
2935
2936  	_animate: function () {
2937  		// animation loop
2938  		this._animId = requestAnimFrame(this._animate, this);
2939  		this._step();
2940  	},
2941
2942  	_step: function (round) {
2943  		var elapsed = (+new Date()) - this._startTime,
2944  		    duration = this._duration * 1000;
2945
2946  		if (elapsed < duration) {
2947  			this._runFrame(this._easeOut(elapsed / duration), round);
2948  		} else {
2949  			this._runFrame(1);
2950  			this._complete();
2951  		}
2952  	},
2953
2954  	_runFrame: function (progress, round) {
2955  		var pos = this._startPos.add(this._offset.multiplyBy(progress));
2956  		if (round) {
2957  			pos._round();
2958  		}
2959  		setPosition(this._el, pos);
2960
2961  		// @event step: Event
2962  		// Fired continuously during the animation.
2963  		this.fire('step');
2964  	},
2965
2966  	_complete: function () {
2967  		cancelAnimFrame(this._animId);
2968
2969  		this._inProgress = false;
2970  		// @event end: Event
2971  		// Fired when the animation ends.
2972  		this.fire('end');
2973  	},
2974
2975  	_easeOut: function (t) {
2976  		return 1 - Math.pow(1 - t, this._easeOutPower);
2977  	}
2978  });
2979
2980  /*
2981   * @class Map
2982   * @aka L.Map
2983   * @inherits Evented
2984   *
2985   * The central class of the API — it is used to create a map on a page and manipulate it.
2986   *
2987   * @example
2988   *
2989   * ```js
2990   * // initialize the map on the "map" div with a given center and zoom
2991   * var map = L.map('map', {
2992   * 	center: [51.505, -0.09],
2993   * 	zoom: 13
2994   * });
2995   * ```
2996   *
2997   */
2998
2999  var Map = Evented.extend({
3000
3001  	options: {
3002  		// @section Map State Options
3003  		// @option crs: CRS = L.CRS.EPSG3857
3004  		// The [Coordinate Reference System](#crs) to use. Don't change this if you're not
3005  		// sure what it means.
3006  		crs: EPSG3857,
3007
3008  		// @option center: LatLng = undefined
3009  		// Initial geographic center of the map
3010  		center: undefined,
3011
3012  		// @option zoom: Number = undefined
3013  		// Initial map zoom level
3014  		zoom: undefined,
3015
3016  		// @option minZoom: Number = *
3017  		// Minimum zoom level of the map.
3018  		// If not specified and at least one `GridLayer` or `TileLayer` is in the map,
3019  		// the lowest of their `minZoom` options will be used instead.
3020  		minZoom: undefined,
3021
3022  		// @option maxZoom: Number = *
3023  		// Maximum zoom level of the map.
3024  		// If not specified and at least one `GridLayer` or `TileLayer` is in the map,
3025  		// the highest of their `maxZoom` options will be used instead.
3026  		maxZoom: undefined,
3027
3028  		// @option layers: Layer[] = []
3029  		// Array of layers that will be added to the map initially
3030  		layers: [],
3031
3032  		// @option maxBounds: LatLngBounds = null
3033  		// When this option is set, the map restricts the view to the given
3034  		// geographical bounds, bouncing the user back if the user tries to pan
3035  		// outside the view. To set the restriction dynamically, use
3036  		// [`setMaxBounds`](#map-setmaxbounds) method.
3037  		maxBounds: undefined,
3038
3039  		// @option renderer: Renderer = *
3040  		// The default method for drawing vector layers on the map. `L.SVG`
3041  		// or `L.Canvas` by default depending on browser support.
3042  		renderer: undefined,
3043
3044
3045  		// @section Animation Options
3046  		// @option zoomAnimation: Boolean = true
3047  		// Whether the map zoom animation is enabled. By default it's enabled
3048  		// in all browsers that support CSS3 Transitions except Android.
3049  		zoomAnimation: true,
3050
3051  		// @option zoomAnimationThreshold: Number = 4
3052  		// Won't animate zoom if the zoom difference exceeds this value.
3053  		zoomAnimationThreshold: 4,
3054
3055  		// @option fadeAnimation: Boolean = true
3056  		// Whether the tile fade animation is enabled. By default it's enabled
3057  		// in all browsers that support CSS3 Transitions except Android.
3058  		fadeAnimation: true,
3059
3060  		// @option markerZoomAnimation: Boolean = true
3061  		// Whether markers animate their zoom with the zoom animation, if disabled
3062  		// they will disappear for the length of the animation. By default it's
3063  		// enabled in all browsers that support CSS3 Transitions except Android.
3064  		markerZoomAnimation: true,
3065
3066  		// @option transform3DLimit: Number = 2^23
3067  		// Defines the maximum size of a CSS translation transform. The default
3068  		// value should not be changed unless a web browser positions layers in
3069  		// the wrong place after doing a large `panBy`.
3070  		transform3DLimit: 8388608, // Precision limit of a 32-bit float
3071
3072  		// @section Interaction Options
3073  		// @option zoomSnap: Number = 1
3074  		// Forces the map's zoom level to always be a multiple of this, particularly
3075  		// right after a [`fitBounds()`](#map-fitbounds) or a pinch-zoom.
3076  		// By default, the zoom level snaps to the nearest integer; lower values
3077  		// (e.g. `0.5` or `0.1`) allow for greater granularity. A value of `0`
3078  		// means the zoom level will not be snapped after `fitBounds` or a pinch-zoom.
3079  		zoomSnap: 1,
3080
3081  		// @option zoomDelta: Number = 1
3082  		// Controls how much the map's zoom level will change after a
3083  		// [`zoomIn()`](#map-zoomin), [`zoomOut()`](#map-zoomout), pressing `+`
3084  		// or `-` on the keyboard, or using the [zoom controls](#control-zoom).
3085  		// Values smaller than `1` (e.g. `0.5`) allow for greater granularity.
3086  		zoomDelta: 1,
3087
3088  		// @option trackResize: Boolean = true
3089  		// Whether the map automatically handles browser window resize to update itself.
3090  		trackResize: true
3091  	},
3092
3093  	initialize: function (id, options) { // (HTMLElement or String, Object)
3094  		options = setOptions(this, options);
3095
3096  		// Make sure to assign internal flags at the beginning,
3097  		// to avoid inconsistent state in some edge cases.
3098  		this._handlers = [];
3099  		this._layers = {};
3100  		this._zoomBoundLayers = {};
3101  		this._sizeChanged = true;
3102
3103  		this._initContainer(id);
3104  		this._initLayout();
3105
3106  		// hack for https://github.com/Leaflet/Leaflet/issues/1980
3107  		this._onResize = bind(this._onResize, this);
3108
3109  		this._initEvents();
3110
3111  		if (options.maxBounds) {
3112  			this.setMaxBounds(options.maxBounds);
3113  		}
3114
3115  		if (options.zoom !== undefined) {
3116  			this._zoom = this._limitZoom(options.zoom);
3117  		}
3118
3119  		if (options.center && options.zoom !== undefined) {
3120  			this.setView(toLatLng(options.center), options.zoom, {reset: true});
3121  		}
3122
3123  		this.callInitHooks();
3124
3125  		// don't animate on browsers without hardware-accelerated transitions or old Android/Opera
3126  		this._zoomAnimated = TRANSITION && any3d && !mobileOpera &&
3127  				this.options.zoomAnimation;
3128
3129  		// zoom transitions run with the same duration for all layers, so if one of transitionend events
3130  		// happens after starting zoom animation (propagating to the map pane), we know that it ended globally
3131  		if (this._zoomAnimated) {
3132  			this._createAnimProxy();
3133  			on(this._proxy, TRANSITION_END, this._catchTransitionEnd, this);
3134  		}
3135
3136  		this._addLayers(this.options.layers);
3137  	},
3138
3139
3140  	// @section Methods for modifying map state
3141
3142  	// @method setView(center: LatLng, zoom: Number, options?: Zoom/pan options): this
3143  	// Sets the view of the map (geographical center and zoom) with the given
3144  	// animation options.
3145  	setView: function (center, zoom, options) {
3146
3147  		zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
3148  		center = this._limitCenter(toLatLng(center), zoom, this.options.maxBounds);
3149  		options = options || {};
3150
3151  		this._stop();
3152
3153  		if (this._loaded && !options.reset && options !== true) {
3154
3155  			if (options.animate !== undefined) {
3156  				options.zoom = extend({animate: options.animate}, options.zoom);
3157  				options.pan = extend({animate: options.animate, duration: options.duration}, options.pan);
3158  			}
3159
3160  			// try animating pan or zoom
3161  			var moved = (this._zoom !== zoom) ?
3162  				this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :
3163  				this._tryAnimatedPan(center, options.pan);
3164
3165  			if (moved) {
3166  				// prevent resize handler call, the view will refresh after animation anyway
3167  				clearTimeout(this._sizeTimer);
3168  				return this;
3169  			}
3170  		}
3171
3172  		// animation didn't start, just reset the map view
3173  		this._resetView(center, zoom);
3174
3175  		return this;
3176  	},
3177
3178  	// @method setZoom(zoom: Number, options?: Zoom/pan options): this
3179  	// Sets the zoom of the map.
3180  	setZoom: function (zoom, options) {
3181  		if (!this._loaded) {
3182  			this._zoom = zoom;
3183  			return this;
3184  		}
3185  		return this.setView(this.getCenter(), zoom, {zoom: options});
3186  	},
3187
3188  	// @method zoomIn(delta?: Number, options?: Zoom options): this
3189  	// Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
3190  	zoomIn: function (delta, options) {
3191  		delta = delta || (any3d ? this.options.zoomDelta : 1);
3192  		return this.setZoom(this._zoom + delta, options);
3193  	},
3194
3195  	// @method zoomOut(delta?: Number, options?: Zoom options): this
3196  	// Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
3197  	zoomOut: function (delta, options) {
3198  		delta = delta || (any3d ? this.options.zoomDelta : 1);
3199  		return this.setZoom(this._zoom - delta, options);
3200  	},
3201
3202  	// @method setZoomAround(latlng: LatLng, zoom: Number, options: Zoom options): this
3203  	// Zooms the map while keeping a specified geographical point on the map
3204  	// stationary (e.g. used internally for scroll zoom and double-click zoom).
3205  	// @alternative
3206  	// @method setZoomAround(offset: Point, zoom: Number, options: Zoom options): this
3207  	// Zooms the map while keeping a specified pixel on the map (relative to the top-left corner) stationary.
3208  	setZoomAround: function (latlng, zoom, options) {
3209  		var scale = this.getZoomScale(zoom),
3210  		    viewHalf = this.getSize().divideBy(2),
3211  		    containerPoint = latlng instanceof Point ? latlng : this.latLngToContainerPoint(latlng),
3212
3213  		    centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),
3214  		    newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));
3215
3216  		return this.setView(newCenter, zoom, {zoom: options});
3217  	},
3218
3219  	_getBoundsCenterZoom: function (bounds, options) {
3220
3221  		options = options || {};
3222  		bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);
3223
3224  		var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
3225  		    paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
3226
3227  		    zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
3228
3229  		zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
3230
3231  		if (zoom === Infinity) {
3232  			return {
3233  				center: bounds.getCenter(),
3234  				zoom: zoom
3235  			};
3236  		}
3237
3238  		var paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),
3239
3240  		    swPoint = this.project(bounds.getSouthWest(), zoom),
3241  		    nePoint = this.project(bounds.getNorthEast(), zoom),
3242  		    center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);
3243
3244  		return {
3245  			center: center,
3246  			zoom: zoom
3247  		};
3248  	},
3249
3250  	// @method fitBounds(bounds: LatLngBounds, options?: fitBounds options): this
3251  	// Sets a map view that contains the given geographical bounds with the
3252  	// maximum zoom level possible.
3253  	fitBounds: function (bounds, options) {
3254
3255  		bounds = toLatLngBounds(bounds);
3256
3257  		if (!bounds.isValid()) {
3258  			throw new Error('Bounds are not valid.');
3259  		}
3260
3261  		var target = this._getBoundsCenterZoom(bounds, options);
3262  		return this.setView(target.center, target.zoom, options);
3263  	},
3264
3265  	// @method fitWorld(options?: fitBounds options): this
3266  	// Sets a map view that mostly contains the whole world with the maximum
3267  	// zoom level possible.
3268  	fitWorld: function (options) {
3269  		return this.fitBounds([[-90, -180], [90, 180]], options);
3270  	},
3271
3272  	// @method panTo(latlng: LatLng, options?: Pan options): this
3273  	// Pans the map to a given center.
3274  	panTo: function (center, options) { // (LatLng)
3275  		return this.setView(center, this._zoom, {pan: options});
3276  	},
3277
3278  	// @method panBy(offset: Point, options?: Pan options): this
3279  	// Pans the map by a given number of pixels (animated).
3280  	panBy: function (offset, options) {
3281  		offset = toPoint(offset).round();
3282  		options = options || {};
3283
3284  		if (!offset.x && !offset.y) {
3285  			return this.fire('moveend');
3286  		}
3287  		// If we pan too far, Chrome gets issues with tiles
3288  		// and makes them disappear or appear in the wrong place (slightly offset) #2602
3289  		if (options.animate !== true && !this.getSize().contains(offset)) {
3290  			this._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom());
3291  			return this;
3292  		}
3293
3294  		if (!this._panAnim) {
3295  			this._panAnim = new PosAnimation();
3296
3297  			this._panAnim.on({
3298  				'step': this._onPanTransitionStep,
3299  				'end': this._onPanTransitionEnd
3300  			}, this);
3301  		}
3302
3303  		// don't fire movestart if animating inertia
3304  		if (!options.noMoveStart) {
3305  			this.fire('movestart');
3306  		}
3307
3308  		// animate pan unless animate: false specified
3309  		if (options.animate !== false) {
3310  			addClass(this._mapPane, 'leaflet-pan-anim');
3311
3312  			var newPos = this._getMapPanePos().subtract(offset).round();
3313  			this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);
3314  		} else {
3315  			this._rawPanBy(offset);
3316  			this.fire('move').fire('moveend');
3317  		}
3318
3319  		return this;
3320  	},
3321
3322  	// @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this
3323  	// Sets the view of the map (geographical center and zoom) performing a smooth
3324  	// pan-zoom animation.
3325  	flyTo: function (targetCenter, targetZoom, options) {
3326
3327  		options = options || {};
3328  		if (options.animate === false || !any3d) {
3329  			return this.setView(targetCenter, targetZoom, options);
3330  		}
3331
3332  		this._stop();
3333
3334  		var from = this.project(this.getCenter()),
3335  		    to = this.project(targetCenter),
3336  		    size = this.getSize(),
3337  		    startZoom = this._zoom;
3338
3339  		targetCenter = toLatLng(targetCenter);
3340  		targetZoom = targetZoom === undefined ? startZoom : targetZoom;
3341
3342  		var w0 = Math.max(size.x, size.y),
3343  		    w1 = w0 * this.getZoomScale(startZoom, targetZoom),
3344  		    u1 = (to.distanceTo(from)) || 1,
3345  		    rho = 1.42,
3346  		    rho2 = rho * rho;
3347
3348  		function r(i) {
3349  			var s1 = i ? -1 : 1,
3350  			    s2 = i ? w1 : w0,
3351  			    t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1,
3352  			    b1 = 2 * s2 * rho2 * u1,
3353  			    b = t1 / b1,
3354  			    sq = Math.sqrt(b * b + 1) - b;
3355
3356  			    // workaround for floating point precision bug when sq = 0, log = -Infinite,
3357  			    // thus triggering an infinite loop in flyTo
3358  			    var log = sq < 0.000000001 ? -18 : Math.log(sq);
3359
3360  			return log;
3361  		}
3362
3363  		function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }
3364  		function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }
3365  		function tanh(n) { return sinh(n) / cosh(n); }
3366
3367  		var r0 = r(0);
3368
3369  		function w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); }
3370  		function u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; }
3371
3372  		function easeOut(t) { return 1 - Math.pow(1 - t, 1.5); }
3373
3374  		var start = Date.now(),
3375  		    S = (r(1) - r0) / rho,
3376  		    duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8;
3377
3378  		function frame() {
3379  			var t = (Date.now() - start) / duration,
3380  			    s = easeOut(t) * S;
3381
3382  			if (t <= 1) {
3383  				this._flyToFrame = requestAnimFrame(frame, this);
3384
3385  				this._move(
3386  					this.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),
3387  					this.getScaleZoom(w0 / w(s), startZoom),
3388  					{flyTo: true});
3389
3390  			} else {
3391  				this
3392  					._move(targetCenter, targetZoom)
3393  					._moveEnd(true);
3394  			}
3395  		}
3396
3397  		this._moveStart(true, options.noMoveStart);
3398
3399  		frame.call(this);
3400  		return this;
3401  	},
3402
3403  	// @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
3404  	// Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
3405  	// but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
3406  	flyToBounds: function (bounds, options) {
3407  		var target = this._getBoundsCenterZoom(bounds, options);
3408  		return this.flyTo(target.center, target.zoom, options);
3409  	},
3410
3411  	// @method setMaxBounds(bounds: LatLngBounds): this
3412  	// Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option).
3413  	setMaxBounds: function (bounds) {
3414  		bounds = toLatLngBounds(bounds);
3415
3416  		if (!bounds.isValid()) {
3417  			this.options.maxBounds = null;
3418  			return this.off('moveend', this._panInsideMaxBounds);
3419  		} else if (this.options.maxBounds) {
3420  			this.off('moveend', this._panInsideMaxBounds);
3421  		}
3422
3423  		this.options.maxBounds = bounds;
3424
3425  		if (this._loaded) {
3426  			this._panInsideMaxBounds();
3427  		}
3428
3429  		return this.on('moveend', this._panInsideMaxBounds);
3430  	},
3431
3432  	// @method setMinZoom(zoom: Number): this
3433  	// Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option).
3434  	setMinZoom: function (zoom) {
3435  		var oldZoom = this.options.minZoom;
3436  		this.options.minZoom = zoom;
3437
3438  		if (this._loaded && oldZoom !== zoom) {
3439  			this.fire('zoomlevelschange');
3440
3441  			if (this.getZoom() < this.options.minZoom) {
3442  				return this.setZoom(zoom);
3443  			}
3444  		}
3445
3446  		return this;
3447  	},
3448
3449  	// @method setMaxZoom(zoom: Number): this
3450  	// Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option).
3451  	setMaxZoom: function (zoom) {
3452  		var oldZoom = this.options.maxZoom;
3453  		this.options.maxZoom = zoom;
3454
3455  		if (this._loaded && oldZoom !== zoom) {
3456  			this.fire('zoomlevelschange');
3457
3458  			if (this.getZoom() > this.options.maxZoom) {
3459  				return this.setZoom(zoom);
3460  			}
3461  		}
3462
3463  		return this;
3464  	},
3465
3466  	// @method panInsideBounds(bounds: LatLngBounds, options?: Pan options): this
3467  	// 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.
3468  	panInsideBounds: function (bounds, options) {
3469  		this._enforcingBounds = true;
3470  		var center = this.getCenter(),
3471  		    newCenter = this._limitCenter(center, this._zoom, toLatLngBounds(bounds));
3472
3473  		if (!center.equals(newCenter)) {
3474  			this.panTo(newCenter, options);
3475  		}
3476
3477  		this._enforcingBounds = false;
3478  		return this;
3479  	},
3480
3481  	// @method panInside(latlng: LatLng, options?: options): this
3482  	// Pans the map the minimum amount to make the `latlng` visible. Use
3483  	// `padding`, `paddingTopLeft` and `paddingTopRight` options to fit
3484  	// the display to more restricted bounds, like [`fitBounds`](#map-fitbounds).
3485  	// If `latlng` is already within the (optionally padded) display bounds,
3486  	// the map will not be panned.
3487  	panInside: function (latlng, options) {
3488  		options = options || {};
3489
3490  		var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
3491  		    paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
3492  		    center = this.getCenter(),
3493  		    pixelCenter = this.project(center),
3494  		    pixelPoint = this.project(latlng),
3495  		    pixelBounds = this.getPixelBounds(),
3496  		    halfPixelBounds = pixelBounds.getSize().divideBy(2),
3497  		    paddedBounds = toBounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]);
3498
3499  		if (!paddedBounds.contains(pixelPoint)) {
3500  			this._enforcingBounds = true;
3501  			var diff = pixelCenter.subtract(pixelPoint),
3502  			    newCenter = toPoint(pixelPoint.x + diff.x, pixelPoint.y + diff.y);
3503
3504  			if (pixelPoint.x < paddedBounds.min.x || pixelPoint.x > paddedBounds.max.x) {
3505  				newCenter.x = pixelCenter.x - diff.x;
3506  				if (diff.x > 0) {
3507  					newCenter.x += halfPixelBounds.x - paddingTL.x;
3508  				} else {
3509  					newCenter.x -= halfPixelBounds.x - paddingBR.x;
3510  				}
3511  			}
3512  			if (pixelPoint.y < paddedBounds.min.y || pixelPoint.y > paddedBounds.max.y) {
3513  				newCenter.y = pixelCenter.y - diff.y;
3514  				if (diff.y > 0) {
3515  					newCenter.y += halfPixelBounds.y - paddingTL.y;
3516  				} else {
3517  					newCenter.y -= halfPixelBounds.y - paddingBR.y;
3518  				}
3519  			}
3520  			this.panTo(this.unproject(new
vendor: 4,387 bytes, lines 3520-3651
3520Center), options);
3521  			this._enforcingBounds = false;
3522  		}
3523  		return this;
3524  	},
3525
3526  	// @method invalidateSize(options: Zoom/pan options): this
3527  	// Checks if the map container size changed and updates the map if so —
3528  	// call it after you've changed the map size dynamically, also animating
3529  	// pan by default. If `options.pan` is `false`, panning will not occur.
3530  	// If `options.debounceMoveend` is `true`, it will delay `moveend` event so
3531  	// that it doesn't happen often even if the method is called many
3532  	// times in a row.
3533
3534  	// @alternative
3535  	// @method invalidateSize(animate: Boolean): this
3536  	// Checks if the map container size changed and updates the map if so —
3537  	// call it after you've changed the map size dynamically, also animating
3538  	// pan by default.
3539  	invalidateSize: function (options) {
3540  		if (!this._loaded) { return this; }
3541
3542  		options = extend({
3543  			animate: false,
3544  			pan: true
3545  		}, options === true ? {animate: true} : options);
3546
3547  		var oldSize = this.getSize();
3548  		this._sizeChanged = true;
3549  		this._lastCenter = null;
3550
3551  		var newSize = this.getSize(),
3552  		    oldCenter = oldSize.divideBy(2).round(),
3553  		    newCenter = newSize.divideBy(2).round(),
3554  		    offset = oldCenter.subtract(newCenter);
3555
3556  		if (!offset.x && !offset.y) { return this; }
3557
3558  		if (options.animate && options.pan) {
3559  			this.panBy(offset);
3560
3561  		} else {
3562  			if (options.pan) {
3563  				this._rawPanBy(offset);
3564  			}
3565
3566  			this.fire('move');
3567
3568  			if (options.debounceMoveend) {
3569  				clearTimeout(this._sizeTimer);
3570  				this._sizeTimer = setTimeout(bind(this.fire, this, 'moveend'), 200);
3571  			} else {
3572  				this.fire('moveend');
3573  			}
3574  		}
3575
3576  		// @section Map state change events
3577  		// @event resize: ResizeEvent
3578  		// Fired when the map is resized.
3579  		return this.fire('resize', {
3580  			oldSize: oldSize,
3581  			newSize: newSize
3582  		});
3583  	},
3584
3585  	// @section Methods for modifying map state
3586  	// @method stop(): this
3587  	// Stops the currently running `panTo` or `flyTo` animation, if any.
3588  	stop: function () {
3589  		this.setZoom(this._limitZoom(this._zoom));
3590  		if (!this.options.zoomSnap) {
3591  			this.fire('viewreset');
3592  		}
3593  		return this._stop();
3594  	},
3595
3596  	// @section Geolocation methods
3597  	// @method locate(options?: Locate options): this
3598  	// Tries to locate the user using the Geolocation API, firing a [`locationfound`](#map-locationfound)
3599  	// event with location data on success or a [`locationerror`](#map-locationerror) event on failure,
3600  	// and optionally sets the map view to the user's location with respect to
3601  	// detection accuracy (or to the world view if geolocation failed).
3602  	// Note that, if your page doesn't use HTTPS, this method will fail in
3603  	// modern browsers ([Chrome 50 and newer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins))
3604  	// See `Locate options` for more details.
3605  	locate: function (options) {
3606
3607  		options = this._locateOptions = extend({
3608  			timeout: 10000,
3609  			watch: false
3610  			// setView: false
3611  			// maxZoom: <Number>
3612  			// maximumAge: 0
3613  			// enableHighAccuracy: false
3614  		}, options);
3615
3616  		if (!('geolocation' in navigator)) {
3617  			this._handleGeolocationError({
3618  				code: 0,
3619  				message: 'Geolocation not supported.'
3620  			});
3621  			return this;
3622  		}
3623
3624  		var onResponse = bind(this._handleGeolocationResponse, this),
3625  		    onError = bind(this._handleGeolocationError, this);
3626
3627  		if (options.watch) {
3628  			this._locationWatchId =
3629  			        navigator.geolocation.watchPosition(onResponse, onError, options);
3630  		} else {
3631  			navigator.geolocation.getCurrentPosition(onResponse, onError, options);
3632  		}
3633  		return this;
3634  	},
3635
3636  	// @method stopLocate(): this
3637  	// Stops watching location previously initiated by `map.locate({watch: true})`
3638  	// and aborts resetting the map view if map.locate was called with
3639  	// `{setView: true}`.
3640  	stopLocate: function () {
3641  		if (navigator.geolocation && navigator.geolocation.clearWatch) {
3642  			navigator.geolocation.clearWatch(this._locationWatchId);
3643  		}
3644  		if (this._locateOptions) {
3645  			this._locateOptions.setView = false;
3646  		}
3647  		return this;
3648  	},
3649
3650  	_handleGeolocationError: function (error) {
3651  		
vendor: 6,375 bytes, lines 3651-3854
3651var c = error.code,
3652  		    message = error.message ||
3653  		            (c === 1 ? 'permission denied' :
3654  		            (c === 2 ? 'position unavailable' : 'timeout'));
3655
3656  		if (this._locateOptions.setView && !this._loaded) {
3657  			this.fitWorld();
3658  		}
3659
3660  		// @section Location events
3661  		// @event locationerror: ErrorEvent
3662  		// Fired when geolocation (using the [`locate`](#map-locate) method) failed.
3663  		this.fire('locationerror', {
3664  			code: c,
3665  			message: 'Geolocation error: ' + message + '.'
3666  		});
3667  	},
3668
3669  	_handleGeolocationResponse: function (pos) {
3670  		var lat = pos.coords.latitude,
3671  		    lng = pos.coords.longitude,
3672  		    latlng = new LatLng(lat, lng),
3673  		    bounds = latlng.toBounds(pos.coords.accuracy * 2),
3674  		    options = this._locateOptions;
3675
3676  		if (options.setView) {
3677  			var zoom = this.getBoundsZoom(bounds);
3678  			this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);
3679  		}
3680
3681  		var data = {
3682  			latlng: latlng,
3683  			bounds: bounds,
3684  			timestamp: pos.timestamp
3685  		};
3686
3687  		for (var i in pos.coords) {
3688  			if (typeof pos.coords[i] === 'number') {
3689  				data[i] = pos.coords[i];
3690  			}
3691  		}
3692
3693  		// @event locationfound: LocationEvent
3694  		// Fired when geolocation (using the [`locate`](#map-locate) method)
3695  		// went successfully.
3696  		this.fire('locationfound', data);
3697  	},
3698
3699  	// TODO Appropriate docs section?
3700  	// @section Other Methods
3701  	// @method addHandler(name: String, HandlerClass: Function): this
3702  	// Adds a new `Handler` to the map, given its name and constructor function.
3703  	addHandler: function (name, HandlerClass) {
3704  		if (!HandlerClass) { return this; }
3705
3706  		var handler = this[name] = new HandlerClass(this);
3707
3708  		this._handlers.push(handler);
3709
3710  		if (this.options[name]) {
3711  			handler.enable();
3712  		}
3713
3714  		return this;
3715  	},
3716
3717  	// @method remove(): this
3718  	// Destroys the map and clears all related event listeners.
3719  	remove: function () {
3720
3721  		this._initEvents(true);
3722  		this.off('moveend', this._panInsideMaxBounds);
3723
3724  		if (this._containerId !== this._container._leaflet_id) {
3725  			throw new Error('Map container is being reused by another instance');
3726  		}
3727
3728  		try {
3729  			// throws error in IE6-8
3730  			delete this._container._leaflet_id;
3731  			delete this._containerId;
3732  		} catch (e) {
3733  			/*eslint-disable */
3734  			this._container._leaflet_id = undefined;
3735  			/* eslint-enable */
3736  			this._containerId = undefined;
3737  		}
3738
3739  		if (this._locationWatchId !== undefined) {
3740  			this.stopLocate();
3741  		}
3742
3743  		this._stop();
3744
3745  		remove(this._mapPane);
3746
3747  		if (this._clearControlPos) {
3748  			this._clearControlPos();
3749  		}
3750  		if (this._resizeRequest) {
3751  			cancelAnimFrame(this._resizeRequest);
3752  			this._resizeRequest = null;
3753  		}
3754
3755  		this._clearHandlers();
3756
3757  		if (this._loaded) {
3758  			// @section Map state change events
3759  			// @event unload: Event
3760  			// Fired when the map is destroyed with [remove](#map-remove) method.
3761  			this.fire('unload');
3762  		}
3763
3764  		var i;
3765  		for (i in this._layers) {
3766  			this._layers[i].remove();
3767  		}
3768  		for (i in this._panes) {
3769  			remove(this._panes[i]);
3770  		}
3771
3772  		this._layers = [];
3773  		this._panes = [];
3774  		delete this._mapPane;
3775  		delete this._renderer;
3776
3777  		return this;
3778  	},
3779
3780  	// @section Other Methods
3781  	// @method createPane(name: String, container?: HTMLElement): HTMLElement
3782  	// Creates a new [map pane](#map-pane) with the given name if it doesn't exist already,
3783  	// then returns it. The pane is created as a child of `container`, or
3784  	// as a child of the main map pane if not set.
3785  	createPane: function (name, container) {
3786  		var className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''),
3787  		    pane = create$1('div', className, container || this._mapPane);
3788
3789  		if (name) {
3790  			this._panes[name] = pane;
3791  		}
3792  		return pane;
3793  	},
3794
3795  	// @section Methods for Getting Map State
3796
3797  	// @method getCenter(): LatLng
3798  	// Returns the geographical center of the map view
3799  	getCenter: function () {
3800  		this._checkIfLoaded();
3801
3802  		if (this._lastCenter && !this._moved()) {
3803  			return this._lastCenter;
3804  		}
3805  		return this.layerPointToLatLng(this._getCenterLayerPoint());
3806  	},
3807
3808  	// @method getZoom(): Number
3809  	// Returns the current zoom level of the map view
3810  	getZoom: function () {
3811  		return this._zoom;
3812  	},
3813
3814  	// @method getBounds(): LatLngBounds
3815  	// Returns the geographical bounds visible in the current map view
3816  	getBounds: function () {
3817  		var bounds = this.getPixelBounds(),
3818  		    sw = this.unproject(bounds.getBottomLeft()),
3819  		    ne = this.unproject(bounds.getTopRight());
3820
3821  		return new LatLngBounds(sw, ne);
3822  	},
3823
3824  	// @method getMinZoom(): Number
3825  	// 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.
3826  	getMinZoom: function () {
3827  		return this.options.minZoom === undefined ? this._layersMinZoom || 0 : this.options.minZoom;
3828  	},
3829
3830  	// @method getMaxZoom(): Number
3831  	// Returns the maximum zoom level of the map (if set in the `maxZoom` option of the map or of any layers).
3832  	getMaxZoom: function () {
3833  		return this.options.maxZoom === undefined ?
3834  			(this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :
3835  			this.options.maxZoom;
3836  	},
3837
3838  	// @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean, padding?: Point): Number
3839  	// Returns the maximum zoom level on which the given bounds fit to the map
3840  	// view in its entirety. If `inside` (optional) is set to `true`, the method
3841  	// instead returns the minimum zoom level on which the map view fits into
3842  	// the given bounds in its entirety.
3843  	getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
3844  		bounds = toLatLngBounds(bounds);
3845  		padding = toPoint(padding || [0, 0]);
3846
3847  		var zoom = this.getZoom() || 0,
3848  		    min = this.getMinZoom(),
3849  		    max = this.getMaxZoom(),
3850  		    nw = bounds.getNorthWest(),
3851  		    se = bounds.getSouthEast(),
3852  		    size = this.getSize().subtract(padding),
3853  		    boundsSize = toBounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),
3854  		    snap = 
vendor: 9,586 bytes, lines 3854-4082
3854any3d ? this.options.zoomSnap : 1,
3855  		    scalex = size.x / boundsSize.x,
3856  		    scaley = size.y / boundsSize.y,
3857  		    scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);
3858
3859  		zoom = this.getScaleZoom(scale, zoom);
3860
3861  		if (snap) {
3862  			zoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level
3863  			zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;
3864  		}
3865
3866  		return Math.max(min, Math.min(max, zoom));
3867  	},
3868
3869  	// @method getSize(): Point
3870  	// Returns the current size of the map container (in pixels).
3871  	getSize: function () {
3872  		if (!this._size || this._sizeChanged) {
3873  			this._size = new Point(
3874  				this._container.clientWidth || 0,
3875  				this._container.clientHeight || 0);
3876
3877  			this._sizeChanged = false;
3878  		}
3879  		return this._size.clone();
3880  	},
3881
3882  	// @method getPixelBounds(): Bounds
3883  	// Returns the bounds of the current map view in projected pixel
3884  	// coordinates (sometimes useful in layer and overlay implementations).
3885  	getPixelBounds: function (center, zoom) {
3886  		var topLeftPoint = this._getTopLeftPoint(center, zoom);
3887  		return new Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
3888  	},
3889
3890  	// TODO: Check semantics - isn't the pixel origin the 0,0 coord relative to
3891  	// the map pane? "left point of the map layer" can be confusing, specially
3892  	// since there can be negative offsets.
3893  	// @method getPixelOrigin(): Point
3894  	// Returns the projected pixel coordinates of the top left point of
3895  	// the map layer (useful in custom layer and overlay implementations).
3896  	getPixelOrigin: function () {
3897  		this._checkIfLoaded();
3898  		return this._pixelOrigin;
3899  	},
3900
3901  	// @method getPixelWorldBounds(zoom?: Number): Bounds
3902  	// Returns the world's bounds in pixel coordinates for zoom level `zoom`.
3903  	// If `zoom` is omitted, the map's current zoom level is used.
3904  	getPixelWorldBounds: function (zoom) {
3905  		return this.options.crs.getProjectedBounds(zoom === undefined ? this.getZoom() : zoom);
3906  	},
3907
3908  	// @section Other Methods
3909
3910  	// @method getPane(pane: String|HTMLElement): HTMLElement
3911  	// Returns a [map pane](#map-pane), given its name or its HTML element (its identity).
3912  	getPane: function (pane) {
3913  		return typeof pane === 'string' ? this._panes[pane] : pane;
3914  	},
3915
3916  	// @method getPanes(): Object
3917  	// Returns a plain object containing the names of all [panes](#map-pane) as keys and
3918  	// the panes as values.
3919  	getPanes: function () {
3920  		return this._panes;
3921  	},
3922
3923  	// @method getContainer: HTMLElement
3924  	// Returns the HTML element that contains the map.
3925  	getContainer: function () {
3926  		return this._container;
3927  	},
3928
3929
3930  	// @section Conversion Methods
3931
3932  	// @method getZoomScale(toZoom: Number, fromZoom: Number): Number
3933  	// Returns the scale factor to be applied to a map transition from zoom level
3934  	// `fromZoom` to `toZoom`. Used internally to help with zoom animations.
3935  	getZoomScale: function (toZoom, fromZoom) {
3936  		// TODO replace with universal implementation after refactoring projections
3937  		var crs = this.options.crs;
3938  		fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
3939  		return crs.scale(toZoom) / crs.scale(fromZoom);
3940  	},
3941
3942  	// @method getScaleZoom(scale: Number, fromZoom: Number): Number
3943  	// Returns the zoom level that the map would end up at, if it is at `fromZoom`
3944  	// level and everything is scaled by a factor of `scale`. Inverse of
3945  	// [`getZoomScale`](#map-getZoomScale).
3946  	getScaleZoom: function (scale, fromZoom) {
3947  		var crs = this.options.crs;
3948  		fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
3949  		var zoom = crs.zoom(scale * crs.scale(fromZoom));
3950  		return isNaN(zoom) ? Infinity : zoom;
3951  	},
3952
3953  	// @method project(latlng: LatLng, zoom: Number): Point
3954  	// Projects a geographical coordinate `LatLng` according to the projection
3955  	// of the map's CRS, then scales it according to `zoom` and the CRS's
3956  	// `Transformation`. The result is pixel coordinate relative to
3957  	// the CRS origin.
3958  	project: function (latlng, zoom) {
3959  		zoom = zoom === undefined ? this._zoom : zoom;
3960  		return this.options.crs.latLngToPoint(toLatLng(latlng), zoom);
3961  	},
3962
3963  	// @method unproject(point: Point, zoom: Number): LatLng
3964  	// Inverse of [`project`](#map-project).
3965  	unproject: function (point, zoom) {
3966  		zoom = zoom === undefined ? this._zoom : zoom;
3967  		return this.options.crs.pointToLatLng(toPoint(point), zoom);
3968  	},
3969
3970  	// @method layerPointToLatLng(point: Point): LatLng
3971  	// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
3972  	// returns the corresponding geographical coordinate (for the current zoom level).
3973  	layerPointToLatLng: function (point) {
3974  		var projectedPoint = toPoint(point).add(this.getPixelOrigin());
3975  		return this.unproject(projectedPoint);
3976  	},
3977
3978  	// @method latLngToLayerPoint(latlng: LatLng): Point
3979  	// Given a geographical coordinate, returns the corresponding pixel coordinate
3980  	// relative to the [origin pixel](#map-getpixelorigin).
3981  	latLngToLayerPoint: function (latlng) {
3982  		var projectedPoint = this.project(toLatLng(latlng))._round();
3983  		return projectedPoint._subtract(this.getPixelOrigin());
3984  	},
3985
3986  	// @method wrapLatLng(latlng: LatLng): LatLng
3987  	// Returns a `LatLng` where `lat` and `lng` has been wrapped according to the
3988  	// map's CRS's `wrapLat` and `wrapLng` properties, if they are outside the
3989  	// CRS's bounds.
3990  	// By default this means longitude is wrapped around the dateline so its
3991  	// value is between -180 and +180 degrees.
3992  	wrapLatLng: function (latlng) {
3993  		return this.options.crs.wrapLatLng(toLatLng(latlng));
3994  	},
3995
3996  	// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds
3997  	// Returns a `LatLngBounds` with the same size as the given one, ensuring that
3998  	// its center is within the CRS's bounds.
3999  	// By default this means the center longitude is wrapped around the dateline so its
4000  	// value is between -180 and +180 degrees, and the majority of the bounds
4001  	// overlaps the CRS's bounds.
4002  	wrapLatLngBounds: function (latlng) {
4003  		return this.options.crs.wrapLatLngBounds(toLatLngBounds(latlng));
4004  	},
4005
4006  	// @method distance(latlng1: LatLng, latlng2: LatLng): Number
4007  	// Returns the distance between two geographical coordinates according to
4008  	// the map's CRS. By default this measures distance in meters.
4009  	distance: function (latlng1, latlng2) {
4010  		return this.options.crs.distance(toLatLng(latlng1), toLatLng(latlng2));
4011  	},
4012
4013  	// @method containerPointToLayerPoint(point: Point): Point
4014  	// Given a pixel coordinate relative to the map container, returns the corresponding
4015  	// pixel coordinate relative to the [origin pixel](#map-getpixelorigin).
4016  	containerPointToLayerPoint: function (point) { // (Point)
4017  		return toPoint(point).subtract(this._getMapPanePos());
4018  	},
4019
4020  	// @method layerPointToContainerPoint(point: Point): Point
4021  	// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
4022  	// returns the corresponding pixel coordinate relative to the map container.
4023  	layerPointToContainerPoint: function (point) { // (Point)
4024  		return toPoint(point).add(this._getMapPanePos());
4025  	},
4026
4027  	// @method containerPointToLatLng(point: Point): LatLng
4028  	// Given a pixel coordinate relative to the map container, returns
4029  	// the corresponding geographical coordinate (for the current zoom level).
4030  	containerPointToLatLng: function (point) {
4031  		var layerPoint = this.containerPointToLayerPoint(toPoint(point));
4032  		return this.layerPointToLatLng(layerPoint);
4033  	},
4034
4035  	// @method latLngToContainerPoint(latlng: LatLng): Point
4036  	// Given a geographical coordinate, returns the corresponding pixel coordinate
4037  	// relative to the map container.
4038  	latLngToContainerPoint: function (latlng) {
4039  		return this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng)));
4040  	},
4041
4042  	// @method mouseEventToContainerPoint(ev: MouseEvent): Point
4043  	// Given a MouseEvent object, returns the pixel coordinate relative to the
4044  	// map container where the event took place.
4045  	mouseEventToContainerPoint: function (e) {
4046  		return getMousePosition(e, this._container);
4047  	},
4048
4049  	// @method mouseEventToLayerPoint(ev: MouseEvent): Point
4050  	// Given a MouseEvent object, returns the pixel coordinate relative to
4051  	// the [origin pixel](#map-getpixelorigin) where the event took place.
4052  	mouseEventToLayerPoint: function (e) {
4053  		return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));
4054  	},
4055
4056  	// @method mouseEventToLatLng(ev: MouseEvent): LatLng
4057  	// Given a MouseEvent object, returns geographical coordinate where the
4058  	// event took place.
4059  	mouseEventToLatLng: function (e) { // (MouseEvent)
4060  		return this.layerPointToLatLng(this.mouseEventToLayerPoint(e));
4061  	},
4062
4063
4064  	// map initialization methods
4065
4066  	_initContainer: function (id) {
4067  		var container = this._container = get(id);
4068
4069  		if (!container) {
4070  			throw new Error('Map container not found.');
4071  		} else if (container._leaflet_id) {
4072  			throw new Error('Map container is already initialized.');
4073  		}
4074
4075  		on(container, 'scroll', this._onScroll, this);
4076  		this._containerId = stamp(container);
4077  	},
4078
4079  	_initLayout: function () {
4080  		var container = this._container;
4081
4082  		this._fadeAnimated = this.options.fadeAnimation && 
vendor: 9,382 bytes, lines 4082-4363
4082any3d;
4083
4084  		addClass(container, 'leaflet-container' +
4085  			(touch ? ' leaflet-touch' : '') +
4086  			(retina ? ' leaflet-retina' : '') +
4087  			(ielt9 ? ' leaflet-oldie' : '') +
4088  			(safari ? ' leaflet-safari' : '') +
4089  			(this._fadeAnimated ? ' leaflet-fade-anim' : ''));
4090
4091  		var position = getStyle(container, 'position');
4092
4093  		if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') {
4094  			container.style.position = 'relative';
4095  		}
4096
4097  		this._initPanes();
4098
4099  		if (this._initControlPos) {
4100  			this._initControlPos();
4101  		}
4102  	},
4103
4104  	_initPanes: function () {
4105  		var panes = this._panes = {};
4106  		this._paneRenderers = {};
4107
4108  		// @section
4109  		//
4110  		// Panes are DOM elements used to control the ordering of layers on the map. You
4111  		// can access panes with [`map.getPane`](#map-getpane) or
4112  		// [`map.getPanes`](#map-getpanes) methods. New panes can be created with the
4113  		// [`map.createPane`](#map-createpane) method.
4114  		//
4115  		// Every map has the following default panes that differ only in zIndex.
4116  		//
4117  		// @pane mapPane: HTMLElement = 'auto'
4118  		// Pane that contains all other map panes
4119
4120  		this._mapPane = this.createPane('mapPane', this._container);
4121  		setPosition(this._mapPane, new Point(0, 0));
4122
4123  		// @pane tilePane: HTMLElement = 200
4124  		// Pane for `GridLayer`s and `TileLayer`s
4125  		this.createPane('tilePane');
4126  		// @pane overlayPane: HTMLElement = 400
4127  		// Pane for overlay shadows (e.g. `Marker` shadows)
4128  		this.createPane('shadowPane');
4129  		// @pane shadowPane: HTMLElement = 500
4130  		// Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s and `VideoOverlay`s
4131  		this.createPane('overlayPane');
4132  		// @pane markerPane: HTMLElement = 600
4133  		// Pane for `Icon`s of `Marker`s
4134  		this.createPane('markerPane');
4135  		// @pane tooltipPane: HTMLElement = 650
4136  		// Pane for `Tooltip`s.
4137  		this.createPane('tooltipPane');
4138  		// @pane popupPane: HTMLElement = 700
4139  		// Pane for `Popup`s.
4140  		this.createPane('popupPane');
4141
4142  		if (!this.options.markerZoomAnimation) {
4143  			addClass(panes.markerPane, 'leaflet-zoom-hide');
4144  			addClass(panes.shadowPane, 'leaflet-zoom-hide');
4145  		}
4146  	},
4147
4148
4149  	// private methods that modify map state
4150
4151  	// @section Map state change events
4152  	_resetView: function (center, zoom) {
4153  		setPosition(this._mapPane, new Point(0, 0));
4154
4155  		var loading = !this._loaded;
4156  		this._loaded = true;
4157  		zoom = this._limitZoom(zoom);
4158
4159  		this.fire('viewprereset');
4160
4161  		var zoomChanged = this._zoom !== zoom;
4162  		this
4163  			._moveStart(zoomChanged, false)
4164  			._move(center, zoom)
4165  			._moveEnd(zoomChanged);
4166
4167  		// @event viewreset: Event
4168  		// Fired when the map needs to redraw its content (this usually happens
4169  		// on map zoom or load). Very useful for creating custom overlays.
4170  		this.fire('viewreset');
4171
4172  		// @event load: Event
4173  		// Fired when the map is initialized (when its center and zoom are set
4174  		// for the first time).
4175  		if (loading) {
4176  			this.fire('load');
4177  		}
4178  	},
4179
4180  	_moveStart: function (zoomChanged, noMoveStart) {
4181  		// @event zoomstart: Event
4182  		// Fired when the map zoom is about to change (e.g. before zoom animation).
4183  		// @event movestart: Event
4184  		// Fired when the view of the map starts changing (e.g. user starts dragging the map).
4185  		if (zoomChanged) {
4186  			this.fire('zoomstart');
4187  		}
4188  		if (!noMoveStart) {
4189  			this.fire('movestart');
4190  		}
4191  		return this;
4192  	},
4193
4194  	_move: function (center, zoom, data) {
4195  		if (zoom === undefined) {
4196  			zoom = this._zoom;
4197  		}
4198  		var zoomChanged = this._zoom !== zoom;
4199
4200  		this._zoom = zoom;
4201  		this._lastCenter = center;
4202  		this._pixelOrigin = this._getNewPixelOrigin(center);
4203
4204  		// @event zoom: Event
4205  		// Fired repeatedly during any change in zoom level, including zoom
4206  		// and fly animations.
4207  		if (zoomChanged || (data && data.pinch)) {	// Always fire 'zoom' if pinching because #3530
4208  			this.fire('zoom', data);
4209  		}
4210
4211  		// @event move: Event
4212  		// Fired repeatedly during any movement of the map, including pan and
4213  		// fly animations.
4214  		return this.fire('move', data);
4215  	},
4216
4217  	_moveEnd: function (zoomChanged) {
4218  		// @event zoomend: Event
4219  		// Fired when the map has changed, after any animations.
4220  		if (zoomChanged) {
4221  			this.fire('zoomend');
4222  		}
4223
4224  		// @event moveend: Event
4225  		// Fired when the center of the map stops changing (e.g. user stopped
4226  		// dragging the map).
4227  		return this.fire('moveend');
4228  	},
4229
4230  	_stop: function () {
4231  		cancelAnimFrame(this._flyToFrame);
4232  		if (this._panAnim) {
4233  			this._panAnim.stop();
4234  		}
4235  		return this;
4236  	},
4237
4238  	_rawPanBy: function (offset) {
4239  		setPosition(this._mapPane, this._getMapPanePos().subtract(offset));
4240  	},
4241
4242  	_getZoomSpan: function () {
4243  		return this.getMaxZoom() - this.getMinZoom();
4244  	},
4245
4246  	_panInsideMaxBounds: function () {
4247  		if (!this._enforcingBounds) {
4248  			this.panInsideBounds(this.options.maxBounds);
4249  		}
4250  	},
4251
4252  	_checkIfLoaded: function () {
4253  		if (!this._loaded) {
4254  			throw new Error('Set map center and zoom first.');
4255  		}
4256  	},
4257
4258  	// DOM event handling
4259
4260  	// @section Interaction events
4261  	_initEvents: function (remove) {
4262  		this._targets = {};
4263  		this._targets[stamp(this._container)] = this;
4264
4265  		var onOff = remove ? off : on;
4266
4267  		// @event click: MouseEvent
4268  		// Fired when the user clicks (or taps) the map.
4269  		// @event dblclick: MouseEvent
4270  		// Fired when the user double-clicks (or double-taps) the map.
4271  		// @event mousedown: MouseEvent
4272  		// Fired when the user pushes the mouse button on the map.
4273  		// @event mouseup: MouseEvent
4274  		// Fired when the user releases the mouse button on the map.
4275  		// @event mouseover: MouseEvent
4276  		// Fired when the mouse enters the map.
4277  		// @event mouseout: MouseEvent
4278  		// Fired when the mouse leaves the map.
4279  		// @event mousemove: MouseEvent
4280  		// Fired while the mouse moves over the map.
4281  		// @event contextmenu: MouseEvent
4282  		// Fired when the user pushes the right mouse button on the map, prevents
4283  		// default browser context menu from showing if there are listeners on
4284  		// this event. Also fired on mobile when the user holds a single touch
4285  		// for a second (also called long press).
4286  		// @event keypress: KeyboardEvent
4287  		// Fired when the user presses a key from the keyboard that produces a character value while the map is focused.
4288  		// @event keydown: KeyboardEvent
4289  		// Fired when the user presses a key from the keyboard while the map is focused. Unlike the `keypress` event,
4290  		// the `keydown` event is fired for keys that produce a character value and for keys
4291  		// that do not produce a character value.
4292  		// @event keyup: KeyboardEvent
4293  		// Fired when the user releases a key from the keyboard while the map is focused.
4294  		onOff(this._container, 'click dblclick mousedown mouseup ' +
4295  			'mouseover mouseout mousemove contextmenu keypress keydown keyup', this._handleDOMEvent, this);
4296
4297  		if (this.options.trackResize) {
4298  			onOff(window, 'resize', this._onResize, this);
4299  		}
4300
4301  		if (any3d && this.options.transform3DLimit) {
4302  			(remove ? this.off : this.on).call(this, 'moveend', this._onMoveEnd);
4303  		}
4304  	},
4305
4306  	_onResize: function () {
4307  		cancelAnimFrame(this._resizeRequest);
4308  		this._resizeRequest = requestAnimFrame(
4309  		        function () { this.invalidateSize({debounceMoveend: true}); }, this);
4310  	},
4311
4312  	_onScroll: function () {
4313  		this._container.scrollTop  = 0;
4314  		this._container.scrollLeft = 0;
4315  	},
4316
4317  	_onMoveEnd: function () {
4318  		var pos = this._getMapPanePos();
4319  		if (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) {
4320  			// https://bugzilla.mozilla.org/show_bug.cgi?id=1203873 but Webkit also have
4321  			// a pixel offset on very high values, see: http://jsfiddle.net/dg6r5hhb/
4322  			this._resetView(this.getCenter(), this.getZoom());
4323  		}
4324  	},
4325
4326  	_findEventTargets: function (e, type) {
4327  		var targets = [],
4328  		    target,
4329  		    isHover = type === 'mouseout' || type === 'mouseover',
4330  		    src = e.target || e.srcElement,
4331  		    dragging = false;
4332
4333  		while (src) {
4334  			target = this._targets[stamp(src)];
4335  			if (target && (type === 'click' || type === 'preclick') && !e._simulated && this._draggableMoved(target)) {
4336  				// Prevent firing click after you just dragged an object.
4337  				dragging = true;
4338  				break;
4339  			}
4340  			if (target && target.listens(type, true)) {
4341  				if (isHover && !isExternalTarget(src, e)) { break; }
4342  				targets.push(target);
4343  				if (isHover) { break; }
4344  			}
4345  			if (src === this._container) { break; }
4346  			src = src.parentNode;
4347  		}
4348  		if (!targets.length && !dragging && !isHover && isExternalTarget(src, e)) {
4349  			targets = [this];
4350  		}
4351  		return targets;
4352  	},
4353
4354  	_handleDOMEvent: function (e) {
4355  		if (!this._loaded || skipped(e)) { return; }
4356
4357  		var type = e.type;
4358
4359  		if (type === 'mousedown' || type === 'keypress' || type === 'keyup' || type === 'keydown') {
4360  			// prevents outline when clicking on keyboard-focusable element
4361  			preventOutline(e.target || e.srcElement);
4362  		}
4363
4364  		this._fireDOMEvent(e, type);
4365  	},
4366
4367  	_mouseEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu'],
4368
4369  	_fireDOMEvent: function (e, type, targets) {
4370
4371  		if (e.type === 'click') {
4372  			// Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).
4373  			// @event preclick: MouseEvent
4374  			// Fired before mouse click on the map (sometimes useful when you
4375  			// want something to happen on click before any existing click
4376  			// handlers start running).
4377  			var synth = extend({}, e);
4378  			synth.type = 'preclick';
4379  			this._fireDOMEvent(synth, synth.type, targets);
4380  		}
4381
4382  		if (e._stopped) { return; }
4383
4384  		// Find the layer the event is propagating from and its parents.
4385  		targets = (targets || []).concat(this._findEventTargets(e, type));
4386
4387  		if (!targets.length) { return; }
4388
4389  		var target = targets[0];
4390  		if (type === 'contextmenu' && target.listens(type, true)) {
4391  			preventDefault(e);
4392  		}
4393
4394  		var data = {
4395  			originalEvent: e
4396  		};
4397
4398  		if (e.type !== 'keypress' && e.type !== 'keydown' && e.type !== 'keyup') {
4399  			var isMarker = target.getLatLng && (!target._radius || target._radius <= 10);
4400  			data.containerPoint = isMarker ?
4401  				this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
4402  			data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);
4403  			data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);
4404  		}
4405
4406  		for (var i = 0; i < targets.length; i++) {
4407  			targets[i].fire(type, data, true);
4408  			if (data.originalEvent._stopped ||
4409  				(targets[i].options.bubblingMouseEvents === false && indexOf(this._mouseEvents, type) !== -1)) { return; }
4410  		}
4411  	},
4412
4413  	_draggableMoved: function (obj) {
4414  		obj = obj.dragging && obj.dragging.enabled() ? obj : this;
4415  		return (obj.dragging && obj.dragging.moved()) || (this.boxZoom && this.boxZoom.moved());
4416  	},
4417
4418  	_clearHandlers: function () {
4419  		for (var i = 0, len = this._handlers.length; i < len; i++) {
4420  			this._handlers[i].disable();
4421  		}
4422  	},
4423
4424  	// @section Other Methods
4425
4426  	// @method whenReady(fn: Function, context?: Object): this
4427  	// Runs the given function `fn` when the map gets initialized with
4428  	// a view (center and zoom) and at least one layer, or immediately
4429  	// if it's already initialized, optionally passing a function context.
4430  	whenReady: function (callback, context) {
4431  		if (this._loaded) {
4432  			callback.call(context || this, {target: this});
4433  		} else {
4434  			this.on('load', callback, context);
4435  		}
4436  		return this;
4437  	},
4438
4439
4440  	// private methods for getting map state
4441
4442  	_getMapPanePos: function () {
4443  		return getPosition(this._mapPane) || new Point(0, 0);
4444  	},
4445
4446  	_moved: function () {
4447  		var pos = this._getMapPanePos();
4448  		return pos && !pos.equals([0, 0]);
4449  	},
4450
4451  	_getTopLeftPoint: function (center, zoom) {
4452  		var pixelOrigin = center && zoom !== undefined ?
4453  			this._getNewPixelOrigin(center, zoom) :
4454  			this.getPixelOrigin();
4455  		return pixelOrigin.subtract(this._getMapPanePos());
4456  	},
4457
4458  	_getNewPixelOrigin: function (center, zoom) {
4459  		var viewHalf = this.getSize()._divideBy(2);
4460  		return this.project(center, zoom)._subtract(viewHalf)._add(this._getMapPanePos())._round();
4461  	},
4462
4463  	_latLngToNewLayerPoint: function (latlng, zoom, center) {
4464  		var topLeft = this._getNewPixelOrigin(center, zoom);
4465  		return this.project(latlng, zoom)._subtract(topLeft);
4466  	},
4467
4468  	_latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) {
4469  		var topLeft = this._getNewPixelOrigin(center, zoom);
4470  		return toBounds([
vendor: 43,530 bytes, lines 4471-5916
4471  			this.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft),
4472  			this.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft),
4473  			this.project(latLngBounds.getSouthEast(), zoom)._subtract(topLeft),
4474  			this.project(latLngBounds.getNorthEast(), zoom)._subtract(topLeft)
4475  		]);
4476  	},
4477
4478  	// layer point of the current center
4479  	_getCenterLayerPoint: function () {
4480  		return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
4481  	},
4482
4483  	// offset of the specified place to the current center in pixels
4484  	_getCenterOffset: function (latlng) {
4485  		return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());
4486  	},
4487
4488  	// adjust center for view to get inside bounds
4489  	_limitCenter: function (center, zoom, bounds) {
4490
4491  		if (!bounds) { return center; }
4492
4493  		var centerPoint = this.project(center, zoom),
4494  		    viewHalf = this.getSize().divideBy(2),
4495  		    viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
4496  		    offset = this._getBoundsOffset(viewBounds, bounds, zoom);
4497
4498  		// If offset is less than a pixel, ignore.
4499  		// This prevents unstable projections from getting into
4500  		// an infinite loop of tiny offsets.
4501  		if (offset.round().equals([0, 0])) {
4502  			return center;
4503  		}
4504
4505  		return this.unproject(centerPoint.add(offset), zoom);
4506  	},
4507
4508  	// adjust offset for view to get inside bounds
4509  	_limitOffset: function (offset, bounds) {
4510  		if (!bounds) { return offset; }
4511
4512  		var viewBounds = this.getPixelBounds(),
4513  		    newBounds = new Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));
4514
4515  		return offset.add(this._getBoundsOffset(newBounds, bounds));
4516  	},
4517
4518  	// returns offset needed for pxBounds to get inside maxBounds at a specified zoom
4519  	_getBoundsOffset: function (pxBounds, maxBounds, zoom) {
4520  		var projectedMaxBounds = toBounds(
4521  		        this.project(maxBounds.getNorthEast(), zoom),
4522  		        this.project(maxBounds.getSouthWest(), zoom)
4523  		    ),
4524  		    minOffset = projectedMaxBounds.min.subtract(pxBounds.min),
4525  		    maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),
4526
4527  		    dx = this._rebound(minOffset.x, -maxOffset.x),
4528  		    dy = this._rebound(minOffset.y, -maxOffset.y);
4529
4530  		return new Point(dx, dy);
4531  	},
4532
4533  	_rebound: function (left, right) {
4534  		return left + right > 0 ?
4535  			Math.round(left - right) / 2 :
4536  			Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));
4537  	},
4538
4539  	_limitZoom: function (zoom) {
4540  		var min = this.getMinZoom(),
4541  		    max = this.getMaxZoom(),
4542  		    snap = any3d ? this.options.zoomSnap : 1;
4543  		if (snap) {
4544  			zoom = Math.round(zoom / snap) * snap;
4545  		}
4546  		return Math.max(min, Math.min(max, zoom));
4547  	},
4548
4549  	_onPanTransitionStep: function () {
4550  		this.fire('move');
4551  	},
4552
4553  	_onPanTransitionEnd: function () {
4554  		removeClass(this._mapPane, 'leaflet-pan-anim');
4555  		this.fire('moveend');
4556  	},
4557
4558  	_tryAnimatedPan: function (center, options) {
4559  		// difference between the new and current centers in pixels
4560  		var offset = this._getCenterOffset(center)._trunc();
4561
4562  		// don't animate too far unless animate: true specified in options
4563  		if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }
4564
4565  		this.panBy(offset, options);
4566
4567  		return true;
4568  	},
4569
4570  	_createAnimProxy: function () {
4571
4572  		var proxy = this._proxy = create$1('div', 'leaflet-proxy leaflet-zoom-animated');
4573  		this._panes.mapPane.appendChild(proxy);
4574
4575  		this.on('zoomanim', function (e) {
4576  			var prop = TRANSFORM,
4577  			    transform = this._proxy.style[prop];
4578
4579  			setTransform(this._proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));
4580
4581  			// workaround for case when transform is the same and so transitionend event is not fired
4582  			if (transform === this._proxy.style[prop] && this._animatingZoom) {
4583  				this._onZoomTransitionEnd();
4584  			}
4585  		}, this);
4586
4587  		this.on('load moveend', this._animMoveEnd, this);
4588
4589  		this._on('unload', this._destroyAnimProxy, this);
4590  	},
4591
4592  	_destroyAnimProxy: function () {
4593  		remove(this._proxy);
4594  		this.off('load moveend', this._animMoveEnd, this);
4595  		delete this._proxy;
4596  	},
4597
4598  	_animMoveEnd: function () {
4599  		var c = this.getCenter(),
4600  		    z = this.getZoom();
4601  		setTransform(this._proxy, this.project(c, z), this.getZoomScale(z, 1));
4602  	},
4603
4604  	_catchTransitionEnd: function (e) {
4605  		if (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) {
4606  			this._onZoomTransitionEnd();
4607  		}
4608  	},
4609
4610  	_nothingToAnimate: function () {
4611  		return !this._container.getElementsByClassName('leaflet-zoom-animated').length;
4612  	},
4613
4614  	_tryAnimatedZoom: function (center, zoom, options) {
4615
4616  		if (this._animatingZoom) { return true; }
4617
4618  		options = options || {};
4619
4620  		// don't animate if disabled, not supported or zoom difference is too large
4621  		if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||
4622  		        Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }
4623
4624  		// offset is the pixel coords of the zoom origin relative to the current center
4625  		var scale = this.getZoomScale(zoom),
4626  		    offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale);
4627
4628  		// don't animate if the zoom origin isn't within one screen from the current center, unless forced
4629  		if (options.animate !== true && !this.getSize().contains(offset)) { return false; }
4630
4631  		requestAnimFrame(function () {
4632  			this
4633  			    ._moveStart(true, false)
4634  			    ._animateZoom(center, zoom, true);
4635  		}, this);
4636
4637  		return true;
4638  	},
4639
4640  	_animateZoom: function (center, zoom, startAnim, noUpdate) {
4641  		if (!this._mapPane) { return; }
4642
4643  		if (startAnim) {
4644  			this._animatingZoom = true;
4645
4646  			// remember what center/zoom to set after animation
4647  			this._animateToCenter = center;
4648  			this._animateToZoom = zoom;
4649
4650  			addClass(this._mapPane, 'leaflet-zoom-anim');
4651  		}
4652
4653  		// @section Other Events
4654  		// @event zoomanim: ZoomAnimEvent
4655  		// Fired at least once per zoom animation. For continuous zoom, like pinch zooming, fired once per frame during zoom.
4656  		this.fire('zoomanim', {
4657  			center: center,
4658  			zoom: zoom,
4659  			noUpdate: noUpdate
4660  		});
4661
4662  		// Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693
4663  		setTimeout(bind(this._onZoomTransitionEnd, this), 250);
4664  	},
4665
4666  	_onZoomTransitionEnd: function () {
4667  		if (!this._animatingZoom) { return; }
4668
4669  		if (this._mapPane) {
4670  			removeClass(this._mapPane, 'leaflet-zoom-anim');
4671  		}
4672
4673  		this._animatingZoom = false;
4674
4675  		this._move(this._animateToCenter, this._animateToZoom);
4676
4677  		// This anim frame should prevent an obscure iOS webkit tile loading race condition.
4678  		requestAnimFrame(function () {
4679  			this._moveEnd(true);
4680  		}, this);
4681  	}
4682  });
4683
4684  // @section
4685
4686  // @factory L.map(id: String, options?: Map options)
4687  // Instantiates a map object given the DOM ID of a `<div>` element
4688  // and optionally an object literal with `Map options`.
4689  //
4690  // @alternative
4691  // @factory L.map(el: HTMLElement, options?: Map options)
4692  // Instantiates a map object given an instance of a `<div>` HTML element
4693  // and optionally an object literal with `Map options`.
4694  function createMap(id, options) {
4695  	return new Map(id, options);
4696  }
4697
4698  /*
4699   * @class Control
4700   * @aka L.Control
4701   * @inherits Class
4702   *
4703   * L.Control is a base class for implementing map controls. Handles positioning.
4704   * All other controls extend from this class.
4705   */
4706
4707  var Control = Class.extend({
4708  	// @section
4709  	// @aka Control options
4710  	options: {
4711  		// @option position: String = 'topright'
4712  		// The position of the control (one of the map corners). Possible values are `'topleft'`,
4713  		// `'topright'`, `'bottomleft'` or `'bottomright'`
4714  		position: 'topright'
4715  	},
4716
4717  	initialize: function (options) {
4718  		setOptions(this, options);
4719  	},
4720
4721  	/* @section
4722  	 * Classes extending L.Control will inherit the following methods:
4723  	 *
4724  	 * @method getPosition: string
4725  	 * Returns the position of the control.
4726  	 */
4727  	getPosition: function () {
4728  		return this.options.position;
4729  	},
4730
4731  	// @method setPosition(position: string): this
4732  	// Sets the position of the control.
4733  	setPosition: function (position) {
4734  		var map = this._map;
4735
4736  		if (map) {
4737  			map.removeControl(this);
4738  		}
4739
4740  		this.options.position = position;
4741
4742  		if (map) {
4743  			map.addControl(this);
4744  		}
4745
4746  		return this;
4747  	},
4748
4749  	// @method getContainer: HTMLElement
4750  	// Returns the HTMLElement that contains the control.
4751  	getContainer: function () {
4752  		return this._container;
4753  	},
4754
4755  	// @method addTo(map: Map): this
4756  	// Adds the control to the given map.
4757  	addTo: function (map) {
4758  		this.remove();
4759  		this._map = map;
4760
4761  		var container = this._container = this.onAdd(map),
4762  		    pos = this.getPosition(),
4763  		    corner = map._controlCorners[pos];
4764
4765  		addClass(container, 'leaflet-control');
4766
4767  		if (pos.indexOf('bottom') !== -1) {
4768  			corner.insertBefore(container, corner.firstChild);
4769  		} else {
4770  			corner.appendChild(container);
4771  		}
4772
4773  		this._map.on('unload', this.remove, this);
4774
4775  		return this;
4776  	},
4777
4778  	// @method remove: this
4779  	// Removes the control from the map it is currently active on.
4780  	remove: function () {
4781  		if (!this._map) {
4782  			return this;
4783  		}
4784
4785  		remove(this._container);
4786
4787  		if (this.onRemove) {
4788  			this.onRemove(this._map);
4789  		}
4790
4791  		this._map.off('unload', this.remove, this);
4792  		this._map = null;
4793
4794  		return this;
4795  	},
4796
4797  	_refocusOnMap: function (e) {
4798  		// if map exists and event is not a keyboard event
4799  		if (this._map && e && e.screenX > 0 && e.screenY > 0) {
4800  			this._map.getContainer().focus();
4801  		}
4802  	}
4803  });
4804
4805  var control = function (options) {
4806  	return new Control(options);
4807  };
4808
4809  /* @section Extension methods
4810   * @uninheritable
4811   *
4812   * Every control should extend from `L.Control` and (re-)implement the following methods.
4813   *
4814   * @method onAdd(map: Map): HTMLElement
4815   * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo).
4816   *
4817   * @method onRemove(map: Map)
4818   * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove).
4819   */
4820
4821  /* @namespace Map
4822   * @section Methods for Layers and Controls
4823   */
4824  Map.include({
4825  	// @method addControl(control: Control): this
4826  	// Adds the given control to the map
4827  	addControl: function (control) {
4828  		control.addTo(this);
4829  		return this;
4830  	},
4831
4832  	// @method removeControl(control: Control): this
4833  	// Removes the given control from the map
4834  	removeControl: function (control) {
4835  		control.remove();
4836  		return this;
4837  	},
4838
4839  	_initControlPos: function () {
4840  		var corners = this._controlCorners = {},
4841  		    l = 'leaflet-',
4842  		    container = this._controlContainer =
4843  		            create$1('div', l + 'control-container', this._container);
4844
4845  		function createCorner(vSide, hSide) {
4846  			var className = l + vSide + ' ' + l + hSide;
4847
4848  			corners[vSide + hSide] = create$1('div', className, container);
4849  		}
4850
4851  		createCorner('top', 'left');
4852  		createCorner('top', 'right');
4853  		createCorner('bottom', 'left');
4854  		createCorner('bottom', 'right');
4855  	},
4856
4857  	_clearControlPos: function () {
4858  		for (var i in this._controlCorners) {
4859  			remove(this._controlCorners[i]);
4860  		}
4861  		remove(this._controlContainer);
4862  		delete this._controlCorners;
4863  		delete this._controlContainer;
4864  	}
4865  });
4866
4867  /*
4868   * @class Control.Layers
4869   * @aka L.Control.Layers
4870   * @inherits Control
4871   *
4872   * 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`.
4873   *
4874   * @example
4875   *
4876   * ```js
4877   * var baseLayers = {
4878   * 	"Mapbox": mapbox,
4879   * 	"OpenStreetMap": osm
4880   * };
4881   *
4882   * var overlays = {
4883   * 	"Marker": marker,
4884   * 	"Roads": roadsLayer
4885   * };
4886   *
4887   * L.control.layers(baseLayers, overlays).addTo(map);
4888   * ```
4889   *
4890   * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values:
4891   *
4892   * ```js
4893   * {
4894   *     "<someName1>": layer1,
4895   *     "<someName2>": layer2
4896   * }
4897   * ```
4898   *
4899   * The layer names can contain HTML, which allows you to add additional styling to the items:
4900   *
4901   * ```js
4902   * {"<img src='my-layer-icon' /> <span class='my-layer-item'>My Layer</span>": myLayer}
4903   * ```
4904   */
4905
4906  var Layers = Control.extend({
4907  	// @section
4908  	// @aka Control.Layers options
4909  	options: {
4910  		// @option collapsed: Boolean = true
4911  		// If `true`, the control will be collapsed into an icon and expanded on mouse hover or touch.
4912  		collapsed: true,
4913  		position: 'topright',
4914
4915  		// @option autoZIndex: Boolean = true
4916  		// 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.
4917  		autoZIndex: true,
4918
4919  		// @option hideSingleBase: Boolean = false
4920  		// If `true`, the base layers in the control will be hidden when there is only one.
4921  		hideSingleBase: false,
4922
4923  		// @option sortLayers: Boolean = false
4924  		// Whether to sort the layers. When `false`, layers will keep the order
4925  		// in which they were added to the control.
4926  		sortLayers: false,
4927
4928  		// @option sortFunction: Function = *
4929  		// A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
4930  		// that will be used for sorting the layers, when `sortLayers` is `true`.
4931  		// The function receives both the `L.Layer` instances and their names, as in
4932  		// `sortFunction(layerA, layerB, nameA, nameB)`.
4933  		// By default, it sorts layers alphabetically by their name.
4934  		sortFunction: function (layerA, layerB, nameA, nameB) {
4935  			return nameA < nameB ? -1 : (nameB < nameA ? 1 : 0);
4936  		}
4937  	},
4938
4939  	initialize: function (baseLayers, overlays, options) {
4940  		setOptions(this, options);
4941
4942  		this._layerControlInputs = [];
4943  		this._layers = [];
4944  		this._lastZIndex = 0;
4945  		this._handlingClick = false;
4946
4947  		for (var i in baseLayers) {
4948  			this._addLayer(baseLayers[i], i);
4949  		}
4950
4951  		for (i in overlays) {
4952  			this._addLayer(overlays[i], i, true);
4953  		}
4954  	},
4955
4956  	onAdd: function (map) {
4957  		this._initLayout();
4958  		this._update();
4959
4960  		this._map = map;
4961  		map.on('zoomend', this._checkDisabledLayers, this);
4962
4963  		for (var i = 0; i < this._layers.length; i++) {
4964  			this._layers[i].layer.on('add remove', this._onLayerChange, this);
4965  		}
4966
4967  		return this._container;
4968  	},
4969
4970  	addTo: function (map) {
4971  		Control.prototype.addTo.call(this, map);
4972  		// Trigger expand after Layers Control has been inserted into DOM so that is now has an actual height.
4973  		return this._expandIfNotCollapsed();
4974  	},
4975
4976  	onRemove: function () {
4977  		this._map.off('zoomend', this._checkDisabledLayers, this);
4978
4979  		for (var i = 0; i < this._layers.length; i++) {
4980  			this._layers[i].layer.off('add remove', this._onLayerChange, this);
4981  		}
4982  	},
4983
4984  	// @method addBaseLayer(layer: Layer, name: String): this
4985  	// Adds a base layer (radio button entry) with the given name to the control.
4986  	addBaseLayer: function (layer, name) {
4987  		this._addLayer(layer, name);
4988  		return (this._map) ? this._update() : this;
4989  	},
4990
4991  	// @method addOverlay(layer: Layer, name: String): this
4992  	// Adds an overlay (checkbox entry) with the given name to the control.
4993  	addOverlay: function (layer, name) {
4994  		this._addLayer(layer, name, true);
4995  		return (this._map) ? this._update() : this;
4996  	},
4997
4998  	// @method removeLayer(layer: Layer): this
4999  	// Remove the given layer from the control.
5000  	removeLayer: function (layer) {
5001  		layer.off('add remove', this._onLayerChange, this);
5002
5003  		var obj = this._getLayer(stamp(layer));
5004  		if (obj) {
5005  			this._layers.splice(this._layers.indexOf(obj), 1);
5006  		}
5007  		return (this._map) ? this._update() : this;
5008  	},
5009
5010  	// @method expand(): this
5011  	// Expand the control container if collapsed.
5012  	expand: function () {
5013  		addClass(this._container, 'leaflet-control-layers-expanded');
5014  		this._section.style.height = null;
5015  		var acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);
5016  		if (acceptableHeight < this._section.clientHeight) {
5017  			addClass(this._section, 'leaflet-control-layers-scrollbar');
5018  			this._section.style.height = acceptableHeight + 'px';
5019  		} else {
5020  			removeClass(this._section, 'leaflet-control-layers-scrollbar');
5021  		}
5022  		this._checkDisabledLayers();
5023  		return this;
5024  	},
5025
5026  	// @method collapse(): this
5027  	// Collapse the control container if expanded.
5028  	collapse: function () {
5029  		removeClass(this._container, 'leaflet-control-layers-expanded');
5030  		return this;
5031  	},
5032
5033  	_initLayout: function () {
5034  		var className = 'leaflet-control-layers',
5035  		    container = this._container = create$1('div', className),
5036  		    collapsed = this.options.collapsed;
5037
5038  		// makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released
5039  		container.setAttribute('aria-haspopup', true);
5040
5041  		disableClickPropagation(container);
5042  		disableScrollPropagation(container);
5043
5044  		var section = this._section = create$1('section', className + '-list');
5045
5046  		if (collapsed) {
5047  			this._map.on('click', this.collapse, this);
5048
5049  			if (!android) {
5050  				on(container, {
5051  					mouseenter: this.expand,
5052  					mouseleave: this.collapse
5053  				}, this);
5054  			}
5055  		}
5056
5057  		var link = this._layersLink = create$1('a', className + '-toggle', container);
5058  		link.href = '#';
5059  		link.title = 'Layers';
5060
5061  		if (touch) {
5062  			on(link, 'click', stop);
5063  			on(link, 'click', this.expand, this);
5064  		} else {
5065  			on(link, 'focus', this.expand, this);
5066  		}
5067
5068  		if (!collapsed) {
5069  			this.expand();
5070  		}
5071
5072  		this._baseLayersList = create$1('div', className + '-base', section);
5073  		this._separator = create$1('div', className + '-separator', section);
5074  		this._overlaysList = create$1('div', className + '-overlays', section);
5075
5076  		container.appendChild(section);
5077  	},
5078
5079  	_getLayer: function (id) {
5080  		for (var i = 0; i < this._layers.length; i++) {
5081
5082  			if (this._layers[i] && stamp(this._layers[i].layer) === id) {
5083  				return this._layers[i];
5084  			}
5085  		}
5086  	},
5087
5088  	_addLayer: function (layer, name, overlay) {
5089  		if (this._map) {
5090  			layer.on('add remove', this._onLayerChange, this);
5091  		}
5092
5093  		this._layers.push({
5094  			layer: layer,
5095  			name: name,
5096  			overlay: overlay
5097  		});
5098
5099  		if (this.options.sortLayers) {
5100  			this._layers.sort(bind(function (a, b) {
5101  				return this.options.sortFunction(a.layer, b.layer, a.name, b.name);
5102  			}, this));
5103  		}
5104
5105  		if (this.options.autoZIndex && layer.setZIndex) {
5106  			this._lastZIndex++;
5107  			layer.setZIndex(this._lastZIndex);
5108  		}
5109
5110  		this._expandIfNotCollapsed();
5111  	},
5112
5113  	_update: function () {
5114  		if (!this._container) { return this; }
5115
5116  		empty(this._baseLayersList);
5117  		empty(this._overlaysList);
5118
5119  		this._layerControlInputs = [];
5120  		var baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;
5121
5122  		for (i = 0; i < this._layers.length; i++) {
5123  			obj = this._layers[i];
5124  			this._addItem(obj);
5125  			overlaysPresent = overlaysPresent || obj.overlay;
5126  			baseLayersPresent = baseLayersPresent || !obj.overlay;
5127  			baseLayersCount += !obj.overlay ? 1 : 0;
5128  		}
5129
5130  		// Hide base layers section if there's only one layer.
5131  		if (this.options.hideSingleBase) {
5132  			baseLayersPresent = baseLayersPresent && baseLayersCount > 1;
5133  			this._baseLayersList.style.display = baseLayersPresent ? '' : 'none';
5134  		}
5135
5136  		this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
5137
5138  		return this;
5139  	},
5140
5141  	_onLayerChange: function (e) {
5142  		if (!this._handlingClick) {
5143  			this._update();
5144  		}
5145
5146  		var obj = this._getLayer(stamp(e.target));
5147
5148  		// @namespace Map
5149  		// @section Layer events
5150  		// @event baselayerchange: LayersControlEvent
5151  		// Fired when the base layer is changed through the [layers control](#control-layers).
5152  		// @event overlayadd: LayersControlEvent
5153  		// Fired when an overlay is selected through the [layers control](#control-layers).
5154  		// @event overlayremove: LayersControlEvent
5155  		// Fired when an overlay is deselected through the [layers control](#control-layers).
5156  		// @namespace Control.Layers
5157  		var type = obj.overlay ?
5158  			(e.type === 'add' ? 'overlayadd' : 'overlayremove') :
5159  			(e.type === 'add' ? 'baselayerchange' : null);
5160
5161  		if (type) {
5162  			this._map.fire(type, obj);
5163  		}
5164  	},
5165
5166  	// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
5167  	_createRadioElement: function (name, checked) {
5168
5169  		var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' +
5170  				name + '"' + (checked ? ' checked="checked"' : '') + '/>';
5171
5172  		var radioFragment = document.createElement('div');
5173  		radioFragment.innerHTML = radioHtml;
5174
5175  		return radioFragment.firstChild;
5176  	},
5177
5178  	_addItem: function (obj) {
5179  		var label = document.createElement('label'),
5180  		    checked = this._map.hasLayer(obj.layer),
5181  		    input;
5182
5183  		if (obj.overlay) {
5184  			input = document.createElement('input');
5185  			input.type = 'checkbox';
5186  			input.className = 'leaflet-control-layers-selector';
5187  			input.defaultChecked = checked;
5188  		} else {
5189  			input = this._createRadioElement('leaflet-base-layers_' + stamp(this), checked);
5190  		}
5191
5192  		this._layerControlInputs.push(input);
5193  		input.layerId = stamp(obj.layer);
5194
5195  		on(input, 'click', this._onInputClick, this);
5196
5197  		var name = document.createElement('span');
5198  		name.innerHTML = ' ' + obj.name;
5199
5200  		// Helps from preventing layer control flicker when checkboxes are disabled
5201  		// https://github.com/Leaflet/Leaflet/issues/2771
5202  		var holder = document.createElement('div');
5203
5204  		label.appendChild(holder);
5205  		holder.appendChild(input);
5206  		holder.appendChild(name);
5207
5208  		var container = obj.overlay ? this._overlaysList : this._baseLayersList;
5209  		container.appendChild(label);
5210
5211  		this._checkDisabledLayers();
5212  		return label;
5213  	},
5214
5215  	_onInputClick: function () {
5216  		var inputs = this._layerControlInputs,
5217  		    input, layer;
5218  		var addedLayers = [],
5219  		    removedLayers = [];
5220
5221  		this._handlingClick = true;
5222
5223  		for (var i = inputs.length - 1; i >= 0; i--) {
5224  			input = inputs[i];
5225  			layer = this._getLayer(input.layerId).layer;
5226
5227  			if (input.checked) {
5228  				addedLayers.push(layer);
5229  			} else if (!input.checked) {
5230  				removedLayers.push(layer);
5231  			}
5232  		}
5233
5234  		// Bugfix issue 2318: Should remove all old layers before readding new ones
5235  		for (i = 0; i < removedLayers.length; i++) {
5236  			if (this._map.hasLayer(removedLayers[i])) {
5237  				this._map.removeLayer(removedLayers[i]);
5238  			}
5239  		}
5240  		for (i = 0; i < addedLayers.length; i++) {
5241  			if (!this._map.hasLayer(addedLayers[i])) {
5242  				this._map.addLayer(addedLayers[i]);
5243  			}
5244  		}
5245
5246  		this._handlingClick = false;
5247
5248  		this._refocusOnMap();
5249  	},
5250
5251  	_checkDisabledLayers: function () {
5252  		var inputs = this._layerControlInputs,
5253  		    input,
5254  		    layer,
5255  		    zoom = this._map.getZoom();
5256
5257  		for (var i = inputs.length - 1; i >= 0; i--) {
5258  			input = inputs[i];
5259  			layer = this._getLayer(input.layerId).layer;
5260  			input.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) ||
5261  			                 (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom);
5262
5263  		}
5264  	},
5265
5266  	_expandIfNotCollapsed: function () {
5267  		if (this._map && !this.options.collapsed) {
5268  			this.expand();
5269  		}
5270  		return this;
5271  	},
5272
5273  	_expand: function () {
5274  		// Backward compatibility, remove me in 1.1.
5275  		return this.expand();
5276  	},
5277
5278  	_collapse: function () {
5279  		// Backward compatibility, remove me in 1.1.
5280  		return this.collapse();
5281  	}
5282
5283  });
5284
5285
5286  // @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options)
5287  // 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.
5288  var layers = function (baseLayers, overlays, options) {
5289  	return new Layers(baseLayers, overlays, options);
5290  };
5291
5292  /*
5293   * @class Control.Zoom
5294   * @aka L.Control.Zoom
5295   * @inherits Control
5296   *
5297   * 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`.
5298   */
5299
5300  var Zoom = Control.extend({
5301  	// @section
5302  	// @aka Control.Zoom options
5303  	options: {
5304  		position: 'topleft',
5305
5306  		// @option zoomInText: String = '+'
5307  		// The text set on the 'zoom in' button.
5308  		zoomInText: '+',
5309
5310  		// @option zoomInTitle: String = 'Zoom in'
5311  		// The title set on the 'zoom in' button.
5312  		zoomInTitle: 'Zoom in',
5313
5314  		// @option zoomOutText: String = '&#x2212;'
5315  		// The text set on the 'zoom out' button.
5316  		zoomOutText: '&#x2212;',
5317
5318  		// @option zoomOutTitle: String = 'Zoom out'
5319  		// The title set on the 'zoom out' button.
5320  		zoomOutTitle: 'Zoom out'
5321  	},
5322
5323  	onAdd: function (map) {
5324  		var zoomName = 'leaflet-control-zoom',
5325  		    container = create$1('div', zoomName + ' leaflet-bar'),
5326  		    options = this.options;
5327
5328  		this._zoomInButton  = this._createButton(options.zoomInText, options.zoomInTitle,
5329  		        zoomName + '-in',  container, this._zoomIn);
5330  		this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,
5331  		        zoomName + '-out', container, this._zoomOut);
5332
5333  		this._updateDisabled();
5334  		map.on('zoomend zoomlevelschange', this._updateDisabled, this);
5335
5336  		return container;
5337  	},
5338
5339  	onRemove: function (map) {
5340  		map.off('zoomend zoomlevelschange', this._updateDisabled, this);
5341  	},
5342
5343  	disable: function () {
5344  		this._disabled = true;
5345  		this._updateDisabled();
5346  		return this;
5347  	},
5348
5349  	enable: function () {
5350  		this._disabled = false;
5351  		this._updateDisabled();
5352  		return this;
5353  	},
5354
5355  	_zoomIn: function (e) {
5356  		if (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {
5357  			this._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
5358  		}
5359  	},
5360
5361  	_zoomOut: function (e) {
5362  		if (!this._disabled && this._map._zoom > this._map.getMinZoom()) {
5363  			this._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
5364  		}
5365  	},
5366
5367  	_createButton: function (html, title, className, container, fn) {
5368  		var link = create$1('a', className, container);
5369  		link.innerHTML = html;
5370  		link.href = '#';
5371  		link.title = title;
5372
5373  		/*
5374  		 * Will force screen readers like VoiceOver to read this as "Zoom in - button"
5375  		 */
5376  		link.setAttribute('role', 'button');
5377  		link.setAttribute('aria-label', title);
5378
5379  		disableClickPropagation(link);
5380  		on(link, 'click', stop);
5381  		on(link, 'click', fn, this);
5382  		on(link, 'click', this._refocusOnMap, this);
5383
5384  		return link;
5385  	},
5386
5387  	_updateDisabled: function () {
5388  		var map = this._map,
5389  		    className = 'leaflet-disabled';
5390
5391  		removeClass(this._zoomInButton, className);
5392  		removeClass(this._zoomOutButton, className);
5393
5394  		if (this._disabled || map._zoom === map.getMinZoom()) {
5395  			addClass(this._zoomOutButton, className);
5396  		}
5397  		if (this._disabled || map._zoom === map.getMaxZoom()) {
5398  			addClass(this._zoomInButton, className);
5399  		}
5400  	}
5401  });
5402
5403  // @namespace Map
5404  // @section Control options
5405  // @option zoomControl: Boolean = true
5406  // Whether a [zoom control](#control-zoom) is added to the map by default.
5407  Map.mergeOptions({
5408  	zoomControl: true
5409  });
5410
5411  Map.addInitHook(function () {
5412  	if (this.options.zoomControl) {
5413  		// @section Controls
5414  		// @property zoomControl: Control.Zoom
5415  		// The default zoom control (only available if the
5416  		// [`zoomControl` option](#map-zoomcontrol) was `true` when creating the map).
5417  		this.zoomControl = new Zoom();
5418  		this.addControl(this.zoomControl);
5419  	}
5420  });
5421
5422  // @namespace Control.Zoom
5423  // @factory L.control.zoom(options: Control.Zoom options)
5424  // Creates a zoom control
5425  var zoom = function (options) {
5426  	return new Zoom(options);
5427  };
5428
5429  /*
5430   * @class Control.Scale
5431   * @aka L.Control.Scale
5432   * @inherits Control
5433   *
5434   * 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`.
5435   *
5436   * @example
5437   *
5438   * ```js
5439   * L.control.scale().addTo(map);
5440   * ```
5441   */
5442
5443  var Scale = Control.extend({
5444  	// @section
5445  	// @aka Control.Scale options
5446  	options: {
5447  		position: 'bottomleft',
5448
5449  		// @option maxWidth: Number = 100
5450  		// Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).
5451  		maxWidth: 100,
5452
5453  		// @option metric: Boolean = True
5454  		// Whether to show the metric scale line (m/km).
5455  		metric: true,
5456
5457  		// @option imperial: Boolean = True
5458  		// Whether to show the imperial scale line (mi/ft).
5459  		imperial: true
5460
5461  		// @option updateWhenIdle: Boolean = false
5462  		// If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).
5463  	},
5464
5465  	onAdd: function (map) {
5466  		var className = 'leaflet-control-scale',
5467  		    container = create$1('div', className),
5468  		    options = this.options;
5469
5470  		this._addScales(options, className + '-line', container);
5471
5472  		map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
5473  		map.whenReady(this._update, this);
5474
5475  		return container;
5476  	},
5477
5478  	onRemove: function (map) {
5479  		map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
5480  	},
5481
5482  	_addScales: function (options, className, container) {
5483  		if (options.metric) {
5484  			this._mScale = create$1('div', className, container);
5485  		}
5486  		if (options.imperial) {
5487  			this._iScale = create$1('div', className, container);
5488  		}
5489  	},
5490
5491  	_update: function () {
5492  		var map = this._map,
5493  		    y = map.getSize().y / 2;
5494
5495  		var maxMeters = map.distance(
5496  			map.containerPointToLatLng([0, y]),
5497  			map.containerPointToLatLng([this.options.maxWidth, y]));
5498
5499  		this._updateScales(maxMeters);
5500  	},
5501
5502  	_updateScales: function (maxMeters) {
5503  		if (this.options.metric && maxMeters) {
5504  			this._updateMetric(maxMeters);
5505  		}
5506  		if (this.options.imperial && maxMeters) {
5507  			this._updateImperial(maxMeters);
5508  		}
5509  	},
5510
5511  	_updateMetric: function (maxMeters) {
5512  		var meters = this._getRoundNum(maxMeters),
5513  		    label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';
5514
5515  		this._updateScale(this._mScale, label, meters / maxMeters);
5516  	},
5517
5518  	_updateImperial: function (maxMeters) {
5519  		var maxFeet = maxMeters * 3.2808399,
5520  		    maxMiles, miles, feet;
5521
5522  		if (maxFeet > 5280) {
5523  			maxMiles = maxFeet / 5280;
5524  			miles = this._getRoundNum(maxMiles);
5525  			this._updateScale(this._iScale, miles + ' mi', miles / maxMiles);
5526
5527  		} else {
5528  			feet = this._getRoundNum(maxFeet);
5529  			this._updateScale(this._iScale, feet + ' ft', feet / maxFeet);
5530  		}
5531  	},
5532
5533  	_updateScale: function (scale, text, ratio) {
5534  		scale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';
5535  		scale.innerHTML = text;
5536  	},
5537
5538  	_getRoundNum: function (num) {
5539  		var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),
5540  		    d = num / pow10;
5541
5542  		d = d >= 10 ? 10 :
5543  		    d >= 5 ? 5 :
5544  		    d >= 3 ? 3 :
5545  		    d >= 2 ? 2 : 1;
5546
5547  		return pow10 * d;
5548  	}
5549  });
5550
5551
5552  // @factory L.control.scale(options?: Control.Scale options)
5553  // Creates an scale control with the given options.
5554  var scale = function (options) {
5555  	return new Scale(options);
5556  };
5557
5558  /*
5559   * @class Control.Attribution
5560   * @aka L.Control.Attribution
5561   * @inherits Control
5562   *
5563   * 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.
5564   */
5565
5566  var Attribution = Control.extend({
5567  	// @section
5568  	// @aka Control.Attribution options
5569  	options: {
5570  		position: 'bottomright',
5571
5572  		// @option prefix: String = 'Leaflet'
5573  		// The HTML text shown before the attributions. Pass `false` to disable.
5574  		prefix: '<a href="https://leafletjs.com" title="A JS library for interactive maps">Leaflet</a>'
5575  	},
5576
5577  	initialize: function (options) {
5578  		setOptions(this, options);
5579
5580  		this._attributions = {};
5581  	},
5582
5583  	onAdd: function (map) {
5584  		map.attributionControl = this;
5585  		this._container = create$1('div', 'leaflet-control-attribution');
5586  		disableClickPropagation(this._container);
5587
5588  		// TODO ugly, refactor
5589  		for (var i in map._layers) {
5590  			if (map._layers[i].getAttribution) {
5591  				this.addAttribution(map._layers[i].getAttribution());
5592  			}
5593  		}
5594
5595  		this._update();
5596
5597  		return this._container;
5598  	},
5599
5600  	// @method setPrefix(prefix: String): this
5601  	// Sets the text before the attributions.
5602  	setPrefix: function (prefix) {
5603  		this.options.prefix = prefix;
5604  		this._update();
5605  		return this;
5606  	},
5607
5608  	// @method addAttribution(text: String): this
5609  	// Adds an attribution text (e.g. `'Vector data &copy; Mapbox'`).
5610  	addAttribution: function (text) {
5611  		if (!text) { return this; }
5612
5613  		if (!this._attributions[text]) {
5614  			this._attributions[text] = 0;
5615  		}
5616  		this._attributions[text]++;
5617
5618  		this._update();
5619
5620  		return this;
5621  	},
5622
5623  	// @method removeAttribution(text: String): this
5624  	// Removes an attribution text.
5625  	removeAttribution: function (text) {
5626  		if (!text) { return this; }
5627
5628  		if (this._attributions[text]) {
5629  			this._attributions[text]--;
5630  			this._update();
5631  		}
5632
5633  		return this;
5634  	},
5635
5636  	_update: function () {
5637  		if (!this._map) { return; }
5638
5639  		var attribs = [];
5640
5641  		for (var i in this._attributions) {
5642  			if (this._attributions[i]) {
5643  				attribs.push(i);
5644  			}
5645  		}
5646
5647  		var prefixAndAttribs = [];
5648
5649  		if (this.options.prefix) {
5650  			prefixAndAttribs.push(this.options.prefix);
5651  		}
5652  		if (attribs.length) {
5653  			prefixAndAttribs.push(attribs.join(', '));
5654  		}
5655
5656  		this._container.innerHTML = prefixAndAttribs.join(' | ');
5657  	}
5658  });
5659
5660  // @namespace Map
5661  // @section Control options
5662  // @option attributionControl: Boolean = true
5663  // Whether a [attribution control](#control-attribution) is added to the map by default.
5664  Map.mergeOptions({
5665  	attributionControl: true
5666  });
5667
5668  Map.addInitHook(function () {
5669  	if (this.options.attributionControl) {
5670  		new Attribution().addTo(this);
5671  	}
5672  });
5673
5674  // @namespace Control.Attribution
5675  // @factory L.control.attribution(options: Control.Attribution options)
5676  // Creates an attribution control.
5677  var attribution = function (options) {
5678  	return new Attribution(options);
5679  };
5680
5681  Control.Layers = Layers;
5682  Control.Zoom = Zoom;
5683  Control.Scale = Scale;
5684  Control.Attribution = Attribution;
5685
5686  control.layers = layers;
5687  control.zoom = zoom;
5688  control.scale = scale;
5689  control.attribution = attribution;
5690
5691  /*
5692  	L.Handler is a base class for handler classes that are used internally to inject
5693  	interaction features like dragging to classes like Map and Marker.
5694  */
5695
5696  // @class Handler
5697  // @aka L.Handler
5698  // Abstract class for map interaction handlers
5699
5700  var Handler = Class.extend({
5701  	initialize: function (map) {
5702  		this._map = map;
5703  	},
5704
5705  	// @method enable(): this
5706  	// Enables the handler
5707  	enable: function () {
5708  		if (this._enabled) { return this; }
5709
5710  		this._enabled = true;
5711  		this.addHooks();
5712  		return this;
5713  	},
5714
5715  	// @method disable(): this
5716  	// Disables the handler
5717  	disable: function () {
5718  		if (!this._enabled) { return this; }
5719
5720  		this._enabled = false;
5721  		this.removeHooks();
5722  		return this;
5723  	},
5724
5725  	// @method enabled(): Boolean
5726  	// Returns `true` if the handler is enabled
5727  	enabled: function () {
5728  		return !!this._enabled;
5729  	}
5730
5731  	// @section Extension methods
5732  	// Classes inheriting from `Handler` must implement the two following methods:
5733  	// @method addHooks()
5734  	// Called when the handler is enabled, should add event hooks.
5735  	// @method removeHooks()
5736  	// Called when the handler is disabled, should remove the event hooks added previously.
5737  });
5738
5739  // @section There is static function which can be called without instantiating L.Handler:
5740  // @function addTo(map: Map, name: String): this
5741  // Adds a new Handler to the given map with the given name.
5742  Handler.addTo = function (map, name) {
5743  	map.addHandler(name, this);
5744  	return this;
5745  };
5746
5747  var Mixin = {Events: Events};
5748
5749  /*
5750   * @class Draggable
5751   * @aka L.Draggable
5752   * @inherits Evented
5753   *
5754   * A class for making DOM elements draggable (including touch support).
5755   * Used internally for map and marker dragging. Only works for elements
5756   * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).
5757   *
5758   * @example
5759   * ```js
5760   * var draggable = new L.Draggable(elementToDrag);
5761   * draggable.enable();
5762   * ```
5763   */
5764
5765  var START = touch ? 'touchstart mousedown' : 'mousedown';
5766  var END = {
5767  	mousedown: 'mouseup',
5768  	touchstart: 'touchend',
5769  	pointerdown: 'touchend',
5770  	MSPointerDown: 'touchend'
5771  };
5772  var MOVE = {
5773  	mousedown: 'mousemove',
5774  	touchstart: 'touchmove',
5775  	pointerdown: 'touchmove',
5776  	MSPointerDown: 'touchmove'
5777  };
5778
5779
5780  var Draggable = Evented.extend({
5781
5782  	options: {
5783  		// @section
5784  		// @aka Draggable options
5785  		// @option clickTolerance: Number = 3
5786  		// The max number of pixels a user can shift the mouse pointer during a click
5787  		// for it to be considered a valid click (as opposed to a mouse drag).
5788  		clickTolerance: 3
5789  	},
5790
5791  	// @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline?: Boolean, options?: Draggable options)
5792  	// Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).
5793  	initialize: function (element, dragStartTarget, preventOutline, options) {
5794  		setOptions(this, options);
5795
5796  		this._element = element;
5797  		this._dragStartTarget = dragStartTarget || element;
5798  		this._preventOutline = preventOutline;
5799  	},
5800
5801  	// @method enable()
5802  	// Enables the dragging ability
5803  	enable: function () {
5804  		if (this._enabled) { return; }
5805
5806  		on(this._dragStartTarget, START, this._onDown, this);
5807
5808  		this._enabled = true;
5809  	},
5810
5811  	// @method disable()
5812  	// Disables the dragging ability
5813  	disable: function () {
5814  		if (!this._enabled) { return; }
5815
5816  		// If we're currently dragging this draggable,
5817  		// disabling it counts as first ending the drag.
5818  		if (Draggable._dragging === this) {
5819  			this.finishDrag();
5820  		}
5821
5822  		off(this._dragStartTarget, START, this._onDown, this);
5823
5824  		this._enabled = false;
5825  		this._moved = false;
5826  	},
5827
5828  	_onDown: function (e) {
5829  		// Ignore simulated events, since we handle both touch and
5830  		// mouse explicitly; otherwise we risk getting duplicates of
5831  		// touch events, see #4315.
5832  		// Also ignore the event if disabled; this happens in IE11
5833  		// under some circumstances, see #3666.
5834  		if (e._simulated || !this._enabled) { return; }
5835
5836  		this._moved = false;
5837
5838  		if (hasClass(this._element, 'leaflet-zoom-anim')) { return; }
5839
5840  		if (Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }
5841  		Draggable._dragging = this;  // Prevent dragging multiple objects at once.
5842
5843  		if (this._preventOutline) {
5844  			preventOutline(this._element);
5845  		}
5846
5847  		disableImageDrag();
5848  		disableTextSelection();
5849
5850  		if (this._moving) { return; }
5851
5852  		// @event down: Event
5853  		// Fired when a drag is about to start.
5854  		this.fire('down');
5855
5856  		var first = e.touches ? e.touches[0] : e,
5857  		    sizedParent = getSizedParentNode(this._element);
5858
5859  		this._startPoint = new Point(first.clientX, first.clientY);
5860
5861  		// Cache the scale, so that we can continuously compensate for it during drag (_onMove).
5862  		this._parentScale = getScale(sizedParent);
5863
5864  		on(document, MOVE[e.type], this._onMove, this);
5865  		on(document, END[e.type], this._onUp, this);
5866  	},
5867
5868  	_onMove: function (e) {
5869  		// Ignore simulated events, since we handle both touch and
5870  		// mouse explicitly; otherwise we risk getting duplicates of
5871  		// touch events, see #4315.
5872  		// Also ignore the event if disabled; this happens in IE11
5873  		// under some circumstances, see #3666.
5874  		if (e._simulated || !this._enabled) { return; }
5875
5876  		if (e.touches && e.touches.length > 1) {
5877  			this._moved = true;
5878  			return;
5879  		}
5880
5881  		var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
5882  		    offset = new Point(first.clientX, first.clientY)._subtract(this._startPoint);
5883
5884  		if (!offset.x && !offset.y) { return; }
5885  		if (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; }
5886
5887  		// We assume that the parent container's position, border and scale do not change for the duration of the drag.
5888  		// Therefore there is no need to account for the position and border (they are eliminated by the subtraction)
5889  		// and we can use the cached value for the scale.
5890  		offset.x /= this._parentScale.x;
5891  		offset.y /= this._parentScale.y;
5892
5893  		preventDefault(e);
5894
5895  		if (!this._moved) {
5896  			// @event dragstart: Event
5897  			// Fired when a drag starts
5898  			this.fire('dragstart');
5899
5900  			this._moved = true;
5901  			this._startPos = getPosition(this._element).subtract(offset);
5902
5903  			addClass(document.body, 'leaflet-dragging');
5904
5905  			this._lastTarget = e.target || e.srcElement;
5906  			// IE and Edge do not give the <use> element, so fetch it
5907  			// if necessary
5908  			if (window.SVGElementInstance && this._lastTarget instanceof window.SVGElementInstance) {
5909  				this._lastTarget = this._lastTarget.correspondingUseElement;
5910  			}
5911  			addClass(this._lastTarget, 'leaflet-drag-target');
5912  		}
5913
5914  		this._newPos = this._startPos.add(offset);
5915  		this._moving = true;
5916
5917  		cancelAnimFrame(this._animRequest);
5918  		this._lastEvent = e;
5919  		this._animRequest = requestAnimFrame(this._updatePosition, this, true);
5920  	},
5921
5922  	_updatePosition: function () {
5923  		var e = {originalEvent: this._lastEvent};
5924
5925  		// @event predrag: Event
5926  		// Fired continuously during dragging *before* each corresponding
5927  		// update of the element's position.
5928  		this.fire('predrag', e);
5929  		setPosition(this._element, this._newPos);
5930
5931  		// @event drag: Event
5932  		// Fired continuously during dragging.
5933  		this.fire('drag', e);
5934  	},
5935
5936  	_onUp: function (e) {
5937  		// Ignore simulated events, since we handle both touch and
5938  		// mouse explicitly; otherwise we risk getting duplicates of
5939  		// touch events, see #4315.
5940  		// Also ignore the event if disabled; this happens in IE11
5941  		// under some circumstances, see #3666.
5942  		if (e._simulated || !this._enabled) { return; }
5943  		this.finishDrag();
5944  	},
5945
5946  	finishDrag: function () {
5947  		removeClass(document.body, 'leaflet-dragging');
5948
5949  		if (this._lastTarget) {
5950  			removeClass(this._lastTarget, 'leaflet-drag-target');
5951  			this._lastTarget = null;
5952  		}
5953
5954  		for (var i in MOVE) {
5955  			off(document, MOVE[i], this._onMove, this);
5956  			off(document, END[i], this._onUp, this);
5957  		}
5958
5959  		enableImageDrag();
5960  		enableTextSelection();
5961
5962  		if (this._moved && this._moving) {
5963  			// ensure drag is not fired after dragend
5964  			cancelAnimFrame(this._animRequest);
5965
5966  			// @event dragend: DragEndEvent
5967  			// Fired when the drag ends.
5968  			this.fire('dragend', {
5969  				distance: this._newPos.distanceTo(this._startPos)
5970  			});
5971  		}
5972
5973  		this._moving = false;
5974  		Draggable._dragging = false;
5975  	}
5976
5977  });
5978
5979  /*
5980   * @namespace LineUtil
5981   *
5982   * Various utility functions for polyline points processing, used by Leaflet internally to make polylines lightning-fast.
5983   */
5984
5985  // Simplify polyline with vertex reduction and Douglas-Peucker simplification.
5986  // Improves rendering performance dramatically by lessening the number of points to draw.
5987
5988  // @function simplify(points: Point[], tolerance: Number): Point[]
5989  // Dramatically reduces the number of points in a polyline while retaining
5990  // its shape and returns a new array of simplified points, using the
5991  // [Douglas-Peucker algorithm](http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm).
5992  // Used for a huge performance boost when processing/displaying Leaflet polylines for
5993  // each zoom level and also reducing visual noise. tolerance affects the amount of
5994  // simplification (lesser value means higher quality but slower and with more points).
5995  // Also released as a separated micro-library [Simplify.js](http://mourner.github.com/simplify-js/).
5996  function simplify(points, tolerance) {
5997  	if (!tolerance || !points.length) {
5998  		return points.slice();
5999  	}
6000
6001  	var sqTolerance = tolerance * tolerance;
6002
6003  	    // stage 1: vertex reduction
6004  	    points = _reducePoints(points, sqTolerance);
6005
6006  	    // stage 2: Douglas-Peucker simplification
6007  	    points = _simplifyDP(points, sqTolerance);
6008
6009  	return points;
6010  }
6011
6012  // @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number
6013  // Returns the distance between point `p` and segment `p1` to `p2`.
6014  function pointToSegmentDistance(p, p1, p2) {
6015  	return Math.sqrt(_sqClosestPointOnSegment(p, p1, p2, true));
6016  }
6017
6018  // @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number
6019  // Returns the closest point from a point `p` on a segment `p1` to `p2`.
6020  function closestPointOnSegment(p, p1, p2) {
6021  	return _sqClosestPointOnSegment(p, p1, p2);
6022  }
6023
6024  // Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm
6025  function _simplifyDP(points, sqTolerance) {
6026
6027  	var len = points.length,
6028  	    ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,
6029  	    markers = new ArrayConstructor(len);
6030
6031  	    markers[0] = markers[len - 1] = 1;
6032
6033  	_simplifyDPStep(points, markers, sqTolerance, 0, len - 1);
6034
6035  	var i,
6036  	    newPoints = [];
6037
6038  	for (i = 0; i < len; i++) {
6039  		if (markers[i]) {
6040  			newPoints.push(points[i]);
6041  		}
6042  	}
6043
6044  	return newPoints;
6045  }
6046
6047  function _simplifyDPStep(points, markers, sqTolerance, first, last) {
6048
6049  	var maxSqDist = 0,
6050  	index, i, sqDist;
6051
6052  	for (i = first + 1; i <= last - 1; i++) {
6053  		sqDist = _sqClosestPointOnSegment(points[i], points[first], points[last], true);
6054
6055  		if (sqDist > maxSqDist) {
6056  			index = i;
6057  			maxSqDist = sqDist;
6058  		}
6059  	}
6060
6061  	if (maxSqDist > sqTolerance) {
6062  		markers[index] = 1;
6063
6064  		_simplifyDPStep(points, markers, sqTolerance, first, index);
6065  		_simplifyDPStep(points, markers, sqTolerance, index, last);
6066  	}
6067  }
6068
6069  // reduce points that are too close to each other to a single point
6070  function _reducePoints(points, sqTolerance) {
6071  	var reducedPoints = [points[0]];
6072
6073  	for (var i = 1, prev = 0, len = points.length; i < len; i++) {
6074  		if (_sqDist(points[i], points[prev]) > sqTolerance) {
6075  			reducedPoints.push(points[i]);
6076  			prev = i;
6077  		}
6078  	}
6079  	if (prev < len - 1) {
6080  		reducedPoints.push(points[len - 1]);
6081  	}
6082  	return reducedPoints;
6083  }
6084
6085  var _lastCode;
6086
6087  // @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, roun
vendor: 7,724 bytes, lines 6087-6365
6087d?: Boolean): Point[]|Boolean
6088  // Clips the segment a to b by rectangular bounds with the
6089  // [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm)
6090  // (modifying the segment points directly!). Used by Leaflet to only show polyline
6091  // points that are on the screen or near, increasing performance.
6092  function clipSegment(a, b, bounds, useLastCode, round) {
6093  	var codeA = useLastCode ? _lastCode : _getBitCode(a, bounds),
6094  	    codeB = _getBitCode(b, bounds),
6095
6096  	    codeOut, p, newCode;
6097
6098  	    // save 2nd code to avoid calculating it on the next segment
6099  	    _lastCode = codeB;
6100
6101  	while (true) {
6102  		// if a,b is inside the clip window (trivial accept)
6103  		if (!(codeA | codeB)) {
6104  			return [a, b];
6105  		}
6106
6107  		// if a,b is outside the clip window (trivial reject)
6108  		if (codeA & codeB) {
6109  			return false;
6110  		}
6111
6112  		// other cases
6113  		codeOut = codeA || codeB;
6114  		p = _getEdgeIntersection(a, b, codeOut, bounds, round);
6115  		newCode = _getBitCode(p, bounds);
6116
6117  		if (codeOut === codeA) {
6118  			a = p;
6119  			codeA = newCode;
6120  		} else {
6121  			b = p;
6122  			codeB = newCode;
6123  		}
6124  	}
6125  }
6126
6127  function _getEdgeIntersection(a, b, code, bounds, round) {
6128  	var dx = b.x - a.x,
6129  	    dy = b.y - a.y,
6130  	    min = bounds.min,
6131  	    max = bounds.max,
6132  	    x, y;
6133
6134  	if (code & 8) { // top
6135  		x = a.x + dx * (max.y - a.y) / dy;
6136  		y = max.y;
6137
6138  	} else if (code & 4) { // bottom
6139  		x = a.x + dx * (min.y - a.y) / dy;
6140  		y = min.y;
6141
6142  	} else if (code & 2) { // right
6143  		x = max.x;
6144  		y = a.y + dy * (max.x - a.x) / dx;
6145
6146  	} else if (code & 1) { // left
6147  		x = min.x;
6148  		y = a.y + dy * (min.x - a.x) / dx;
6149  	}
6150
6151  	return new Point(x, y, round);
6152  }
6153
6154  function _getBitCode(p, bounds) {
6155  	var code = 0;
6156
6157  	if (p.x < bounds.min.x) { // left
6158  		code |= 1;
6159  	} else if (p.x > bounds.max.x) { // right
6160  		code |= 2;
6161  	}
6162
6163  	if (p.y < bounds.min.y) { // bottom
6164  		code |= 4;
6165  	} else if (p.y > bounds.max.y) { // top
6166  		code |= 8;
6167  	}
6168
6169  	return code;
6170  }
6171
6172  // square distance (to avoid unnecessary Math.sqrt calls)
6173  function _sqDist(p1, p2) {
6174  	var dx = p2.x - p1.x,
6175  	    dy = p2.y - p1.y;
6176  	return dx * dx + dy * dy;
6177  }
6178
6179  // return closest point on segment or distance to that point
6180  function _sqClosestPointOnSegment(p, p1, p2, sqDist) {
6181  	var x = p1.x,
6182  	    y = p1.y,
6183  	    dx = p2.x - x,
6184  	    dy = p2.y - y,
6185  	    dot = dx * dx + dy * dy,
6186  	    t;
6187
6188  	if (dot > 0) {
6189  		t = ((p.x - x) * dx + (p.y - y) * dy) / dot;
6190
6191  		if (t > 1) {
6192  			x = p2.x;
6193  			y = p2.y;
6194  		} else if (t > 0) {
6195  			x += dx * t;
6196  			y += dy * t;
6197  		}
6198  	}
6199
6200  	dx = p.x - x;
6201  	dy = p.y - y;
6202
6203  	return sqDist ? dx * dx + dy * dy : new Point(x, y);
6204  }
6205
6206
6207  // @function isFlat(latlngs: LatLng[]): Boolean
6208  // Returns true if `latlngs` is a flat array, false is nested.
6209  function isFlat(latlngs) {
6210  	return !isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');
6211  }
6212
6213  function _flat(latlngs) {
6214  	console.warn('Deprecated use of _flat, please use L.LineUtil.isFlat instead.');
6215  	return isFlat(latlngs);
6216  }
6217
6218  var LineUtil = {
6219    __proto__: null,
6220    simplify: simplify,
6221    pointToSegmentDistance: pointToSegmentDistance,
6222    closestPointOnSegment: closestPointOnSegment,
6223    clipSegment: clipSegment,
6224    _getEdgeIntersection: _getEdgeIntersection,
6225    _getBitCode: _getBitCode,
6226    _sqClosestPointOnSegment: _sqClosestPointOnSegment,
6227    isFlat: isFlat,
6228    _flat: _flat
6229  };
6230
6231  /*
6232   * @namespace PolyUtil
6233   * Various utility functions for polygon geometries.
6234   */
6235
6236  /* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]
6237   * 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)).
6238   * Used by Leaflet to only show polygon points that are on the screen or near, increasing
6239   * performance. Note that polygon points needs different algorithm for clipping
6240   * than polyline, so there's a separate method for it.
6241   */
6242  function clipPolygon(points, bounds, round) {
6243  	var clippedPoints,
6244  	    edges = [1, 4, 2, 8],
6245  	    i, j, k,
6246  	    a, b,
6247  	    len, edge, p;
6248
6249  	for (i = 0, len = points.length; i < len; i++) {
6250  		points[i]._code = _getBitCode(points[i], bounds);
6251  	}
6252
6253  	// for each edge (left, bottom, right, top)
6254  	for (k = 0; k < 4; k++) {
6255  		edge = edges[k];
6256  		clippedPoints = [];
6257
6258  		for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
6259  			a = points[i];
6260  			b = points[j];
6261
6262  			// if a is inside the clip window
6263  			if (!(a._code & edge)) {
6264  				// if b is outside the clip window (a->b goes out of screen)
6265  				if (b._code & edge) {
6266  					p = _getEdgeIntersection(b, a, edge, bounds, round);
6267  					p._code = _getBitCode(p, bounds);
6268  					clippedPoints.push(p);
6269  				}
6270  				clippedPoints.push(a);
6271
6272  			// else if b is inside the clip window (a->b enters the screen)
6273  			} else if (!(b._code & edge)) {
6274  				p = _getEdgeIntersection(b, a, edge, bounds, round);
6275  				p._code = _getBitCode(p, bounds);
6276  				clippedPoints.push(p);
6277  			}
6278  		}
6279  		points = clippedPoints;
6280  	}
6281
6282  	return points;
6283  }
6284
6285  var PolyUtil = {
6286    __proto__: null,
6287    clipPolygon: clipPolygon
6288  };
6289
6290  /*
6291   * @namespace Projection
6292   * @section
6293   * Leaflet comes with a set of already defined Projections out of the box:
6294   *
6295   * @projection L.Projection.LonLat
6296   *
6297   * Equirectangular, or Plate Carree projection — the most simple projection,
6298   * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as
6299   * latitude. Also suitable for flat worlds, e.g. game maps. Used by the
6300   * `EPSG:4326` and `Simple` CRS.
6301   */
6302
6303  var LonLat = {
6304  	project: function (latlng) {
6305  		return new Point(latlng.lng, latlng.lat);
6306  	},
6307
6308  	unproject: function (point) {
6309  		return new LatLng(point.y, point.x);
6310  	},
6311
6312  	bounds: new Bounds([-180, -90], [180, 90])
6313  };
6314
6315  /*
6316   * @namespace Projection
6317   * @projection L.Projection.Mercator
6318   *
6319   * Elliptical Mercator projection — more complex than Spherical Mercator. Assumes that Earth is an ellipsoid. Used by the EPSG:3395 CRS.
6320   */
6321
6322  var Mercator = {
6323  	R: 6378137,
6324  	R_MINOR: 6356752.314245179,
6325
6326  	bounds: new Bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]),
6327
6328  	project: function (latlng) {
6329  		var d = Math.PI / 180,
6330  		    r = this.R,
6331  		    y = latlng.lat * d,
6332  		    tmp = this.R_MINOR / r,
6333  		    e = Math.sqrt(1 - tmp * tmp),
6334  		    con = e * Math.sin(y);
6335
6336  		var ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2);
6337  		y = -r * Math.log(Math.max(ts, 1E-10));
6338
6339  		return new Point(latlng.lng * d * r, y);
6340  	},
6341
6342  	unproject: function (point) {
6343  		var d = 180 / Math.PI,
6344  		    r = this.R,
6345  		    tmp = this.R_MINOR / r,
6346  		    e = Math.sqrt(1 - tmp * tmp),
6347  		    ts = Math.exp(-point.y / r),
6348  		    phi = Math.PI / 2 - 2 * Math.atan(ts);
6349
6350  		for (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) {
6351  			con = e * Math.sin(phi);
6352  			con = Math.pow((1 - con) / (1 + con), e / 2);
6353  			dphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi;
6354  			phi += dphi;
6355  		}
6356
6357  		return new LatLng(phi * d, point.x * d / r);
6358  	}
6359  };
6360
6361  /*
6362   * @class Projection
6363
6364   * An object with methods for projecting geographical coordinates of the world onto
6365   * a flat surface (and back). See [Map projection](http
vendor: 6,145 bytes, lines 6365-6576
6365://en.wikipedia.org/wiki/Map_projection).
6366
6367   * @property bounds: Bounds
6368   * The bounds (specified in CRS units) where the projection is valid
6369
6370   * @method project(latlng: LatLng): Point
6371   * Projects geographical coordinates into a 2D point.
6372   * Only accepts actual `L.LatLng` instances, not arrays.
6373
6374   * @method unproject(point: Point): LatLng
6375   * The inverse of `project`. Projects a 2D point into a geographical location.
6376   * Only accepts actual `L.Point` instances, not arrays.
6377
6378   * Note that the projection instances do not inherit from Leaflet's `Class` object,
6379   * and can't be instantiated. Also, new classes can't inherit from them,
6380   * and methods can't be added to them with the `include` function.
6381
6382   */
6383
6384  var index = {
6385    __proto__: null,
6386    LonLat: LonLat,
6387    Mercator: Mercator,
6388    SphericalMercator: SphericalMercator
6389  };
6390
6391  /*
6392   * @namespace CRS
6393   * @crs L.CRS.EPSG3395
6394   *
6395   * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection.
6396   */
6397  var EPSG3395 = extend({}, Earth, {
6398  	code: 'EPSG:3395',
6399  	projection: Mercator,
6400
6401  	transformation: (function () {
6402  		var scale = 0.5 / (Math.PI * Mercator.R);
6403  		return toTransformation(scale, 0.5, -scale, 0.5);
6404  	}())
6405  });
6406
6407  /*
6408   * @namespace CRS
6409   * @crs L.CRS.EPSG4326
6410   *
6411   * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection.
6412   *
6413   * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic),
6414   * which is a breaking change from 0.7.x behaviour.  If you are using a `TileLayer`
6415   * with this CRS, ensure that there are two 256x256 pixel tiles covering the
6416   * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90),
6417   * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set.
6418   */
6419
6420  var EPSG4326 = extend({}, Earth, {
6421  	code: 'EPSG:4326',
6422  	projection: LonLat,
6423  	transformation: toTransformation(1 / 180, 1, -1 / 180, 0.5)
6424  });
6425
6426  /*
6427   * @namespace CRS
6428   * @crs L.CRS.Simple
6429   *
6430   * A simple CRS that maps longitude and latitude into `x` and `y` directly.
6431   * May be used for maps of flat surfaces (e.g. game maps). Note that the `y`
6432   * axis should still be inverted (going from bottom to top). `distance()` returns
6433   * simple euclidean distance.
6434   */
6435
6436  var Simple = extend({}, CRS, {
6437  	projection: LonLat,
6438  	transformation: toTransformation(1, 0, -1, 0),
6439
6440  	scale: function (zoom) {
6441  		return Math.pow(2, zoom);
6442  	},
6443
6444  	zoom: function (scale) {
6445  		return Math.log(scale) / Math.LN2;
6446  	},
6447
6448  	distance: function (latlng1, latlng2) {
6449  		var dx = latlng2.lng - latlng1.lng,
6450  		    dy = latlng2.lat - latlng1.lat;
6451
6452  		return Math.sqrt(dx * dx + dy * dy);
6453  	},
6454
6455  	infinite: true
6456  });
6457
6458  CRS.Earth = Earth;
6459  CRS.EPSG3395 = EPSG3395;
6460  CRS.EPSG3857 = EPSG3857;
6461  CRS.EPSG900913 = EPSG900913;
6462  CRS.EPSG4326 = EPSG4326;
6463  CRS.Simple = Simple;
6464
6465  /*
6466   * @class Layer
6467   * @inherits Evented
6468   * @aka L.Layer
6469   * @aka ILayer
6470   *
6471   * A set of methods from the Layer base class that all Leaflet layers use.
6472   * Inherits all methods, options and events from `L.Evented`.
6473   *
6474   * @example
6475   *
6476   * ```js
6477   * var layer = L.marker(latlng).addTo(map);
6478   * layer.addTo(map);
6479   * layer.remove();
6480   * ```
6481   *
6482   * @event add: Event
6483   * Fired after the layer is added to a map
6484   *
6485   * @event remove: Event
6486   * Fired after the layer is removed from a map
6487   */
6488
6489
6490  var Layer = Evented.extend({
6491
6492  	// Classes extending `L.Layer` will inherit the following options:
6493  	options: {
6494  		// @option pane: String = 'overlayPane'
6495  		// 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.
6496  		pane: 'overlayPane',
6497
6498  		// @option attribution: String = null
6499  		// 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.
6500  		attribution: null,
6501
6502  		bubblingMouseEvents: true
6503  	},
6504
6505  	/* @section
6506  	 * Classes extending `L.Layer` will inherit the following methods:
6507  	 *
6508  	 * @method addTo(map: Map|LayerGroup): this
6509  	 * Adds the layer to the given map or layer group.
6510  	 */
6511  	addTo: function (map) {
6512  		map.addLayer(this);
6513  		return this;
6514  	},
6515
6516  	// @method remove: this
6517  	// Removes the layer from the map it is currently active on.
6518  	remove: function () {
6519  		return this.removeFrom(this._map || this._mapToAdd);
6520  	},
6521
6522  	// @method removeFrom(map: Map): this
6523  	// Removes the layer from the given map
6524  	//
6525  	// @alternative
6526  	// @method removeFrom(group: LayerGroup): this
6527  	// Removes the layer from the given `LayerGroup`
6528  	removeFrom: function (obj) {
6529  		if (obj) {
6530  			obj.removeLayer(this);
6531  		}
6532  		return this;
6533  	},
6534
6535  	// @method getPane(name? : String): HTMLElement
6536  	// Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer.
6537  	getPane: function (name) {
6538  		return this._map.getPane(name ? (this.options[name] || name) : this.options.pane);
6539  	},
6540
6541  	addInteractiveTarget: function (targetEl) {
6542  		this._map._targets[stamp(targetEl)] = this;
6543  		return this;
6544  	},
6545
6546  	removeInteractiveTarget: function (targetEl) {
6547  		delete this._map._targets[stamp(targetEl)];
6548  		return this;
6549  	},
6550
6551  	// @method getAttribution: String
6552  	// Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution).
6553  	getAttribution: function () {
6554  		return this.options.attribution;
6555  	},
6556
6557  	_layerAdd: function (e) {
6558  		var map = e.target;
6559
6560  		// check in case layer gets added and then removed before the map is ready
6561  		if (!map.hasLayer(this)) { return; }
6562
6563  		this._map = map;
6564  		this._zoomAnimated = map._zoomAnimated;
6565
6566  		if (this.getEvents) {
6567  			var events = this.getEvents();
6568  			map.on(events, this);
6569  			this.once('remove', function () {
6570  				map.off(events, this);
6571  			}, this);
6572  		}
6573
6574  		this.onAdd(map);
6575
6576  		
6576if (this.getAttribution && map.attributionControl) {
6577  			map.attributionControl.addAttribution(this.getAttribution());
6578  		}
6579
6580  		this.fire('add');
6581  		map.fire('layeradd', {layer: this});
6582  	}
6583  });
6584
6585  /* @section Extension methods
6586   * @uninheritable
6587   *
6588   * Every layer should extend from `L.Layer` and (re-)implement the following methods.
6589   *
6590   * @method onAdd(map: Map): this
6591   * 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).
6592   *
6593   * @method onRemove(map: Map): this
6594   * 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).
6595   *
6596   * @method getEvents(): Object
6597   * 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.
6598   *
6599   * @method getAttribution(): String
6600   * This optional method should return a string containing HTML to be shown on the `Attribution control` whenever the layer is visible.
6601   *
6602   * @method beforeAdd(map: Map): this
6603   * 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.
6604   */
6605
6606
6607  /* @namespace Map
6608   * @section Layer events
6609   *
6610   * @event layeradd: LayerEvent
6611   * Fired when a new layer is added to the map.
6612   *
6613   * @event layerremove: LayerEvent
6614   * Fired when some layer is removed from the map
6615   *
6616   * @section Methods for Layers and Controls
6617   */
6618  Map.include({
6619  	// @method addLayer(layer: Layer): this
6620  	// Adds the given layer to the map
6621  	addLayer: function (layer) {
6622  		if (!layer._layerAdd) {
6623  			throw new Error('The provided object is not a Layer.');
6624  		}
6625
6626  		var id = stamp(layer);
6627  		if (this._layers[id]) { return this; }
6628  		this._layers[id] = layer;
6629
6630  		layer._mapToAdd = this;
6631
6632  		if (layer.beforeAdd) {
6633  			layer.beforeAdd(this);
6634  		}
6635
6636  		this.whenReady(layer._layerAdd, layer);
6637
6638  		return this;
6639  	},
6640
6641  	// @method removeLayer(layer: Layer): this
6642  	// Removes the given layer from the map.
6643  	removeLayer: function (layer) {
6644  		var id = stamp(layer);
6645
6646  		if (!this._layers[id]) { return this; }
6647
6648  		if (this._loaded) {
6649  			layer.onRemove(this);
6650  		}
6651
6652  		if (layer.getAttribution && this.attributionControl) {
6653  			this.attributionControl.removeAttribution(layer.getAttribution());
6654  		}
6655
6656  		delete this._layers[id];
6657
6658  		if (this._loaded) {
6659  			this.fire('layerremove', {layer: layer});
6660  			layer.fire('remove');
6661  		}
6662
6663  		layer._map = layer._mapToAdd = null;
6664
6665  		return this;
6666  	},
6667
6668  	// @method hasLayer(layer: Layer): Boolean
6669  	// Returns `true` if the given layer is currently added to the map
6670  	hasLayer: function (layer) {
6671  		return !!layer && (stamp(layer) in this._layers);
6672  	},
6673
6674  	/* @method eachLayer(fn: Function, context?: Object): this
6675  	 * Iterates over the layers of the map, optionally specifying context of the iterator function.
6676  	 * ```
6677  	 * map.eachLayer(function(layer){
6678  	 *     layer.bindPopup('Hello');
6679  	 * });
6680  	 * ```
6681  	 */
6682  	eachLayer: function (method, context) {
6683  		for (var i in this._layers) {
6684  			method.call(context, this._layers[i]);
6685  		}
6686  		return this;
6687  	},
6688
6689  	_addLayers: function (layers) {
6690  		layers = layers ? (isArray(layers) ? layers : [layers]) : [];
6691
6692  		for (var i = 0, len = layers.length; i < len; i++) {
6693  			this.addLayer(layers[i]);
6694  		}
6695  	},
6696
6697  	_addZoomLimit: function (layer) {
6698  		if (isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {
6699  			this._zoomBoundLayers[stamp(layer)] = layer;
6700  			this._updateZoomLevels();
6701  		}
6702  	},
6703
6704  	_removeZoomLimit: function (layer) {
6705  		var id = stamp(layer);
6706
6707  		if (this._zoomBoundLayers[id]) {
6708  			delete this._zoomBoundLayers[id];
6709  			this._updateZoomLevels();
6710  		}
6711  	},
6712
6713  	_updateZoomLevels: function () {
6714  		var minZoom = Infinity,
6715  		    maxZoom = -Infinity,
6716  		    oldZoomSpan = this._getZoomSpan();
6717
6718  		for (var i in this._zoomBoundLayers) {
6719  			var options = this._zoomBoundLayers[i].options;
6720
vendor: 2,756 bytes, lines 6721-6816
6721  			minZoom = options.minZoom === undefined ? minZoom : Math.min(minZoom, options.minZoom);
6722  			maxZoom = options.maxZoom === undefined ? maxZoom : Math.max(maxZoom, options.maxZoom);
6723  		}
6724
6725  		this._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom;
6726  		this._layersMinZoom = minZoom === Infinity ? undefined : minZoom;
6727
6728  		// @section Map state change events
6729  		// @event zoomlevelschange: Event
6730  		// Fired when the number of zoomlevels on the map is changed due
6731  		// to adding or removing a layer.
6732  		if (oldZoomSpan !== this._getZoomSpan()) {
6733  			this.fire('zoomlevelschange');
6734  		}
6735
6736  		if (this.options.maxZoom === undefined && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) {
6737  			this.setZoom(this._layersMaxZoom);
6738  		}
6739  		if (this.options.minZoom === undefined && this._layersMinZoom && this.getZoom() < this._layersMinZoom) {
6740  			this.setZoom(this._layersMinZoom);
6741  		}
6742  	}
6743  });
6744
6745  /*
6746   * @class LayerGroup
6747   * @aka L.LayerGroup
6748   * @inherits Layer
6749   *
6750   * Used to group several layers and handle them as one. If you add it to the map,
6751   * any layers added or removed from the group will be added/removed on the map as
6752   * well. Extends `Layer`.
6753   *
6754   * @example
6755   *
6756   * ```js
6757   * L.layerGroup([marker1, marker2])
6758   * 	.addLayer(polyline)
6759   * 	.addTo(map);
6760   * ```
6761   */
6762
6763  var LayerGroup = Layer.extend({
6764
6765  	initialize: function (layers, options) {
6766  		setOptions(this, options);
6767
6768  		this._layers = {};
6769
6770  		var i, len;
6771
6772  		if (layers) {
6773  			for (i = 0, len = layers.length; i < len; i++) {
6774  				this.addLayer(layers[i]);
6775  			}
6776  		}
6777  	},
6778
6779  	// @method addLayer(layer: Layer): this
6780  	// Adds the given layer to the group.
6781  	addLayer: function (layer) {
6782  		var id = this.getLayerId(layer);
6783
6784  		this._layers[id] = layer;
6785
6786  		if (this._map) {
6787  			this._map.addLayer(layer);
6788  		}
6789
6790  		return this;
6791  	},
6792
6793  	// @method removeLayer(layer: Layer): this
6794  	// Removes the given layer from the group.
6795  	// @alternative
6796  	// @method removeLayer(id: Number): this
6797  	// Removes the layer with the given internal ID from the group.
6798  	removeLayer: function (layer) {
6799  		var id = layer in this._layers ? layer : this.getLayerId(layer);
6800
6801  		if (this._map && this._layers[id]) {
6802  			this._map.removeLayer(this._layers[id]);
6803  		}
6804
6805  		delete this._layers[id];
6806
6807  		return this;
6808  	},
6809
6810  	// @method hasLayer(layer: Layer): Boolean
6811  	// Returns `true` if the given layer is currently added to the group.
6812  	// @alternative
6813  	// @method hasLayer(id: Number): Boolean
6814  	// Returns `true` if the given internal ID is currently added to the group.
6815  	hasLayer: function (layer) {
6816  		if (!layer) { return false; }
vendor: 7,845 bytes, lines 6816-7066
6816
6817  		var layerId = typeof layer === 'number' ? layer : this.getLayerId(layer);
6818  		return layerId in this._layers;
6819  	},
6820
6821  	// @method clearLayers(): this
6822  	// Removes all the layers from the group.
6823  	clearLayers: function () {
6824  		return this.eachLayer(this.removeLayer, this);
6825  	},
6826
6827  	// @method invoke(methodName: String, …): this
6828  	// Calls `methodName` on every layer contained in this group, passing any
6829  	// additional parameters. Has no effect if the layers contained do not
6830  	// implement `methodName`.
6831  	invoke: function (methodName) {
6832  		var args = Array.prototype.slice.call(arguments, 1),
6833  		    i, layer;
6834
6835  		for (i in this._layers) {
6836  			layer = this._layers[i];
6837
6838  			if (layer[methodName]) {
6839  				layer[methodName].apply(layer, args);
6840  			}
6841  		}
6842
6843  		return this;
6844  	},
6845
6846  	onAdd: function (map) {
6847  		this.eachLayer(map.addLayer, map);
6848  	},
6849
6850  	onRemove: function (map) {
6851  		this.eachLayer(map.removeLayer, map);
6852  	},
6853
6854  	// @method eachLayer(fn: Function, context?: Object): this
6855  	// Iterates over the layers of the group, optionally specifying context of the iterator function.
6856  	// ```js
6857  	// group.eachLayer(function (layer) {
6858  	// 	layer.bindPopup('Hello');
6859  	// });
6860  	// ```
6861  	eachLayer: function (method, context) {
6862  		for (var i in this._layers) {
6863  			method.call(context, this._layers[i]);
6864  		}
6865  		return this;
6866  	},
6867
6868  	// @method getLayer(id: Number): Layer
6869  	// Returns the layer with the given internal ID.
6870  	getLayer: function (id) {
6871  		return this._layers[id];
6872  	},
6873
6874  	// @method getLayers(): Layer[]
6875  	// Returns an array of all the layers added to the group.
6876  	getLayers: function () {
6877  		var layers = [];
6878  		this.eachLayer(layers.push, layers);
6879  		return layers;
6880  	},
6881
6882  	// @method setZIndex(zIndex: Number): this
6883  	// Calls `setZIndex` on every layer contained in this group, passing the z-index.
6884  	setZIndex: function (zIndex) {
6885  		return this.invoke('setZIndex', zIndex);
6886  	},
6887
6888  	// @method getLayerId(layer: Layer): Number
6889  	// Returns the internal ID for a layer
6890  	getLayerId: function (layer) {
6891  		return stamp(layer);
6892  	}
6893  });
6894
6895
6896  // @factory L.layerGroup(layers?: Layer[], options?: Object)
6897  // Create a layer group, optionally given an initial set of layers and an `options` object.
6898  var layerGroup = function (layers, options) {
6899  	return new LayerGroup(layers, options);
6900  };
6901
6902  /*
6903   * @class FeatureGroup
6904   * @aka L.FeatureGroup
6905   * @inherits LayerGroup
6906   *
6907   * Extended `LayerGroup` that makes it easier to do the same thing to all its member layers:
6908   *  * [`bindPopup`](#layer-bindpopup) binds a popup to all of the layers at once (likewise with [`bindTooltip`](#layer-bindtooltip))
6909   *  * Events are propagated to the `FeatureGroup`, so if the group has an event
6910   * handler, it will handle events from any of the layers. This includes mouse events
6911   * and custom events.
6912   *  * Has `layeradd` and `layerremove` events
6913   *
6914   * @example
6915   *
6916   * ```js
6917   * L.featureGroup([marker1, marker2, polyline])
6918   * 	.bindPopup('Hello world!')
6919   * 	.on('click', function() { alert('Clicked on a member of the group!'); })
6920   * 	.addTo(map);
6921   * ```
6922   */
6923
6924  var FeatureGroup = LayerGroup.extend({
6925
6926  	addLayer: function (layer) {
6927  		if (this.hasLayer(layer)) {
6928  			return this;
6929  		}
6930
6931  		layer.addEventParent(this);
6932
6933  		LayerGroup.prototype.addLayer.call(this, layer);
6934
6935  		// @event layeradd: LayerEvent
6936  		// Fired when a layer is added to this `FeatureGroup`
6937  		return this.fire('layeradd', {layer: layer});
6938  	},
6939
6940  	removeLayer: function (layer) {
6941  		if (!this.hasLayer(layer)) {
6942  			return this;
6943  		}
6944  		if (layer in this._layers) {
6945  			layer = this._layers[layer];
6946  		}
6947
6948  		layer.removeEventParent(this);
6949
6950  		LayerGroup.prototype.removeLayer.call(this, layer);
6951
6952  		// @event layerremove: LayerEvent
6953  		// Fired when a layer is removed from this `FeatureGroup`
6954  		return this.fire('layerremove', {layer: layer});
6955  	},
6956
6957  	// @method setStyle(style: Path options): this
6958  	// Sets the given path options to each layer of the group that has a `setStyle` method.
6959  	setStyle: function (style) {
6960  		return this.invoke('setStyle', style);
6961  	},
6962
6963  	// @method bringToFront(): this
6964  	// Brings the layer group to the top of all other layers
6965  	bringToFront: function () {
6966  		return this.invoke('bringToFront');
6967  	},
6968
6969  	// @method bringToBack(): this
6970  	// Brings the layer group to the back of all other layers
6971  	bringToBack: function () {
6972  		return this.invoke('bringToBack');
6973  	},
6974
6975  	// @method getBounds(): LatLngBounds
6976  	// Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).
6977  	getBounds: function () {
6978  		var bounds = new LatLngBounds();
6979
6980  		for (var id in this._layers) {
6981  			var layer = this._layers[id];
6982  			bounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());
6983  		}
6984  		return bounds;
6985  	}
6986  });
6987
6988  // @factory L.featureGroup(layers?: Layer[], options?: Object)
6989  // Create a feature group, optionally given an initial set of layers and an `options` object.
6990  var featureGroup = function (layers, options) {
6991  	return new FeatureGroup(layers, options);
6992  };
6993
6994  /*
6995   * @class Icon
6996   * @aka L.Icon
6997   *
6998   * Represents an icon to provide when creating a marker.
6999   *
7000   * @example
7001   *
7002   * ```js
7003   * var myIcon = L.icon({
7004   *     iconUrl: 'my-icon.png',
7005   *     iconRetinaUrl: '[email protected]',
7006   *     iconSize: [38, 95],
7007   *     iconAnchor: [22, 94],
7008   *     popupAnchor: [-3, -76],
7009   *     shadowUrl: 'my-icon-shadow.png',
7010   *     shadowRetinaUrl: '[email protected]',
7011   *     shadowSize: [68, 95],
7012   *     shadowAnchor: [22, 94]
7013   * });
7014   *
7015   * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
7016   * ```
7017   *
7018   * `L.Icon.Default` extends `L.Icon` and is the blue icon Leaflet uses for markers by default.
7019   *
7020   */
7021
7022  var Icon = Class.extend({
7023
7024  	/* @section
7025  	 * @aka Icon options
7026  	 *
7027  	 * @option iconUrl: String = null
7028  	 * **(required)** The URL to the icon image (absolute or relative to your script path).
7029  	 *
7030  	 * @option iconRetinaUrl: String = null
7031  	 * The URL to a retina sized version of the icon image (absolute or relative to your
7032  	 * script path). Used for Retina screen devices.
7033  	 *
7034  	 * @option iconSize: Point = null
7035  	 * Size of the icon image in pixels.
7036  	 *
7037  	 * @option iconAnchor: Point = null
7038  	 * The coordinates of the "tip" of the icon (relative to its top left corner). The icon
7039  	 * will be aligned so that this point is at the marker's geographical location. Centered
7040  	 * by default if size is specified, also can be set in CSS with negative margins.
7041  	 *
7042  	 * @option popupAnchor: Point = [0, 0]
7043  	 * The coordinates of the point from which popups will "open", relative to the icon anchor.
7044  	 *
7045  	 * @option tooltipAnchor: Point = [0, 0]
7046  	 * The coordinates of the point from which tooltips will "open", relative to the icon anchor.
7047  	 *
7048  	 * @option shadowUrl: String = null
7049  	 * The URL to the icon shadow image. If not specified, no shadow image will be created.
7050  	 *
7051  	 * @option shadowRetinaUrl: String = null
7052  	 *
7053  	 * @option shadowSize: Point = null
7054  	 * Size of the shadow image in pixels.
7055  	 *
7056  	 * @option shadowAnchor: Point = null
7057  	 * The coordinates of the "tip" of the shadow (relative to its top left corner) (the same
7058  	 * as iconAnchor if not specified).
7059  	 *
7060  	 * @option className: String = ''
7061  	 * A custom class name to assign to both icon and shadow images. Empty by default.
7062  	 */
7063
7064  	options: {
7065  		popupAnchor: [0, 0],
7066  		tooltipAnchor: [0, 0]
vendor: 22,921 bytes, lines 7066-7879
7066
7067  	},
7068
7069  	initialize: function (options) {
7070  		setOptions(this, options);
7071  	},
7072
7073  	// @method createIcon(oldIcon?: HTMLElement): HTMLElement
7074  	// Called internally when the icon has to be shown, returns a `<img>` HTML element
7075  	// styled according to the options.
7076  	createIcon: function (oldIcon) {
7077  		return this._createIcon('icon', oldIcon);
7078  	},
7079
7080  	// @method createShadow(oldIcon?: HTMLElement): HTMLElement
7081  	// As `createIcon`, but for the shadow beneath it.
7082  	createShadow: function (oldIcon) {
7083  		return this._createIcon('shadow', oldIcon);
7084  	},
7085
7086  	_createIcon: function (name, oldIcon) {
7087  		var src = this._getIconUrl(name);
7088
7089  		if (!src) {
7090  			if (name === 'icon') {
7091  				throw new Error('iconUrl not set in Icon options (see the docs).');
7092  			}
7093  			return null;
7094  		}
7095
7096  		var img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null);
7097  		this._setIconStyles(img, name);
7098
7099  		return img;
7100  	},
7101
7102  	_setIconStyles: function (img, name) {
7103  		var options = this.options;
7104  		var sizeOption = options[name + 'Size'];
7105
7106  		if (typeof sizeOption === 'number') {
7107  			sizeOption = [sizeOption, sizeOption];
7108  		}
7109
7110  		var size = toPoint(sizeOption),
7111  		    anchor = toPoint(name === 'shadow' && options.shadowAnchor || options.iconAnchor ||
7112  		            size && size.divideBy(2, true));
7113
7114  		img.className = 'leaflet-marker-' + name + ' ' + (options.className || '');
7115
7116  		if (anchor) {
7117  			img.style.marginLeft = (-anchor.x) + 'px';
7118  			img.style.marginTop  = (-anchor.y) + 'px';
7119  		}
7120
7121  		if (size) {
7122  			img.style.width  = size.x + 'px';
7123  			img.style.height = size.y + 'px';
7124  		}
7125  	},
7126
7127  	_createImg: function (src, el) {
7128  		el = el || document.createElement('img');
7129  		el.src = src;
7130  		return el;
7131  	},
7132
7133  	_getIconUrl: function (name) {
7134  		return retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url'];
7135  	}
7136  });
7137
7138
7139  // @factory L.icon(options: Icon options)
7140  // Creates an icon instance with the given options.
7141  function icon(options) {
7142  	return new Icon(options);
7143  }
7144
7145  /*
7146   * @miniclass Icon.Default (Icon)
7147   * @aka L.Icon.Default
7148   * @section
7149   *
7150   * A trivial subclass of `Icon`, represents the icon to use in `Marker`s when
7151   * no icon is specified. Points to the blue marker image distributed with Leaflet
7152   * releases.
7153   *
7154   * In order to customize the default icon, just change the properties of `L.Icon.Default.prototype.options`
7155   * (which is a set of `Icon options`).
7156   *
7157   * If you want to _completely_ replace the default icon, override the
7158   * `L.Marker.prototype.options.icon` with your own icon instead.
7159   */
7160
7161  var IconDefault = Icon.extend({
7162
7163  	options: {
7164  		iconUrl:       'marker-icon.png',
7165  		iconRetinaUrl: 'marker-icon-2x.png',
7166  		shadowUrl:     'marker-shadow.png',
7167  		iconSize:    [25, 41],
7168  		iconAnchor:  [12, 41],
7169  		popupAnchor: [1, -34],
7170  		tooltipAnchor: [16, -28],
7171  		shadowSize:  [41, 41]
7172  	},
7173
7174  	_getIconUrl: function (name) {
7175  		if (!IconDefault.imagePath) {	// Deprecated, backwards-compatibility only
7176  			IconDefault.imagePath = this._detectIconPath();
7177  		}
7178
7179  		// @option imagePath: String
7180  		// `Icon.Default` will try to auto-detect the location of the
7181  		// blue icon images. If you are placing these images in a non-standard
7182  		// way, set this option to point to the right path.
7183  		return (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name);
7184  	},
7185
7186  	_detectIconPath: function () {
7187  		var el = create$1('div',  'leaflet-default-icon-path', document.body);
7188  		var path = getStyle(el, 'background-image') ||
7189  		           getStyle(el, 'backgroundImage');	// IE8
7190
7191  		document.body.removeChild(el);
7192
7193  		if (path === null || path.indexOf('url') !== 0) {
7194  			path = '';
7195  		} else {
7196  			path = path.replace(/^url\(["']?/, '').replace(/marker-icon\.png["']?\)$/, '');
7197  		}
7198
7199  		return path;
7200  	}
7201  });
7202
7203  /*
7204   * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.
7205   */
7206
7207
7208  /* @namespace Marker
7209   * @section Interaction handlers
7210   *
7211   * 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:
7212   *
7213   * ```js
7214   * marker.dragging.disable();
7215   * ```
7216   *
7217   * @property dragging: Handler
7218   * Marker dragging handler (by both mouse and touch). Only valid when the marker is on the map (Otherwise set [`marker.options.draggable`](#marker-draggable)).
7219   */
7220
7221  var MarkerDrag = Handler.extend({
7222  	initialize: function (marker) {
7223  		this._marker = marker;
7224  	},
7225
7226  	addHooks: function () {
7227  		var icon = this._marker._icon;
7228
7229  		if (!this._draggable) {
7230  			this._draggable = new Draggable(icon, icon, true);
7231  		}
7232
7233  		this._draggable.on({
7234  			dragstart: this._onDragStart,
7235  			predrag: this._onPreDrag,
7236  			drag: this._onDrag,
7237  			dragend: this._onDragEnd
7238  		}, this).enable();
7239
7240  		addClass(icon, 'leaflet-marker-draggable');
7241  	},
7242
7243  	removeHooks: function () {
7244  		this._draggable.off({
7245  			dragstart: this._onDragStart,
7246  			predrag: this._onPreDrag,
7247  			drag: this._onDrag,
7248  			dragend: this._onDragEnd
7249  		}, this).disable();
7250
7251  		if (this._marker._icon) {
7252  			removeClass(this._marker._icon, 'leaflet-marker-draggable');
7253  		}
7254  	},
7255
7256  	moved: function () {
7257  		return this._draggable && this._draggable._moved;
7258  	},
7259
7260  	_adjustPan: function (e) {
7261  		var marker = this._marker,
7262  		    map = marker._map,
7263  		    speed = this._marker.options.autoPanSpeed,
7264  		    padding = this._marker.options.autoPanPadding,
7265  		    iconPos = getPosition(marker._icon),
7266  		    bounds = map.getPixelBounds(),
7267  		    origin = map.getPixelOrigin();
7268
7269  		var panBounds = toBounds(
7270  			bounds.min._subtract(origin).add(padding),
7271  			bounds.max._subtract(origin).subtract(padding)
7272  		);
7273
7274  		if (!panBounds.contains(iconPos)) {
7275  			// Compute incremental movement
7276  			var movement = toPoint(
7277  				(Math.max(panBounds.max.x, iconPos.x) - panBounds.max.x) / (bounds.max.x - panBounds.max.x) -
7278  				(Math.min(panBounds.min.x, iconPos.x) - panBounds.min.x) / (bounds.min.x - panBounds.min.x),
7279
7280  				(Math.max(panBounds.max.y, iconPos.y) - panBounds.max.y) / (bounds.max.y - panBounds.max.y) -
7281  				(Math.min(panBounds.min.y, iconPos.y) - panBounds.min.y) / (bounds.min.y - panBounds.min.y)
7282  			).multiplyBy(speed);
7283
7284  			map.panBy(movement, {animate: false});
7285
7286  			this._draggable._newPos._add(movement);
7287  			this._draggable._startPos._add(movement);
7288
7289  			setPosition(marker._icon, this._draggable._newPos);
7290  			this._onDrag(e);
7291
7292  			this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
7293  		}
7294  	},
7295
7296  	_onDragStart: function () {
7297  		// @section Dragging events
7298  		// @event dragstart: Event
7299  		// Fired when the user starts dragging the marker.
7300
7301  		// @event movestart: Event
7302  		// Fired when the marker starts moving (because of dragging).
7303
7304  		this._oldLatLng = this._marker.getLatLng();
7305
7306  		// When using ES6 imports it could not be set when `Popup` was not imported as well
7307  		this._marker.closePopup && this._marker.closePopup();
7308
7309  		this._marker
7310  			.fire('movestart')
7311  			.fire('dragstart');
7312  	},
7313
7314  	_onPreDrag: function (e) {
7315  		if (this._marker.options.autoPan) {
7316  			cancelAnimFrame(this._panRequest);
7317  			this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
7318  		}
7319  	},
7320
7321  	_onDrag: function (e) {
7322  		var marker = this._marker,
7323  		    shadow = marker._shadow,
7324  		    iconPos = getPosition(marker._icon),
7325  		    latlng = marker._map.layerPointToLatLng(iconPos);
7326
7327  		// update shadow position
7328  		if (shadow) {
7329  			setPosition(shadow, iconPos);
7330  		}
7331
7332  		marker._latlng = latlng;
7333  		e.latlng = latlng;
7334  		e.oldLatLng = this._oldLatLng;
7335
7336  		// @event drag: Event
7337  		// Fired repeatedly while the user drags the marker.
7338  		marker
7339  		    .fire('move', e)
7340  		    .fire('drag', e);
7341  	},
7342
7343  	_onDragEnd: function (e) {
7344  		// @event dragend: DragEndEvent
7345  		// Fired when the user stops dragging the marker.
7346
7347  		 cancelAnimFrame(this._panRequest);
7348
7349  		// @event moveend: Event
7350  		// Fired when the marker stops moving (because of dragging).
7351  		delete this._oldLatLng;
7352  		this._marker
7353  		    .fire('moveend')
7354  		    .fire('dragend', e);
7355  	}
7356  });
7357
7358  /*
7359   * @class Marker
7360   * @inherits Interactive layer
7361   * @aka L.Marker
7362   * L.Marker is used to display clickable/draggable icons on the map. Extends `Layer`.
7363   *
7364   * @example
7365   *
7366   * ```js
7367   * L.marker([50.5, 30.5]).addTo(map);
7368   * ```
7369   */
7370
7371  var Marker = Layer.extend({
7372
7373  	// @section
7374  	// @aka Marker options
7375  	options: {
7376  		// @option icon: Icon = *
7377  		// Icon instance to use for rendering the marker.
7378  		// See [Icon documentation](#L.Icon) for details on how to customize the marker icon.
7379  		// If not specified, a common instance of `L.Icon.Default` is used.
7380  		icon: new IconDefault(),
7381
7382  		// Option inherited from "Interactive layer" abstract class
7383  		interactive: true,
7384
7385  		// @option keyboard: Boolean = true
7386  		// Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.
7387  		keyboard: true,
7388
7389  		// @option title: String = ''
7390  		// Text for the browser tooltip that appear on marker hover (no tooltip by default).
7391  		title: '',
7392
7393  		// @option alt: String = ''
7394  		// Text for the `alt` attribute of the icon image (useful for accessibility).
7395  		alt: '',
7396
7397  		// @option zIndexOffset: Number = 0
7398  		// 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).
7399  		zIndexOffset: 0,
7400
7401  		// @option opacity: Number = 1.0
7402  		// The opacity of the marker.
7403  		opacity: 1,
7404
7405  		// @option riseOnHover: Boolean = false
7406  		// If `true`, the marker will get on top of others when you hover the mouse over it.
7407  		riseOnHover: false,
7408
7409  		// @option riseOffset: Number = 250
7410  		// The z-index offset used for the `riseOnHover` feature.
7411  		riseOffset: 250,
7412
7413  		// @option pane: String = 'markerPane'
7414  		// `Map pane` where the markers icon will be added.
7415  		pane: 'markerPane',
7416
7417  		// @option shadowPane: String = 'shadowPane'
7418  		// `Map pane` where the markers shadow will be added.
7419  		shadowPane: 'shadowPane',
7420
7421  		// @option bubblingMouseEvents: Boolean = false
7422  		// When `true`, a mouse event on this marker will trigger the same event on the map
7423  		// (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).
7424  		bubblingMouseEvents: false,
7425
7426  		// @section Draggable marker options
7427  		// @option draggable: Boolean = false
7428  		// Whether the marker is draggable with mouse/touch or not.
7429  		draggable: false,
7430
7431  		// @option autoPan: Boolean = false
7432  		// Whether to pan the map when dragging this marker near its edge or not.
7433  		autoPan: false,
7434
7435  		// @option autoPanPadding: Point = Point(50, 50)
7436  		// Distance (in pixels to the left/right and to the top/bottom) of the
7437  		// map edge to start panning the map.
7438  		autoPanPadding: [50, 50],
7439
7440  		// @option autoPanSpeed: Number = 10
7441  		// Number of pixels the map should pan by.
7442  		autoPanSpeed: 10
7443  	},
7444
7445  	/* @section
7446  	 *
7447  	 * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods:
7448  	 */
7449
7450  	initialize: function (latlng, options) {
7451  		setOptions(this, options);
7452  		this._latlng = toLatLng(latlng);
7453  	},
7454
7455  	onAdd: function (map) {
7456  		this._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation;
7457
7458  		if (this._zoomAnimated) {
7459  			map.on('zoomanim', this._animateZoom, this);
7460  		}
7461
7462  		this._initIcon();
7463  		this.update();
7464  	},
7465
7466  	onRemove: function (map) {
7467  		if (this.dragging && this.dragging.enabled()) {
7468  			this.options.draggable = true;
7469  			this.dragging.removeHooks();
7470  		}
7471  		delete this.dragging;
7472
7473  		if (this._zoomAnimated) {
7474  			map.off('zoomanim', this._animateZoom, this);
7475  		}
7476
7477  		this._removeIcon();
7478  		this._removeShadow();
7479  	},
7480
7481  	getEvents: function () {
7482  		return {
7483  			zoom: this.update,
7484  			viewreset: this.update
7485  		};
7486  	},
7487
7488  	// @method getLatLng: LatLng
7489  	// Returns the current geographical position of the marker.
7490  	getLatLng: function () {
7491  		return this._latlng;
7492  	},
7493
7494  	// @method setLatLng(latlng: LatLng): this
7495  	// Changes the marker position to the given point.
7496  	setLatLng: function (latlng) {
7497  		var oldLatLng = this._latlng;
7498  		this._latlng = toLatLng(latlng);
7499  		this.update();
7500
7501  		// @event move: Event
7502  		// 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`.
7503  		return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
7504  	},
7505
7506  	// @method setZIndexOffset(offset: Number): this
7507  	// Changes the [zIndex offset](#marker-zindexoffset) of the marker.
7508  	setZIndexOffset: function (offset) {
7509  		this.options.zIndexOffset = offset;
7510  		return this.update();
7511  	},
7512
7513  	// @method getIcon: Icon
7514  	// Returns the current icon used by the marker
7515  	getIcon: function () {
7516  		return this.options.icon;
7517  	},
7518
7519  	// @method setIcon(icon: Icon): this
7520  	// Changes the marker icon.
7521  	setIcon: function (icon) {
7522
7523  		this.options.icon = icon;
7524
7525  		if (this._map) {
7526  			this._initIcon();
7527  			this.update();
7528  		}
7529
7530  		if (this._popup) {
7531  			this.bindPopup(this._popup, this._popup.options);
7532  		}
7533
7534  		return this;
7535  	},
7536
7537  	getElement: function () {
7538  		return this._icon;
7539  	},
7540
7541  	update: function () {
7542
7543  		if (this._icon && this._map) {
7544  			var pos = this._map.latLngToLayerPoint(this._latlng).round();
7545  			this._setPos(pos);
7546  		}
7547
7548  		return this;
7549  	},
7550
7551  	_initIcon: function () {
7552  		var options = this.options,
7553  		    classToAdd = 'leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
7554
7555  		var icon = options.icon.createIcon(this._icon),
7556  		    addIcon = false;
7557
7558  		// if we're not reusing the icon, remove the old one and init new one
7559  		if (icon !== this._icon) {
7560  			if (this._icon) {
7561  				this._removeIcon();
7562  			}
7563  			addIcon = true;
7564
7565  			if (options.title) {
7566  				icon.title = options.title;
7567  			}
7568
7569  			if (icon.tagName === 'IMG') {
7570  				icon.alt = options.alt || '';
7571  			}
7572  		}
7573
7574  		addClass(icon, classToAdd);
7575
7576  		if (options.keyboard) {
7577  			icon.tabIndex = '0';
7578  		}
7579
7580  		this._icon = icon;
7581
7582  		if (options.riseOnHover) {
7583  			this.on({
7584  				mouseover: this._bringToFront,
7585  				mouseout: this._resetZIndex
7586  			});
7587  		}
7588
7589  		var newShadow = options.icon.createShadow(this._shadow),
7590  		    addShadow = false;
7591
7592  		if (newShadow !== this._shadow) {
7593  			this._removeShadow();
7594  			addShadow = true;
7595  		}
7596
7597  		if (newShadow) {
7598  			addClass(newShadow, classToAdd);
7599  			newShadow.alt = '';
7600  		}
7601  		this._shadow = newShadow;
7602
7603
7604  		if (options.opacity < 1) {
7605  			this._updateOpacity();
7606  		}
7607
7608
7609  		if (addIcon) {
7610  			this.getPane().appendChild(this._icon);
7611  		}
7612  		this._initInteraction();
7613  		if (newShadow && addShadow) {
7614  			this.getPane(options.shadowPane).appendChild(this._shadow);
7615  		}
7616  	},
7617
7618  	_removeIcon: function () {
7619  		if (this.options.riseOnHover) {
7620  			this.off({
7621  				mouseover: this._bringToFront,
7622  				mouseout: this._resetZIndex
7623  			});
7624  		}
7625
7626  		remove(this._icon);
7627  		this.removeInteractiveTarget(this._icon);
7628
7629  		this._icon = null;
7630  	},
7631
7632  	_removeShadow: function () {
7633  		if (this._shadow) {
7634  			remove(this._shadow);
7635  		}
7636  		this._shadow = null;
7637  	},
7638
7639  	_setPos: function (pos) {
7640
7641  		if (this._icon) {
7642  			setPosition(this._icon, pos);
7643  		}
7644
7645  		if (this._shadow) {
7646  			setPosition(this._shadow, pos);
7647  		}
7648
7649  		this._zIndex = pos.y + this.options.zIndexOffset;
7650
7651  		this._resetZIndex();
7652  	},
7653
7654  	_updateZIndex: function (offset) {
7655  		if (this._icon) {
7656  			this._icon.style.zIndex = this._zIndex + offset;
7657  		}
7658  	},
7659
7660  	_animateZoom: function (opt) {
7661  		var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
7662
7663  		this._setPos(pos);
7664  	},
7665
7666  	_initInteraction: function () {
7667
7668  		if (!this.options.interactive) { return; }
7669
7670  		addClass(this._icon, 'leaflet-interactive');
7671
7672  		this.addInteractiveTarget(this._icon);
7673
7674  		if (MarkerDrag) {
7675  			var draggable = this.options.draggable;
7676  			if (this.dragging) {
7677  				draggable = this.dragging.enabled();
7678  				this.dragging.disable();
7679  			}
7680
7681  			this.dragging = new MarkerDrag(this);
7682
7683  			if (draggable) {
7684  				this.dragging.enable();
7685  			}
7686  		}
7687  	},
7688
7689  	// @method setOpacity(opacity: Number): this
7690  	// Changes the opacity of the marker.
7691  	setOpacity: function (opacity) {
7692  		this.options.opacity = opacity;
7693  		if (this._map) {
7694  			this._updateOpacity();
7695  		}
7696
7697  		return this;
7698  	},
7699
7700  	_updateOpacity: function () {
7701  		var opacity = this.options.opacity;
7702
7703  		if (this._icon) {
7704  			setOpacity(this._icon, opacity);
7705  		}
7706
7707  		if (this._shadow) {
7708  			setOpacity(this._shadow, opacity);
7709  		}
7710  	},
7711
7712  	_bringToFront: function () {
7713  		this._updateZIndex(this.options.riseOffset);
7714  	},
7715
7716  	_resetZIndex: function () {
7717  		this._updateZIndex(0);
7718  	},
7719
7720  	_getPopupAnchor: function () {
7721  		return this.options.icon.options.popupAnchor;
7722  	},
7723
7724  	_getTooltipAnchor: function () {
7725  		return this.options.icon.options.tooltipAnchor;
7726  	}
7727  });
7728
7729
7730  // factory L.marker(latlng: LatLng, options? : Marker options)
7731
7732  // @factory L.marker(latlng: LatLng, options? : Marker options)
7733  // Instantiates a Marker object given a geographical point and optionally an options object.
7734  function marker(latlng, options) {
7735  	return new Marker(latlng, options);
7736  }
7737
7738  /*
7739   * @class Path
7740   * @aka L.Path
7741   * @inherits Interactive layer
7742   *
7743   * An abstract class that contains options and constants shared between vector
7744   * overlays (Polygon, Polyline, Circle). Do not use it directly. Extends `Layer`.
7745   */
7746
7747  var Path = Layer.extend({
7748
7749  	// @section
7750  	// @aka Path options
7751  	options: {
7752  		// @option stroke: Boolean = true
7753  		// Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles.
7754  		stroke: true,
7755
7756  		// @option color: String = '#3388ff'
7757  		// Stroke color
7758  		color: '#3388ff',
7759
7760  		// @option weight: Number = 3
7761  		// Stroke width in pixels
7762  		weight: 3,
7763
7764  		// @option opacity: Number = 1.0
7765  		// Stroke opacity
7766  		opacity: 1,
7767
7768  		// @option lineCap: String= 'round'
7769  		// A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke.
7770  		lineCap: 'round',
7771
7772  		// @option lineJoin: String = 'round'
7773  		// A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke.
7774  		lineJoin: 'round',
7775
7776  		// @option dashArray: String = null
7777  		// 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).
7778  		dashArray: null,
7779
7780  		// @option dashOffset: String = null
7781  		// 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).
7782  		dashOffset: null,
7783
7784  		// @option fill: Boolean = depends
7785  		// Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles.
7786  		fill: false,
7787
7788  		// @option fillColor: String = *
7789  		// Fill color. Defaults to the value of the [`color`](#path-color) option
7790  		fillColor: null,
7791
7792  		// @option fillOpacity: Number = 0.2
7793  		// Fill opacity.
7794  		fillOpacity: 0.2,
7795
7796  		// @option fillRule: String = 'evenodd'
7797  		// A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined.
7798  		fillRule: 'evenodd',
7799
7800  		// className: '',
7801
7802  		// Option inherited from "Interactive layer" abstract class
7803  		interactive: true,
7804
7805  		// @option bubblingMouseEvents: Boolean = true
7806  		// When `true`, a mouse event on this path will trigger the same event on the map
7807  		// (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).
7808  		bubblingMouseEvents: true
7809  	},
7810
7811  	beforeAdd: function (map) {
7812  		// Renderer is set here because we need to call renderer.getEvents
7813  		// before this.getEvents.
7814  		this._renderer = map.getRenderer(this);
7815  	},
7816
7817  	onAdd: function () {
7818  		this._renderer._initPath(this);
7819  		this._reset();
7820  		this._renderer._addPath(this);
7821  	},
7822
7823  	onRemove: function () {
7824  		this._renderer._removePath(this);
7825  	},
7826
7827  	// @method redraw(): this
7828  	// Redraws the layer. Sometimes useful after you changed the coordinates that the path uses.
7829  	redraw: function () {
7830  		if (this._map) {
7831  			this._renderer._updatePath(this);
7832  		}
7833  		return this;
7834  	},
7835
7836  	// @method setStyle(style: Path options): this
7837  	// Changes the appearance of a Path based on the options in the `Path options` object.
7838  	setStyle: function (style) {
7839  		setOptions(this, style);
7840  		if (this._renderer) {
7841  			this._renderer._updateStyle(this);
7842  			if (this.options.stroke && style && Object.prototype.hasOwnProperty.call(style, 'weight')) {
7843  				this._updateBounds();
7844  			}
7845  		}
7846  		return this;
7847  	},
7848
7849  	// @method bringToFront(): this
7850  	// Brings the layer to the top of all path layers.
7851  	bringToFront: function () {
7852  		if (this._renderer) {
7853  			this._renderer._bringToFront(this);
7854  		}
7855  		return this;
7856  	},
7857
7858  	// @method bringToBack(): this
7859  	// Brings the layer to the bottom of all path layers.
7860  	bringToBack: function () {
7861  		if (this._renderer) {
7862  			this._renderer._bringToBack(this);
7863  		}
7864  		return this;
7865  	},
7866
7867  	getElement: function () {
7868  		return this._path;
7869  	},
7870
7871  	_reset: function () {
7872  		// defined in child classes
7873  		this._project();
7874  		this._update();
7875  	},
7876
7877  	_clickTolerance: function () {
7878  		// used when doing hit detection for Canvas layers
7879  		return (this.options.stroke ? this.options.weight / 2 : 0) + this._renderer.options.tolerance
vendor: 9,092 bytes, lines 7879-8201
7879;
7880  	}
7881  });
7882
7883  /*
7884   * @class CircleMarker
7885   * @aka L.CircleMarker
7886   * @inherits Path
7887   *
7888   * A circle of a fixed size with radius specified in pixels. Extends `Path`.
7889   */
7890
7891  var CircleMarker = Path.extend({
7892
7893  	// @section
7894  	// @aka CircleMarker options
7895  	options: {
7896  		fill: true,
7897
7898  		// @option radius: Number = 10
7899  		// Radius of the circle marker, in pixels
7900  		radius: 10
7901  	},
7902
7903  	initialize: function (latlng, options) {
7904  		setOptions(this, options);
7905  		this._latlng = toLatLng(latlng);
7906  		this._radius = this.options.radius;
7907  	},
7908
7909  	// @method setLatLng(latLng: LatLng): this
7910  	// Sets the position of a circle marker to a new location.
7911  	setLatLng: function (latlng) {
7912  		var oldLatLng = this._latlng;
7913  		this._latlng = toLatLng(latlng);
7914  		this.redraw();
7915
7916  		// @event move: Event
7917  		// Fired when the marker is moved via [`setLatLng`](#circlemarker-setlatlng). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`.
7918  		return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
7919  	},
7920
7921  	// @method getLatLng(): LatLng
7922  	// Returns the current geographical position of the circle marker
7923  	getLatLng: function () {
7924  		return this._latlng;
7925  	},
7926
7927  	// @method setRadius(radius: Number): this
7928  	// Sets the radius of a circle marker. Units are in pixels.
7929  	setRadius: function (radius) {
7930  		this.options.radius = this._radius = radius;
7931  		return this.redraw();
7932  	},
7933
7934  	// @method getRadius(): Number
7935  	// Returns the current radius of the circle
7936  	getRadius: function () {
7937  		return this._radius;
7938  	},
7939
7940  	setStyle : function (options) {
7941  		var radius = options && options.radius || this._radius;
7942  		Path.prototype.setStyle.call(this, options);
7943  		this.setRadius(radius);
7944  		return this;
7945  	},
7946
7947  	_project: function () {
7948  		this._point = this._map.latLngToLayerPoint(this._latlng);
7949  		this._updateBounds();
7950  	},
7951
7952  	_updateBounds: function () {
7953  		var r = this._radius,
7954  		    r2 = this._radiusY || r,
7955  		    w = this._clickTolerance(),
7956  		    p = [r + w, r2 + w];
7957  		this._pxBounds = new Bounds(this._point.subtract(p), this._point.add(p));
7958  	},
7959
7960  	_update: function () {
7961  		if (this._map) {
7962  			this._updatePath();
7963  		}
7964  	},
7965
7966  	_updatePath: function () {
7967  		this._renderer._updateCircle(this);
7968  	},
7969
7970  	_empty: function () {
7971  		return this._radius && !this._renderer._bounds.intersects(this._pxBounds);
7972  	},
7973
7974  	// Needed by the `Canvas` renderer for interactivity
7975  	_containsPoint: function (p) {
7976  		return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
7977  	}
7978  });
7979
7980
7981  // @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options)
7982  // Instantiates a circle marker object given a geographical point, and an optional options object.
7983  function circleMarker(latlng, options) {
7984  	return new CircleMarker(latlng, options);
7985  }
7986
7987  /*
7988   * @class Circle
7989   * @aka L.Circle
7990   * @inherits CircleMarker
7991   *
7992   * A class for drawing circle overlays on a map. Extends `CircleMarker`.
7993   *
7994   * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion).
7995   *
7996   * @example
7997   *
7998   * ```js
7999   * L.circle([50.5, 30.5], {radius: 200}).addTo(map);
8000   * ```
8001   */
8002
8003  var Circle = CircleMarker.extend({
8004
8005  	initialize: function (latlng, options, legacyOptions) {
8006  		if (typeof options === 'number') {
8007  			// Backwards compatibility with 0.7.x factory (latlng, radius, options?)
8008  			options = extend({}, legacyOptions, {radius: options});
8009  		}
8010  		setOptions(this, options);
8011  		this._latlng = toLatLng(latlng);
8012
8013  		if (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); }
8014
8015  		// @section
8016  		// @aka Circle options
8017  		// @option radius: Number; Radius of the circle, in meters.
8018  		this._mRadius = this.options.radius;
8019  	},
8020
8021  	// @method setRadius(radius: Number): this
8022  	// Sets the radius of a circle. Units are in meters.
8023  	setRadius: function (radius) {
8024  		this._mRadius = radius;
8025  		return this.redraw();
8026  	},
8027
8028  	// @method getRadius(): Number
8029  	// Returns the current radius of a circle. Units are in meters.
8030  	getRadius: function () {
8031  		return this._mRadius;
8032  	},
8033
8034  	// @method getBounds(): LatLngBounds
8035  	// Returns the `LatLngBounds` of the path.
8036  	getBounds: function () {
8037  		var half = [this._radius, this._radiusY || this._radius];
8038
8039  		return new LatLngBounds(
8040  			this._map.layerPointToLatLng(this._point.subtract(half)),
8041  			this._map.layerPointToLatLng(this._point.add(half)));
8042  	},
8043
8044  	setStyle: Path.prototype.setStyle,
8045
8046  	_project: function () {
8047
8048  		var lng = this._latlng.lng,
8049  		    lat = this._latlng.lat,
8050  		    map = this._map,
8051  		    crs = map.options.crs;
8052
8053  		if (crs.distance === Earth.distance) {
8054  			var d = Math.PI / 180,
8055  			    latR = (this._mRadius / Earth.R) / d,
8056  			    top = map.project([lat + latR, lng]),
8057  			    bottom = map.project([lat - latR, lng]),
8058  			    p = top.add(bottom).divideBy(2),
8059  			    lat2 = map.unproject(p).lat,
8060  			    lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) /
8061  			            (Math.cos(lat * d) * Math.cos(lat2 * d))) / d;
8062
8063  			if (isNaN(lngR) || lngR === 0) {
8064  				lngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425
8065  			}
8066
8067  			this._point = p.subtract(map.getPixelOrigin());
8068  			this._radius = isNaN(lngR) ? 0 : p.x - map.project([lat2, lng - lngR]).x;
8069  			this._radiusY = p.y - top.y;
8070
8071  		} else {
8072  			var latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));
8073
8074  			this._point = map.latLngToLayerPoint(this._latlng);
8075  			this._radius = this._point.x - map.latLngToLayerPoint(latlng2).x;
8076  		}
8077
8078  		this._updateBounds();
8079  	}
8080  });
8081
8082  // @factory L.circle(latlng: LatLng, options?: Circle options)
8083  // Instantiates a circle object given a geographical point, and an options object
8084  // which contains the circle radius.
8085  // @alternative
8086  // @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options)
8087  // Obsolete way of instantiating a circle, for compatibility with 0.7.x code.
8088  // Do not use in new applications or plugins.
8089  function circle(latlng, options, legacyOptions) {
8090  	return new Circle(latlng, options, legacyOptions);
8091  }
8092
8093  /*
8094   * @class Polyline
8095   * @aka L.Polyline
8096   * @inherits Path
8097   *
8098   * A class for drawing polyline overlays on a map. Extends `Path`.
8099   *
8100   * @example
8101   *
8102   * ```js
8103   * // create a red polyline from an array of LatLng points
8104   * var latlngs = [
8105   * 	[45.51, -122.68],
8106   * 	[37.77, -122.43],
8107   * 	[34.04, -118.2]
8108   * ];
8109   *
8110   * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);
8111   *
8112   * // zoom the map to the polyline
8113   * map.fitBounds(polyline.getBounds());
8114   * ```
8115   *
8116   * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:
8117   *
8118   * ```js
8119   * // create a red polyline from an array of arrays of LatLng points
8120   * var latlngs = [
8121   * 	[[45.51, -122.68],
8122   * 	 [37.77, -122.43],
8123   * 	 [34.04, -118.2]],
8124   * 	[[40.78, -73.91],
8125   * 	 [41.83, -87.62],
8126   * 	 [32.76, -96.72]]
8127   * ];
8128   * ```
8129   */
8130
8131
8132  var Polyline = Path.extend({
8133
8134  	// @section
8135  	// @aka Polyline options
8136  	options: {
8137  		// @option smoothFactor: Number = 1.0
8138  		// How much to simplify the polyline on each zoom level. More means
8139  		// better performance and smoother look, and less means more accurate representation.
8140  		smoothFactor: 1.0,
8141
8142  		// @option noClip: Boolean = false
8143  		// Disable polyline clipping.
8144  		noClip: false
8145  	},
8146
8147  	initialize: function (latlngs, options) {
8148  		setOptions(this, options);
8149  		this._setLatLngs(latlngs);
8150  	},
8151
8152  	// @method getLatLngs(): LatLng[]
8153  	// Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.
8154  	getLatLngs: function () {
8155  		return this._latlngs;
8156  	},
8157
8158  	// @method setLatLngs(latlngs: LatLng[]): this
8159  	// Replaces all the points in the polyline with the given array of geographical points.
8160  	setLatLngs: function (latlngs) {
8161  		this._setLatLngs(latlngs);
8162  		return this.redraw();
8163  	},
8164
8165  	// @method isEmpty(): Boolean
8166  	// Returns `true` if the Polyline has no LatLngs.
8167  	isEmpty: function () {
8168  		return !this._latlngs.length;
8169  	},
8170
8171  	// @method closestLayerPoint(p: Point): Point
8172  	// Returns the point closest to `p` on the Polyline.
8173  	closestLayerPoint: function (p) {
8174  		var minDistance = Infinity,
8175  		    minPoint = null,
8176  		    closest = _sqClosestPointOnSegment,
8177  		    p1, p2;
8178
8179  		for (var j = 0, jLen = this._parts.length; j < jLen; j++) {
8180  			var points = this._parts[j];
8181
8182  			for (var i = 1, len = points.length; i < len; i++) {
8183  				p1 = points[i - 1];
8184  				p2 = points[i];
8185
8186  				var sqDist = closest(p, p1, p2, true);
8187
8188  				if (sqDist < minDistance) {
8189  					minDistance = sqDist;
8190  					minPoint = closest(p, p1, p2);
8191  				}
8192  			}
8193  		}
8194  		if (minPoint) {
8195  			minPoint.distance = Math.sqrt(minDistance);
8196  		}
8197  		return minPoint;
8198  	},
8199
8200  	// @method getCenter(): LatLng
8201  	// Returns the center ([centroid](http
8201://en.wikipedia.org/wiki/Centroid)) of the polyline.
8202  	getCenter: function () {
8203  		// throws error when not yet added to map as this center calculation requires projected coordinates
8204  		if (!this._map) {
8205  			throw new Error('Must add layer to map before using getCenter()');
8206  		}
8207
8208  		var i, halfDist, segDist, dist, p1, p2, ratio,
8209  		    points = this._rings[0],
8210  		    len = points.length;
8211
8212  		if (!len) { return null; }
8213
8214  		// polyline centroid algorithm; only uses the first ring if there are multiple
8215
8216  		for (i = 0, halfDist = 0; i < len - 1; i++) {
8217  			halfDist += points[i].distanceTo(points[i + 1]) / 2;
8218  		}
8219
8220  		// The line is so small in the current view that all points are on the same pixel.
8221  		if (halfDist === 0) {
8222  			return this._map.layerPointToLatLng(points[0]);
8223  		}
8224
8225  		for (i = 0, dist = 0; i < len - 1; i++) {
8226  			p1 = points[i];
8227  			p2 = points[i + 1];
8228  			segDist = p1.distanceTo(p2);
8229  			dist += segDist;
8230
8231  			if (dist > halfDist) {
8232  				ratio = (dist - halfDist) / segDist;
8233  				return this._map.layerPointToLatLng([
8234  					p2.x - ratio * (p2.x - p1.x),
8235  					p2.y - ratio * (p2.y - p1.y)
8236  				]);
8237  			}
8238  		}
8239  	},
8240
8241  	// @method getBounds(): LatLngBounds
8242  	// Returns the `LatLngBounds` of the path.
vendor: 7,582 bytes, lines 8243-8507
8243  	getBounds: function () {
8244  		return this._bounds;
8245  	},
8246
8247  	// @method addLatLng(latlng: LatLng, latlngs?: LatLng[]): this
8248  	// Adds a given point to the polyline. By default, adds to the first ring of
8249  	// the polyline in case of a multi-polyline, but can be overridden by passing
8250  	// a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).
8251  	addLatLng: function (latlng, latlngs) {
8252  		latlngs = latlngs || this._defaultShape();
8253  		latlng = toLatLng(latlng);
8254  		latlngs.push(latlng);
8255  		this._bounds.extend(latlng);
8256  		return this.redraw();
8257  	},
8258
8259  	_setLatLngs: function (latlngs) {
8260  		this._bounds = new LatLngBounds();
8261  		this._latlngs = this._convertLatLngs(latlngs);
8262  	},
8263
8264  	_defaultShape: function () {
8265  		return isFlat(this._latlngs) ? this._latlngs : this._latlngs[0];
8266  	},
8267
8268  	// recursively convert latlngs input into actual LatLng instances; calculate bounds along the way
8269  	_convertLatLngs: function (latlngs) {
8270  		var result = [],
8271  		    flat = isFlat(latlngs);
8272
8273  		for (var i = 0, len = latlngs.length; i < len; i++) {
8274  			if (flat) {
8275  				result[i] = toLatLng(latlngs[i]);
8276  				this._bounds.extend(result[i]);
8277  			} else {
8278  				result[i] = this._convertLatLngs(latlngs[i]);
8279  			}
8280  		}
8281
8282  		return result;
8283  	},
8284
8285  	_project: function () {
8286  		var pxBounds = new Bounds();
8287  		this._rings = [];
8288  		this._projectLatlngs(this._latlngs, this._rings, pxBounds);
8289
8290  		if (this._bounds.isValid() && pxBounds.isValid()) {
8291  			this._rawPxBounds = pxBounds;
8292  			this._updateBounds();
8293  		}
8294  	},
8295
8296  	_updateBounds: function () {
8297  		var w = this._clickTolerance(),
8298  		    p = new Point(w, w);
8299  		this._pxBounds = new Bounds([
8300  			this._rawPxBounds.min.subtract(p),
8301  			this._rawPxBounds.max.add(p)
8302  		]);
8303  	},
8304
8305  	// recursively turns latlngs into a set of rings with projected coordinates
8306  	_projectLatlngs: function (latlngs, result, projectedBounds) {
8307  		var flat = latlngs[0] instanceof LatLng,
8308  		    len = latlngs.length,
8309  		    i, ring;
8310
8311  		if (flat) {
8312  			ring = [];
8313  			for (i = 0; i < len; i++) {
8314  				ring[i] = this._map.latLngToLayerPoint(latlngs[i]);
8315  				projectedBounds.extend(ring[i]);
8316  			}
8317  			result.push(ring);
8318  		} else {
8319  			for (i = 0; i < len; i++) {
8320  				this._projectLatlngs(latlngs[i], result, projectedBounds);
8321  			}
8322  		}
8323  	},
8324
8325  	// clip polyline by renderer bounds so that we have less to render for performance
8326  	_clipPoints: function () {
8327  		var bounds = this._renderer._bounds;
8328
8329  		this._parts = [];
8330  		if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
8331  			return;
8332  		}
8333
8334  		if (this.options.noClip) {
8335  			this._parts = this._rings;
8336  			return;
8337  		}
8338
8339  		var parts = this._parts,
8340  		    i, j, k, len, len2, segment, points;
8341
8342  		for (i = 0, k = 0, len = this._rings.length; i < len; i++) {
8343  			points = this._rings[i];
8344
8345  			for (j = 0, len2 = points.length; j < len2 - 1; j++) {
8346  				segment = clipSegment(points[j], points[j + 1], bounds, j, true);
8347
8348  				if (!segment) { continue; }
8349
8350  				parts[k] = parts[k] || [];
8351  				parts[k].push(segment[0]);
8352
8353  				// if segment goes out of screen, or it's the last one, it's the end of the line part
8354  				if ((segment[1] !== points[j + 1]) || (j === len2 - 2)) {
8355  					parts[k].push(segment[1]);
8356  					k++;
8357  				}
8358  			}
8359  		}
8360  	},
8361
8362  	// simplify each clipped part of the polyline for performance
8363  	_simplifyPoints: function () {
8364  		var parts = this._parts,
8365  		    tolerance = this.options.smoothFactor;
8366
8367  		for (var i = 0, len = parts.length; i < len; i++) {
8368  			parts[i] = simplify(parts[i], tolerance);
8369  		}
8370  	},
8371
8372  	_update: function () {
8373  		if (!this._map) { return; }
8374
8375  		this._clipPoints();
8376  		this._simplifyPoints();
8377  		this._updatePath();
8378  	},
8379
8380  	_updatePath: function () {
8381  		this._renderer._updatePoly(this);
8382  	},
8383
8384  	// Needed by the `Canvas` renderer for interactivity
8385  	_containsPoint: function (p, closed) {
8386  		var i, j, k, len, len2, part,
8387  		    w = this._clickTolerance();
8388
8389  		if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }
8390
8391  		// hit detection for polylines
8392  		for (i = 0, len = this._parts.length; i < len; i++) {
8393  			part = this._parts[i];
8394
8395  			for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
8396  				if (!closed && (j === 0)) { continue; }
8397
8398  				if (pointToSegmentDistance(p, part[k], part[j]) <= w) {
8399  					return true;
8400  				}
8401  			}
8402  		}
8403  		return false;
8404  	}
8405  });
8406
8407  // @factory L.polyline(latlngs: LatLng[], options?: Polyline options)
8408  // Instantiates a polyline object given an array of geographical points and
8409  // optionally an options object. You can create a `Polyline` object with
8410  // multiple separate lines (`MultiPolyline`) by passing an array of arrays
8411  // of geographic points.
8412  function polyline(latlngs, options) {
8413  	return new Polyline(latlngs, options);
8414  }
8415
8416  // Retrocompat. Allow plugins to support Leaflet versions before and after 1.1.
8417  Polyline._flat = _flat;
8418
8419  /*
8420   * @class Polygon
8421   * @aka L.Polygon
8422   * @inherits Polyline
8423   *
8424   * A class for drawing polygon overlays on a map. Extends `Polyline`.
8425   *
8426   * 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.
8427   *
8428   *
8429   * @example
8430   *
8431   * ```js
8432   * // create a red polygon from an array of LatLng points
8433   * var latlngs = [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]];
8434   *
8435   * var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map);
8436   *
8437   * // zoom the map to the polygon
8438   * map.fitBounds(polygon.getBounds());
8439   * ```
8440   *
8441   * 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:
8442   *
8443   * ```js
8444   * var latlngs = [
8445   *   [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring
8446   *   [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole
8447   * ];
8448   * ```
8449   *
8450   * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape.
8451   *
8452   * ```js
8453   * var latlngs = [
8454   *   [ // first polygon
8455   *     [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring
8456   *     [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole
8457   *   ],
8458   *   [ // second polygon
8459   *     [[41, -111.03],[45, -111.04],[45, -104.05],[41, -104.05]]
8460   *   ]
8461   * ];
8462   * ```
8463   */
8464
8465  var Polygon = Polyline.extend({
8466
8467  	options: {
8468  		fill: true
8469  	},
8470
8471  	isEmpty: function () {
8472  		return !this._latlngs.length || !this._latlngs[0].length;
8473  	},
8474
8475  	getCenter: function () {
8476  		// throws error when not yet added to map as this center calculation requires projected coordinates
8477  		if (!this._map) {
8478  			throw new Error('Must add layer to map before using getCenter()');
8479  		}
8480
8481  		var i, j, p1, p2, f, area, x, y, center,
8482  		    points = this._rings[0],
8483  		    len = points.length;
8484
8485  		if (!len) { return null; }
8486
8487  		// polygon centroid algorithm; only uses the first ring if there are multiple
8488
8489  		area = x = y = 0;
8490
8491  		for (i = 0, j = len - 1; i < len; j = i++) {
8492  			p1 = points[i];
8493  			p2 = points[j];
8494
8495  			f = p1.y * p2.x - p2.y * p1.x;
8496  			x += (p1.x + p2.x) * f;
8497  			y += (p1.y + p2.y) * f;
8498  			area += f * 3;
8499  		}
8500
8501  		if (area === 0) {
8502  			// Polygon is so small that all points are on same pixel.
8503  			center = points[0];
8504  		} else {
8505  			center = [x / area, y / area];
8506  		}
8507  		return this._map.layerPointToLatLng(center
vendor: 8,784 bytes, lines 8507-8792
8507);
8508  	},
8509
8510  	_convertLatLngs: function (latlngs) {
8511  		var result = Polyline.prototype._convertLatLngs.call(this, latlngs),
8512  		    len = result.length;
8513
8514  		// remove last point if it equals first one
8515  		if (len >= 2 && result[0] instanceof LatLng && result[0].equals(result[len - 1])) {
8516  			result.pop();
8517  		}
8518  		return result;
8519  	},
8520
8521  	_setLatLngs: function (latlngs) {
8522  		Polyline.prototype._setLatLngs.call(this, latlngs);
8523  		if (isFlat(this._latlngs)) {
8524  			this._latlngs = [this._latlngs];
8525  		}
8526  	},
8527
8528  	_defaultShape: function () {
8529  		return isFlat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0];
8530  	},
8531
8532  	_clipPoints: function () {
8533  		// polygons need a different clipping algorithm so we redefine that
8534
8535  		var bounds = this._renderer._bounds,
8536  		    w = this.options.weight,
8537  		    p = new Point(w, w);
8538
8539  		// increase clip padding by stroke width to avoid stroke on clip edges
8540  		bounds = new Bounds(bounds.min.subtract(p), bounds.max.add(p));
8541
8542  		this._parts = [];
8543  		if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
8544  			return;
8545  		}
8546
8547  		if (this.options.noClip) {
8548  			this._parts = this._rings;
8549  			return;
8550  		}
8551
8552  		for (var i = 0, len = this._rings.length, clipped; i < len; i++) {
8553  			clipped = clipPolygon(this._rings[i], bounds, true);
8554  			if (clipped.length) {
8555  				this._parts.push(clipped);
8556  			}
8557  		}
8558  	},
8559
8560  	_updatePath: function () {
8561  		this._renderer._updatePoly(this, true);
8562  	},
8563
8564  	// Needed by the `Canvas` renderer for interactivity
8565  	_containsPoint: function (p) {
8566  		var inside = false,
8567  		    part, p1, p2, i, j, k, len, len2;
8568
8569  		if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }
8570
8571  		// ray casting algorithm for detecting if point is in polygon
8572  		for (i = 0, len = this._parts.length; i < len; i++) {
8573  			part = this._parts[i];
8574
8575  			for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
8576  				p1 = part[j];
8577  				p2 = part[k];
8578
8579  				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)) {
8580  					inside = !inside;
8581  				}
8582  			}
8583  		}
8584
8585  		// also check if it's on polygon stroke
8586  		return inside || Polyline.prototype._containsPoint.call(this, p, true);
8587  	}
8588
8589  });
8590
8591
8592  // @factory L.polygon(latlngs: LatLng[], options?: Polyline options)
8593  function polygon(latlngs, options) {
8594  	return new Polygon(latlngs, options);
8595  }
8596
8597  /*
8598   * @class GeoJSON
8599   * @aka L.GeoJSON
8600   * @inherits FeatureGroup
8601   *
8602   * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse
8603   * GeoJSON data and display it on the map. Extends `FeatureGroup`.
8604   *
8605   * @example
8606   *
8607   * ```js
8608   * L.geoJSON(data, {
8609   * 	style: function (feature) {
8610   * 		return {color: feature.properties.color};
8611   * 	}
8612   * }).bindPopup(function (layer) {
8613   * 	return layer.feature.properties.description;
8614   * }).addTo(map);
8615   * ```
8616   */
8617
8618  var GeoJSON = FeatureGroup.extend({
8619
8620  	/* @section
8621  	 * @aka GeoJSON options
8622  	 *
8623  	 * @option pointToLayer: Function = *
8624  	 * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally
8625  	 * called when data is added, passing the GeoJSON point feature and its `LatLng`.
8626  	 * The default is to spawn a default `Marker`:
8627  	 * ```js
8628  	 * function(geoJsonPoint, latlng) {
8629  	 * 	return L.marker(latlng);
8630  	 * }
8631  	 * ```
8632  	 *
8633  	 * @option style: Function = *
8634  	 * A `Function` defining the `Path options` for styling GeoJSON lines and polygons,
8635  	 * called internally when data is added.
8636  	 * The default value is to not override any defaults:
8637  	 * ```js
8638  	 * function (geoJsonFeature) {
8639  	 * 	return {}
8640  	 * }
8641  	 * ```
8642  	 *
8643  	 * @option onEachFeature: Function = *
8644  	 * A `Function` that will be called once for each created `Feature`, after it has
8645  	 * been created and styled. Useful for attaching events and popups to features.
8646  	 * The default is to do nothing with the newly created layers:
8647  	 * ```js
8648  	 * function (feature, layer) {}
8649  	 * ```
8650  	 *
8651  	 * @option filter: Function = *
8652  	 * A `Function` that will be used to decide whether to include a feature or not.
8653  	 * The default is to include all features:
8654  	 * ```js
8655  	 * function (geoJsonFeature) {
8656  	 * 	return true;
8657  	 * }
8658  	 * ```
8659  	 * Note: dynamically changing the `filter` option will have effect only on newly
8660  	 * added data. It will _not_ re-evaluate already included features.
8661  	 *
8662  	 * @option coordsToLatLng: Function = *
8663  	 * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s.
8664  	 * The default is the `coordsToLatLng` static method.
8665  	 *
8666  	 * @option markersInheritOptions: Boolean = false
8667  	 * Whether default Markers for "Point" type Features inherit from group options.
8668  	 */
8669
8670  	initialize: function (geojson, options) {
8671  		setOptions(this, options);
8672
8673  		this._layers = {};
8674
8675  		if (geojson) {
8676  			this.addData(geojson);
8677  		}
8678  	},
8679
8680  	// @method addData( <GeoJSON> data ): this
8681  	// Adds a GeoJSON object to the layer.
8682  	addData: function (geojson) {
8683  		var features = isArray(geojson) ? geojson : geojson.features,
8684  		    i, len, feature;
8685
8686  		if (features) {
8687  			for (i = 0, len = features.length; i < len; i++) {
8688  				// only add this if geometry or geometries are set and not null
8689  				feature = features[i];
8690  				if (feature.geometries || feature.geometry || feature.features || feature.coordinates) {
8691  					this.addData(feature);
8692  				}
8693  			}
8694  			return this;
8695  		}
8696
8697  		var options = this.options;
8698
8699  		if (options.filter && !options.filter(geojson)) { return this; }
8700
8701  		var layer = geometryToLayer(geojson, options);
8702  		if (!layer) {
8703  			return this;
8704  		}
8705  		layer.feature = asFeature(geojson);
8706
8707  		layer.defaultOptions = layer.options;
8708  		this.resetStyle(layer);
8709
8710  		if (options.onEachFeature) {
8711  			options.onEachFeature(geojson, layer);
8712  		}
8713
8714  		return this.addLayer(layer);
8715  	},
8716
8717  	// @method resetStyle( <Path> layer? ): this
8718  	// Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.
8719  	// If `layer` is omitted, the style of all features in the current layer is reset.
8720  	resetStyle: function (layer) {
8721  		if (layer === undefined) {
8722  			return this.eachLayer(this.resetStyle, this);
8723  		}
8724  		// reset any custom styles
8725  		layer.options = extend({}, layer.defaultOptions);
8726  		this._setLayerStyle(layer, this.options.style);
8727  		return this;
8728  	},
8729
8730  	// @method setStyle( <Function> style ): this
8731  	// Changes styles of GeoJSON vector layers with the given style function.
8732  	setStyle: function (style) {
8733  		return this.eachLayer(function (layer) {
8734  			this._setLayerStyle(layer, style);
8735  		}, this);
8736  	},
8737
8738  	_setLayerStyle: function (layer, style) {
8739  		if (layer.setStyle) {
8740  			if (typeof style === 'function') {
8741  				style = style(layer.feature);
8742  			}
8743  			layer.setStyle(style);
8744  		}
8745  	}
8746  });
8747
8748  // @section
8749  // There are several static functions which can be called without instantiating L.GeoJSON:
8750
8751  // @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer
8752  // Creates a `Layer` from a given GeoJSON feature. Can use a custom
8753  // [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng)
8754  // functions if provided as options.
8755  function geometryToLayer(geojson, options) {
8756
8757  	var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,
8758  	    coords = geometry ? geometry.coordinates : null,
8759  	    layers = [],
8760  	    pointToLayer = options && options.pointToLayer,
8761  	    _coordsToLatLng = options && options.coordsToLatLng || coordsToLatLng,
8762  	    latlng, latlngs, i, len;
8763
8764  	if (!coords && !geometry) {
8765  		return null;
8766  	}
8767
8768  	switch (geometry.type) {
8769  	case 'Point':
8770  		latlng = _coordsToLatLng(coords);
8771  		return _pointToLayer(pointToLayer, geojson, latlng, options);
8772
8773  	case 'MultiPoint':
8774  		for (i = 0, len = coords.length; i < len; i++) {
8775  			latlng = _coordsToLatLng(coords[i]);
8776  			layers.push(_pointToLayer(pointToLayer, geojson, latlng, options));
8777  		}
8778  		return new FeatureGroup(layers);
8779
8780  	case 'LineString':
8781  	case 'MultiLineString':
8782  		latlngs = coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, _coordsToLatLng);
8783  		return new Polyline(latlngs, options);
8784
8785  	case 'Polygon':
8786  	case 'MultiPolygon':
8787  		latlngs = coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, _coordsToLatLng);
8788  		return new Polygon(latlngs, options);
8789
8790  	case 'GeometryCollection':
8791  		for (i = 0, len = geometry.geometries.length; i < len; i++) {
8792  			var 
8792layer = geometryToLayer({
8793  				geometry: geometry.geometries[i],
8794  				type: 'Feature',
8795  				properties: geojson.properties
8796  			}, options);
8797
8798  			if (layer) {
8799  				layers.push(layer);
8800  			}
8801  		}
8802  		return new FeatureGroup(layers);
8803
8804  	default:
8805  		throw new Error('Invalid GeoJSON object.');
8806  	}
8807  }
8808
8809  function _pointToLayer(pointToLayerFn, geojson, latlng, options) {
8810  	return pointToLayerFn ?
8811  		pointToLayerFn(geojson, latlng) :
8812  		new Marker(latlng, options && options.markersInheritOptions && options);
8813  }
8814
8815  // @function coordsToLatLng(coords: Array): LatLng
8816  // Creates a `LatLng` object from an array of 2 numbers (longitude, latitude)
8817  // or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points.
8818  function coordsToLatLng(coords) {
8819  	return new LatLng(coords[1], coords[0], coords[2]);
8820  }
8821
8822  // @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array
8823  // Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array.
8824  // `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default).
8825  // Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function.
8826  function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) {
8827  	var latlngs = [];
8828
8829  	for (var i = 0, len = coords.length, latlng; i < len; i++) {
8830  		latlng = levelsDeep ?
8831  			coordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng) :
8832  			(_coordsToLatLng || coordsToLatLng)(coords[i]);
8833
8834  		latlngs.push(latlng);
8835  	}
8836
8837  	return latlngs;
8838  }
8839
8840  // @function latLngToCoords(latlng: LatLng, precision?: Number): Array
8841  // Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)
8842  function latLngToCoords(latlng, precision) {
8843  	precision = typeof precision === 'number' ? precision : 6;
8844  	return latlng.alt !== undefined ?
8845  		[formatNum(latlng.lng, precision), formatNum(latlng.lat, precision), formatNum(latlng.alt, precision)] :
8846  		[formatNum(latlng.lng, precision), formatNum(latlng.lat, precision)];
8847  }
8848
8849  // @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, 
vendor: 32,065 bytes, lines 8849-9898
8849closed?: Boolean): Array
8850  // Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)
8851  // `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.
8852  function latLngsToCoords(latlngs, levelsDeep, closed, precision) {
8853  	var coords = [];
8854
8855  	for (var i = 0, len = latlngs.length; i < len; i++) {
8856  		coords.push(levelsDeep ?
8857  			latLngsToCoords(latlngs[i], levelsDeep - 1, closed, precision) :
8858  			latLngToCoords(latlngs[i], precision));
8859  	}
8860
8861  	if (!levelsDeep && closed) {
8862  		coords.push(coords[0]);
8863  	}
8864
8865  	return coords;
8866  }
8867
8868  function getFeature(layer, newGeometry) {
8869  	return layer.feature ?
8870  		extend({}, layer.feature, {geometry: newGeometry}) :
8871  		asFeature(newGeometry);
8872  }
8873
8874  // @function asFeature(geojson: Object): Object
8875  // Normalize GeoJSON geometries/features into GeoJSON features.
8876  function asFeature(geojson) {
8877  	if (geojson.type === 'Feature' || geojson.type === 'FeatureCollection') {
8878  		return geojson;
8879  	}
8880
8881  	return {
8882  		type: 'Feature',
8883  		properties: {},
8884  		geometry: geojson
8885  	};
8886  }
8887
8888  var PointToGeoJSON = {
8889  	toGeoJSON: function (precision) {
8890  		return getFeature(this, {
8891  			type: 'Point',
8892  			coordinates: latLngToCoords(this.getLatLng(), precision)
8893  		});
8894  	}
8895  };
8896
8897  // @namespace Marker
8898  // @section Other methods
8899  // @method toGeoJSON(precision?: Number): Object
8900  // `precision` is the number of decimal places for coordinates.
8901  // The default value is 6 places.
8902  // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).
8903  Marker.include(PointToGeoJSON);
8904
8905  // @namespace CircleMarker
8906  // @method toGeoJSON(precision?: Number): Object
8907  // `precision` is the number of decimal places for coordinates.
8908  // The default value is 6 places.
8909  // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).
8910  Circle.include(PointToGeoJSON);
8911  CircleMarker.include(PointToGeoJSON);
8912
8913
8914  // @namespace Polyline
8915  // @method toGeoJSON(precision?: Number): Object
8916  // `precision` is the number of decimal places for coordinates.
8917  // The default value is 6 places.
8918  // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).
8919  Polyline.include({
8920  	toGeoJSON: function (precision) {
8921  		var multi = !isFlat(this._latlngs);
8922
8923  		var coords = latLngsToCoords(this._latlngs, multi ? 1 : 0, false, precision);
8924
8925  		return getFeature(this, {
8926  			type: (multi ? 'Multi' : '') + 'LineString',
8927  			coordinates: coords
8928  		});
8929  	}
8930  });
8931
8932  // @namespace Polygon
8933  // @method toGeoJSON(precision?: Number): Object
8934  // `precision` is the number of decimal places for coordinates.
8935  // The default value is 6 places.
8936  // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).
8937  Polygon.include({
8938  	toGeoJSON: function (precision) {
8939  		var holes = !isFlat(this._latlngs),
8940  		    multi = holes && !isFlat(this._latlngs[0]);
8941
8942  		var coords = latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true, precision);
8943
8944  		if (!holes) {
8945  			coords = [coords];
8946  		}
8947
8948  		return getFeature(this, {
8949  			type: (multi ? 'Multi' : '') + 'Polygon',
8950  			coordinates: coords
8951  		});
8952  	}
8953  });
8954
8955
8956  // @namespace LayerGroup
8957  LayerGroup.include({
8958  	toMultiPoint: function (precision) {
8959  		var coords = [];
8960
8961  		this.eachLayer(function (layer) {
8962  			coords.push(layer.toGeoJSON(precision).geometry.coordinates);
8963  		});
8964
8965  		return getFeature(this, {
8966  			type: 'MultiPoint',
8967  			coordinates: coords
8968  		});
8969  	},
8970
8971  	// @method toGeoJSON(precision?: Number): Object
8972  	// `precision` is the number of decimal places for coordinates.
8973  	// The default value is 6 places.
8974  	// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`).
8975  	toGeoJSON: function (precision) {
8976
8977  		var type = this.feature && this.feature.geometry && this.feature.geometry.type;
8978
8979  		if (type === 'MultiPoint') {
8980  			return this.toMultiPoint(precision);
8981  		}
8982
8983  		var isGeometryCollection = type === 'GeometryCollection',
8984  		    jsons = [];
8985
8986  		this.eachLayer(function (layer) {
8987  			if (layer.toGeoJSON) {
8988  				var json = layer.toGeoJSON(precision);
8989  				if (isGeometryCollection) {
8990  					jsons.push(json.geometry);
8991  				} else {
8992  					var feature = asFeature(json);
8993  					// Squash nested feature collections
8994  					if (feature.type === 'FeatureCollection') {
8995  						jsons.push.apply(jsons, feature.features);
8996  					} else {
8997  						jsons.push(feature);
8998  					}
8999  				}
9000  			}
9001  		});
9002
9003  		if (isGeometryCollection) {
9004  			return getFeature(this, {
9005  				geometries: jsons,
9006  				type: 'GeometryCollection'
9007  			});
9008  		}
9009
9010  		return {
9011  			type: 'FeatureCollection',
9012  			features: jsons
9013  		};
9014  	}
9015  });
9016
9017  // @namespace GeoJSON
9018  // @factory L.geoJSON(geojson?: Object, options?: GeoJSON options)
9019  // Creates a GeoJSON layer. Optionally accepts an object in
9020  // [GeoJSON format](https://tools.ietf.org/html/rfc7946) to display on the map
9021  // (you can alternatively add it later with `addData` method) and an `options` object.
9022  function geoJSON(geojson, options) {
9023  	return new GeoJSON(geojson, options);
9024  }
9025
9026  // Backward compatibility.
9027  var geoJson = geoJSON;
9028
9029  /*
9030   * @class ImageOverlay
9031   * @aka L.ImageOverlay
9032   * @inherits Interactive layer
9033   *
9034   * Used to load and display a single image over specific bounds of the map. Extends `Layer`.
9035   *
9036   * @example
9037   *
9038   * ```js
9039   * var imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
9040   * 	imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];
9041   * L.imageOverlay(imageUrl, imageBounds).addTo(map);
9042   * ```
9043   */
9044
9045  var ImageOverlay = Layer.extend({
9046
9047  	// @section
9048  	// @aka ImageOverlay options
9049  	options: {
9050  		// @option opacity: Number = 1.0
9051  		// The opacity of the image overlay.
9052  		opacity: 1,
9053
9054  		// @option alt: String = ''
9055  		// Text for the `alt` attribute of the image (useful for accessibility).
9056  		alt: '',
9057
9058  		// @option interactive: Boolean = false
9059  		// If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.
9060  		interactive: false,
9061
9062  		// @option crossOrigin: Boolean|String = false
9063  		// Whether the crossOrigin attribute will be added to the image.
9064  		// 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.
9065  		// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
9066  		crossOrigin: false,
9067
9068  		// @option errorOverlayUrl: String = ''
9069  		// URL to the overlay image to show in place of the overlay that failed to load.
9070  		errorOverlayUrl: '',
9071
9072  		// @option zIndex: Number = 1
9073  		// The explicit [zIndex](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index) of the overlay layer.
9074  		zIndex: 1,
9075
9076  		// @option className: String = ''
9077  		// A custom class name to assign to the image. Empty by default.
9078  		className: ''
9079  	},
9080
9081  	initialize: function (url, bounds, options) { // (String, LatLngBounds, Object)
9082  		this._url = url;
9083  		this._bounds = toLatLngBounds(bounds);
9084
9085  		setOptions(this, options);
9086  	},
9087
9088  	onAdd: function () {
9089  		if (!this._image) {
9090  			this._initImage();
9091
9092  			if (this.options.opacity < 1) {
9093  				this._updateOpacity();
9094  			}
9095  		}
9096
9097  		if (this.options.interactive) {
9098  			addClass(this._image, 'leaflet-interactive');
9099  			this.addInteractiveTarget(this._image);
9100  		}
9101
9102  		this.getPane().appendChild(this._image);
9103  		this._reset();
9104  	},
9105
9106  	onRemove: function () {
9107  		remove(this._image);
9108  		if (this.options.interactive) {
9109  			this.removeInteractiveTarget(this._image);
9110  		}
9111  	},
9112
9113  	// @method setOpacity(opacity: Number): this
9114  	// Sets the opacity of the overlay.
9115  	setOpacity: function (opacity) {
9116  		this.options.opacity = opacity;
9117
9118  		if (this._image) {
9119  			this._updateOpacity();
9120  		}
9121  		return this;
9122  	},
9123
9124  	setStyle: function (styleOpts) {
9125  		if (styleOpts.opacity) {
9126  			this.setOpacity(styleOpts.opacity);
9127  		}
9128  		return this;
9129  	},
9130
9131  	// @method bringToFront(): this
9132  	// Brings the layer to the top of all overlays.
9133  	bringToFront: function () {
9134  		if (this._map) {
9135  			toFront(this._image);
9136  		}
9137  		return this;
9138  	},
9139
9140  	// @method bringToBack(): this
9141  	// Brings the layer to the bottom of all overlays.
9142  	bringToBack: function () {
9143  		if (this._map) {
9144  			toBack(this._image);
9145  		}
9146  		return this;
9147  	},
9148
9149  	// @method setUrl(url: String): this
9150  	// Changes the URL of the image.
9151  	setUrl: function (url) {
9152  		this._url = url;
9153
9154  		if (this._image) {
9155  			this._image.src = url;
9156  		}
9157  		return this;
9158  	},
9159
9160  	// @method setBounds(bounds: LatLngBounds): this
9161  	// Update the bounds that this ImageOverlay covers
9162  	setBounds: function (bounds) {
9163  		this._bounds = toLatLngBounds(bounds);
9164
9165  		if (this._map) {
9166  			this._reset();
9167  		}
9168  		return this;
9169  	},
9170
9171  	getEvents: function () {
9172  		var events = {
9173  			zoom: this._reset,
9174  			viewreset: this._reset
9175  		};
9176
9177  		if (this._zoomAnimated) {
9178  			events.zoomanim = this._animateZoom;
9179  		}
9180
9181  		return events;
9182  	},
9183
9184  	// @method setZIndex(value: Number): this
9185  	// Changes the [zIndex](#imageoverlay-zindex) of the image overlay.
9186  	setZIndex: function (value) {
9187  		this.options.zIndex = value;
9188  		this._updateZIndex();
9189  		return this;
9190  	},
9191
9192  	// @method getBounds(): LatLngBounds
9193  	// Get the bounds that this ImageOverlay covers
9194  	getBounds: function () {
9195  		return this._bounds;
9196  	},
9197
9198  	// @method getElement(): HTMLElement
9199  	// Returns the instance of [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement)
9200  	// used by this overlay.
9201  	getElement: function () {
9202  		return this._image;
9203  	},
9204
9205  	_initImage: function () {
9206  		var wasElementSupplied = this._url.tagName === 'IMG';
9207  		var img = this._image = wasElementSupplied ? this._url : create$1('img');
9208
9209  		addClass(img, 'leaflet-image-layer');
9210  		if (this._zoomAnimated) { addClass(img, 'leaflet-zoom-animated'); }
9211  		if (this.options.className) { addClass(img, this.options.className); }
9212
9213  		img.onselectstart = falseFn;
9214  		img.onmousemove = falseFn;
9215
9216  		// @event load: Event
9217  		// Fired when the ImageOverlay layer has loaded its image
9218  		img.onload = bind(this.fire, this, 'load');
9219  		img.onerror = bind(this._overlayOnError, this, 'error');
9220
9221  		if (this.options.crossOrigin || this.options.crossOrigin === '') {
9222  			img.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
9223  		}
9224
9225  		if (this.options.zIndex) {
9226  			this._updateZIndex();
9227  		}
9228
9229  		if (wasElementSupplied) {
9230  			this._url = img.src;
9231  			return;
9232  		}
9233
9234  		img.src = this._url;
9235  		img.alt = this.options.alt;
9236  	},
9237
9238  	_animateZoom: function (e) {
9239  		var scale = this._map.getZoomScale(e.zoom),
9240  		    offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min;
9241
9242  		setTransform(this._image, offset, scale);
9243  	},
9244
9245  	_reset: function () {
9246  		var image = this._image,
9247  		    bounds = new Bounds(
9248  		        this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
9249  		        this._map.latLngToLayerPoint(this._bounds.getSouthEast())),
9250  		    size = bounds.getSize();
9251
9252  		setPosition(image, bounds.min);
9253
9254  		image.style.width  = size.x + 'px';
9255  		image.style.height = size.y + 'px';
9256  	},
9257
9258  	_updateOpacity: function () {
9259  		setOpacity(this._image, this.options.opacity);
9260  	},
9261
9262  	_updateZIndex: function () {
9263  		if (this._image && this.options.zIndex !== undefined && this.options.zIndex !== null) {
9264  			this._image.style.zIndex = this.options.zIndex;
9265  		}
9266  	},
9267
9268  	_overlayOnError: function () {
9269  		// @event error: Event
9270  		// Fired when the ImageOverlay layer fails to load its image
9271  		this.fire('error');
9272
9273  		var errorUrl = this.options.errorOverlayUrl;
9274  		if (errorUrl && this._url !== errorUrl) {
9275  			this._url = errorUrl;
9276  			this._image.src = errorUrl;
9277  		}
9278  	}
9279  });
9280
9281  // @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options)
9282  // Instantiates an image overlay object given the URL of the image and the
9283  // geographical bounds it is tied to.
9284  var imageOverlay = function (url, bounds, options) {
9285  	return new ImageOverlay(url, bounds, options);
9286  };
9287
9288  /*
9289   * @class VideoOverlay
9290   * @aka L.VideoOverlay
9291   * @inherits ImageOverlay
9292   *
9293   * Used to load and display a video player over specific bounds of the map. Extends `ImageOverlay`.
9294   *
9295   * A video overlay uses the [`<video>`](https://developer.mozilla.org/docs/Web/HTML/Element/video)
9296   * HTML5 element.
9297   *
9298   * @example
9299   *
9300   * ```js
9301   * var videoUrl = 'https://www.mapbox.com/bites/00188/patricia_nasa.webm',
9302   * 	videoBounds = [[ 32, -130], [ 13, -100]];
9303   * L.videoOverlay(videoUrl, videoBounds ).addTo(map);
9304   * ```
9305   */
9306
9307  var VideoOverlay = ImageOverlay.extend({
9308
9309  	// @section
9310  	// @aka VideoOverlay options
9311  	options: {
9312  		// @option autoplay: Boolean = true
9313  		// Whether the video starts playing automatically when loaded.
9314  		autoplay: true,
9315
9316  		// @option loop: Boolean = true
9317  		// Whether the video will loop back to the beginning when played.
9318  		loop: true,
9319
9320  		// @option keepAspectRatio: Boolean = true
9321  		// Whether the video will save aspect ratio after the projection.
9322  		// Relevant for supported browsers. Browser compatibility- https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit
9323  		keepAspectRatio: true,
9324
9325  		// @option muted: Boolean = false
9326  		// Whether the video starts on mute when loaded.
9327  		muted: false
9328  	},
9329
9330  	_initImage: function () {
9331  		var wasElementSupplied = this._url.tagName === 'VIDEO';
9332  		var vid = this._image = wasElementSupplied ? this._url : create$1('video');
9333
9334  		addClass(vid, 'leaflet-image-layer');
9335  		if (this._zoomAnimated) { addClass(vid, 'leaflet-zoom-animated'); }
9336  		if (this.options.className) { addClass(vid, this.options.className); }
9337
9338  		vid.onselectstart = falseFn;
9339  		vid.onmousemove = falseFn;
9340
9341  		// @event load: Event
9342  		// Fired when the video has finished loading the first frame
9343  		vid.onloadeddata = bind(this.fire, this, 'load');
9344
9345  		if (wasElementSupplied) {
9346  			var sourceElements = vid.getElementsByTagName('source');
9347  			var sources = [];
9348  			for (var j = 0; j < sourceElements.length; j++) {
9349  				sources.push(sourceElements[j].src);
9350  			}
9351
9352  			this._url = (sourceElements.length > 0) ? sources : [vid.src];
9353  			return;
9354  		}
9355
9356  		if (!isArray(this._url)) { this._url = [this._url]; }
9357
9358  		if (!this.options.keepAspectRatio && Object.prototype.hasOwnProperty.call(vid.style, 'objectFit')) {
9359  			vid.style['objectFit'] = 'fill';
9360  		}
9361  		vid.autoplay = !!this.options.autoplay;
9362  		vid.loop = !!this.options.loop;
9363  		vid.muted = !!this.options.muted;
9364  		for (var i = 0; i < this._url.length; i++) {
9365  			var source = create$1('source');
9366  			source.src = this._url[i];
9367  			vid.appendChild(source);
9368  		}
9369  	}
9370
9371  	// @method getElement(): HTMLVideoElement
9372  	// Returns the instance of [`HTMLVideoElement`](https://developer.mozilla.org/docs/Web/API/HTMLVideoElement)
9373  	// used by this overlay.
9374  });
9375
9376
9377  // @factory L.videoOverlay(video: String|Array|HTMLVideoElement, bounds: LatLngBounds, options?: VideoOverlay options)
9378  // Instantiates an image overlay object given the URL of the video (or array of URLs, or even a video element) and the
9379  // geographical bounds it is tied to.
9380
9381  function videoOverlay(video, bounds, options) {
9382  	return new VideoOverlay(video, bounds, options);
9383  }
9384
9385  /*
9386   * @class SVGOverlay
9387   * @aka L.SVGOverlay
9388   * @inherits ImageOverlay
9389   *
9390   * Used to load, display and provide DOM access to an SVG file over specific bounds of the map. Extends `ImageOverlay`.
9391   *
9392   * An SVG overlay uses the [`<svg>`](https://developer.mozilla.org/docs/Web/SVG/Element/svg) element.
9393   *
9394   * @example
9395   *
9396   * ```js
9397   * var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
9398   * svgElement.setAttribute('xmlns', "http://www.w3.org/2000/svg");
9399   * svgElement.setAttribute('viewBox', "0 0 200 200");
9400   * 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"/>';
9401   * var svgElementBounds = [ [ 32, -130 ], [ 13, -100 ] ];
9402   * L.svgOverlay(svgElement, svgElementBounds).addTo(map);
9403   * ```
9404   */
9405
9406  var SVGOverlay = ImageOverlay.extend({
9407  	_initImage: function () {
9408  		var el = this._image = this._url;
9409
9410  		addClass(el, 'leaflet-image-layer');
9411  		if (this._zoomAnimated) { addClass(el, 'leaflet-zoom-animated'); }
9412  		if (this.options.className) { addClass(el, this.options.className); }
9413
9414  		el.onselectstart = falseFn;
9415  		el.onmousemove = falseFn;
9416  	}
9417
9418  	// @method getElement(): SVGElement
9419  	// Returns the instance of [`SVGElement`](https://developer.mozilla.org/docs/Web/API/SVGElement)
9420  	// used by this overlay.
9421  });
9422
9423
9424  // @factory L.svgOverlay(svg: String|SVGElement, bounds: LatLngBounds, options?: SVGOverlay options)
9425  // Instantiates an image overlay object given an SVG element and the geographical bounds it is tied to.
9426  // A viewBox attribute is required on the SVG element to zoom in and out properly.
9427
9428  function svgOverlay(el, bounds, options) {
9429  	return new SVGOverlay(el, bounds, options);
9430  }
9431
9432  /*
9433   * @class DivOverlay
9434   * @inherits Layer
9435   * @aka L.DivOverlay
9436   * Base model for L.Popup and L.Tooltip. Inherit from it for custom popup like plugins.
9437   */
9438
9439  // @namespace DivOverlay
9440  var DivOverlay = Layer.extend({
9441
9442  	// @section
9443  	// @aka DivOverlay options
9444  	options: {
9445  		// @option offset: Point = Point(0, 7)
9446  		// The offset of the popup position. Useful to control the anchor
9447  		// of the popup when opening it on some overlays.
9448  		offset: [0, 7],
9449
9450  		// @option className: String = ''
9451  		// A custom CSS class name to assign to the popup.
9452  		className: '',
9453
9454  		// @option pane: String = 'popupPane'
9455  		// `Map pane` where the popup will be added.
9456  		pane: 'popupPane'
9457  	},
9458
9459  	initialize: function (options, source) {
9460  		setOptions(this, options);
9461
9462  		this._source = source;
9463  	},
9464
9465  	onAdd: function (map) {
9466  		this._zoomAnimated = map._zoomAnimated;
9467
9468  		if (!this._container) {
9469  			this._initLayout();
9470  		}
9471
9472  		if (map._fadeAnimated) {
9473  			setOpacity(this._container, 0);
9474  		}
9475
9476  		clearTimeout(this._removeTimeout);
9477  		this.getPane().appendChild(this._container);
9478  		this.update();
9479
9480  		if (map._fadeAnimated) {
9481  			setOpacity(this._container, 1);
9482  		}
9483
9484  		this.bringToFront();
9485  	},
9486
9487  	onRemove: function (map) {
9488  		if (map._fadeAnimated) {
9489  			setOpacity(this._container, 0);
9490  			this._removeTimeout = setTimeout(bind(remove, undefined, this._container), 200);
9491  		} else {
9492  			remove(this._container);
9493  		}
9494  	},
9495
9496  	// @namespace Popup
9497  	// @method getLatLng: LatLng
9498  	// Returns the geographical point of popup.
9499  	getLatLng: function () {
9500  		return this._latlng;
9501  	},
9502
9503  	// @method setLatLng(latlng: LatLng): this
9504  	// Sets the geographical point where the popup will open.
9505  	setLatLng: function (latlng) {
9506  		this._latlng = toLatLng(latlng);
9507  		if (this._map) {
9508  			this._updatePosition();
9509  			this._adjustPan();
9510  		}
9511  		return this;
9512  	},
9513
9514  	// @method getContent: String|HTMLElement
9515  	// Returns the content of the popup.
9516  	getContent: function () {
9517  		return this._content;
9518  	},
9519
9520  	// @method setContent(htmlContent: String|HTMLElement|Function): this
9521  	// 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.
9522  	setContent: function (content) {
9523  		this._content = content;
9524  		this.update();
9525  		return this;
9526  	},
9527
9528  	// @method getElement: String|HTMLElement
9529  	// Returns the HTML container of the popup.
9530  	getElement: function () {
9531  		return this._container;
9532  	},
9533
9534  	// @method update: null
9535  	// Updates the popup content, layout and position. Useful for updating the popup after something inside changed, e.g. image loaded.
9536  	update: function () {
9537  		if (!this._map) { return; }
9538
9539  		this._container.style.visibility = 'hidden';
9540
9541  		this._updateContent();
9542  		this._updateLayout();
9543  		this._updatePosition();
9544
9545  		this._container.style.visibility = '';
9546
9547  		this._adjustPan();
9548  	},
9549
9550  	getEvents: function () {
9551  		var events = {
9552  			zoom: this._updatePosition,
9553  			viewreset: this._updatePosition
9554  		};
9555
9556  		if (this._zoomAnimated) {
9557  			events.zoomanim = this._animateZoom;
9558  		}
9559  		return events;
9560  	},
9561
9562  	// @method isOpen: Boolean
9563  	// Returns `true` when the popup is visible on the map.
9564  	isOpen: function () {
9565  		return !!this._map && this._map.hasLayer(this);
9566  	},
9567
9568  	// @method bringToFront: this
9569  	// Brings this popup in front of other popups (in the same map pane).
9570  	bringToFront: function () {
9571  		if (this._map) {
9572  			toFront(this._container);
9573  		}
9574  		return this;
9575  	},
9576
9577  	// @method bringToBack: this
9578  	// Brings this popup to the back of other popups (in the same map pane).
9579  	bringToBack: function () {
9580  		if (this._map) {
9581  			toBack(this._container);
9582  		}
9583  		return this;
9584  	},
9585
9586  	_prepareOpen: function (parent, layer, latlng) {
9587  		if (!(layer instanceof Layer)) {
9588  			latlng = layer;
9589  			layer = parent;
9590  		}
9591
9592  		if (layer instanceof FeatureGroup) {
9593  			for (var id in parent._layers) {
9594  				layer = parent._layers[id];
9595  				break;
9596  			}
9597  		}
9598
9599  		if (!latlng) {
9600  			if (layer.getCenter) {
9601  				latlng = layer.getCenter();
9602  			} else if (layer.getLatLng) {
9603  				latlng = layer.getLatLng();
9604  			} else {
9605  				throw new Error('Unable to get source layer LatLng.');
9606  			}
9607  		}
9608
9609  		// set overlay source to this layer
9610  		this._source = layer;
9611
9612  		// update the overlay (content, layout, ect...)
9613  		this.update();
9614
9615  		return latlng;
9616  	},
9617
9618  	_updateContent: function () {
9619  		if (!this._content) { return; }
9620
9621  		var node = this._contentNode;
9622  		var content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content;
9623
9624  		if (typeof content === 'string') {
9625  			node.innerHTML = content;
9626  		} else {
9627  			while (node.hasChildNodes()) {
9628  				node.removeChild(node.firstChild);
9629  			}
9630  			node.appendChild(content);
9631  		}
9632  		this.fire('contentupdate');
9633  	},
9634
9635  	_updatePosition: function () {
9636  		if (!this._map) { return; }
9637
9638  		var pos = this._map.latLngToLayerPoint(this._latlng),
9639  		    offset = toPoint(this.options.offset),
9640  		    anchor = this._getAnchor();
9641
9642  		if (this._zoomAnimated) {
9643  			setPosition(this._container, pos.add(anchor));
9644  		} else {
9645  			offset = offset.add(pos).add(anchor);
9646  		}
9647
9648  		var bottom = this._containerBottom = -offset.y,
9649  		    left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;
9650
9651  		// bottom position the popup in case the height of the popup changes (images loading etc)
9652  		this._container.style.bottom = bottom + 'px';
9653  		this._container.style.left = left + 'px';
9654  	},
9655
9656  	_getAnchor: function () {
9657  		return [0, 0];
9658  	}
9659
9660  });
9661
9662  /*
9663   * @class Popup
9664   * @inherits DivOverlay
9665   * @aka L.Popup
9666   * Used to open popups in certain places of the map. Use [Map.openPopup](#map-openpopup) to
9667   * open popups while making sure that only one popup is open at one time
9668   * (recommended for usability), or use [Map.addLayer](#map-addlayer) to open as many as you want.
9669   *
9670   * @example
9671   *
9672   * If you want to just bind a popup to marker click and then open it, it's really easy:
9673   *
9674   * ```js
9675   * marker.bindPopup(popupContent).openPopup();
9676   * ```
9677   * Path overlays like polylines also have a `bindPopup` method.
9678   * Here's a more complicated way to open a popup on a map:
9679   *
9680   * ```js
9681   * var popup = L.popup()
9682   * 	.setLatLng(latlng)
9683   * 	.setContent('<p>Hello world!<br />This is a nice popup.</p>')
9684   * 	.openOn(map);
9685   * ```
9686   */
9687
9688
9689  // @namespace Popup
9690  var Popup = DivOverlay.extend({
9691
9692  	// @section
9693  	// @aka Popup options
9694  	options: {
9695  		// @option maxWidth: Number = 300
9696  		// Max width of the popup, in pixels.
9697  		maxWidth: 300,
9698
9699  		// @option minWidth: Number = 50
9700  		// Min width of the popup, in pixels.
9701  		minWidth: 50,
9702
9703  		// @option maxHeight: Number = null
9704  		// If set, creates a scrollable container of the given height
9705  		// inside a popup if its content exceeds it.
9706  		maxHeight: null,
9707
9708  		// @option autoPan: Boolean = true
9709  		// Set it to `false` if you don't want the map to do panning animation
9710  		// to fit the opened popup.
9711  		autoPan: true,
9712
9713  		// @option autoPanPaddingTopLeft: Point = null
9714  		// The margin between the popup and the top left corner of the map
9715  		// view after autopanning was performed.
9716  		autoPanPaddingTopLeft: null,
9717
9718  		// @option autoPanPaddingBottomRight: Point = null
9719  		// The margin between the popup and the bottom right corner of the map
9720  		// view after autopanning was performed.
9721  		autoPanPaddingBottomRight: null,
9722
9723  		// @option autoPanPadding: Point = Point(5, 5)
9724  		// Equivalent of setting both top left and bottom right autopan padding to the same value.
9725  		autoPanPadding: [5, 5],
9726
9727  		// @option keepInView: Boolean = false
9728  		// Set it to `true` if you want to prevent users from panning the popup
9729  		// off of the screen while it is open.
9730  		keepInView: false,
9731
9732  		// @option closeButton: Boolean = true
9733  		// Controls the presence of a close button in the popup.
9734  		closeButton: true,
9735
9736  		// @option autoClose: Boolean = true
9737  		// Set it to `false` if you want to override the default behavior of
9738  		// the popup closing when another popup is opened.
9739  		autoClose: true,
9740
9741  		// @option closeOnEscapeKey: Boolean = true
9742  		// Set it to `false` if you want to override the default behavior of
9743  		// the ESC key for closing of the popup.
9744  		closeOnEscapeKey: true,
9745
9746  		// @option closeOnClick: Boolean = *
9747  		// Set it if you want to override the default behavior of the popup closing when user clicks
9748  		// on the map. Defaults to the map's [`closePopupOnClick`](#map-closepopuponclick) option.
9749
9750  		// @option className: String = ''
9751  		// A custom CSS class name to assign to the popup.
9752  		className: ''
9753  	},
9754
9755  	// @namespace Popup
9756  	// @method openOn(map: Map): this
9757  	// Adds the popup to the map and closes the previous one. The same as `map.openPopup(popup)`.
9758  	openOn: function (map) {
9759  		map.openPopup(this);
9760  		return this;
9761  	},
9762
9763  	onAdd: function (map) {
9764  		DivOverlay.prototype.onAdd.call(this, map);
9765
9766  		// @namespace Map
9767  		// @section Popup events
9768  		// @event popupopen: PopupEvent
9769  		// Fired when a popup is opened in the map
9770  		map.fire('popupopen', {popup: this});
9771
9772  		if (this._source) {
9773  			// @namespace Layer
9774  			// @section Popup events
9775  			// @event popupopen: PopupEvent
9776  			// Fired when a popup bound to this layer is opened
9777  			this._source.fire('popupopen', {popup: this}, true);
9778  			// For non-path layers, we toggle the popup when clicking
9779  			// again the layer, so prevent the map to reopen it.
9780  			if (!(this._source instanceof Path)) {
9781  				this._source.on('preclick', stopPropagation);
9782  			}
9783  		}
9784  	},
9785
9786  	onRemove: function (map) {
9787  		DivOverlay.prototype.onRemove.call(this, map);
9788
9789  		// @namespace Map
9790  		// @section Popup events
9791  		// @event popupclose: PopupEvent
9792  		// Fired when a popup in the map is closed
9793  		map.fire('popupclose', {popup: this});
9794
9795  		if (this._source) {
9796  			// @namespace Layer
9797  			// @section Popup events
9798  			// @event popupclose: PopupEvent
9799  			// Fired when a popup bound to this layer is closed
9800  			this._source.fire('popupclose', {popup: this}, true);
9801  			if (!(this._source instanceof Path)) {
9802  				this._source.off('preclick', stopPropagation);
9803  			}
9804  		}
9805  	},
9806
9807  	getEvents: function () {
9808  		var events = DivOverlay.prototype.getEvents.call(this);
9809
9810  		if (this.options.closeOnClick !== undefined ? this.options.closeOnClick : this._map.options.closePopupOnClick) {
9811  			events.preclick = this._close;
9812  		}
9813
9814  		if (this.options.keepInView) {
9815  			events.moveend = this._adjustPan;
9816  		}
9817
9818  		return events;
9819  	},
9820
9821  	_close: function () {
9822  		if (this._map) {
9823  			this._map.closePopup(this);
9824  		}
9825  	},
9826
9827  	_initLayout: function () {
9828  		var prefix = 'leaflet-popup',
9829  		    container = this._container = create$1('div',
9830  			prefix + ' ' + (this.options.className || '') +
9831  			' leaflet-zoom-animated');
9832
9833  		var wrapper = this._wrapper = create$1('div', prefix + '-content-wrapper', container);
9834  		this._contentNode = create$1('div', prefix + '-content', wrapper);
9835
9836  		disableClickPropagation(container);
9837  		disableScrollPropagation(this._contentNode);
9838  		on(container, 'contextmenu', stopPropagation);
9839
9840  		this._tipContainer = create$1('div', prefix + '-tip-container', container);
9841  		this._tip = create$1('div', prefix + '-tip', this._tipContainer);
9842
9843  		if (this.options.closeButton) {
9844  			var closeButton = this._closeButton = create$1('a', prefix + '-close-button', container);
9845  			closeButton.href = '#close';
9846  			closeButton.innerHTML = '&#215;';
9847
9848  			on(closeButton, 'click', this._onCloseButtonClick, this);
9849  		}
9850  	},
9851
9852  	_updateLayout: function () {
9853  		var container = this._contentNode,
9854  		    style = container.style;
9855
9856  		style.width = '';
9857  		style.whiteSpace = 'nowrap';
9858
9859  		var width = container.offsetWidth;
9860  		width = Math.min(width, this.options.maxWidth);
9861  		width = Math.max(width, this.options.minWidth);
9862
9863  		style.width = (width + 1) + 'px';
9864  		style.whiteSpace = '';
9865
9866  		style.height = '';
9867
9868  		var height = container.offsetHeight,
9869  		    maxHeight = this.options.maxHeight,
9870  		    scrolledClass = 'leaflet-popup-scrolled';
9871
9872  		if (maxHeight && height > maxHeight) {
9873  			style.height = maxHeight + 'px';
9874  			addClass(container, scrolledClass);
9875  		} else {
9876  			removeClass(container, scrolledClass);
9877  		}
9878
9879  		this._containerWidth = this._container.offsetWidth;
9880  	},
9881
9882  	_animateZoom: function (e) {
9883  		var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center),
9884  		    anchor = this._getAnchor();
9885  		setPosition(this._container, pos.add(anchor));
9886  	},
9887
9888  	_adjustPan: function () {
9889  		if (!this.options.autoPan) { return; }
9890  		if (this._map._panAnim) { this._map._panAnim.stop(); }
9891
9892  		var map = this._map,
9893  		    marginBottom = parseInt(getStyle(this._container, 'marginBottom'), 10) || 0,
9894  		    containerHeight = this._container.offsetHeight + marginBottom,
9895  		    containerWidth = this._containerWidth,
9896  		    layerPos = new Point(this._containerLeft, -containerHeight - this._containerBottom);
9897
9898  		layerPos._add(getPosition(this._container));
9899
9900  		var containerPos = map.layerPointToContainerPoint(layerPos),
9901  		    padding = toPoint(this.options.autoPanPadding),
9902  		    paddingTL = toPoint(this.options.autoPanPaddingTopLeft || padding),
9903  		    paddingBR = toPoint(this.options.autoPanPaddingBottomRight || padding),
9904  		    size = map.getSize(),
9905  		    dx = 0,
9906  		    dy = 0;
9907
9908  		if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right
9909  			dx = containerPos.x + containerWidth - size.x + paddingBR.x;
9910  		}
9911  		if (containerPos.x - dx - paddingTL.x < 0) { // left
9912  			dx = containerPos.x - paddingTL.x;
9913  		}
9914  		if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom
9915  			dy = containerPos.y + containerHeight - size.y + paddingBR.y;
9916  		}
9917  		if (containerPos.y - dy - paddingTL.y < 0) { // top
9918  			dy = containerPos.y - paddingTL.y;
9919  		}
9920
9921  		// @namespace Map
9922  		// @section Popup events
9923  		// @event autopanstart: Event
9924  		// Fired when the map starts autopanning when opening a popup.
9925  		if (dx || dy) {
9926  			map
9927  			    .fire('autopanstart')
9928  			    .panBy([dx, dy]);
9929  		}
9930  	},
9931
9932  	_onCloseButtonClick: function (e) {
9933  		this._close();
9934  		stop(e);
9935  	},
9936
9937  	_getAnchor: function () {
9938  		// Where should we anchor the popup on the source layer?
9939  		return toPoint(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]);
9940  	}
9941
9942  });
9943
9944  // @namespace Popup
9945  // @factory L.popup(options?: Popup options, source?: Layer)
9946  // 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.
9947  var popup = function (options, source) {
9948  	return new Popup(options, source);
9949  };
9950
9951
9952  /* @namespace Map
9953   * @section Interaction Options
9954   * @option closePopupOnClick: Boolean = true
9955   * Set it to `false` if you don't want popups to close when user clicks the map.
9956   */
9957  Map.mergeOptions({
9958  	closePopupOnClick: true
9959  });
9960
9961
9962  // @namespace Map
9963  // @section Methods for Layers and Controls
9964  Map.include({
9965  	// @method openPopup(popup: Popup): this
9966  	// Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability).
9967  	// @alternative
9968  	// @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this
9969  	// Creates a popup with the specified content and options and opens it in the given point on a map.
9970  	openPopup: function (popup, latlng, options) {
9971  		if (!(popup instanceof Popup)) {
9972  			popup = new Popup(options).setContent(popup);
9973  		}
9974
9975  		if (latlng) {
9976  			popup.setLatLng(latlng);
9977  		}
9978
9979  		if (this.hasLayer(popup)) {
9980  			return this;
9981  		}
9982
9983  		if (this._popup && this._popup.options.autoClose) {
9984  			this.closePopup();
9985  		}
9986
9987  		this._popup = popup;
9988  		return this.addLayer(popup);
9989  	},
9990
9991  	// @method closePopup(popup?: Popup): this
9992  	// Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one).
9993  	closePopup: function (popup) {
9994  		if (!popup || popup === this._popup) {
9995  			popup = this._popup;
9996  			this._popup = null;
9997  		}
9998  		if (popup) {
9999  			this.removeLayer(popup);
10000  		}
10001  		return this;
10002  	}
10003  });
10004
10005  /*
10006   * @namespace Layer
10007   * @section Popup methods example
10008   *
10009   * All layers share a set of methods convenient for binding popups to it.
10010   *
10011   * ```js
10012   * var layer = L.Polygon(latlngs).bindPopup('Hi There!').addTo(map);
10013   * layer.openPopup();
10014   * layer.closePopup();
10015   * ```
10016   *
10017   * 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.
10018   */
10019
10020  // @section Popup methods
10021  Layer.include({
10022
10023  	// @method bindPopup(content: String|HTMLElement|Function|Popup, options?: Popup options): this
10024  	// Binds a popup to the layer with the passed `content` and sets up the
10025  	// necessary event listeners. If a `Function` is passed it will receive
10026  	// the layer as the first argument and should return a `String` or `HTMLElement`.
10027  	bindPopup: function (content, options) {
10028
10029  		if (content instanceof Popup) {
10030  			setOptions(content, options);
10031  			this._popup = content;
10032  			content._source = this;
10033  		} else {
10034  			if (!this._popup || options) {
10035  				this._popup = new Popup(options, this);
10036  			}
10037  			this._popup.setContent(content);
10038  		}
10039
10040  		if (!this._popupHandlersAdded) {
10041  			this.on({
10042  				click: this._openPopup,
10043  				keypress: this._onKeyPress,
10044  				remove: this.closePopup,
10045  				move: this._movePopup
10046  			});
10047  			this._popupHandlersAdded = true;
10048  		}
10049
10050  		return this;
10051  	},
10052
10053  	// @method unbindPopup(): this
10054  	// Removes the popup previously bound with `bindPopup`.
10055  	unbindPopup: function () {
10056  		if (this._popup) {
10057  			this.off({
10058  				click: this._openPopup,
10059  				keypress: this._onKeyPress,
10060  				remove: this.closePopup,
10061  				move: this._movePopup
10062  			});
10063  			this._popupHandlersAdded = false;
10064  			this._popup = null;
10065  		}
10066  		return this;
10067  	},
10068
10069  	// @method openPopup(latlng?: LatLng): this
10070  	// Opens the bound popup at the specified `latlng` or at the default popup anchor if no `latlng` is passed.
10071  	openPopup: function (layer, latlng) {
10072  		if (this._popup && this._map) {
10073  			latlng = this._popup._prepareOpen(this, layer, latlng);
10074
10075  			// open the popup on the map
10076  			this._map.openPopup(this._popup, latlng);
10077  		}
10078
10079  		return this;
10080  	},
10081
10082  	// @method closePopup(): this
10083  	// Closes the popup bound to this layer if it is open.
10084  	closePopup: function () {
10085  		if (this._popup) {
10086  			this._popup._close();
10087  		}
10088  		return this;
10089  	},
10090
10091  	// @method togglePopup(): this
10092  	// Opens or closes the popup bound to this layer depending on its current state.
10093  	togglePopup: function (target) {
10094  		if (this._popup) {
10095  			if (this._popup._map) {
10096  				this.closePopup();
10097  			} else {
10098  				this.openPopup(target);
10099  			}
10100  		}
10101  		return this;
10102  	},
10103
10104  	// @method isPopupOpen(): boolean
10105  	// Returns `true` if the popup bound to this layer is currently open.
10106  	isPopupOpen: function () {
10107  		return (this._popup ? this._popup.isOpen() : false);
10108  	},
10109
10110  	// @method setPopupContent(content: String|HTMLElement|Popup): this
10111  	// Sets the content of the popup bound to this layer.
10112  	setPopupContent: function (content) {
10113  		if (this._popup) {
10114  			this._popup.setContent(content);
10115  		}
10116  		return this;
10117  	},
10118
10119  	// @method getPopup(): Popup
10120  	// Returns the popup bound to this layer.
10121  	getPopup: function () {
10122  		return this._popup;
10123  	},
10124
10125  	_openPopup: function (e) {
10126  		var layer = e.layer || e.target;
10127
10128  		if (!this._popup) {
10129  			return;
10130  		}
10131
10132  		if (!this._map) {
10133  			return;
10134  		}
10135
10136  		// prevent map click
10137  		stop(e);
10138
10139  		// if this inherits from Path its a vector and we can just
10140  		// open the popup at the new location
10141  		if (layer instanceof Path) {
10142  			this.openPopup(e.layer || e.target, e.latlng);
10143  			return;
10144  		}
10145
10146  		// otherwise treat it like a marker and figure out
10147  		// if we should toggle it open/closed
10148  		if (this._map.hasLayer(this._popup) && this._popup._source === layer) {
10149  			this.closePopup();
10150  		} else {
10151  			this.openPopup(layer, e.latlng);
10152  		}
10153  	},
10154
10155  	_movePopup: function (e) {
10156  		this._popup.setLatLng(e.latlng);
10157  	},
10158
10159  	_onKeyPress: function (e) {
10160  		if (e.originalEvent.keyCode === 13) {
10161  			this._openPopup(e);
10162  		}
10163  	}
10164  });
10165
10166  /*
10167   * @class Tooltip
10168   * @inherits DivOverlay
10169   * @aka L.Tooltip
10170   * Used to display small texts on top of map layers.
10171   *
10172   * @example
10173   *
10174   * ```js
10175   * marker.bindTooltip("my tooltip text").openTooltip();
10176   * ```
10177   * Note about tooltip offset. Leaflet takes two options in consideration
10178   * for computing tooltip offsetting:
10179   * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.
10180   *   Add a positive x offset to move the tooltip to the right, and a positive y offset to
10181   *   move it to the bottom. Negatives will move to the left and top.
10182   * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You
10183   *   should adapt this value if you use a custom icon.
10184   */
10185
10186
10187  // @namespace Tooltip
10188  var Tooltip = DivOverlay.extend({
10189
10190  	// @section
10191  	// @aka Tooltip options
10192  	options: {
10193  		// @option pane: String = 'tooltipPane'
10194  		// `Map pane` where the tooltip will be added.
10195  		pane: 'tooltipPane',
10196
10197  		// @option offset: Point = Point(0, 0)
10198  		// Optional offset of the tooltip position.
10199  		offset: [0, 0],
10200
10201  		// @option direction: String = 'auto'
10202  		// Direction where to open the tooltip. Possible values are: `right`, `left`,
10203  		// `top`, `bottom`, `center`, `auto`.
10204  		// `auto` will dynamically switch between `right` and `left` according to the tooltip
10205  		// position on the map.
10206  		direction: 'auto',
10207
10208  		// @option permanent: Boolean = false
10209  		// Whether to open the tooltip permanently or only on mouseover.
10210  		permanent: false,
10211
10212  		// @option sticky: Boolean = false
10213  		// If true, the tooltip will follow the mouse instead of being fixed at the feature center.
vendor: 13,806 bytes, lines 10214-10678
10214  		sticky: false,
10215
10216  		// @option interactive: Boolean = false
10217  		// If true, the tooltip will listen to the feature events.
10218  		interactive: false,
10219
10220  		// @option opacity: Number = 0.9
10221  		// Tooltip container opacity.
10222  		opacity: 0.9
10223  	},
10224
10225  	onAdd: function (map) {
10226  		DivOverlay.prototype.onAdd.call(this, map);
10227  		this.setOpacity(this.options.opacity);
10228
10229  		// @namespace Map
10230  		// @section Tooltip events
10231  		// @event tooltipopen: TooltipEvent
10232  		// Fired when a tooltip is opened in the map.
10233  		map.fire('tooltipopen', {tooltip: this});
10234
10235  		if (this._source) {
10236  			// @namespace Layer
10237  			// @section Tooltip events
10238  			// @event tooltipopen: TooltipEvent
10239  			// Fired when a tooltip bound to this layer is opened.
10240  			this._source.fire('tooltipopen', {tooltip: this}, true);
10241  		}
10242  	},
10243
10244  	onRemove: function (map) {
10245  		DivOverlay.prototype.onRemove.call(this, map);
10246
10247  		// @namespace Map
10248  		// @section Tooltip events
10249  		// @event tooltipclose: TooltipEvent
10250  		// Fired when a tooltip in the map is closed.
10251  		map.fire('tooltipclose', {tooltip: this});
10252
10253  		if (this._source) {
10254  			// @namespace Layer
10255  			// @section Tooltip events
10256  			// @event tooltipclose: TooltipEvent
10257  			// Fired when a tooltip bound to this layer is closed.
10258  			this._source.fire('tooltipclose', {tooltip: this}, true);
10259  		}
10260  	},
10261
10262  	getEvents: function () {
10263  		var events = DivOverlay.prototype.getEvents.call(this);
10264
10265  		if (touch && !this.options.permanent) {
10266  			events.preclick = this._close;
10267  		}
10268
10269  		return events;
10270  	},
10271
10272  	_close: function () {
10273  		if (this._map) {
10274  			this._map.closeTooltip(this);
10275  		}
10276  	},
10277
10278  	_initLayout: function () {
10279  		var prefix = 'leaflet-tooltip',
10280  		    className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
10281
10282  		this._contentNode = this._container = create$1('div', className);
10283  	},
10284
10285  	_updateLayout: function () {},
10286
10287  	_adjustPan: function () {},
10288
10289  	_setPosition: function (pos) {
10290  		var subX, subY,
10291  		    map = this._map,
10292  		    container = this._container,
10293  		    centerPoint = map.latLngToContainerPoint(map.getCenter()),
10294  		    tooltipPoint = map.layerPointToContainerPoint(pos),
10295  		    direction = this.options.direction,
10296  		    tooltipWidth = container.offsetWidth,
10297  		    tooltipHeight = container.offsetHeight,
10298  		    offset = toPoint(this.options.offset),
10299  		    anchor = this._getAnchor();
10300
10301  		if (direction === 'top') {
10302  			subX = tooltipWidth / 2;
10303  			subY = tooltipHeight;
10304  		} else if (direction === 'bottom') {
10305  			subX = tooltipWidth / 2;
10306  			subY = 0;
10307  		} else if (direction === 'center') {
10308  			subX = tooltipWidth / 2;
10309  			subY = tooltipHeight / 2;
10310  		} else if (direction === 'right') {
10311  			subX = 0;
10312  			subY = tooltipHeight / 2;
10313  		} else if (direction === 'left') {
10314  			subX = tooltipWidth;
10315  			subY = tooltipHeight / 2;
10316  		} else if (tooltipPoint.x < centerPoint.x) {
10317  			direction = 'right';
10318  			subX = 0;
10319  			subY = tooltipHeight / 2;
10320  		} else {
10321  			direction = 'left';
10322  			subX = tooltipWidth + (offset.x + anchor.x) * 2;
10323  			subY = tooltipHeight / 2;
10324  		}
10325
10326  		pos = pos.subtract(toPoint(subX, subY, true)).add(offset).add(anchor);
10327
10328  		removeClass(container, 'leaflet-tooltip-right');
10329  		removeClass(container, 'leaflet-tooltip-left');
10330  		removeClass(container, 'leaflet-tooltip-top');
10331  		removeClass(container, 'leaflet-tooltip-bottom');
10332  		addClass(container, 'leaflet-tooltip-' + direction);
10333  		setPosition(container, pos);
10334  	},
10335
10336  	_updatePosition: function () {
10337  		var pos = this._map.latLngToLayerPoint(this._latlng);
10338  		this._setPosition(pos);
10339  	},
10340
10341  	setOpacity: function (opacity) {
10342  		this.options.opacity = opacity;
10343
10344  		if (this._container) {
10345  			setOpacity(this._container, opacity);
10346  		}
10347  	},
10348
10349  	_animateZoom: function (e) {
10350  		var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
10351  		this._setPosition(pos);
10352  	},
10353
10354  	_getAnchor: function () {
10355  		// Where should we anchor the tooltip on the source layer?
10356  		return toPoint(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);
10357  	}
10358
10359  });
10360
10361  // @namespace Tooltip
10362  // @factory L.tooltip(options?: Tooltip options, source?: Layer)
10363  // 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.
10364  var tooltip = function (options, source) {
10365  	return new Tooltip(options, source);
10366  };
10367
10368  // @namespace Map
10369  // @section Methods for Layers and Controls
10370  Map.include({
10371
10372  	// @method openTooltip(tooltip: Tooltip): this
10373  	// Opens the specified tooltip.
10374  	// @alternative
10375  	// @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this
10376  	// Creates a tooltip with the specified content and options and open it.
10377  	openTooltip: function (tooltip, latlng, options) {
10378  		if (!(tooltip instanceof Tooltip)) {
10379  			tooltip = new Tooltip(options).setContent(tooltip);
10380  		}
10381
10382  		if (latlng) {
10383  			tooltip.setLatLng(latlng);
10384  		}
10385
10386  		if (this.hasLayer(tooltip)) {
10387  			return this;
10388  		}
10389
10390  		return this.addLayer(tooltip);
10391  	},
10392
10393  	// @method closeTooltip(tooltip?: Tooltip): this
10394  	// Closes the tooltip given as parameter.
10395  	closeTooltip: function (tooltip) {
10396  		if (tooltip) {
10397  			this.removeLayer(tooltip);
10398  		}
10399  		return this;
10400  	}
10401
10402  });
10403
10404  /*
10405   * @namespace Layer
10406   * @section Tooltip methods example
10407   *
10408   * All layers share a set of methods convenient for binding tooltips to it.
10409   *
10410   * ```js
10411   * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);
10412   * layer.openTooltip();
10413   * layer.closeTooltip();
10414   * ```
10415   */
10416
10417  // @section Tooltip methods
10418  Layer.include({
10419
10420  	// @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this
10421  	// Binds a tooltip to the layer with the passed `content` and sets up the
10422  	// necessary event listeners. If a `Function` is passed it will receive
10423  	// the layer as the first argument and should return a `String` or `HTMLElement`.
10424  	bindTooltip: function (content, options) {
10425
10426  		if (content instanceof Tooltip) {
10427  			setOptions(content, options);
10428  			this._tooltip = content;
10429  			content._source = this;
10430  		} else {
10431  			if (!this._tooltip || options) {
10432  				this._tooltip = new Tooltip(options, this);
10433  			}
10434  			this._tooltip.setContent(content);
10435
10436  		}
10437
10438  		this._initTooltipInteractions();
10439
10440  		if (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {
10441  			this.openTooltip();
10442  		}
10443
10444  		return this;
10445  	},
10446
10447  	// @method unbindTooltip(): this
10448  	// Removes the tooltip previously bound with `bindTooltip`.
10449  	unbindTooltip: function () {
10450  		if (this._tooltip) {
10451  			this._initTooltipInteractions(true);
10452  			this.closeTooltip();
10453  			this._tooltip = null;
10454  		}
10455  		return this;
10456  	},
10457
10458  	_initTooltipInteractions: function (remove) {
10459  		if (!remove && this._tooltipHandlersAdded) { return; }
10460  		var onOff = remove ? 'off' : 'on',
10461  		    events = {
10462  			remove: this.closeTooltip,
10463  			move: this._moveTooltip
10464  		    };
10465  		if (!this._tooltip.options.permanent) {
10466  			events.mouseover = this._openTooltip;
10467  			events.mouseout = this.closeTooltip;
10468  			if (this._tooltip.options.sticky) {
10469  				events.mousemove = this._moveTooltip;
10470  			}
10471  			if (touch) {
10472  				events.click = this._openTooltip;
10473  			}
10474  		} else {
10475  			events.add = this._openTooltip;
10476  		}
10477  		this[onOff](events);
10478  		this._tooltipHandlersAdded = !remove;
10479  	},
10480
10481  	// @method openTooltip(latlng?: LatLng): this
10482  	// Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed.
10483  	openTooltip: function (layer, latlng) {
10484  		if (this._tooltip && this._map) {
10485  			latlng = this._tooltip._prepareOpen(this, layer, latlng);
10486
10487  			// open the tooltip on the map
10488  			this._map.openTooltip(this._tooltip, latlng);
10489
10490  			// Tooltip container may not be defined if not permanent and never
10491  			// opened.
10492  			if (this._tooltip.options.interactive && this._tooltip._container) {
10493  				addClass(this._tooltip._container, 'leaflet-clickable');
10494  				this.addInteractiveTarget(this._tooltip._container);
10495  			}
10496  		}
10497
10498  		return this;
10499  	},
10500
10501  	// @method closeTooltip(): this
10502  	// Closes the tooltip bound to this layer if it is open.
10503  	closeTooltip: function () {
10504  		if (this._tooltip) {
10505  			this._tooltip._close();
10506  			if (this._tooltip.options.interactive && this._tooltip._container) {
10507  				removeClass(this._tooltip._container, 'leaflet-clickable');
10508  				this.removeInteractiveTarget(this._tooltip._container);
10509  			}
10510  		}
10511  		return this;
10512  	},
10513
10514  	// @method toggleTooltip(): this
10515  	// Opens or closes the tooltip bound to this layer depending on its current state.
10516  	toggleTooltip: function (target) {
10517  		if (this._tooltip) {
10518  			if (this._tooltip._map) {
10519  				this.closeTooltip();
10520  			} else {
10521  				this.openTooltip(target);
10522  			}
10523  		}
10524  		return this;
10525  	},
10526
10527  	// @method isTooltipOpen(): boolean
10528  	// Returns `true` if the tooltip bound to this layer is currently open.
10529  	isTooltipOpen: function () {
10530  		return this._tooltip.isOpen();
10531  	},
10532
10533  	// @method setTooltipContent(content: String|HTMLElement|Tooltip): this
10534  	// Sets the content of the tooltip bound to this layer.
10535  	setTooltipContent: function (content) {
10536  		if (this._tooltip) {
10537  			this._tooltip.setContent(content);
10538  		}
10539  		return this;
10540  	},
10541
10542  	// @method getTooltip(): Tooltip
10543  	// Returns the tooltip bound to this layer.
10544  	getTooltip: function () {
10545  		return this._tooltip;
10546  	},
10547
10548  	_openTooltip: function (e) {
10549  		var layer = e.layer || e.target;
10550
10551  		if (!this._tooltip || !this._map) {
10552  			return;
10553  		}
10554  		this.openTooltip(layer, this._tooltip.options.sticky ? e.latlng : undefined);
10555  	},
10556
10557  	_moveTooltip: function (e) {
10558  		var latlng = e.latlng, containerPoint, layerPoint;
10559  		if (this._tooltip.options.sticky && e.originalEvent) {
10560  			containerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);
10561  			layerPoint = this._map.containerPointToLayerPoint(containerPoint);
10562  			latlng = this._map.layerPointToLatLng(layerPoint);
10563  		}
10564  		this._tooltip.setLatLng(latlng);
10565  	}
10566  });
10567
10568  /*
10569   * @class DivIcon
10570   * @aka L.DivIcon
10571   * @inherits Icon
10572   *
10573   * Represents a lightweight icon for markers that uses a simple `<div>`
10574   * element instead of an image. Inherits from `Icon` but ignores the `iconUrl` and shadow options.
10575   *
10576   * @example
10577   * ```js
10578   * var myIcon = L.divIcon({className: 'my-div-icon'});
10579   * // you can set .my-div-icon styles in CSS
10580   *
10581   * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
10582   * ```
10583   *
10584   * By default, it has a 'leaflet-div-icon' CSS class and is styled as a little white square with a shadow.
10585   */
10586
10587  var DivIcon = Icon.extend({
10588  	options: {
10589  		// @section
10590  		// @aka DivIcon options
10591  		iconSize: [12, 12], // also can be set through CSS
10592
10593  		// iconAnchor: (Point),
10594  		// popupAnchor: (Point),
10595
10596  		// @option html: String|HTMLElement = ''
10597  		// Custom HTML code to put inside the div element, empty by default. Alternatively,
10598  		// an instance of `HTMLElement`.
10599  		html: false,
10600
10601  		// @option bgPos: Point = [0, 0]
10602  		// Optional relative position of the background, in pixels
10603  		bgPos: null,
10604
10605  		className: 'leaflet-div-icon'
10606  	},
10607
10608  	createIcon: function (oldIcon) {
10609  		var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),
10610  		    options = this.options;
10611
10612  		if (options.html instanceof Element) {
10613  			empty(div);
10614  			div.appendChild(options.html);
10615  		} else {
10616  			div.innerHTML = options.html !== false ? options.html : '';
10617  		}
10618
10619  		if (options.bgPos) {
10620  			var bgPos = toPoint(options.bgPos);
10621  			div.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px';
10622  		}
10623  		this._setIconStyles(div, 'icon');
10624
10625  		return div;
10626  	},
10627
10628  	createShadow: function () {
10629  		return null;
10630  	}
10631  });
10632
10633  // @factory L.divIcon(options: DivIcon options)
10634  // Creates a `DivIcon` instance with the given options.
10635  function divIcon(options) {
10636  	return new DivIcon(options);
10637  }
10638
10639  Icon.Default = IconDefault;
10640
10641  /*
10642   * @class GridLayer
10643   * @inherits Layer
10644   * @aka L.GridLayer
10645   *
10646   * Generic class for handling a tiled grid of HTML elements. This is the base class for all tile layers and replaces `TileLayer.Canvas`.
10647   * 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.
10648   *
10649   *
10650   * @section Synchronous usage
10651   * @example
10652   *
10653   * 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.
10654   *
10655   * ```js
10656   * var CanvasLayer = L.GridLayer.extend({
10657   *     createTile: function(coords){
10658   *         // create a <canvas> element for drawing
10659   *         var tile = L.DomUtil.create('canvas', 'leaflet-tile');
10660   *
10661   *         // setup tile width and height according to the options
10662   *         var size = this.getTileSize();
10663   *         tile.width = size.x;
10664   *         tile.height = size.y;
10665   *
10666   *         // get a canvas context and draw something on it using coords.x, coords.y and coords.z
10667   *         var ctx = tile.getContext('2d');
10668   *
10669   *         // return the tile so it can be rendered on screen
10670   *         return tile;
10671   *     }
10672   * });
10673   * ```
10674   *
10675   * @section Asynchronous usage
10676   * @example
10677   *
10678   * Tile creation can also be asynchronous, this is useful when using a third-party drawing library. O
10678nce the tile is finished drawing it can be passed to the `done()` callback.
10679   *
10680   * ```js
10681   * var CanvasLayer = L.GridLayer.extend({
10682   *     createTile: function(coords, done){
10683   *         var error;
10684   *
10685   *         // create a <canvas> element for drawing
10686   *         var tile = L.DomUtil.create('canvas', 'leaflet-tile');
10687   *
10688   *         // setup tile width and height according to the options
10689   *         var size = this.getTileSize();
10690   *         tile.width = size.x;
10691   *         tile.height = size.y;
10692   *
10693   *         // draw something asynchronously and pass the tile to the done() callback
10694   *         setTimeout(function() {
10695   *             done(error, tile);
10696   *         }, 1000);
10697   *
10698   *         return tile;
10699   *     }
10700   * });
10701   * ```
10702   *
10703   * @section
10704   */
10705
10706
10707  var GridLayer = Layer.extend({
10708
10709  	// @section
10710  	// @aka GridLayer options
10711  	options: {
10712  		// @option tileSize: Number|Point = 256
10713  		// Width and height of tiles in the grid. Use a number if width and height are equal, or `L.point(width, height)` otherwise.
10714  		tileSize: 256,
10715
10716  		// @option opacity: Number = 1.0
10717  		// Opacity of the tiles. Can be used in the `createTile()` function.
10718  		opacity: 1,
10719
10720  		// @option updateWhenIdle: Boolean = (depends)
10721  		// Load new tiles only when panning ends.
10722  		// `true` by default on mobile browsers, in order to avoid too many requests and keep smooth navigation.
10723  		// `false` otherwise in order to display new tiles _during_ panning, since it is easy to pan outside the
10724  		// [`keepBuffer`](#gridlayer-keepbuffer) option in desktop browsers.
10725  		updateWhenIdle: mobile,
10726
10727  		// @option updateWhenZooming: Boolean = true
10728  		// 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.
10729  		updateWhenZooming: true,
10730
10731  		// @option updateInterval: Number = 200
10732  		// Tiles will not update more than once every `updateInterval` milliseconds when panning.
10733  		updateInterval: 200,
10734
10735  		// @option zIndex: Number = 1
10736  		// The explicit zIndex of the tile layer.
10737  		zIndex: 1,
10738
10739  		// @option bounds: LatLngBounds = undefined
10740  		// If set, tiles will only be loaded inside the set `LatLngBounds`.
10741  		bounds: null,
10742
10743  		// @option minZoom: Number = 0
10744  		// The minimum zoom level down to which this layer will be displayed (inclusive).
10745  		minZoom: 0,
10746
10747  		// @option maxZoom: Number = undefined
10748  		// The maximum zoom level up to which this layer will be displayed (inclusive).
10749  		maxZoom: undefined,
10750
10751  		// @option maxNativeZoom: Number = undefined
10752  		// Maximum zoom number the tile source has available. If it is specified,
10753  		// the tiles on all zoom levels higher than `maxNativeZoom` will be loaded
10754  		// from `maxNativeZoom` level and auto-scaled.
10755  		maxNativeZoom: undefined,
10756
10757  		// @option minNativeZoom: Number = undefined
10758  		// Minimum zoom number the tile source has available. If it is specified,
10759  		// the tiles on all zoom levels lower than `minNativeZoom` will be loaded
10760  		// from `minNativeZoom` level and auto-scaled.
10761  		minNativeZoom: undefined,
10762
10763  		// @option noWrap: Boolean = false
10764  		// Whether the layer is wrapped around the antimeridian. If `true`, the
10765  		// GridLayer will only be displayed once at low zoom levels. Has no
10766  		// effect when the [map CRS](#map-crs) doesn't wrap around. Can be used
10767  		// in combination with [`bounds`](#gridlayer-bounds) to prevent requesting
10768  		// tiles outside the CRS limits.
10769  		noWrap: false,
10770
10771  		// @option pane: String = 'tilePane'
10772  		// `Map pane` where the grid layer will be added.
10773  		pane: 'tilePane',
10774
10775  		// @option className: String = ''
10776  		// A custom class name to assign to the tile layer. Empty by default.
10777  		className: '',
10778
10779  		// @option keepBuffer: Number = 2
10780  		// When panning the map, keep this many rows and columns of tiles before unloading them.
10781  		keepBuffer: 2
10782  	},
10783
10784  	initialize: function (options) {
10785  		setOptions(this, options);
10786  	},
10787
10788  	onAdd: function () {
10789  		this._initContainer();
10790
10791  		this._levels = {};
10792  		this._tiles = {};
10793
10794  		this._resetView();
10795  		this._update();
10796  	},
10797
10798  	beforeAdd: function (map) {
vendor: 4,091 bytes, lines 10799-10942
10799  		map._addZoomLimit(this);
10800  	},
10801
10802  	onRemove: function (map) {
10803  		this._removeAllTiles();
10804  		remove(this._container);
10805  		map._removeZoomLimit(this);
10806  		this._container = null;
10807  		this._tileZoom = undefined;
10808  	},
10809
10810  	// @method bringToFront: this
10811  	// Brings the tile layer to the top of all tile layers.
10812  	bringToFront: function () {
10813  		if (this._map) {
10814  			toFront(this._container);
10815  			this._setAutoZIndex(Math.max);
10816  		}
10817  		return this;
10818  	},
10819
10820  	// @method bringToBack: this
10821  	// Brings the tile layer to the bottom of all tile layers.
10822  	bringToBack: function () {
10823  		if (this._map) {
10824  			toBack(this._container);
10825  			this._setAutoZIndex(Math.min);
10826  		}
10827  		return this;
10828  	},
10829
10830  	// @method getContainer: HTMLElement
10831  	// Returns the HTML element that contains the tiles for this layer.
10832  	getContainer: function () {
10833  		return this._container;
10834  	},
10835
10836  	// @method setOpacity(opacity: Number): this
10837  	// Changes the [opacity](#gridlayer-opacity) of the grid layer.
10838  	setOpacity: function (opacity) {
10839  		this.options.opacity = opacity;
10840  		this._updateOpacity();
10841  		return this;
10842  	},
10843
10844  	// @method setZIndex(zIndex: Number): this
10845  	// Changes the [zIndex](#gridlayer-zindex) of the grid layer.
10846  	setZIndex: function (zIndex) {
10847  		this.options.zIndex = zIndex;
10848  		this._updateZIndex();
10849
10850  		return this;
10851  	},
10852
10853  	// @method isLoading: Boolean
10854  	// Returns `true` if any tile in the grid layer has not finished loading.
10855  	isLoading: function () {
10856  		return this._loading;
10857  	},
10858
10859  	// @method redraw: this
10860  	// Causes the layer to clear all the tiles and request them again.
10861  	redraw: function () {
10862  		if (this._map) {
10863  			this._removeAllTiles();
10864  			this._update();
10865  		}
10866  		return this;
10867  	},
10868
10869  	getEvents: function () {
10870  		var events = {
10871  			viewprereset: this._invalidateAll,
10872  			viewreset: this._resetView,
10873  			zoom: this._resetView,
10874  			moveend: this._onMoveEnd
10875  		};
10876
10877  		if (!this.options.updateWhenIdle) {
10878  			// update tiles on move, but not more often than once per given interval
10879  			if (!this._onMove) {
10880  				this._onMove = throttle(this._onMoveEnd, this.options.updateInterval, this);
10881  			}
10882
10883  			events.move = this._onMove;
10884  		}
10885
10886  		if (this._zoomAnimated) {
10887  			events.zoomanim = this._animateZoom;
10888  		}
10889
10890  		return events;
10891  	},
10892
10893  	// @section Extension methods
10894  	// Layers extending `GridLayer` shall reimplement the following method.
10895  	// @method createTile(coords: Object, done?: Function): HTMLElement
10896  	// Called only internally, must be overridden by classes extending `GridLayer`.
10897  	// Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback
10898  	// is specified, it must be called when the tile has finished loading and drawing.
10899  	createTile: function () {
10900  		return document.createElement('div');
10901  	},
10902
10903  	// @section
10904  	// @method getTileSize: Point
10905  	// Normalizes the [tileSize option](#gridlayer-tilesize) into a point. Used by the `createTile()` method.
10906  	getTileSize: function () {
10907  		var s = this.options.tileSize;
10908  		return s instanceof Point ? s : new Point(s, s);
10909  	},
10910
10911  	_updateZIndex: function () {
10912  		if (this._container && this.options.zIndex !== undefined && this.options.zIndex !== null) {
10913  			this._container.style.zIndex = this.options.zIndex;
10914  		}
10915  	},
10916
10917  	_setAutoZIndex: function (compare) {
10918  		// go through all other layers of the same pane, set zIndex to max + 1 (front) or min - 1 (back)
10919
10920  		var layers = this.getPane().children,
10921  		    edgeZIndex = -compare(-Infinity, Infinity); // -Infinity for max, Infinity for min
10922
10923  		for (var i = 0, len = layers.length, zIndex; i < len; i++) {
10924
10925  			zIndex = layers[i].style.zIndex;
10926
10927  			if (layers[i] !== this._container && zIndex) {
10928  				edgeZIndex = compare(edgeZIndex, +zIndex);
10929  			}
10930  		}
10931
10932  		if (isFinite(edgeZIndex)) {
10933  			this.options.zIndex = edgeZIndex + compare(-1, 1);
10934  			this._updateZIndex();
10935  		}
10936  	},
10937
10938  	_updateOpacity: function () {
10939  		if (!this._map) { return; }
10940
10941  		// IE doesn't inherit filter opacity properly, so we're forced to set it on tiles
10942  		if (
vendor: 6,720 bytes, lines 10942-11228
10942ielt9) { return; }
10943
10944  		setOpacity(this._container, this.options.opacity);
10945
10946  		var now = +new Date(),
10947  		    nextFrame = false,
10948  		    willPrune = false;
10949
10950  		for (var key in this._tiles) {
10951  			var tile = this._tiles[key];
10952  			if (!tile.current || !tile.loaded) { continue; }
10953
10954  			var fade = Math.min(1, (now - tile.loaded) / 200);
10955
10956  			setOpacity(tile.el, fade);
10957  			if (fade < 1) {
10958  				nextFrame = true;
10959  			} else {
10960  				if (tile.active) {
10961  					willPrune = true;
10962  				} else {
10963  					this._onOpaqueTile(tile);
10964  				}
10965  				tile.active = true;
10966  			}
10967  		}
10968
10969  		if (willPrune && !this._noPrune) { this._pruneTiles(); }
10970
10971  		if (nextFrame) {
10972  			cancelAnimFrame(this._fadeFrame);
10973  			this._fadeFrame = requestAnimFrame(this._updateOpacity, this);
10974  		}
10975  	},
10976
10977  	_onOpaqueTile: falseFn,
10978
10979  	_initContainer: function () {
10980  		if (this._container) { return; }
10981
10982  		this._container = create$1('div', 'leaflet-layer ' + (this.options.className || ''));
10983  		this._updateZIndex();
10984
10985  		if (this.options.opacity < 1) {
10986  			this._updateOpacity();
10987  		}
10988
10989  		this.getPane().appendChild(this._container);
10990  	},
10991
10992  	_updateLevels: function () {
10993
10994  		var zoom = this._tileZoom,
10995  		    maxZoom = this.options.maxZoom;
10996
10997  		if (zoom === undefined) { return undefined; }
10998
10999  		for (var z in this._levels) {
11000  			z = Number(z);
11001  			if (this._levels[z].el.children.length || z === zoom) {
11002  				this._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z);
11003  				this._onUpdateLevel(z);
11004  			} else {
11005  				remove(this._levels[z].el);
11006  				this._removeTilesAtZoom(z);
11007  				this._onRemoveLevel(z);
11008  				delete this._levels[z];
11009  			}
11010  		}
11011
11012  		var level = this._levels[zoom],
11013  		    map = this._map;
11014
11015  		if (!level) {
11016  			level = this._levels[zoom] = {};
11017
11018  			level.el = create$1('div', 'leaflet-tile-container leaflet-zoom-animated', this._container);
11019  			level.el.style.zIndex = maxZoom;
11020
11021  			level.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round();
11022  			level.zoom = zoom;
11023
11024  			this._setZoomTransform(level, map.getCenter(), map.getZoom());
11025
11026  			// force the browser to consider the newly added element for transition
11027  			falseFn(level.el.offsetWidth);
11028
11029  			this._onCreateLevel(level);
11030  		}
11031
11032  		this._level = level;
11033
11034  		return level;
11035  	},
11036
11037  	_onUpdateLevel: falseFn,
11038
11039  	_onRemoveLevel: falseFn,
11040
11041  	_onCreateLevel: falseFn,
11042
11043  	_pruneTiles: function () {
11044  		if (!this._map) {
11045  			return;
11046  		}
11047
11048  		var key, tile;
11049
11050  		var zoom = this._map.getZoom();
11051  		if (zoom > this.options.maxZoom ||
11052  			zoom < this.options.minZoom) {
11053  			this._removeAllTiles();
11054  			return;
11055  		}
11056
11057  		for (key in this._tiles) {
11058  			tile = this._tiles[key];
11059  			tile.retain = tile.current;
11060  		}
11061
11062  		for (key in this._tiles) {
11063  			tile = this._tiles[key];
11064  			if (tile.current && !tile.active) {
11065  				var coords = tile.coords;
11066  				if (!this._retainParent(coords.x, coords.y, coords.z, coords.z - 5)) {
11067  					this._retainChildren(coords.x, coords.y, coords.z, coords.z + 2);
11068  				}
11069  			}
11070  		}
11071
11072  		for (key in this._tiles) {
11073  			if (!this._tiles[key].retain) {
11074  				this._removeTile(key);
11075  			}
11076  		}
11077  	},
11078
11079  	_removeTilesAtZoom: function (zoom) {
11080  		for (var key in this._tiles) {
11081  			if (this._tiles[key].coords.z !== zoom) {
11082  				continue;
11083  			}
11084  			this._removeTile(key);
11085  		}
11086  	},
11087
11088  	_removeAllTiles: function () {
11089  		for (var key in this._tiles) {
11090  			this._removeTile(key);
11091  		}
11092  	},
11093
11094  	_invalidateAll: function () {
11095  		for (var z in this._levels) {
11096  			remove(this._levels[z].el);
11097  			this._onRemoveLevel(Number(z));
11098  			delete this._levels[z];
11099  		}
11100  		this._removeAllTiles();
11101
11102  		this._tileZoom = undefined;
11103  	},
11104
11105  	_retainParent: function (x, y, z, minZoom) {
11106  		var x2 = Math.floor(x / 2),
11107  		    y2 = Math.floor(y / 2),
11108  		    z2 = z - 1,
11109  		    coords2 = new Point(+x2, +y2);
11110  		coords2.z = +z2;
11111
11112  		var key = this._tileCoordsToKey(coords2),
11113  		    tile = this._tiles[key];
11114
11115  		if (tile && tile.active) {
11116  			tile.retain = true;
11117  			return true;
11118
11119  		} else if (tile && tile.loaded) {
11120  			tile.retain = true;
11121  		}
11122
11123  		if (z2 > minZoom) {
11124  			return this._retainParent(x2, y2, z2, minZoom);
11125  		}
11126
11127  		return false;
11128  	},
11129
11130  	_retainChildren: function (x, y, z, maxZoom) {
11131
11132  		for (var i = 2 * x; i < 2 * x + 2; i++) {
11133  			for (var j = 2 * y; j < 2 * y + 2; j++) {
11134
11135  				var coords = new Point(i, j);
11136  				coords.z = z + 1;
11137
11138  				var key = this._tileCoordsToKey(coords),
11139  				    tile = this._tiles[key];
11140
11141  				if (tile && tile.active) {
11142  					tile.retain = true;
11143  					continue;
11144
11145  				} else if (tile && tile.loaded) {
11146  					tile.retain = true;
11147  				}
11148
11149  				if (z + 1 < maxZoom) {
11150  					this._retainChildren(i, j, z + 1, maxZoom);
11151  				}
11152  			}
11153  		}
11154  	},
11155
11156  	_resetView: function (e) {
11157  		var animating = e && (e.pinch || e.flyTo);
11158  		this._setView(this._map.getCenter(), this._map.getZoom(), animating, animating);
11159  	},
11160
11161  	_animateZoom: function (e) {
11162  		this._setView(e.center, e.zoom, true, e.noUpdate);
11163  	},
11164
11165  	_clampZoom: function (zoom) {
11166  		var options = this.options;
11167
11168  		if (undefined !== options.minNativeZoom && zoom < options.minNativeZoom) {
11169  			return options.minNativeZoom;
11170  		}
11171
11172  		if (undefined !== options.maxNativeZoom && options.maxNativeZoom < zoom) {
11173  			return options.maxNativeZoom;
11174  		}
11175
11176  		return zoom;
11177  	},
11178
11179  	_setView: function (center, zoom, noPrune, noUpdate) {
11180  		var tileZoom = Math.round(zoom);
11181  		if ((this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) ||
11182  		    (this.options.minZoom !== undefined && tileZoom < this.options.minZoom)) {
11183  			tileZoom = undefined;
11184  		} else {
11185  			tileZoom = this._clampZoom(tileZoom);
11186  		}
11187
11188  		var tileZoomChanged = this.options.updateWhenZooming && (tileZoom !== this._tileZoom);
11189
11190  		if (!noUpdate || tileZoomChanged) {
11191
11192  			this._tileZoom = tileZoom;
11193
11194  			if (this._abortLoading) {
11195  				this._abortLoading();
11196  			}
11197
11198  			this._updateLevels();
11199  			this._resetGrid();
11200
11201  			if (tileZoom !== undefined) {
11202  				this._update(center);
11203  			}
11204
11205  			if (!noPrune) {
11206  				this._pruneTiles();
11207  			}
11208
11209  			// Flag to prevent _updateOpacity from pruning tiles during
11210  			// a zoom anim or a pinch gesture
11211  			this._noPrune = !!noPrune;
11212  		}
11213
11214  		this._setZoomTransforms(center, zoom);
11215  	},
11216
11217  	_setZoomTransforms: function (center, zoom) {
11218  		for (var i in this._levels) {
11219  			this._setZoomTransform(this._levels[i], center, zoom);
11220  		}
11221  	},
11222
11223  	_setZoomTransform: function (level, center, zoom) {
11224  		var scale = this._map.getZoomScale(zoom, level.zoom),
11225  		    translate = level.origin.multiplyBy(scale)
11226  		        .subtract(this._map._getNewPixelOrigin(center, zoom)).round();
11227
11228  		if (
vendor: 12,019 bytes, lines 11228-11604
11228any3d) {
11229  			setTransform(level.el, translate, scale);
11230  		} else {
11231  			setPosition(level.el, translate);
11232  		}
11233  	},
11234
11235  	_resetGrid: function () {
11236  		var map = this._map,
11237  		    crs = map.options.crs,
11238  		    tileSize = this._tileSize = this.getTileSize(),
11239  		    tileZoom = this._tileZoom;
11240
11241  		var bounds = this._map.getPixelWorldBounds(this._tileZoom);
11242  		if (bounds) {
11243  			this._globalTileRange = this._pxBoundsToTileRange(bounds);
11244  		}
11245
11246  		this._wrapX = crs.wrapLng && !this.options.noWrap && [
11247  			Math.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x),
11248  			Math.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y)
11249  		];
11250  		this._wrapY = crs.wrapLat && !this.options.noWrap && [
11251  			Math.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x),
11252  			Math.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y)
11253  		];
11254  	},
11255
11256  	_onMoveEnd: function () {
11257  		if (!this._map || this._map._animatingZoom) { return; }
11258
11259  		this._update();
11260  	},
11261
11262  	_getTiledPixelBounds: function (center) {
11263  		var map = this._map,
11264  		    mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),
11265  		    scale = map.getZoomScale(mapZoom, this._tileZoom),
11266  		    pixelCenter = map.project(center, this._tileZoom).floor(),
11267  		    halfSize = map.getSize().divideBy(scale * 2);
11268
11269  		return new Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
11270  	},
11271
11272  	// Private method to load tiles in the grid's active zoom level according to map bounds
11273  	_update: function (center) {
11274  		var map = this._map;
11275  		if (!map) { return; }
11276  		var zoom = this._clampZoom(map.getZoom());
11277
11278  		if (center === undefined) { center = map.getCenter(); }
11279  		if (this._tileZoom === undefined) { return; }	// if out of minzoom/maxzoom
11280
11281  		var pixelBounds = this._getTiledPixelBounds(center),
11282  		    tileRange = this._pxBoundsToTileRange(pixelBounds),
11283  		    tileCenter = tileRange.getCenter(),
11284  		    queue = [],
11285  		    margin = this.options.keepBuffer,
11286  		    noPruneRange = new Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),
11287  		                              tileRange.getTopRight().add([margin, -margin]));
11288
11289  		// Sanity check: panic if the tile range contains Infinity somewhere.
11290  		if (!(isFinite(tileRange.min.x) &&
11291  		      isFinite(tileRange.min.y) &&
11292  		      isFinite(tileRange.max.x) &&
11293  		      isFinite(tileRange.max.y))) { throw new Error('Attempted to load an infinite number of tiles'); }
11294
11295  		for (var key in this._tiles) {
11296  			var c = this._tiles[key].coords;
11297  			if (c.z !== this._tileZoom || !noPruneRange.contains(new Point(c.x, c.y))) {
11298  				this._tiles[key].current = false;
11299  			}
11300  		}
11301
11302  		// _update just loads more tiles. If the tile zoom level differs too much
11303  		// from the map's, let _setView reset levels and prune old tiles.
11304  		if (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }
11305
11306  		// create a queue of coordinates to load tiles from
11307  		for (var j = tileRange.min.y; j <= tileRange.max.y; j++) {
11308  			for (var i = tileRange.min.x; i <= tileRange.max.x; i++) {
11309  				var coords = new Point(i, j);
11310  				coords.z = this._tileZoom;
11311
11312  				if (!this._isValidTile(coords)) { continue; }
11313
11314  				var tile = this._tiles[this._tileCoordsToKey(coords)];
11315  				if (tile) {
11316  					tile.current = true;
11317  				} else {
11318  					queue.push(coords);
11319  				}
11320  			}
11321  		}
11322
11323  		// sort tile queue to load tiles in order of their distance to center
11324  		queue.sort(function (a, b) {
11325  			return a.distanceTo(tileCenter) - b.distanceTo(tileCenter);
11326  		});
11327
11328  		if (queue.length !== 0) {
11329  			// if it's the first batch of tiles to load
11330  			if (!this._loading) {
11331  				this._loading = true;
11332  				// @event loading: Event
11333  				// Fired when the grid layer starts loading tiles.
11334  				this.fire('loading');
11335  			}
11336
11337  			// create DOM fragment to append tiles in one batch
11338  			var fragment = document.createDocumentFragment();
11339
11340  			for (i = 0; i < queue.length; i++) {
11341  				this._addTile(queue[i], fragment);
11342  			}
11343
11344  			this._level.el.appendChild(fragment);
11345  		}
11346  	},
11347
11348  	_isValidTile: function (coords) {
11349  		var crs = this._map.options.crs;
11350
11351  		if (!crs.infinite) {
11352  			// don't load tile if it's out of bounds and not wrapped
11353  			var bounds = this._globalTileRange;
11354  			if ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||
11355  			    (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }
11356  		}
11357
11358  		if (!this.options.bounds) { return true; }
11359
11360  		// don't load tile if it doesn't intersect the bounds in options
11361  		var tileBounds = this._tileCoordsToBounds(coords);
11362  		return toLatLngBounds(this.options.bounds).overlaps(tileBounds);
11363  	},
11364
11365  	_keyToBounds: function (key) {
11366  		return this._tileCoordsToBounds(this._keyToTileCoords(key));
11367  	},
11368
11369  	_tileCoordsToNwSe: function (coords) {
11370  		var map = this._map,
11371  		    tileSize = this.getTileSize(),
11372  		    nwPoint = coords.scaleBy(tileSize),
11373  		    sePoint = nwPoint.add(tileSize),
11374  		    nw = map.unproject(nwPoint, coords.z),
11375  		    se = map.unproject(sePoint, coords.z);
11376  		return [nw, se];
11377  	},
11378
11379  	// converts tile coordinates to its geographical bounds
11380  	_tileCoordsToBounds: function (coords) {
11381  		var bp = this._tileCoordsToNwSe(coords),
11382  		    bounds = new LatLngBounds(bp[0], bp[1]);
11383
11384  		if (!this.options.noWrap) {
11385  			bounds = this._map.wrapLatLngBounds(bounds);
11386  		}
11387  		return bounds;
11388  	},
11389  	// converts tile coordinates to key for the tile cache
11390  	_tileCoordsToKey: function (coords) {
11391  		return coords.x + ':' + coords.y + ':' + coords.z;
11392  	},
11393
11394  	// converts tile cache key to coordinates
11395  	_keyToTileCoords: function (key) {
11396  		var k = key.split(':'),
11397  		    coords = new Point(+k[0], +k[1]);
11398  		coords.z = +k[2];
11399  		return coords;
11400  	},
11401
11402  	_removeTile: function (key) {
11403  		var tile = this._tiles[key];
11404  		if (!tile) { return; }
11405
11406  		remove(tile.el);
11407
11408  		delete this._tiles[key];
11409
11410  		// @event tileunload: TileEvent
11411  		// Fired when a tile is removed (e.g. when a tile goes off the screen).
11412  		this.fire('tileunload', {
11413  			tile: tile.el,
11414  			coords: this._keyToTileCoords(key)
11415  		});
11416  	},
11417
11418  	_initTile: function (tile) {
11419  		addClass(tile, 'leaflet-tile');
11420
11421  		var tileSize = this.getTileSize();
11422  		tile.style.width = tileSize.x + 'px';
11423  		tile.style.height = tileSize.y + 'px';
11424
11425  		tile.onselectstart = falseFn;
11426  		tile.onmousemove = falseFn;
11427
11428  		// update opacity on tiles in IE7-8 because of filter inheritance problems
11429  		if (ielt9 && this.options.opacity < 1) {
11430  			setOpacity(tile, this.options.opacity);
11431  		}
11432
11433  		// without this hack, tiles disappear after zoom on Chrome for Android
11434  		// https://github.com/Leaflet/Leaflet/issues/2078
11435  		if (android && !android23) {
11436  			tile.style.WebkitBackfaceVisibility = 'hidden';
11437  		}
11438  	},
11439
11440  	_addTile: function (coords, container) {
11441  		var tilePos = this._getTilePos(coords),
11442  		    key = this._tileCoordsToKey(coords);
11443
11444  		var tile = this.createTile(this._wrapCoords(coords), bind(this._tileReady, this, coords));
11445
11446  		this._initTile(tile);
11447
11448  		// if createTile is defined with a second argument ("done" callback),
11449  		// we know that tile is async and will be ready later; otherwise
11450  		if (this.createTile.length < 2) {
11451  			// mark tile as ready, but delay one frame for opacity animation to happen
11452  			requestAnimFrame(bind(this._tileReady, this, coords, null, tile));
11453  		}
11454
11455  		setPosition(tile, tilePos);
11456
11457  		// save tile in cache
11458  		this._tiles[key] = {
11459  			el: tile,
11460  			coords: coords,
11461  			current: true
11462  		};
11463
11464  		container.appendChild(tile);
11465  		// @event tileloadstart: TileEvent
11466  		// Fired when a tile is requested and starts loading.
11467  		this.fire('tileloadstart', {
11468  			tile: tile,
11469  			coords: coords
11470  		});
11471  	},
11472
11473  	_tileReady: function (coords, err, tile) {
11474  		if (err) {
11475  			// @event tileerror: TileErrorEvent
11476  			// Fired when there is an error loading a tile.
11477  			this.fire('tileerror', {
11478  				error: err,
11479  				tile: tile,
11480  				coords: coords
11481  			});
11482  		}
11483
11484  		var key = this._tileCoordsToKey(coords);
11485
11486  		tile = this._tiles[key];
11487  		if (!tile) { return; }
11488
11489  		tile.loaded = +new Date();
11490  		if (this._map._fadeAnimated) {
11491  			setOpacity(tile.el, 0);
11492  			cancelAnimFrame(this._fadeFrame);
11493  			this._fadeFrame = requestAnimFrame(this._updateOpacity, this);
11494  		} else {
11495  			tile.active = true;
11496  			this._pruneTiles();
11497  		}
11498
11499  		if (!err) {
11500  			addClass(tile.el, 'leaflet-tile-loaded');
11501
11502  			// @event tileload: TileEvent
11503  			// Fired when a tile loads.
11504  			this.fire('tileload', {
11505  				tile: tile.el,
11506  				coords: coords
11507  			});
11508  		}
11509
11510  		if (this._noTilesToLoad()) {
11511  			this._loading = false;
11512  			// @event load: Event
11513  			// Fired when the grid layer loaded all visible tiles.
11514  			this.fire('load');
11515
11516  			if (ielt9 || !this._map._fadeAnimated) {
11517  				requestAnimFrame(this._pruneTiles, this);
11518  			} else {
11519  				// Wait a bit more than 0.2 secs (the duration of the tile fade-in)
11520  				// to trigger a pruning.
11521  				setTimeout(bind(this._pruneTiles, this), 250);
11522  			}
11523  		}
11524  	},
11525
11526  	_getTilePos: function (coords) {
11527  		return coords.scaleBy(this.getTileSize()).subtract(this._level.origin);
11528  	},
11529
11530  	_wrapCoords: function (coords) {
11531  		var newCoords = new Point(
11532  			this._wrapX ? wrapNum(coords.x, this._wrapX) : coords.x,
11533  			this._wrapY ? wrapNum(coords.y, this._wrapY) : coords.y);
11534  		newCoords.z = coords.z;
11535  		return newCoords;
11536  	},
11537
11538  	_pxBoundsToTileRange: function (bounds) {
11539  		var tileSize = this.getTileSize();
11540  		return new Bounds(
11541  			bounds.min.unscaleBy(tileSize).floor(),
11542  			bounds.max.unscaleBy(tileSize).ceil().subtract([1, 1]));
11543  	},
11544
11545  	_noTilesToLoad: function () {
11546  		for (var key in this._tiles) {
11547  			if (!this._tiles[key].loaded) { return false; }
11548  		}
11549  		return true;
11550  	}
11551  });
11552
11553  // @factory L.gridLayer(options?: GridLayer options)
11554  // Creates a new instance of GridLayer with the supplied options.
11555  function gridLayer(options) {
11556  	return new GridLayer(options);
11557  }
11558
11559  /*
11560   * @class TileLayer
11561   * @inherits GridLayer
11562   * @aka L.TileLayer
11563   * 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`.
11564   *
11565   * @example
11566   *
11567   * ```js
11568   * L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar', attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'}).addTo(map);
11569   * ```
11570   *
11571   * @section URL template
11572   * @example
11573   *
11574   * A string of the following form:
11575   *
11576   * ```
11577   * 'http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'
11578   * ```
11579   *
11580   * `{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.
11581   *
11582   * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:
11583   *
11584   * ```
11585   * L.tileLayer('http://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});
11586   * ```
11587   */
11588
11589
11590  var TileLayer = GridLayer.extend({
11591
11592  	// @section
11593  	// @aka TileLayer options
11594  	options: {
11595  		// @option minZoom: Number = 0
11596  		// The minimum zoom level down to which this layer will be displayed (inclusive).
11597  		minZoom: 0,
11598
11599  		// @option maxZoom: Number = 18
11600  		// The maximum zoom level up to which this layer will be displayed (inclusive).
11601  		maxZoom: 18,
11602
11603  		// @option subdomains: String|String[] = 'abc'
11604  		// 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
11604ings.
11605  		subdomains: 'abc',
11606
11607  		// @option errorTileUrl: String = ''
11608  		// URL to the tile image to show in place of the tile that failed to load.
11609  		errorTileUrl: '',
11610
11611  		// @option zoomOffset: Number = 0
11612  		// The zoom number used in tile URLs will be offset with this value.
11613  		zoomOffset: 0,
11614
11615  		// @option tms: Boolean = false
11616  		// If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).
11617  		tms: false,
11618
11619  		// @option zoomReverse: Boolean = false
11620  		// If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)
11621  		zoomReverse: false,
11622
11623  		// @option detectRetina: Boolean = false
11624  		// 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.
11625  		detectRetina: false,
11626
11627  		// @option crossOrigin: Boolean|String = false
11628  		// Whether the crossOrigin attribute will be added to the tiles.
11629  		// 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.
11630  		// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
11631  		crossOrigin: false
11632  	},
11633
11634  	initialize: function (url, options) {
11635
11636  		this._url = url;
11637
11638  		options = setOptions(this, options);
11639
11640  		// detecting retina displays, adjusting tileSize and zoom levels
11641  		if (options.detectRetina && retina && options.maxZoom > 0) {
11642
11643  			options.tileSize = Math.floor(options.tileSize / 2);
11644
11645  			if (!options.zoomReverse) {
11646  				options.zoomOffset++;
11647  				options.maxZoom--;
11648  			} else {
11649  				options.zoomOffset--;
11650  				options.minZoom++;
11651  			}
11652
11653  			options.minZoom = Math.max(0, options.minZoom);
11654  		}
11655
11656  		if (typeof options.subdomains === 'string') {
11657  			options.subdomains = options.subdomains.split('');
11658  		}
11659
11660  		// for https://github.com/Leaflet/Leaflet/issues/137
11661  		if (!android) {
11662  			this.on('tileunload', this._onTileRemove);
11663  		}
11664  	},
11665
11666  	// @method setUrl(url: String, noRedraw?: Boolean): this
11667  	// Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).
11668  	// If the URL does not change, the layer will not be redrawn unless
11669  	// the noRedraw parameter is set to false.
11670  	setUrl: function (url, noRedraw) {
11671  		if (this._url === url && noRedraw === undefined) {
11672  			noRedraw = true;
11673  		}
11674
11675  		this._url = url;
11676
11677  		if (!noRedraw) {
11678  			this.redraw();
11679  		}
11680  		return this;
11681  	},
11682
11683  	// @method createTile(coords: Object, done?: Function): HTMLElement
11684  	// Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)
11685  	// to return an `<img>` HTML element with the appropriate image URL given `coords`. The `done`
11686  	// callback is called when the tile has been loaded.
11687  	createTile: function (coords, done) {
11688  		var tile = document.createElement('img');
11689
11690  		on(tile, 'load', bind(this._tileOnLoad, this, done, tile));
11691  		on(tile, 'error', bind(this._tileOnError, this, done, tile));
11692
11693  		if (this.options.crossOrigin || this.options.crossOrigin === '') {
11694  			tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
11695  		}
11696
11697  		/*
11698  		 Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons
11699  		 http://www.w3.org/TR/WCAG20-TECHS/H67
11700  		*/
11701  		tile.alt = '';
11702
11703  		/*
11704  		 Set role="presentation" to force screen readers to ignore this
11705  		 https://www.w3.org/TR/wai-aria/roles#textalternativecomputation
11706  		*/
11707  		tile.setAttribute('role', 'presentation');
11708
11709  		tile.src = this.getTileUrl(coords);
11710
11711  		return tile;
11712  	},
11713
11714  	// @section Extension methods
11715  	// @uninheritable
11716  	// Layers extending `TileLayer` might reimplement the following method.
11717  	// @method getTileUrl(coords: Object): String
11718  	// Called only internally, returns the URL for a tile given its coordinates.
11719  	// Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.
11720  	getTileUrl: function (coords) {
11721  		var data = {
11722  			r: retina ? '@2x' : '',
11723  			s: this._getSubdomain(coords),
11724  			x: coords.x,
11725  			y: coords.y,
11726  			z: this._getZoomForUrl()
11727  		};
11728  		if (this._map && !this._map.options.crs.infinite) {
11729  			var invertedY = this._globalTileRange.max.y - coords.y;
11730  			if (this.options.tms) {
11731  				data['y'] = invertedY;
11732  			}
vendor: 32,187 bytes, lines 11733-12925
11733  			data['-y'] = invertedY;
11734  		}
11735
11736  		return template(this._url, extend(data, this.options));
11737  	},
11738
11739  	_tileOnLoad: function (done, tile) {
11740  		// For https://github.com/Leaflet/Leaflet/issues/3332
11741  		if (ielt9) {
11742  			setTimeout(bind(done, this, null, tile), 0);
11743  		} else {
11744  			done(null, tile);
11745  		}
11746  	},
11747
11748  	_tileOnError: function (done, tile, e) {
11749  		var errorUrl = this.options.errorTileUrl;
11750  		if (errorUrl && tile.getAttribute('src') !== errorUrl) {
11751  			tile.src = errorUrl;
11752  		}
11753  		done(e, tile);
11754  	},
11755
11756  	_onTileRemove: function (e) {
11757  		e.tile.onload = null;
11758  	},
11759
11760  	_getZoomForUrl: function () {
11761  		var zoom = this._tileZoom,
11762  		maxZoom = this.options.maxZoom,
11763  		zoomReverse = this.options.zoomReverse,
11764  		zoomOffset = this.options.zoomOffset;
11765
11766  		if (zoomReverse) {
11767  			zoom = maxZoom - zoom;
11768  		}
11769
11770  		return zoom + zoomOffset;
11771  	},
11772
11773  	_getSubdomain: function (tilePoint) {
11774  		var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;
11775  		return this.options.subdomains[index];
11776  	},
11777
11778  	// stops loading all tiles in the background layer
11779  	_abortLoading: function () {
11780  		var i, tile;
11781  		for (i in this._tiles) {
11782  			if (this._tiles[i].coords.z !== this._tileZoom) {
11783  				tile = this._tiles[i].el;
11784
11785  				tile.onload = falseFn;
11786  				tile.onerror = falseFn;
11787
11788  				if (!tile.complete) {
11789  					tile.src = emptyImageUrl;
11790  					remove(tile);
11791  					delete this._tiles[i];
11792  				}
11793  			}
11794  		}
11795  	},
11796
11797  	_removeTile: function (key) {
11798  		var tile = this._tiles[key];
11799  		if (!tile) { return; }
11800
11801  		// Cancels any pending http requests associated with the tile
11802  		// unless we're on Android's stock browser,
11803  		// see https://github.com/Leaflet/Leaflet/issues/137
11804  		if (!androidStock) {
11805  			tile.el.setAttribute('src', emptyImageUrl);
11806  		}
11807
11808  		return GridLayer.prototype._removeTile.call(this, key);
11809  	},
11810
11811  	_tileReady: function (coords, err, tile) {
11812  		if (!this._map || (tile && tile.getAttribute('src') === emptyImageUrl)) {
11813  			return;
11814  		}
11815
11816  		return GridLayer.prototype._tileReady.call(this, coords, err, tile);
11817  	}
11818  });
11819
11820
11821  // @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)
11822  // Instantiates a tile layer object given a `URL template` and optionally an options object.
11823
11824  function tileLayer(url, options) {
11825  	return new TileLayer(url, options);
11826  }
11827
11828  /*
11829   * @class TileLayer.WMS
11830   * @inherits TileLayer
11831   * @aka L.TileLayer.WMS
11832   * Used to display [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services as tile layers on the map. Extends `TileLayer`.
11833   *
11834   * @example
11835   *
11836   * ```js
11837   * var nexrad = L.tileLayer.wms("http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", {
11838   * 	layers: 'nexrad-n0r-900913',
11839   * 	format: 'image/png',
11840   * 	transparent: true,
11841   * 	attribution: "Weather data © 2012 IEM Nexrad"
11842   * });
11843   * ```
11844   */
11845
11846  var TileLayerWMS = TileLayer.extend({
11847
11848  	// @section
11849  	// @aka TileLayer.WMS options
11850  	// If any custom options not documented here are used, they will be sent to the
11851  	// WMS server as extra parameters in each request URL. This can be useful for
11852  	// [non-standard vendor WMS parameters](http://docs.geoserver.org/stable/en/user/services/wms/vendor.html).
11853  	defaultWmsParams: {
11854  		service: 'WMS',
11855  		request: 'GetMap',
11856
11857  		// @option layers: String = ''
11858  		// **(required)** Comma-separated list of WMS layers to show.
11859  		layers: '',
11860
11861  		// @option styles: String = ''
11862  		// Comma-separated list of WMS styles.
11863  		styles: '',
11864
11865  		// @option format: String = 'image/jpeg'
11866  		// WMS image format (use `'image/png'` for layers with transparency).
11867  		format: 'image/jpeg',
11868
11869  		// @option transparent: Boolean = false
11870  		// If `true`, the WMS service will return images with transparency.
11871  		transparent: false,
11872
11873  		// @option version: String = '1.1.1'
11874  		// Version of the WMS service to use
11875  		version: '1.1.1'
11876  	},
11877
11878  	options: {
11879  		// @option crs: CRS = null
11880  		// Coordinate Reference System to use for the WMS requests, defaults to
11881  		// map CRS. Don't change this if you're not sure what it means.
11882  		crs: null,
11883
11884  		// @option uppercase: Boolean = false
11885  		// If `true`, WMS request parameter keys will be uppercase.
11886  		uppercase: false
11887  	},
11888
11889  	initialize: function (url, options) {
11890
11891  		this._url = url;
11892
11893  		var wmsParams = extend({}, this.defaultWmsParams);
11894
11895  		// all keys that are not TileLayer options go to WMS params
11896  		for (var i in options) {
11897  			if (!(i in this.options)) {
11898  				wmsParams[i] = options[i];
11899  			}
11900  		}
11901
11902  		options = setOptions(this, options);
11903
11904  		var realRetina = options.detectRetina && retina ? 2 : 1;
11905  		var tileSize = this.getTileSize();
11906  		wmsParams.width = tileSize.x * realRetina;
11907  		wmsParams.height = tileSize.y * realRetina;
11908
11909  		this.wmsParams = wmsParams;
11910  	},
11911
11912  	onAdd: function (map) {
11913
11914  		this._crs = this.options.crs || map.options.crs;
11915  		this._wmsVersion = parseFloat(this.wmsParams.version);
11916
11917  		var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';
11918  		this.wmsParams[projectionKey] = this._crs.code;
11919
11920  		TileLayer.prototype.onAdd.call(this, map);
11921  	},
11922
11923  	getTileUrl: function (coords) {
11924
11925  		var tileBounds = this._tileCoordsToNwSe(coords),
11926  		    crs = this._crs,
11927  		    bounds = toBounds(crs.project(tileBounds[0]), crs.project(tileBounds[1])),
11928  		    min = bounds.min,
11929  		    max = bounds.max,
11930  		    bbox = (this._wmsVersion >= 1.3 && this._crs === EPSG4326 ?
11931  		    [min.y, min.x, max.y, max.x] :
11932  		    [min.x, min.y, max.x, max.y]).join(','),
11933  		    url = TileLayer.prototype.getTileUrl.call(this, coords);
11934  		return url +
11935  			getParamString(this.wmsParams, url, this.options.uppercase) +
11936  			(this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;
11937  	},
11938
11939  	// @method setParams(params: Object, noRedraw?: Boolean): this
11940  	// Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true).
11941  	setParams: function (params, noRedraw) {
11942
11943  		extend(this.wmsParams, params);
11944
11945  		if (!noRedraw) {
11946  			this.redraw();
11947  		}
11948
11949  		return this;
11950  	}
11951  });
11952
11953
11954  // @factory L.tileLayer.wms(baseUrl: String, options: TileLayer.WMS options)
11955  // Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS parameters/options object.
11956  function tileLayerWMS(url, options) {
11957  	return new TileLayerWMS(url, options);
11958  }
11959
11960  TileLayer.WMS = TileLayerWMS;
11961  tileLayer.wms = tileLayerWMS;
11962
11963  /*
11964   * @class Renderer
11965   * @inherits Layer
11966   * @aka L.Renderer
11967   *
11968   * Base class for vector renderer implementations (`SVG`, `Canvas`). Handles the
11969   * DOM container of the renderer, its bounds, and its zoom animation.
11970   *
11971   * A `Renderer` works as an implicit layer group for all `Path`s - the renderer
11972   * itself can be added or removed to the map. All paths use a renderer, which can
11973   * be implicit (the map will decide the type of renderer and use it automatically)
11974   * or explicit (using the [`renderer`](#path-renderer) option of the path).
11975   *
11976   * Do not use this class directly, use `SVG` and `Canvas` instead.
11977   *
11978   * @event update: Event
11979   * Fired when the renderer updates its bounds, center and zoom, for example when
11980   * its map has moved
11981   */
11982
11983  var Renderer = Layer.extend({
11984
11985  	// @section
11986  	// @aka Renderer options
11987  	options: {
11988  		// @option padding: Number = 0.1
11989  		// How much to extend the clip area around the map view (relative to its size)
11990  		// e.g. 0.1 would be 10% of map view in each direction
11991  		padding: 0.1,
11992
11993  		// @option tolerance: Number = 0
11994  		// How much to extend click tolerance round a path/object on the map
11995  		tolerance : 0
11996  	},
11997
11998  	initialize: function (options) {
11999  		setOptions(this, options);
12000  		stamp(this);
12001  		this._layers = this._layers || {};
12002  	},
12003
12004  	onAdd: function () {
12005  		if (!this._container) {
12006  			this._initContainer(); // defined by renderer implementations
12007
12008  			if (this._zoomAnimated) {
12009  				addClass(this._container, 'leaflet-zoom-animated');
12010  			}
12011  		}
12012
12013  		this.getPane().appendChild(this._container);
12014  		this._update();
12015  		this.on('update', this._updatePaths, this);
12016  	},
12017
12018  	onRemove: function () {
12019  		this.off('update', this._updatePaths, this);
12020  		this._destroyContainer();
12021  	},
12022
12023  	getEvents: function () {
12024  		var events = {
12025  			viewreset: this._reset,
12026  			zoom: this._onZoom,
12027  			moveend: this._update,
12028  			zoomend: this._onZoomEnd
12029  		};
12030  		if (this._zoomAnimated) {
12031  			events.zoomanim = this._onAnimZoom;
12032  		}
12033  		return events;
12034  	},
12035
12036  	_onAnimZoom: function (ev) {
12037  		this._updateTransform(ev.center, ev.zoom);
12038  	},
12039
12040  	_onZoom: function () {
12041  		this._updateTransform(this._map.getCenter(), this._map.getZoom());
12042  	},
12043
12044  	_updateTransform: function (center, zoom) {
12045  		var scale = this._map.getZoomScale(zoom, this._zoom),
12046  		    position = getPosition(this._container),
12047  		    viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding),
12048  		    currentCenterPoint = this._map.project(this._center, zoom),
12049  		    destCenterPoint = this._map.project(center, zoom),
12050  		    centerOffset = destCenterPoint.subtract(currentCenterPoint),
12051
12052  		    topLeftOffset = viewHalf.multiplyBy(-scale).add(position).add(viewHalf).subtract(centerOffset);
12053
12054  		if (any3d) {
12055  			setTransform(this._container, topLeftOffset, scale);
12056  		} else {
12057  			setPosition(this._container, topLeftOffset);
12058  		}
12059  	},
12060
12061  	_reset: function () {
12062  		this._update();
12063  		this._updateTransform(this._center, this._zoom);
12064
12065  		for (var id in this._layers) {
12066  			this._layers[id]._reset();
12067  		}
12068  	},
12069
12070  	_onZoomEnd: function () {
12071  		for (var id in this._layers) {
12072  			this._layers[id]._project();
12073  		}
12074  	},
12075
12076  	_updatePaths: function () {
12077  		for (var id in this._layers) {
12078  			this._layers[id]._update();
12079  		}
12080  	},
12081
12082  	_update: function () {
12083  		// Update pixel bounds of renderer container (for positioning/sizing/clipping later)
12084  		// Subclasses are responsible of firing the 'update' event.
12085  		var p = this.options.padding,
12086  		    size = this._map.getSize(),
12087  		    min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();
12088
12089  		this._bounds = new Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round());
12090
12091  		this._center = this._map.getCenter();
12092  		this._zoom = this._map.getZoom();
12093  	}
12094  });
12095
12096  /*
12097   * @class Canvas
12098   * @inherits Renderer
12099   * @aka L.Canvas
12100   *
12101   * Allows vector layers to be displayed with [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
12102   * Inherits `Renderer`.
12103   *
12104   * Due to [technical limitations](http://caniuse.com/#search=canvas), Canvas is not
12105   * available in all web browsers, notably IE8, and overlapping geometries might
12106   * not display properly in some edge cases.
12107   *
12108   * @example
12109   *
12110   * Use Canvas by default for all paths in the map:
12111   *
12112   * ```js
12113   * var map = L.map('map', {
12114   * 	renderer: L.canvas()
12115   * });
12116   * ```
12117   *
12118   * Use a Canvas renderer with extra padding for specific vector geometries:
12119   *
12120   * ```js
12121   * var map = L.map('map');
12122   * var myRenderer = L.canvas({ padding: 0.5 });
12123   * var line = L.polyline( coordinates, { renderer: myRenderer } );
12124   * var circle = L.circle( center, { renderer: myRenderer } );
12125   * ```
12126   */
12127
12128  var Canvas = Renderer.extend({
12129  	getEvents: function () {
12130  		var events = Renderer.prototype.getEvents.call(this);
12131  		events.viewprereset = this._onViewPreReset;
12132  		return events;
12133  	},
12134
12135  	_onViewPreReset: function () {
12136  		// Set a flag so that a viewprereset+moveend+viewreset only updates&redraws once
12137  		this._postponeUpdatePaths = true;
12138  	},
12139
12140  	onAdd: function () {
12141  		Renderer.prototype.onAdd.call(this);
12142
12143  		// Redraw vectors since canvas is cleared upon removal,
12144  		// in case of removing the renderer itself from the map.
12145  		this._draw();
12146  	},
12147
12148  	_initContainer: function () {
12149  		var container = this._container = document.createElement('canvas');
12150
12151  		on(container, 'mousemove', this._onMouseMove, this);
12152  		on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this);
12153  		on(container, 'mouseout', this._handleMouseOut, this);
12154
12155  		this._ctx = container.getContext('2d');
12156  	},
12157
12158  	_destroyContainer: function () {
12159  		cancelAnimFrame(this._redrawRequest);
12160  		delete this._ctx;
12161  		remove(this._container);
12162  		off(this._container);
12163  		delete this._container;
12164  	},
12165
12166  	_updatePaths: function () {
12167  		if (this._postponeUpdatePaths) { return; }
12168
12169  		var layer;
12170  		this._redrawBounds = null;
12171  		for (var id in this._layers) {
12172  			layer = this._layers[id];
12173  			layer._update();
12174  		}
12175  		this._redraw();
12176  	},
12177
12178  	_update: function () {
12179  		if (this._map._animatingZoom && this._bounds) { return; }
12180
12181  		Renderer.prototype._update.call(this);
12182
12183  		var b = this._bounds,
12184  		    container = this._container,
12185  		    size = b.getSize(),
12186  		    m = retina ? 2 : 1;
12187
12188  		setPosition(container, b.min);
12189
12190  		// set canvas size (also clearing it); use double size on retina
12191  		container.width = m * size.x;
12192  		container.height = m * size.y;
12193  		container.style.width = size.x + 'px';
12194  		container.style.height = size.y + 'px';
12195
12196  		if (retina) {
12197  			this._ctx.scale(2, 2);
12198  		}
12199
12200  		// translate so we use the same path coordinates after canvas element moves
12201  		this._ctx.translate(-b.min.x, -b.min.y);
12202
12203  		// Tell paths to redraw themselves
12204  		this.fire('update');
12205  	},
12206
12207  	_reset: function () {
12208  		Renderer.prototype._reset.call(this);
12209
12210  		if (this._postponeUpdatePaths) {
12211  			this._postponeUpdatePaths = false;
12212  			this._updatePaths();
12213  		}
12214  	},
12215
12216  	_initPath: function (layer) {
12217  		this._updateDashArray(layer);
12218  		this._layers[stamp(layer)] = layer;
12219
12220  		var order = layer._order = {
12221  			layer: layer,
12222  			prev: this._drawLast,
12223  			next: null
12224  		};
12225  		if (this._drawLast) { this._drawLast.next = order; }
12226  		this._drawLast = order;
12227  		this._drawFirst = this._drawFirst || this._drawLast;
12228  	},
12229
12230  	_addPath: function (layer) {
12231  		this._requestRedraw(layer);
12232  	},
12233
12234  	_removePath: function (layer) {
12235  		var order = layer._order;
12236  		var next = order.next;
12237  		var prev = order.prev;
12238
12239  		if (next) {
12240  			next.prev = prev;
12241  		} else {
12242  			this._drawLast = prev;
12243  		}
12244  		if (prev) {
12245  			prev.next = next;
12246  		} else {
12247  			this._drawFirst = next;
12248  		}
12249
12250  		delete layer._order;
12251
12252  		delete this._layers[stamp(layer)];
12253
12254  		this._requestRedraw(layer);
12255  	},
12256
12257  	_updatePath: function (layer) {
12258  		// Redraw the union of the layer's old pixel
12259  		// bounds and the new pixel bounds.
12260  		this._extendRedrawBounds(layer);
12261  		layer._project();
12262  		layer._update();
12263  		// The redraw will extend the redraw bounds
12264  		// with the new pixel bounds.
12265  		this._requestRedraw(layer);
12266  	},
12267
12268  	_updateStyle: function (layer) {
12269  		this._updateDashArray(layer);
12270  		this._requestRedraw(layer);
12271  	},
12272
12273  	_updateDashArray: function (layer) {
12274  		if (typeof layer.options.dashArray === 'string') {
12275  			var parts = layer.options.dashArray.split(/[, ]+/),
12276  			    dashArray = [],
12277  			    dashValue,
12278  			    i;
12279  			for (i = 0; i < parts.length; i++) {
12280  				dashValue = Number(parts[i]);
12281  				// Ignore dash array containing invalid lengths
12282  				if (isNaN(dashValue)) { return; }
12283  				dashArray.push(dashValue);
12284  			}
12285  			layer.options._dashArray = dashArray;
12286  		} else {
12287  			layer.options._dashArray = layer.options.dashArray;
12288  		}
12289  	},
12290
12291  	_requestRedraw: function (layer) {
12292  		if (!this._map) { return; }
12293
12294  		this._extendRedrawBounds(layer);
12295  		this._redrawRequest = this._redrawRequest || requestAnimFrame(this._redraw, this);
12296  	},
12297
12298  	_extendRedrawBounds: function (layer) {
12299  		if (layer._pxBounds) {
12300  			var padding = (layer.options.weight || 0) + 1;
12301  			this._redrawBounds = this._redrawBounds || new Bounds();
12302  			this._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding]));
12303  			this._redrawBounds.extend(layer._pxBounds.max.add([padding, padding]));
12304  		}
12305  	},
12306
12307  	_redraw: function () {
12308  		this._redrawRequest = null;
12309
12310  		if (this._redrawBounds) {
12311  			this._redrawBounds.min._floor();
12312  			this._redrawBounds.max._ceil();
12313  		}
12314
12315  		this._clear(); // clear layers in redraw bounds
12316  		this._draw(); // draw layers
12317
12318  		this._redrawBounds = null;
12319  	},
12320
12321  	_clear: function () {
12322  		var bounds = this._redrawBounds;
12323  		if (bounds) {
12324  			var size = bounds.getSize();
12325  			this._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y);
12326  		} else {
12327  			this._ctx.save();
12328  			this._ctx.setTransform(1, 0, 0, 1, 0, 0);
12329  			this._ctx.clearRect(0, 0, this._container.width, this._container.height);
12330  			this._ctx.restore();
12331  		}
12332  	},
12333
12334  	_draw: function () {
12335  		var layer, bounds = this._redrawBounds;
12336  		this._ctx.save();
12337  		if (bounds) {
12338  			var size = bounds.getSize();
12339  			this._ctx.beginPath();
12340  			this._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y);
12341  			this._ctx.clip();
12342  		}
12343
12344  		this._drawing = true;
12345
12346  		for (var order = this._drawFirst; order; order = order.next) {
12347  			layer = order.layer;
12348  			if (!bounds || (layer._pxBounds && layer._pxBounds.intersects(bounds))) {
12349  				layer._updatePath();
12350  			}
12351  		}
12352
12353  		this._drawing = false;
12354
12355  		this._ctx.restore();  // Restore state before clipping.
12356  	},
12357
12358  	_updatePoly: function (layer, closed) {
12359  		if (!this._drawing) { return; }
12360
12361  		var i, j, len2, p,
12362  		    parts = layer._parts,
12363  		    len = parts.length,
12364  		    ctx = this._ctx;
12365
12366  		if (!len) { return; }
12367
12368  		ctx.beginPath();
12369
12370  		for (i = 0; i < len; i++) {
12371  			for (j = 0, len2 = parts[i].length; j < len2; j++) {
12372  				p = parts[i][j];
12373  				ctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);
12374  			}
12375  			if (closed) {
12376  				ctx.closePath();
12377  			}
12378  		}
12379
12380  		this._fillStroke(ctx, layer);
12381
12382  		// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
12383  	},
12384
12385  	_updateCircle: function (layer) {
12386
12387  		if (!this._drawing || layer._empty()) { return; }
12388
12389  		var p = layer._point,
12390  		    ctx = this._ctx,
12391  		    r = Math.max(Math.round(layer._radius), 1),
12392  		    s = (Math.max(Math.round(layer._radiusY), 1) || r) / r;
12393
12394  		if (s !== 1) {
12395  			ctx.save();
12396  			ctx.scale(1, s);
12397  		}
12398
12399  		ctx.beginPath();
12400  		ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);
12401
12402  		if (s !== 1) {
12403  			ctx.restore();
12404  		}
12405
12406  		this._fillStroke(ctx, layer);
12407  	},
12408
12409  	_fillStroke: function (ctx, layer) {
12410  		var options = layer.options;
12411
12412  		if (options.fill) {
12413  			ctx.globalAlpha = options.fillOpacity;
12414  			ctx.fillStyle = options.fillColor || options.color;
12415  			ctx.fill(options.fillRule || 'evenodd');
12416  		}
12417
12418  		if (options.stroke && options.weight !== 0) {
12419  			if (ctx.setLineDash) {
12420  				ctx.setLineDash(layer.options && layer.options._dashArray || []);
12421  			}
12422  			ctx.globalAlpha = options.opacity;
12423  			ctx.lineWidth = options.weight;
12424  			ctx.strokeStyle = options.color;
12425  			ctx.lineCap = options.lineCap;
12426  			ctx.lineJoin = options.lineJoin;
12427  			ctx.stroke();
12428  		}
12429  	},
12430
12431  	// Canvas obviously doesn't have mouse events for individual drawn objects,
12432  	// so we emulate that by calculating what's under the mouse on mousemove/click manually
12433
12434  	_onClick: function (e) {
12435  		var point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer;
12436
12437  		for (var order = this._drawFirst; order; order = order.next) {
12438  			layer = order.layer;
12439  			if (layer.options.interactive && layer._containsPoint(point)) {
12440  				if (!(e.type === 'click' || e.type !== 'preclick') || !this._map._draggableMoved(layer)) {
12441  					clickedLayer = layer;
12442  				}
12443  			}
12444  		}
12445  		if (clickedLayer)  {
12446  			fakeStop(e);
12447  			this._fireEvent([clickedLayer], e);
12448  		}
12449  	},
12450
12451  	_onMouseMove: function (e) {
12452  		if (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; }
12453
12454  		var point = this._map.mouseEventToLayerPoint(e);
12455  		this._handleMouseHover(e, point);
12456  	},
12457
12458
12459  	_handleMouseOut: function (e) {
12460  		var layer = this._hoveredLayer;
12461  		if (layer) {
12462  			// if we're leaving the layer, fire mouseout
12463  			removeClass(this._container, 'leaflet-interactive');
12464  			this._fireEvent([layer], e, 'mouseout');
12465  			this._hoveredLayer = null;
12466  			this._mouseHoverThrottled = false;
12467  		}
12468  	},
12469
12470  	_handleMouseHover: function (e, point) {
12471  		if (this._mouseHoverThrottled) {
12472  			return;
12473  		}
12474
12475  		var layer, candidateHoveredLayer;
12476
12477  		for (var order = this._drawFirst; order; order = order.next) {
12478  			layer = order.layer;
12479  			if (layer.options.interactive && layer._containsPoint(point)) {
12480  				candidateHoveredLayer = layer;
12481  			}
12482  		}
12483
12484  		if (candidateHoveredLayer !== this._hoveredLayer) {
12485  			this._handleMouseOut(e);
12486
12487  			if (candidateHoveredLayer) {
12488  				addClass(this._container, 'leaflet-interactive'); // change cursor
12489  				this._fireEvent([candidateHoveredLayer], e, 'mouseover');
12490  				this._hoveredLayer = candidateHoveredLayer;
12491  			}
12492  		}
12493
12494  		if (this._hoveredLayer) {
12495  			this._fireEvent([this._hoveredLayer], e);
12496  		}
12497
12498  		this._mouseHoverThrottled = true;
12499  		setTimeout(bind(function () {
12500  			this._mouseHoverThrottled = false;
12501  		}, this), 32);
12502  	},
12503
12504  	_fireEvent: function (layers, e, type) {
12505  		this._map._fireDOMEvent(e, type || e.type, layers);
12506  	},
12507
12508  	_bringToFront: function (layer) {
12509  		var order = layer._order;
12510
12511  		if (!order) { return; }
12512
12513  		var next = order.next;
12514  		var prev = order.prev;
12515
12516  		if (next) {
12517  			next.prev = prev;
12518  		} else {
12519  			// Already last
12520  			return;
12521  		}
12522  		if (prev) {
12523  			prev.next = next;
12524  		} else if (next) {
12525  			// Update first entry unless this is the
12526  			// single entry
12527  			this._drawFirst = next;
12528  		}
12529
12530  		order.prev = this._drawLast;
12531  		this._drawLast.next = order;
12532
12533  		order.next = null;
12534  		this._drawLast = order;
12535
12536  		this._requestRedraw(layer);
12537  	},
12538
12539  	_bringToBack: function (layer) {
12540  		var order = layer._order;
12541
12542  		if (!order) { return; }
12543
12544  		var next = order.next;
12545  		var prev = order.prev;
12546
12547  		if (prev) {
12548  			prev.next = next;
12549  		} else {
12550  			// Already first
12551  			return;
12552  		}
12553  		if (next) {
12554  			next.prev = prev;
12555  		} else if (prev) {
12556  			// Update last entry unless this is the
12557  			// single entry
12558  			this._drawLast = prev;
12559  		}
12560
12561  		order.prev = null;
12562
12563  		order.next = this._drawFirst;
12564  		this._drawFirst.prev = order;
12565  		this._drawFirst = order;
12566
12567  		this._requestRedraw(layer);
12568  	}
12569  });
12570
12571  // @factory L.canvas(options?: Renderer options)
12572  // Creates a Canvas renderer with the given options.
12573  function canvas(options) {
12574  	return canvas$1 ? new Canvas(options) : null;
12575  }
12576
12577  /*
12578   * Thanks to Dmitry Baranovsky and his Raphael library for inspiration!
12579   */
12580
12581
12582  var vmlCreate = (function () {
12583  	try {
12584  		document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');
12585  		return function (name) {
12586  			return document.createElement('<lvml:' + name + ' class="lvml">');
12587  		};
12588  	} catch (e) {
12589  		return function (name) {
12590  			return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
12591  		};
12592  	}
12593  })();
12594
12595
12596  /*
12597   * @class SVG
12598   *
12599   *
12600   * VML was deprecated in 2012, which means VML functionality exists only for backwards compatibility
12601   * with old versions of Internet Explorer.
12602   */
12603
12604  // mixin to redefine some SVG methods to handle VML syntax which is similar but with some differences
12605  var vmlMixin = {
12606
12607  	_initContainer: function () {
12608  		this._container = create$1('div', 'leaflet-vml-container');
12609  	},
12610
12611  	_update: function () {
12612  		if (this._map._animatingZoom) { return; }
12613  		Renderer.prototype._update.call(this);
12614  		this.fire('update');
12615  	},
12616
12617  	_initPath: function (layer) {
12618  		var container = layer._container = vmlCreate('shape');
12619
12620  		addClass(container, 'leaflet-vml-shape ' + (this.options.className || ''));
12621
12622  		container.coordsize = '1 1';
12623
12624  		layer._path = vmlCreate('path');
12625  		container.appendChild(layer._path);
12626
12627  		this._updateStyle(layer);
12628  		this._layers[stamp(layer)] = layer;
12629  	},
12630
12631  	_addPath: function (layer) {
12632  		var container = layer._container;
12633  		this._container.appendChild(container);
12634
12635  		if (layer.options.interactive) {
12636  			layer.addInteractiveTarget(container);
12637  		}
12638  	},
12639
12640  	_removePath: function (layer) {
12641  		var container = layer._container;
12642  		remove(container);
12643  		layer.removeInteractiveTarget(container);
12644  		delete this._layers[stamp(layer)];
12645  	},
12646
12647  	_updateStyle: function (layer) {
12648  		var stroke = layer._stroke,
12649  		    fill = layer._fill,
12650  		    options = layer.options,
12651  		    container = layer._container;
12652
12653  		container.stroked = !!options.stroke;
12654  		container.filled = !!options.fill;
12655
12656  		if (options.stroke) {
12657  			if (!stroke) {
12658  				stroke = layer._stroke = vmlCreate('stroke');
12659  			}
12660  			container.appendChild(stroke);
12661  			stroke.weight = options.weight + 'px';
12662  			stroke.color = options.color;
12663  			stroke.opacity = options.opacity;
12664
12665  			if (options.dashArray) {
12666  				stroke.dashStyle = isArray(options.dashArray) ?
12667  				    options.dashArray.join(' ') :
12668  				    options.dashArray.replace(/( *, *)/g, ' ');
12669  			} else {
12670  				stroke.dashStyle = '';
12671  			}
12672  			stroke.endcap = options.lineCap.replace('butt', 'flat');
12673  			stroke.joinstyle = options.lineJoin;
12674
12675  		} else if (stroke) {
12676  			container.removeChild(stroke);
12677  			layer._stroke = null;
12678  		}
12679
12680  		if (options.fill) {
12681  			if (!fill) {
12682  				fill = layer._fill = vmlCreate('fill');
12683  			}
12684  			container.appendChild(fill);
12685  			fill.color = options.fillColor || options.color;
12686  			fill.opacity = options.fillOpacity;
12687
12688  		} else if (fill) {
12689  			container.removeChild(fill);
12690  			layer._fill = null;
12691  		}
12692  	},
12693
12694  	_updateCircle: function (layer) {
12695  		var p = layer._point.round(),
12696  		    r = Math.round(layer._radius),
12697  		    r2 = Math.round(layer._radiusY || r);
12698
12699  		this._setPath(layer, layer._empty() ? 'M0 0' :
12700  			'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360));
12701  	},
12702
12703  	_setPath: function (layer, path) {
12704  		layer._path.v = path;
12705  	},
12706
12707  	_bringToFront: function (layer) {
12708  		toFront(layer._container);
12709  	},
12710
12711  	_bringToBack: function (layer) {
12712  		toBack(layer._container);
12713  	}
12714  };
12715
12716  var create = vml ? vmlCreate : svgCreate;
12717
12718  /*
12719   * @class SVG
12720   * @inherits Renderer
12721   * @aka L.SVG
12722   *
12723   * Allows vector layers to be displayed with [SVG](https://developer.mozilla.org/docs/Web/SVG).
12724   * Inherits `Renderer`.
12725   *
12726   * Due to [technical limitations](http://caniuse.com/#search=svg), SVG is not
12727   * available in all web browsers, notably Android 2.x and 3.x.
12728   *
12729   * Although SVG is not available on IE7 and IE8, these browsers support
12730   * [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language)
12731   * (a now deprecated technology), and the SVG renderer will fall back to VML in
12732   * this case.
12733   *
12734   * @example
12735   *
12736   * Use SVG by default for all paths in the map:
12737   *
12738   * ```js
12739   * var map = L.map('map', {
12740   * 	renderer: L.svg()
12741   * });
12742   * ```
12743   *
12744   * Use a SVG renderer with extra padding for specific vector geometries:
12745   *
12746   * ```js
12747   * var map = L.map('map');
12748   * var myRenderer = L.svg({ padding: 0.5 });
12749   * var line = L.polyline( coordinates, { renderer: myRenderer } );
12750   * var circle = L.circle( center, { renderer: myRenderer } );
12751   * ```
12752   */
12753
12754  var SVG = Renderer.extend({
12755
12756  	getEvents: function () {
12757  		var events = Renderer.prototype.getEvents.call(this);
12758  		events.zoomstart = this._onZoomStart;
12759  		return events;
12760  	},
12761
12762  	_initContainer: function () {
12763  		this._container = create('svg');
12764
12765  		// makes it possible to click through svg root; we'll reset it back in individual paths
12766  		this._container.setAttribute('pointer-events', 'none');
12767
12768  		this._rootGroup = create('g');
12769  		this._container.appendChild(this._rootGroup);
12770  	},
12771
12772  	_destroyContainer: function () {
12773  		remove(this._container);
12774  		off(this._container);
12775  		delete this._container;
12776  		delete this._rootGroup;
12777  		delete this._svgSize;
12778  	},
12779
12780  	_onZoomStart: function () {
12781  		// Drag-then-pinch interactions might mess up the center and zoom.
12782  		// In this case, the easiest way to prevent this is re-do the renderer
12783  		//   bounds and padding when the zooming starts.
12784  		this._update();
12785  	},
12786
12787  	_update: function () {
12788  		if (this._map._animatingZoom && this._bounds) { return; }
12789
12790  		Renderer.prototype._update.call(this);
12791
12792  		var b = this._bounds,
12793  		    size = b.getSize(),
12794  		    container = this._container;
12795
12796  		// set size of svg-container if changed
12797  		if (!this._svgSize || !this._svgSize.equals(size)) {
12798  			this._svgSize = size;
12799  			container.setAttribute('width', size.x);
12800  			container.setAttribute('height', size.y);
12801  		}
12802
12803  		// movement: update container viewBox so that we don't have to change coordinates of individual layers
12804  		setPosition(container, b.min);
12805  		container.setAttribute('viewBox', [b.min.x, b.min.y, size.x, size.y].join(' '));
12806
12807  		this.fire('update');
12808  	},
12809
12810  	// methods below are called by vector layers implementations
12811
12812  	_initPath: function (layer) {
12813  		var path = layer._path = create('path');
12814
12815  		// @namespace Path
12816  		// @option className: String = null
12817  		// Custom class name set on an element. Only for SVG renderer.
12818  		if (layer.options.className) {
12819  			addClass(path, layer.options.className);
12820  		}
12821
12822  		if (layer.options.interactive) {
12823  			addClass(path, 'leaflet-interactive');
12824  		}
12825
12826  		this._updateStyle(layer);
12827  		this._layers[stamp(layer)] = layer;
12828  	},
12829
12830  	_addPath: function (layer) {
12831  		if (!this._rootGroup) { this._initContainer(); }
12832  		this._rootGroup.appendChild(layer._path);
12833  		layer.addInteractiveTarget(layer._path);
12834  	},
12835
12836  	_removePath: function (layer) {
12837  		remove(layer._path);
12838  		layer.removeInteractiveTarget(layer._path);
12839  		delete this._layers[stamp(layer)];
12840  	},
12841
12842  	_updatePath: function (layer) {
12843  		layer._project();
12844  		layer._update();
12845  	},
12846
12847  	_updateStyle: function (layer) {
12848  		var path = layer._path,
12849  		    options = layer.options;
12850
12851  		if (!path) { return; }
12852
12853  		if (options.stroke) {
12854  			path.setAttribute('stroke', options.color);
12855  			path.setAttribute('stroke-opacity', options.opacity);
12856  			path.setAttribute('stroke-width', options.weight);
12857  			path.setAttribute('stroke-linecap', options.lineCap);
12858  			path.setAttribute('stroke-linejoin', options.lineJoin);
12859
12860  			if (options.dashArray) {
12861  				path.setAttribute('stroke-dasharray', options.dashArray);
12862  			} else {
12863  				path.removeAttribute('stroke-dasharray');
12864  			}
12865
12866  			if (options.dashOffset) {
12867  				path.setAttribute('stroke-dashoffset', options.dashOffset);
12868  			} else {
12869  				path.removeAttribute('stroke-dashoffset');
12870  			}
12871  		} else {
12872  			path.setAttribute('stroke', 'none');
12873  		}
12874
12875  		if (options.fill) {
12876  			path.setAttribute('fill', options.fillColor || options.color);
12877  			path.setAttribute('fill-opacity', options.fillOpacity);
12878  			path.setAttribute('fill-rule', options.fillRule || 'evenodd');
12879  		} else {
12880  			path.setAttribute('fill', 'none');
12881  		}
12882  	},
12883
12884  	_updatePoly: function (layer, closed) {
12885  		this._setPath(layer, pointsToPath(layer._parts, closed));
12886  	},
12887
12888  	_updateCircle: function (layer) {
12889  		var p = layer._point,
12890  		    r = Math.max(Math.round(layer._radius), 1),
12891  		    r2 = Math.max(Math.round(layer._radiusY), 1) || r,
12892  		    arc = 'a' + r + ',' + r2 + ' 0 1,0 ';
12893
12894  		// drawing a circle with two half-arcs
12895  		var d = layer._empty() ? 'M0 0' :
12896  			'M' + (p.x - r) + ',' + p.y +
12897  			arc + (r * 2) + ',0 ' +
12898  			arc + (-r * 2) + ',0 ';
12899
12900  		this._setPath(layer, d);
12901  	},
12902
12903  	_setPath: function (layer, path) {
12904  		layer._path.setAttribute('d', path);
12905  	},
12906
12907  	// SVG does not have the concept of zIndex so we resort to changing the DOM order of elements
12908  	_bringToFront: function (layer) {
12909  		toFront(layer._path);
12910  	},
12911
12912  	_bringToBack: function (layer) {
12913  		toBack(layer._path);
12914  	}
12915  });
12916
12917  if (vml) {
12918  	SVG.include(vmlMixin);
12919  }
12920
12921  // @namespace SVG
12922  // @factory L.svg(options?: Renderer options)
12923  // Creates a SVG renderer with the given options.
12924  function svg(options) {
12925  	return svg$1 || 
vendor: 6,797 bytes, lines 12925-13170
12925vml ? new SVG(options) : null;
12926  }
12927
12928  Map.include({
12929  	// @namespace Map; @method getRenderer(layer: Path): Renderer
12930  	// Returns the instance of `Renderer` that should be used to render the given
12931  	// `Path`. It will ensure that the `renderer` options of the map and paths
12932  	// are respected, and that the renderers do exist on the map.
12933  	getRenderer: function (layer) {
12934  		// @namespace Path; @option renderer: Renderer
12935  		// Use this specific instance of `Renderer` for this path. Takes
12936  		// precedence over the map's [default renderer](#map-renderer).
12937  		var renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;
12938
12939  		if (!renderer) {
12940  			renderer = this._renderer = this._createRenderer();
12941  		}
12942
12943  		if (!this.hasLayer(renderer)) {
12944  			this.addLayer(renderer);
12945  		}
12946  		return renderer;
12947  	},
12948
12949  	_getPaneRenderer: function (name) {
12950  		if (name === 'overlayPane' || name === undefined) {
12951  			return false;
12952  		}
12953
12954  		var renderer = this._paneRenderers[name];
12955  		if (renderer === undefined) {
12956  			renderer = this._createRenderer({pane: name});
12957  			this._paneRenderers[name] = renderer;
12958  		}
12959  		return renderer;
12960  	},
12961
12962  	_createRenderer: function (options) {
12963  		// @namespace Map; @option preferCanvas: Boolean = false
12964  		// Whether `Path`s should be rendered on a `Canvas` renderer.
12965  		// By default, all `Path`s are rendered in a `SVG` renderer.
12966  		return (this.options.preferCanvas && canvas(options)) || svg(options);
12967  	}
12968  });
12969
12970  /*
12971   * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object.
12972   */
12973
12974  /*
12975   * @class Rectangle
12976   * @aka L.Rectangle
12977   * @inherits Polygon
12978   *
12979   * A class for drawing rectangle overlays on a map. Extends `Polygon`.
12980   *
12981   * @example
12982   *
12983   * ```js
12984   * // define rectangle geographical bounds
12985   * var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];
12986   *
12987   * // create an orange rectangle
12988   * L.rectangle(bounds, {color: "#ff7800", weight: 1}).addTo(map);
12989   *
12990   * // zoom the map to the rectangle bounds
12991   * map.fitBounds(bounds);
12992   * ```
12993   *
12994   */
12995
12996
12997  var Rectangle = Polygon.extend({
12998  	initialize: function (latLngBounds, options) {
12999  		Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);
13000  	},
13001
13002  	// @method setBounds(latLngBounds: LatLngBounds): this
13003  	// Redraws the rectangle with the passed bounds.
13004  	setBounds: function (latLngBounds) {
13005  		return this.setLatLngs(this._boundsToLatLngs(latLngBounds));
13006  	},
13007
13008  	_boundsToLatLngs: function (latLngBounds) {
13009  		latLngBounds = toLatLngBounds(latLngBounds);
13010  		return [
13011  			latLngBounds.getSouthWest(),
13012  			latLngBounds.getNorthWest(),
13013  			latLngBounds.getNorthEast(),
13014  			latLngBounds.getSouthEast()
13015  		];
13016  	}
13017  });
13018
13019
13020  // @factory L.rectangle(latLngBounds: LatLngBounds, options?: Polyline options)
13021  function rectangle(latLngBounds, options) {
13022  	return new Rectangle(latLngBounds, options);
13023  }
13024
13025  SVG.create = create;
13026  SVG.pointsToPath = pointsToPath;
13027
13028  GeoJSON.geometryToLayer = geometryToLayer;
13029  GeoJSON.coordsToLatLng = coordsToLatLng;
13030  GeoJSON.coordsToLatLngs = coordsToLatLngs;
13031  GeoJSON.latLngToCoords = latLngToCoords;
13032  GeoJSON.latLngsToCoords = latLngsToCoords;
13033  GeoJSON.getFeature = getFeature;
13034  GeoJSON.asFeature = asFeature;
13035
13036  /*
13037   * L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map
13038   * (zoom to a selected bounding box), enabled by default.
13039   */
13040
13041  // @namespace Map
13042  // @section Interaction Options
13043  Map.mergeOptions({
13044  	// @option boxZoom: Boolean = true
13045  	// Whether the map can be zoomed to a rectangular area specified by
13046  	// dragging the mouse while pressing the shift key.
13047  	boxZoom: true
13048  });
13049
13050  var BoxZoom = Handler.extend({
13051  	initialize: function (map) {
13052  		this._map = map;
13053  		this._container = map._container;
13054  		this._pane = map._panes.overlayPane;
13055  		this._resetStateTimeout = 0;
13056  		map.on('unload', this._destroy, this);
13057  	},
13058
13059  	addHooks: function () {
13060  		on(this._container, 'mousedown', this._onMouseDown, this);
13061  	},
13062
13063  	removeHooks: function () {
13064  		off(this._container, 'mousedown', this._onMouseDown, this);
13065  	},
13066
13067  	moved: function () {
13068  		return this._moved;
13069  	},
13070
13071  	_destroy: function () {
13072  		remove(this._pane);
13073  		delete this._pane;
13074  	},
13075
13076  	_resetState: function () {
13077  		this._resetStateTimeout = 0;
13078  		this._moved = false;
13079  	},
13080
13081  	_clearDeferredResetState: function () {
13082  		if (this._resetStateTimeout !== 0) {
13083  			clearTimeout(this._resetStateTimeout);
13084  			this._resetStateTimeout = 0;
13085  		}
13086  	},
13087
13088  	_onMouseDown: function (e) {
13089  		if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
13090
13091  		// Clear the deferred resetState if it hasn't executed yet, otherwise it
13092  		// will interrupt the interaction and orphan a box element in the container.
13093  		this._clearDeferredResetState();
13094  		this._resetState();
13095
13096  		disableTextSelection();
13097  		disableImageDrag();
13098
13099  		this._startPoint = this._map.mouseEventToContainerPoint(e);
13100
13101  		on(document, {
13102  			contextmenu: stop,
13103  			mousemove: this._onMouseMove,
13104  			mouseup: this._onMouseUp,
13105  			keydown: this._onKeyDown
13106  		}, this);
13107  	},
13108
13109  	_onMouseMove: function (e) {
13110  		if (!this._moved) {
13111  			this._moved = true;
13112
13113  			this._box = create$1('div', 'leaflet-zoom-box', this._container);
13114  			addClass(this._container, 'leaflet-crosshair');
13115
13116  			this._map.fire('boxzoomstart');
13117  		}
13118
13119  		this._point = this._map.mouseEventToContainerPoint(e);
13120
13121  		var bounds = new Bounds(this._point, this._startPoint),
13122  		    size = bounds.getSize();
13123
13124  		setPosition(this._box, bounds.min);
13125
13126  		this._box.style.width  = size.x + 'px';
13127  		this._box.style.height = size.y + 'px';
13128  	},
13129
13130  	_finish: function () {
13131  		if (this._moved) {
13132  			remove(this._box);
13133  			removeClass(this._container, 'leaflet-crosshair');
13134  		}
13135
13136  		enableTextSelection();
13137  		enableImageDrag();
13138
13139  		off(document, {
13140  			contextmenu: stop,
13141  			mousemove: this._onMouseMove,
13142  			mouseup: this._onMouseUp,
13143  			keydown: this._onKeyDown
13144  		}, this);
13145  	},
13146
13147  	_onMouseUp: function (e) {
13148  		if ((e.which !== 1) && (e.button !== 1)) { return; }
13149
13150  		this._finish();
13151
13152  		if (!this._moved) { return; }
13153  		// Postpone to next JS tick so internal click event handling
13154  		// still see it as "moved".
13155  		this._clearDeferredResetState();
13156  		this._resetStateTimeout = setTimeout(bind(this._resetState, this), 0);
13157
13158  		var bounds = new LatLngBounds(
13159  		        this._map.containerPointToLatLng(this._startPoint),
13160  		        this._map.containerPointToLatLng(this._point));
13161
13162  		this._map
13163  			.fitBounds(bounds)
13164  			.fire('boxzoomend', {boxZoomBounds: bounds});
13165  	},
13166
13167  	_onKeyDown: function (e) {
13168  		if (e.keyCode === 27) {
13169  			this._finish();
13170  		
vendor: 17,310 bytes, lines 13170-13775
13170}
13171  	}
13172  });
13173
13174  // @section Handlers
13175  // @property boxZoom: Handler
13176  // Box (shift-drag with mouse) zoom handler.
13177  Map.addInitHook('addHandler', 'boxZoom', BoxZoom);
13178
13179  /*
13180   * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default.
13181   */
13182
13183  // @namespace Map
13184  // @section Interaction Options
13185
13186  Map.mergeOptions({
13187  	// @option doubleClickZoom: Boolean|String = true
13188  	// Whether the map can be zoomed in by double clicking on it and
13189  	// zoomed out by double clicking while holding shift. If passed
13190  	// `'center'`, double-click zoom will zoom to the center of the
13191  	//  view regardless of where the mouse was.
13192  	doubleClickZoom: true
13193  });
13194
13195  var DoubleClickZoom = Handler.extend({
13196  	addHooks: function () {
13197  		this._map.on('dblclick', this._onDoubleClick, this);
13198  	},
13199
13200  	removeHooks: function () {
13201  		this._map.off('dblclick', this._onDoubleClick, this);
13202  	},
13203
13204  	_onDoubleClick: function (e) {
13205  		var map = this._map,
13206  		    oldZoom = map.getZoom(),
13207  		    delta = map.options.zoomDelta,
13208  		    zoom = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta;
13209
13210  		if (map.options.doubleClickZoom === 'center') {
13211  			map.setZoom(zoom);
13212  		} else {
13213  			map.setZoomAround(e.containerPoint, zoom);
13214  		}
13215  	}
13216  });
13217
13218  // @section Handlers
13219  //
13220  // Map properties include interaction handlers that allow you to control
13221  // interaction behavior in runtime, enabling or disabling certain features such
13222  // as dragging or touch zoom (see `Handler` methods). For example:
13223  //
13224  // ```js
13225  // map.doubleClickZoom.disable();
13226  // ```
13227  //
13228  // @property doubleClickZoom: Handler
13229  // Double click zoom handler.
13230  Map.addInitHook('addHandler', 'doubleClickZoom', DoubleClickZoom);
13231
13232  /*
13233   * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default.
13234   */
13235
13236  // @namespace Map
13237  // @section Interaction Options
13238  Map.mergeOptions({
13239  	// @option dragging: Boolean = true
13240  	// Whether the map be draggable with mouse/touch or not.
13241  	dragging: true,
13242
13243  	// @section Panning Inertia Options
13244  	// @option inertia: Boolean = *
13245  	// If enabled, panning of the map will have an inertia effect where
13246  	// the map builds momentum while dragging and continues moving in
13247  	// the same direction for some time. Feels especially nice on touch
13248  	// devices. Enabled by default unless running on old Android devices.
13249  	inertia: !android23,
13250
13251  	// @option inertiaDeceleration: Number = 3000
13252  	// The rate with which the inertial movement slows down, in pixels/second².
13253  	inertiaDeceleration: 3400, // px/s^2
13254
13255  	// @option inertiaMaxSpeed: Number = Infinity
13256  	// Max speed of the inertial movement, in pixels/second.
13257  	inertiaMaxSpeed: Infinity, // px/s
13258
13259  	// @option easeLinearity: Number = 0.2
13260  	easeLinearity: 0.2,
13261
13262  	// TODO refactor, move to CRS
13263  	// @option worldCopyJump: Boolean = false
13264  	// With this option enabled, the map tracks when you pan to another "copy"
13265  	// of the world and seamlessly jumps to the original one so that all overlays
13266  	// like markers and vector layers are still visible.
13267  	worldCopyJump: false,
13268
13269  	// @option maxBoundsViscosity: Number = 0.0
13270  	// If `maxBounds` is set, this option will control how solid the bounds
13271  	// are when dragging the map around. The default value of `0.0` allows the
13272  	// user to drag outside the bounds at normal speed, higher values will
13273  	// slow down map dragging outside bounds, and `1.0` makes the bounds fully
13274  	// solid, preventing the user from dragging outside the bounds.
13275  	maxBoundsViscosity: 0.0
13276  });
13277
13278  var Drag = Handler.extend({
13279  	addHooks: function () {
13280  		if (!this._draggable) {
13281  			var map = this._map;
13282
13283  			this._draggable = new Draggable(map._mapPane, map._container);
13284
13285  			this._draggable.on({
13286  				dragstart: this._onDragStart,
13287  				drag: this._onDrag,
13288  				dragend: this._onDragEnd
13289  			}, this);
13290
13291  			this._draggable.on('predrag', this._onPreDragLimit, this);
13292  			if (map.options.worldCopyJump) {
13293  				this._draggable.on('predrag', this._onPreDragWrap, this);
13294  				map.on('zoomend', this._onZoomEnd, this);
13295
13296  				map.whenReady(this._onZoomEnd, this);
13297  			}
13298  		}
13299  		addClass(this._map._container, 'leaflet-grab leaflet-touch-drag');
13300  		this._draggable.enable();
13301  		this._positions = [];
13302  		this._times = [];
13303  	},
13304
13305  	removeHooks: function () {
13306  		removeClass(this._map._container, 'leaflet-grab');
13307  		removeClass(this._map._container, 'leaflet-touch-drag');
13308  		this._draggable.disable();
13309  	},
13310
13311  	moved: function () {
13312  		return this._draggable && this._draggable._moved;
13313  	},
13314
13315  	moving: function () {
13316  		return this._draggable && this._draggable._moving;
13317  	},
13318
13319  	_onDragStart: function () {
13320  		var map = this._map;
13321
13322  		map._stop();
13323  		if (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) {
13324  			var bounds = toLatLngBounds(this._map.options.maxBounds);
13325
13326  			this._offsetLimit = toBounds(
13327  				this._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),
13328  				this._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1)
13329  					.add(this._map.getSize()));
13330
13331  			this._viscosity = Math.min(1.0, Math.max(0.0, this._map.options.maxBoundsViscosity));
13332  		} else {
13333  			this._offsetLimit = null;
13334  		}
13335
13336  		map
13337  		    .fire('movestart')
13338  		    .fire('dragstart');
13339
13340  		if (map.options.inertia) {
13341  			this._positions = [];
13342  			this._times = [];
13343  		}
13344  	},
13345
13346  	_onDrag: function (e) {
13347  		if (this._map.options.inertia) {
13348  			var time = this._lastTime = +new Date(),
13349  			    pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;
13350
13351  			this._positions.push(pos);
13352  			this._times.push(time);
13353
13354  			this._prunePositions(time);
13355  		}
13356
13357  		this._map
13358  		    .fire('move', e)
13359  		    .fire('drag', e);
13360  	},
13361
13362  	_prunePositions: function (time) {
13363  		while (this._positions.length > 1 && time - this._times[0] > 50) {
13364  			this._positions.shift();
13365  			this._times.shift();
13366  		}
13367  	},
13368
13369  	_onZoomEnd: function () {
13370  		var pxCenter = this._map.getSize().divideBy(2),
13371  		    pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);
13372
13373  		this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;
13374  		this._worldWidth = this._map.getPixelWorldBounds().getSize().x;
13375  	},
13376
13377  	_viscousLimit: function (value, threshold) {
13378  		return value - (value - threshold) * this._viscosity;
13379  	},
13380
13381  	_onPreDragLimit: function () {
13382  		if (!this._viscosity || !this._offsetLimit) { return; }
13383
13384  		var offset = this._draggable._newPos.subtract(this._draggable._startPos);
13385
13386  		var limit = this._offsetLimit;
13387  		if (offset.x < limit.min.x) { offset.x = this._viscousLimit(offset.x, limit.min.x); }
13388  		if (offset.y < limit.min.y) { offset.y = this._viscousLimit(offset.y, limit.min.y); }
13389  		if (offset.x > limit.max.x) { offset.x = this._viscousLimit(offset.x, limit.max.x); }
13390  		if (offset.y > limit.max.y) { offset.y = this._viscousLimit(offset.y, limit.max.y); }
13391
13392  		this._draggable._newPos = this._draggable._startPos.add(offset);
13393  	},
13394
13395  	_onPreDragWrap: function () {
13396  		// TODO refactor to be able to adjust map pane position after zoom
13397  		var worldWidth = this._worldWidth,
13398  		    halfWidth = Math.round(worldWidth / 2),
13399  		    dx = this._initialWorldOffset,
13400  		    x = this._draggable._newPos.x,
13401  		    newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx,
13402  		    newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx,
13403  		    newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;
13404
13405  		this._draggable._absPos = this._draggable._newPos.clone();
13406  		this._draggable._newPos.x = newX;
13407  	},
13408
13409  	_onDragEnd: function (e) {
13410  		var map = this._map,
13411  		    options = map.options,
13412
13413  		    noInertia = !options.inertia || this._times.length < 2;
13414
13415  		map.fire('dragend', e);
13416
13417  		if (noInertia) {
13418  			map.fire('moveend');
13419
13420  		} else {
13421  			this._prunePositions(+new Date());
13422
13423  			var direction = this._lastPos.subtract(this._positions[0]),
13424  			    duration = (this._lastTime - this._times[0]) / 1000,
13425  			    ease = options.easeLinearity,
13426
13427  			    speedVector = direction.multiplyBy(ease / duration),
13428  			    speed = speedVector.distanceTo([0, 0]),
13429
13430  			    limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),
13431  			    limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),
13432
13433  			    decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease),
13434  			    offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();
13435
13436  			if (!offset.x && !offset.y) {
13437  				map.fire('moveend');
13438
13439  			} else {
13440  				offset = map._limitOffset(offset, map.options.maxBounds);
13441
13442  				requestAnimFrame(function () {
13443  					map.panBy(offset, {
13444  						duration: decelerationDuration,
13445  						easeLinearity: ease,
13446  						noMoveStart: true,
13447  						animate: true
13448  					});
13449  				});
13450  			}
13451  		}
13452  	}
13453  });
13454
13455  // @section Handlers
13456  // @property dragging: Handler
13457  // Map dragging handler (by both mouse and touch).
13458  Map.addInitHook('addHandler', 'dragging', Drag);
13459
13460  /*
13461   * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default.
13462   */
13463
13464  // @namespace Map
13465  // @section Keyboard Navigation Options
13466  Map.mergeOptions({
13467  	// @option keyboard: Boolean = true
13468  	// Makes the map focusable and allows users to navigate the map with keyboard
13469  	// arrows and `+`/`-` keys.
13470  	keyboard: true,
13471
13472  	// @option keyboardPanDelta: Number = 80
13473  	// Amount of pixels to pan when pressing an arrow key.
13474  	keyboardPanDelta: 80
13475  });
13476
13477  var Keyboard = Handler.extend({
13478
13479  	keyCodes: {
13480  		left:    [37],
13481  		right:   [39],
13482  		down:    [40],
13483  		up:      [38],
13484  		zoomIn:  [187, 107, 61, 171],
13485  		zoomOut: [189, 109, 54, 173]
13486  	},
13487
13488  	initialize: function (map) {
13489  		this._map = map;
13490
13491  		this._setPanDelta(map.options.keyboardPanDelta);
13492  		this._setZoomDelta(map.options.zoomDelta);
13493  	},
13494
13495  	addHooks: function () {
13496  		var container = this._map._container;
13497
13498  		// make the container focusable by tabbing
13499  		if (container.tabIndex <= 0) {
13500  			container.tabIndex = '0';
13501  		}
13502
13503  		on(container, {
13504  			focus: this._onFocus,
13505  			blur: this._onBlur,
13506  			mousedown: this._onMouseDown
13507  		}, this);
13508
13509  		this._map.on({
13510  			focus: this._addHooks,
13511  			blur: this._removeHooks
13512  		}, this);
13513  	},
13514
13515  	removeHooks: function () {
13516  		this._removeHooks();
13517
13518  		off(this._map._container, {
13519  			focus: this._onFocus,
13520  			blur: this._onBlur,
13521  			mousedown: this._onMouseDown
13522  		}, this);
13523
13524  		this._map.off({
13525  			focus: this._addHooks,
13526  			blur: this._removeHooks
13527  		}, this);
13528  	},
13529
13530  	_onMouseDown: function () {
13531  		if (this._focused) { return; }
13532
13533  		var body = document.body,
13534  		    docEl = document.documentElement,
13535  		    top = body.scrollTop || docEl.scrollTop,
13536  		    left = body.scrollLeft || docEl.scrollLeft;
13537
13538  		this._map._container.focus();
13539
13540  		window.scrollTo(left, top);
13541  	},
13542
13543  	_onFocus: function () {
13544  		this._focused = true;
13545  		this._map.fire('focus');
13546  	},
13547
13548  	_onBlur: function () {
13549  		this._focused = false;
13550  		this._map.fire('blur');
13551  	},
13552
13553  	_setPanDelta: function (panDelta) {
13554  		var keys = this._panKeys = {},
13555  		    codes = this.keyCodes,
13556  		    i, len;
13557
13558  		for (i = 0, len = codes.left.length; i < len; i++) {
13559  			keys[codes.left[i]] = [-1 * panDelta, 0];
13560  		}
13561  		for (i = 0, len = codes.right.length; i < len; i++) {
13562  			keys[codes.right[i]] = [panDelta, 0];
13563  		}
13564  		for (i = 0, len = codes.down.length; i < len; i++) {
13565  			keys[codes.down[i]] = [0, panDelta];
13566  		}
13567  		for (i = 0, len = codes.up.length; i < len; i++) {
13568  			keys[codes.up[i]] = [0, -1 * panDelta];
13569  		}
13570  	},
13571
13572  	_setZoomDelta: function (zoomDelta) {
13573  		var keys = this._zoomKeys = {},
13574  		    codes = this.keyCodes,
13575  		    i, len;
13576
13577  		for (i = 0, len = codes.zoomIn.length; i < len; i++) {
13578  			keys[codes.zoomIn[i]] = zoomDelta;
13579  		}
13580  		for (i = 0, len = codes.zoomOut.length; i < len; i++) {
13581  			keys[codes.zoomOut[i]] = -zoomDelta;
13582  		}
13583  	},
13584
13585  	_addHooks: function () {
13586  		on(document, 'keydown', this._onKeyDown, this);
13587  	},
13588
13589  	_removeHooks: function () {
13590  		off(document, 'keydown', this._onKeyDown, this);
13591  	},
13592
13593  	_onKeyDown: function (e) {
13594  		if (e.altKey || e.ctrlKey || e.metaKey) { return; }
13595
13596  		var key = e.keyCode,
13597  		    map = this._map,
13598  		    offset;
13599
13600  		if (key in this._panKeys) {
13601  			if (!map._panAnim || !map._panAnim._inProgress) {
13602  				offset = this._panKeys[key];
13603  				if (e.shiftKey) {
13604  					offset = toPoint(offset).multiplyBy(3);
13605  				}
13606
13607  				map.panBy(offset);
13608
13609  				if (map.options.maxBounds) {
13610  					map.panInsideBounds(map.options.maxBounds);
13611  				}
13612  			}
13613  		} else if (key in this._zoomKeys) {
13614  			map.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);
13615
13616  		} else if (key === 27 && map._popup && map._popup.options.closeOnEscapeKey) {
13617  			map.closePopup();
13618
13619  		} else {
13620  			return;
13621  		}
13622
13623  		stop(e);
13624  	}
13625  });
13626
13627  // @section Handlers
13628  // @section Handlers
13629  // @property keyboard: Handler
13630  // Keyboard navigation handler.
13631  Map.addInitHook('addHandler', 'keyboard', Keyboard);
13632
13633  /*
13634   * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map.
13635   */
13636
13637  // @namespace Map
13638  // @section Interaction Options
13639  Map.mergeOptions({
13640  	// @section Mouse wheel options
13641  	// @option scrollWheelZoom: Boolean|String = true
13642  	// Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,
13643  	// it will zoom to the center of the view regardless of where the mouse was.
13644  	scrollWheelZoom: true,
13645
13646  	// @option wheelDebounceTime: Number = 40
13647  	// Limits the rate at which a wheel can fire (in milliseconds). By default
13648  	// user can't zoom via wheel more often than once per 40 ms.
13649  	wheelDebounceTime: 40,
13650
13651  	// @option wheelPxPerZoomLevel: Number = 60
13652  	// How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta))
13653  	// mean a change of one full zoom level. Smaller values will make wheel-zooming
13654  	// faster (and vice versa).
13655  	wheelPxPerZoomLevel: 60
13656  });
13657
13658  var ScrollWheelZoom = Handler.extend({
13659  	addHooks: function () {
13660  		on(this._map._container, 'wheel', this._onWheelScroll, this);
13661
13662  		this._delta = 0;
13663  	},
13664
13665  	removeHooks: function () {
13666  		off(this._map._container, 'wheel', this._onWheelScroll, this);
13667  	},
13668
13669  	_onWheelScroll: function (e) {
13670  		var delta = getWheelDelta(e);
13671
13672  		var debounce = this._map.options.wheelDebounceTime;
13673
13674  		this._delta += delta;
13675  		this._lastMousePos = this._map.mouseEventToContainerPoint(e);
13676
13677  		if (!this._startTime) {
13678  			this._startTime = +new Date();
13679  		}
13680
13681  		var left = Math.max(debounce - (+new Date() - this._startTime), 0);
13682
13683  		clearTimeout(this._timer);
13684  		this._timer = setTimeout(bind(this._performZoom, this), left);
13685
13686  		stop(e);
13687  	},
13688
13689  	_performZoom: function () {
13690  		var map = this._map,
13691  		    zoom = map.getZoom(),
13692  		    snap = this._map.options.zoomSnap || 0;
13693
13694  		map._stop(); // stop panning and fly animations if any
13695
13696  		// map the delta with a sigmoid function to -4..4 range leaning on -1..1
13697  		var d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),
13698  		    d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,
13699  		    d4 = snap ? Math.ceil(d3 / snap) * snap : d3,
13700  		    delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;
13701
13702  		this._delta = 0;
13703  		this._startTime = null;
13704
13705  		if (!delta) { return; }
13706
13707  		if (map.options.scrollWheelZoom === 'center') {
13708  			map.setZoom(zoom + delta);
13709  		} else {
13710  			map.setZoomAround(this._lastMousePos, zoom + delta);
13711  		}
13712  	}
13713  });
13714
13715  // @section Handlers
13716  // @property scrollWheelZoom: Handler
13717  // Scroll wheel zoom handler.
13718  Map.addInitHook('addHandler', 'scrollWheelZoom', ScrollWheelZoom);
13719
13720  /*
13721   * L.Map.Tap is used to enable mobile hacks like quick taps and long hold.
13722   */
13723
13724  // @namespace Map
13725  // @section Interaction Options
13726  Map.mergeOptions({
13727  	// @section Touch interaction options
13728  	// @option tap: Boolean = true
13729  	// Enables mobile hacks for supporting instant taps (fixing 200ms click
13730  	// delay on iOS/Android) and touch holds (fired as `contextmenu` events).
13731  	tap: true,
13732
13733  	// @option tapTolerance: Number = 15
13734  	// The max number of pixels a user can shift his finger during touch
13735  	// for it to be considered a valid tap.
13736  	tapTolerance: 15
13737  });
13738
13739  var Tap = Handler.extend({
13740  	addHooks: function () {
13741  		on(this._map._container, 'touchstart', this._onDown, this);
13742  	},
13743
13744  	removeHooks: function () {
13745  		off(this._map._container, 'touchstart', this._onDown, this);
13746  	},
13747
13748  	_onDown: function (e) {
13749  		if (!e.touches) { return; }
13750
13751  		preventDefault(e);
13752
13753  		this._fireClick = true;
13754
13755  		// don't simulate click or track longpress if more than 1 touch
13756  		if (e.touches.length > 1) {
13757  			this._fireClick = false;
13758  			clearTimeout(this._holdTimeout);
13759  			return;
13760  		}
13761
13762  		var first = e.touches[0],
13763  		    el = first.target;
13764
13765  		this._startPos = this._newPos = new Point(first.clientX, first.clientY);
13766
13767  		// if touching a link, highlight it
13768  		if (el.tagName && el.tagName.toLowerCase() === 'a') {
13769  			addClass(el, 'leaflet-active');
13770  		}
13771
13772  		// simulate long hold but setting a timeout
13773  		this._holdTimeout = setTimeout(bind(function () {
13774  			if (this._isTapValid()) {
13775  				this._fireClick = false;
13776  				this._onUp();
13777  				this._simulateEvent('contextmenu', first);
13778  			}
13779  		}, this), 1000);
13780
13781  		this._simulateEvent('mousedown', first);
13782
13783  		on(document, {
13784  			touchmove: this._onMove,
13785  			touchend: this._onUp
13786  		}, this);
13787  	},
13788
13789  	_onUp: function (e) {
13790  		clearTimeout(this._holdTimeout);
13791
13792  		off(document, {
13793  			touchmove: this._onMove,
13794  			touchend: this._onUp
13795  		}, this);
13796
13797  		if (this._fireClick && e && e.changedTouches) {
13798
13799  			var first = e.changedTouches[0],
13800  			    el = first.target;
13801
13802  			if (el && el.tagName && el.tagName.toLowerCase() === 'a') {
13803  				removeClass(el, 'leaflet-active');
13804  			}
13805
13806  			this._simulateEvent('mouseup', first);
13807
13808  			// simulate click if the touch didn't move too much
13809  			if (this._isTapValid()) {
13810  				this._simulateEvent('click', first);
13811  			}
13812  		}
13813  	},
13814
13815  	_isTapValid: function () {
13816  		return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;
13817  	},
13818
13819  	_onMove: function (e) {
13820  		var first = e.touches[0];
13821  		this._newPos = new Point(first.clientX, first.clientY);
13822  		this._simulateEvent('mousemove', first);
13823  	},
13824
13825  	_simulateEvent: function (type, e) {
13826  		var simulatedEvent = document.createEvent('MouseEvents');
13827
13828  		simulatedEvent._simulated = true;
13829  		e.target._simulatedClick = true;
13830
13831  		simulatedEvent.initMouseEvent(
13832  		        type, true, true, window, 1,
13833  		        e.screenX, e.screenY,
13834  		        e.clientX, e.clientY,
13835  		        false, false, false, false, 0, null);
13836
13837  		e.target.dispatchEvent(simulatedEvent);
13838  	}
13839  });
13840
13841  // @section Handlers
13842  // @property tap: Handler
13843  // Mobile touch hacks (quick tap and touch hold) handler.
13844  if (touch && (!pointer || safari)) {
13845  	Map.addInitHook('addHandler', 'tap', Tap);
13846  }
13847
13848  /*
13849   * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.
13850   */
13851
13852  // @namespace Map
13853  // @section Interaction Options
13854  Map.mergeOptions({
13855  	// @section Touch interaction options
13856  	// @option touchZoom: Boolean|String = *
13857  	// Whether the map can be zoomed by touch-dragging with two fingers. If
13858  	// passed `'center'`, it will zoom to the center of the view regardless of
13859  	// where the touch events (fingers) were. Enabled for touch-capable web
13860  	// browsers except for old Androids.
13861  	touchZoom: touch && !android23,
13862
13863  	// @option bounceAtZoomLimits: Boolean = true
13864  	// Set it to false if you don't want the map to zoom beyond min/max zoom
13865  	// and then bounce back when pinch-zooming.
13866  	bounceAtZoomLimits: true
13867  });
13868
13869  var TouchZoom = Handler.extend({
13870  	addHooks: function () {
13871  		addClass(this._map._container, 'leaflet-touch-zoom');
13872  		on(this._map._container, 'touchstart', this._onTouchStart, this);
13873  	},
13874
13875  	removeHooks: function () {
13876  		removeClass(this._map._container, 'leaflet-touch-zoom');
13877  		off(this._map._container, 'touchstart', this._onTouchStart, this);
13878  	},
13879
13880  	_onTouchStart: function (e) {
13881  		var map = this._map;
13882  		if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; }
13883
13884  		var p1 = map.mouseEventToContainerPoint(e.touches[0]),
13885  		    p2 = map.mouseEventToContainerPoint(e.touches[1]);
13886
13887  		this._centerPoint = map.getSize()._divideBy(2);
13888  		this._startLatLng = map.containerPointToLatLng(this._centerPoint);
13889  		if (map.options.touchZoom !== 'center') {
13890  			this._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));
13891  		}
13892
13893  		this._startDist = p1.distanceTo(p2);
13894  		this._startZoom = map.getZoom();
13895
13896  		this._moved = false;
13897  		this._zooming = true;
13898
13899  		map._stop();
13900
13901  		on(document, 'touchmove', this._onTouchMove, this);
13902  		on(document, 'touchend', this._onTouchEnd, this);
13903
13904  		preventDefault(e);
13905  	},
13906
13907  	_onTouchMove: function (e) {
13908  		if (!e.touches || e.touches.length !== 2 || !this._zooming) { return; }
13909
13910  		var map = this._map,
13911  		    p1 = map.mouseEventToContainerPoint(e.touches[0]),
13912  		    p2 = map.mouseEventToContainerPoint(e.touches[1]),
13913  		    scale = p1.distanceTo(p2) / this._startDist;
13914
13915  		this._zoom = map.getScaleZoom(scale, this._startZoom);
13916
13917  		if (!map.options.bounceAtZoomLimits && (
13918  			(this._zoom < map.getMinZoom() && scale < 1) ||
13919  			(this._zoom > map.getMaxZoom() && scale > 1))) {
13920  			this._zoom = map._limitZoom(this._zoom);
13921  		}
13922
13923  		if (map.options.touchZoom === 'center') {
13924  			this._center = this._startLatLng;
13925  			if (scale === 1) { return; }
13926  		} else {
13927  			// Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng
13928  			var delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);
13929  			if (scale === 1 && delta.x === 0 && delta.y === 0) { return; }
13930  			this._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom);
13931  		}
13932
13933  		if (!this._moved) {
13934  			map._moveStart(true, false);
13935  			this._moved = true;
13936  		}
13937
vendor: 3,815 bytes, lines 13938-14069
13938  		cancelAnimFrame(this._animRequest);
13939
13940  		var moveFn = bind(map._move, map, this._center, this._zoom, {pinch: true, round: false});
13941  		this._animRequest = requestAnimFrame(moveFn, this, true);
13942
13943  		preventDefault(e);
13944  	},
13945
13946  	_onTouchEnd: function () {
13947  		if (!this._moved || !this._zooming) {
13948  			this._zooming = false;
13949  			return;
13950  		}
13951
13952  		this._zooming = false;
13953  		cancelAnimFrame(this._animRequest);
13954
13955  		off(document, 'touchmove', this._onTouchMove, this);
13956  		off(document, 'touchend', this._onTouchEnd, this);
13957
13958  		// Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.
13959  		if (this._map.options.zoomAnimation) {
13960  			this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);
13961  		} else {
13962  			this._map._resetView(this._center, this._map._limitZoom(this._zoom));
13963  		}
13964  	}
13965  });
13966
13967  // @section Handlers
13968  // @property touchZoom: Handler
13969  // Touch zoom handler.
13970  Map.addInitHook('addHandler', 'touchZoom', TouchZoom);
13971
13972  Map.BoxZoom = BoxZoom;
13973  Map.DoubleClickZoom = DoubleClickZoom;
13974  Map.Drag = Drag;
13975  Map.Keyboard = Keyboard;
13976  Map.ScrollWheelZoom = ScrollWheelZoom;
13977  Map.Tap = Tap;
13978  Map.TouchZoom = TouchZoom;
13979
13980  exports.Bounds = Bounds;
13981  exports.Browser = Browser;
13982  exports.CRS = CRS;
13983  exports.Canvas = Canvas;
13984  exports.Circle = Circle;
13985  exports.CircleMarker = CircleMarker;
13986  exports.Class = Class;
13987  exports.Control = Control;
13988  exports.DivIcon = DivIcon;
13989  exports.DivOverlay = DivOverlay;
13990  exports.DomEvent = DomEvent;
13991  exports.DomUtil = DomUtil;
13992  exports.Draggable = Draggable;
13993  exports.Evented = Evented;
13994  exports.FeatureGroup = FeatureGroup;
13995  exports.GeoJSON = GeoJSON;
13996  exports.GridLayer = GridLayer;
13997  exports.Handler = Handler;
13998  exports.Icon = Icon;
13999  exports.ImageOverlay = ImageOverlay;
14000  exports.LatLng = LatLng;
14001  exports.LatLngBounds = LatLngBounds;
14002  exports.Layer = Layer;
14003  exports.LayerGroup = LayerGroup;
14004  exports.LineUtil = LineUtil;
14005  exports.Map = Map;
14006  exports.Marker = Marker;
14007  exports.Mixin = Mixin;
14008  exports.Path = Path;
14009  exports.Point = Point;
14010  exports.PolyUtil = PolyUtil;
14011  exports.Polygon = Polygon;
14012  exports.Polyline = Polyline;
14013  exports.Popup = Popup;
14014  exports.PosAnimation = PosAnimation;
14015  exports.Projection = index;
14016  exports.Rectangle = Rectangle;
14017  exports.Renderer = Renderer;
14018  exports.SVG = SVG;
14019  exports.SVGOverlay = SVGOverlay;
14020  exports.TileLayer = TileLayer;
14021  exports.Tooltip = Tooltip;
14022  exports.Transformation = Transformation;
14023  exports.Util = Util;
14024  exports.VideoOverlay = VideoOverlay;
14025  exports.bind = bind;
14026  exports.bounds = toBounds;
14027  exports.canvas = canvas;
14028  exports.circle = circle;
14029  exports.circleMarker = circleMarker;
14030  exports.control = control;
14031  exports.divIcon = divIcon;
14032  exports.extend = extend;
14033  exports.featureGroup = featureGroup;
14034  exports.geoJSON = geoJSON;
14035  exports.geoJson = geoJson;
14036  exports.gridLayer = gridLayer;
14037  exports.icon = icon;
14038  exports.imageOverlay = imageOverlay;
14039  exports.latLng = toLatLng;
14040  exports.latLngBounds = toLatLngBounds;
14041  exports.layerGroup = layerGroup;
14042  exports.map = createMap;
14043  exports.marker = marker;
14044  exports.point = toPoint;
14045  exports.polygon = polygon;
14046  exports.polyline = polyline;
14047  exports.popup = popup;
14048  exports.rectangle = rectangle;
14049  exports.setOptions = setOptions;
14050  exports.stamp = stamp;
14051  exports.svg = svg;
14052  exports.svgOverlay = svgOverlay;
14053  exports.tileLayer = tileLayer;
14054  exports.tooltip = tooltip;
14055  exports.transformation = toTransformation;
14056  exports.version = version;
14057  exports.videoOverlay = videoOverlay;
14058
14059  var oldL = window.L;
14060  exports.noConflict = function() {
14061  	window.L = oldL;
14062  	return this;
14063  }
14064
14065  // Always export us to window global (see #2364)
14066  window.L = exports;
14067
14068}));
14069//# 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.