/files/leaflet/0.6.2/leaflet-src.js
JavaScript | 2053 lines | 1398 code | 513 blank | 142 comment | 291 complexity | 3a5eb55db7f425f866344556f9ee6ada MD5 | raw file
- /*
- Leaflet, a JavaScript library for mobile-friendly interactive maps. http://leafletjs.com
- (c) 2010-2013, Vladimir Agafonkin
- (c) 2010-2011, CloudMade
- */
- (function (window, document, undefined) {
- var oldL = window.L,
- L = {};
- L.version = '0.6.2';
- // define Leaflet for Node module pattern loaders, including Browserify
- if (typeof module === 'object' && typeof module.exports === 'object') {
- module.exports = L;
- // define Leaflet as an AMD module
- } else if (typeof define === 'function' && define.amd) {
- define(L);
- }
- // define Leaflet as a global L variable, saving the original L to restore later if needed
- L.noConflict = function () {
- window.L = oldL;
- return this;
- };
- window.L = L;
- /*
- * L.Util contains various utility functions used throughout Leaflet code.
- */
- L.Util = {
- extend: function (dest) { // (Object[, Object, ...]) ->
- var sources = Array.prototype.slice.call(arguments, 1),
- i, j, len, src;
- for (j = 0, len = sources.length; j < len; j++) {
- src = sources[j] || {};
- for (i in src) {
- if (src.hasOwnProperty(i)) {
- dest[i] = src[i];
- }
- }
- }
- return dest;
- },
- bind: function (fn, obj) { // (Function, Object) -> Function
- var args = arguments.length > 2 ? Array.prototype.slice.call(arguments, 2) : null;
- return function () {
- return fn.apply(obj, args || arguments);
- };
- },
- stamp: (function () {
- var lastId = 0,
- key = '_leaflet_id';
- return function (obj) {
- obj[key] = obj[key] || ++lastId;
- return obj[key];
- };
- }()),
- invokeEach: function (obj, method, context) {
- var i, args;
- if (typeof obj === 'object') {
- args = Array.prototype.slice.call(arguments, 3);
- for (i in obj) {
- method.apply(context, [i, obj[i]].concat(args));
- }
- return true;
- }
- return false;
- },
- limitExecByInterval: function (fn, time, context) {
- var lock, execOnUnlock;
- return function wrapperFn() {
- var args = arguments;
- if (lock) {
- execOnUnlock = true;
- return;
- }
- lock = true;
- setTimeout(function () {
- lock = false;
- if (execOnUnlock) {
- wrapperFn.apply(context, args);
- execOnUnlock = false;
- }
- }, time);
- fn.apply(context, args);
- };
- },
- falseFn: function () {
- return false;
- },
- formatNum: function (num, digits) {
- var pow = Math.pow(10, digits || 5);
- return Math.round(num * pow) / pow;
- },
- trim: function (str) {
- return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
- },
- splitWords: function (str) {
- return L.Util.trim(str).split(/\s+/);
- },
- setOptions: function (obj, options) {
- obj.options = L.extend({}, obj.options, options);
- return obj.options;
- },
- getParamString: function (obj, existingUrl, uppercase) {
- var params = [];
- for (var i in obj) {
- params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
- }
- return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
- },
- template: function (str, data) {
- return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) {
- var value = data[key];
- if (value === undefined) {
- throw new Error('No value provided for variable ' + str);
- } else if (typeof value === 'function') {
- value = value(data);
- }
- return value;
- });
- },
- isArray: function (obj) {
- return (Object.prototype.toString.call(obj) === '[object Array]');
- },
- emptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
- };
- (function () {
- // inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/
- function getPrefixed(name) {
- var i, fn,
- prefixes = ['webkit', 'moz', 'o', 'ms'];
- for (i = 0; i < prefixes.length && !fn; i++) {
- fn = window[prefixes[i] + name];
- }
- return fn;
- }
- var lastTime = 0;
- function timeoutDefer(fn) {
- var time = +new Date(),
- timeToCall = Math.max(0, 16 - (time - lastTime));
- lastTime = time + timeToCall;
- return window.setTimeout(fn, timeToCall);
- }
- var requestFn = window.requestAnimationFrame ||
- getPrefixed('RequestAnimationFrame') || timeoutDefer;
- var cancelFn = window.cancelAnimationFrame ||
- getPrefixed('CancelAnimationFrame') ||
- getPrefixed('CancelRequestAnimationFrame') ||
- function (id) { window.clearTimeout(id); };
- L.Util.requestAnimFrame = function (fn, context, immediate, element) {
- fn = L.bind(fn, context);
- if (immediate && requestFn === timeoutDefer) {
- fn();
- } else {
- return requestFn.call(window, fn, element);
- }
- };
- L.Util.cancelAnimFrame = function (id) {
- if (id) {
- cancelFn.call(window, id);
- }
- };
- }());
- // shortcuts for most used utility functions
- L.extend = L.Util.extend;
- L.bind = L.Util.bind;
- L.stamp = L.Util.stamp;
- L.setOptions = L.Util.setOptions;
- /*
- * L.Class powers the OOP facilities of the library.
- * Thanks to John Resig and Dean Edwards for inspiration!
- */
- L.Class = function () {};
- L.Class.extend = function (props) {
- // extended class with the new prototype
- var NewClass = function () {
- // call the constructor
- if (this.initialize) {
- this.initialize.apply(this, arguments);
- }
- // call all constructor hooks
- if (this._initHooks) {
- this.callInitHooks();
- }
- };
- // instantiate class without calling constructor
- var F = function () {};
- F.prototype = this.prototype;
- var proto = new F();
- proto.constructor = NewClass;
- NewClass.prototype = proto;
- //inherit parent's statics
- for (var i in this) {
- if (this.hasOwnProperty(i) && i !== 'prototype') {
- NewClass[i] = this[i];
- }
- }
- // mix static properties into the class
- if (props.statics) {
- L.extend(NewClass, props.statics);
- delete props.statics;
- }
- // mix includes into the prototype
- if (props.includes) {
- L.Util.extend.apply(null, [proto].concat(props.includes));
- delete props.includes;
- }
- // merge options
- if (props.options && proto.options) {
- props.options = L.extend({}, proto.options, props.options);
- }
- // mix given properties into the prototype
- L.extend(proto, props);
- proto._initHooks = [];
- var parent = this;
- // jshint camelcase: false
- NewClass.__super__ = parent.prototype;
- // add method for calling all hooks
- proto.callInitHooks = function () {
- if (this._initHooksCalled) { return; }
- if (parent.prototype.callInitHooks) {
- parent.prototype.callInitHooks.call(this);
- }
- this._initHooksCalled = true;
- for (var i = 0, len = proto._initHooks.length; i < len; i++) {
- proto._initHooks[i].call(this);
- }
- };
- return NewClass;
- };
- // method for adding properties to prototype
- L.Class.include = function (props) {
- L.extend(this.prototype, props);
- };
- // merge new default options to the Class
- L.Class.mergeOptions = function (options) {
- L.extend(this.prototype.options, options);
- };
- // add a constructor hook
- L.Class.addInitHook = function (fn) { // (Function) || (String, args...)
- var args = Array.prototype.slice.call(arguments, 1);
- var init = typeof fn === 'function' ? fn : function () {
- this[fn].apply(this, args);
- };
- this.prototype._initHooks = this.prototype._initHooks || [];
- this.prototype._initHooks.push(init);
- };
- /*
- * L.Mixin.Events is used to add custom events functionality to Leaflet classes.
- */
- var eventsKey = '_leaflet_events';
- L.Mixin = {};
- L.Mixin.Events = {
- addEventListener: function (types, fn, context) { // (String, Function[, Object]) or (Object[, Object])
- // types can be a map of types/handlers
- if (L.Util.invokeEach(types, this.addEventListener, this, fn, context)) { return this; }
- var events = this[eventsKey] = this[eventsKey] || {},
- contextId = context && L.stamp(context),
- i, len, event, type, indexKey, indexLenKey, typeIndex;
- // types can be a string of space-separated words
- types = L.Util.splitWords(types);
- for (i = 0, len = types.length; i < len; i++) {
- event = {
- action: fn,
- context: context || this
- };
- type = types[i];
- if (context) {
- // store listeners of a particular context in a separate hash (if it has an id)
- // gives a major performance boost when removing thousands of map layers
- indexKey = type + '_idx';
- indexLenKey = indexKey + '_len';
- typeIndex = events[indexKey] = events[indexKey] || {};
- if (!typeIndex[contextId]) {
- typeIndex[contextId] = [];
- // keep track of the number of keys in the index to quickly check if it's empty
- events[indexLenKey] = (events[indexLenKey] || 0) + 1;
- }
- typeIndex[contextId].push(event);
- } else {
- events[type] = events[type] || [];
- events[type].push(event);
- }
- }
- return this;
- },
- hasEventListeners: function (type) { // (String) -> Boolean
- var events = this[eventsKey];
- return !!events && ((type in events && events[type].length > 0) ||
- (type + '_idx' in events && events[type + '_idx_len'] > 0));
- },
- removeEventListener: function (types, fn, context) { // ([String, Function, Object]) or (Object[, Object])
- if (!this[eventsKey]) {
- return this;
- }
- if (!types) {
- return this.clearAllEventListeners();
- }
- if (L.Util.invokeEach(types, this.removeEventListener, this, fn, context)) { return this; }
- var events = this[eventsKey],
- contextId = context && L.stamp(context),
- i, len, type, listeners, j, indexKey, indexLenKey, typeIndex, removed;
- types = L.Util.splitWords(types);
- for (i = 0, len = types.length; i < len; i++) {
- type = types[i];
- indexKey = type + '_idx';
- indexLenKey = indexKey + '_len';
- typeIndex = events[indexKey];
- if (!fn) {
- // clear all listeners for a type if function isn't specified
- delete events[type];
- delete events[indexKey];
- } else {
- listeners = context && typeIndex ? typeIndex[contextId] : events[type];
- if (listeners) {
- for (j = listeners.length - 1; j >= 0; j--) {
- if ((listeners[j].action === fn) && (!context || (listeners[j].context === context))) {
- removed = listeners.splice(j, 1);
- // set the old action to a no-op, because it is possible
- // that the listener is being iterated over as part of a dispatch
- removed[0].action = L.Util.falseFn;
- }
- }
- if (context && typeIndex && (listeners.length === 0)) {
- delete typeIndex[contextId];
- events[indexLenKey]--;
- }
- }
- }
- }
- return this;
- },
- clearAllEventListeners: function () {
- delete this[eventsKey];
- return this;
- },
- fireEvent: function (type, data) { // (String[, Object])
- if (!this.hasEventListeners(type)) {
- return this;
- }
- var event = L.Util.extend({}, data, { type: type, target: this });
- var events = this[eventsKey],
- listeners, i, len, typeIndex, contextId;
- if (events[type]) {
- // make sure adding/removing listeners inside other listeners won't cause infinite loop
- listeners = events[type].slice();
- for (i = 0, len = listeners.length; i < len; i++) {
- listeners[i].action.call(listeners[i].context || this, event);
- }
- }
- // fire event for the context-indexed listeners as well
- typeIndex = events[type + '_idx'];
- for (contextId in typeIndex) {
- listeners = typeIndex[contextId].slice();
- if (listeners) {
- for (i = 0, len = listeners.length; i < len; i++) {
- listeners[i].action.call(listeners[i].context || this, event);
- }
- }
- }
- return this;
- },
- addOneTimeEventListener: function (types, fn, context) {
- if (L.Util.invokeEach(types, this.addOneTimeEventListener, this, fn, context)) { return this; }
- var handler = L.bind(function () {
- this
- .removeEventListener(types, fn, context)
- .removeEventListener(types, handler, context);
- }, this);
- return this
- .addEventListener(types, fn, context)
- .addEventListener(types, handler, context);
- }
- };
- L.Mixin.Events.on = L.Mixin.Events.addEventListener;
- L.Mixin.Events.off = L.Mixin.Events.removeEventListener;
- L.Mixin.Events.once = L.Mixin.Events.addOneTimeEventListener;
- L.Mixin.Events.fire = L.Mixin.Events.fireEvent;
- /*
- * L.Browser handles different browser and feature detections for internal Leaflet use.
- */
- (function () {
- var ie = !!window.ActiveXObject,
- ie6 = ie && !window.XMLHttpRequest,
- ie7 = ie && !document.querySelector,
- ielt9 = ie && !document.addEventListener,
- // terrible browser detection to work around Safari / iOS / Android browser bugs
- ua = navigator.userAgent.toLowerCase(),
- webkit = ua.indexOf('webkit') !== -1,
- chrome = ua.indexOf('chrome') !== -1,
- phantomjs = ua.indexOf('phantom') !== -1,
- android = ua.indexOf('android') !== -1,
- android23 = ua.search('android [23]') !== -1,
- mobile = typeof orientation !== undefined + '',
- msTouch = window.navigator && window.navigator.msPointerEnabled &&
- window.navigator.msMaxTouchPoints,
- retina = ('devicePixelRatio' in window && window.devicePixelRatio > 1) ||
- ('matchMedia' in window && window.matchMedia('(min-resolution:144dpi)') &&
- window.matchMedia('(min-resolution:144dpi)').matches),
- doc = document.documentElement,
- ie3d = ie && ('transition' in doc.style),
- webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()),
- gecko3d = 'MozPerspective' in doc.style,
- opera3d = 'OTransition' in doc.style,
- any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d || opera3d) && !phantomjs;
- // PhantomJS has 'ontouchstart' in document.documentElement, but doesn't actually support touch.
- // https://github.com/Leaflet/Leaflet/pull/1434#issuecomment-13843151
- var touch = !window.L_NO_TOUCH && !phantomjs && (function () {
- var startName = 'ontouchstart';
- // IE10+ (We simulate these into touch* events in L.DomEvent and L.DomEvent.MsTouch) or WebKit, etc.
- if (msTouch || (startName in doc)) {
- return true;
- }
- // Firefox/Gecko
- var div = document.createElement('div'),
- supported = false;
- if (!div.setAttribute) {
- return false;
- }
- div.setAttribute(startName, 'return;');
- if (typeof div[startName] === 'function') {
- supported = true;
- }
- div.removeAttribute(startName);
- div = null;
- return supported;
- }());
- L.Browser = {
- ie: ie,
- ie6: ie6,
- ie7: ie7,
- ielt9: ielt9,
- webkit: webkit,
- android: android,
- android23: android23,
- chrome: chrome,
- ie3d: ie3d,
- webkit3d: webkit3d,
- gecko3d: gecko3d,
- opera3d: opera3d,
- any3d: any3d,
- mobile: mobile,
- mobileWebkit: mobile && webkit,
- mobileWebkit3d: mobile && webkit3d,
- mobileOpera: mobile && window.opera,
- touch: touch,
- msTouch: msTouch,
- retina: retina
- };
- }());
- /*
- * L.Point represents a point with x and y coordinates.
- */
- L.Point = function (/*Number*/ x, /*Number*/ y, /*Boolean*/ round) {
- this.x = (round ? Math.round(x) : x);
- this.y = (round ? Math.round(y) : y);
- };
- L.Point.prototype = {
- clone: function () {
- return new L.Point(this.x, this.y);
- },
- // non-destructive, returns a new point
- add: function (point) {
- return this.clone()._add(L.point(point));
- },
- // destructive, used directly for performance in situations where it's safe to modify existing point
- _add: function (point) {
- this.x += point.x;
- this.y += point.y;
- return this;
- },
- subtract: function (point) {
- return this.clone()._subtract(L.point(point));
- },
- _subtract: function (point) {
- this.x -= point.x;
- this.y -= point.y;
- return this;
- },
- divideBy: function (num) {
- return this.clone()._divideBy(num);
- },
- _divideBy: function (num) {
- this.x /= num;
- this.y /= num;
- return this;
- },
- multiplyBy: function (num) {
- return this.clone()._multiplyBy(num);
- },
- _multiplyBy: function (num) {
- this.x *= num;
- this.y *= num;
- return this;
- },
- round: function () {
- return this.clone()._round();
- },
- _round: function () {
- this.x = Math.round(this.x);
- this.y = Math.round(this.y);
- return this;
- },
- floor: function () {
- return this.clone()._floor();
- },
- _floor: function () {
- this.x = Math.floor(this.x);
- this.y = Math.floor(this.y);
- return this;
- },
- distanceTo: function (point) {
- point = L.point(point);
- var x = point.x - this.x,
- y = point.y - this.y;
- return Math.sqrt(x * x + y * y);
- },
- equals: function (point) {
- point = L.point(point);
- return point.x === this.x &&
- point.y === this.y;
- },
- contains: function (point) {
- point = L.point(point);
- return Math.abs(point.x) <= Math.abs(this.x) &&
- Math.abs(point.y) <= Math.abs(this.y);
- },
- toString: function () {
- return 'Point(' +
- L.Util.formatNum(this.x) + ', ' +
- L.Util.formatNum(this.y) + ')';
- }
- };
- L.point = function (x, y, round) {
- if (x instanceof L.Point) {
- return x;
- }
- if (L.Util.isArray(x)) {
- return new L.Point(x[0], x[1]);
- }
- if (x === undefined || x === null) {
- return x;
- }
- return new L.Point(x, y, round);
- };
- /*
- * L.Bounds represents a rectangular area on the screen in pixel coordinates.
- */
- L.Bounds = function (a, b) { //(Point, Point) or Point[]
- if (!a) { return; }
- var points = b ? [a, b] : a;
- for (var i = 0, len = points.length; i < len; i++) {
- this.extend(points[i]);
- }
- };
- L.Bounds.prototype = {
- // extend the bounds to contain the given point
- extend: function (point) { // (Point)
- point = L.point(point);
- if (!this.min && !this.max) {
- this.min = point.clone();
- this.max = point.clone();
- } else {
- this.min.x = Math.min(point.x, this.min.x);
- this.max.x = Math.max(point.x, this.max.x);
- this.min.y = Math.min(point.y, this.min.y);
- this.max.y = Math.max(point.y, this.max.y);
- }
- return this;
- },
- getCenter: function (round) { // (Boolean) -> Point
- return new L.Point(
- (this.min.x + this.max.x) / 2,
- (this.min.y + this.max.y) / 2, round);
- },
- getBottomLeft: function () { // -> Point
- return new L.Point(this.min.x, this.max.y);
- },
- getTopRight: function () { // -> Point
- return new L.Point(this.max.x, this.min.y);
- },
- getSize: function () {
- return this.max.subtract(this.min);
- },
- contains: function (obj) { // (Bounds) or (Point) -> Boolean
- var min, max;
- if (typeof obj[0] === 'number' || obj instanceof L.Point) {
- obj = L.point(obj);
- } else {
- obj = L.bounds(obj);
- }
- if (obj instanceof L.Bounds) {
- min = obj.min;
- max = obj.max;
- } else {
- min = max = obj;
- }
- return (min.x >= this.min.x) &&
- (max.x <= this.max.x) &&
- (min.y >= this.min.y) &&
- (max.y <= this.max.y);
- },
- intersects: function (bounds) { // (Bounds) -> Boolean
- bounds = L.bounds(bounds);
- var min = this.min,
- max = this.max,
- min2 = bounds.min,
- max2 = bounds.max,
- xIntersects = (max2.x >= min.x) && (min2.x <= max.x),
- yIntersects = (max2.y >= min.y) && (min2.y <= max.y);
- return xIntersects && yIntersects;
- },
- isValid: function () {
- return !!(this.min && this.max);
- }
- };
- L.bounds = function (a, b) { // (Bounds) or (Point, Point) or (Point[])
- if (!a || a instanceof L.Bounds) {
- return a;
- }
- return new L.Bounds(a, b);
- };
- /*
- * L.Transformation is an utility class to perform simple point transformations through a 2d-matrix.
- */
- L.Transformation = function (a, b, c, d) {
- this._a = a;
- this._b = b;
- this._c = c;
- this._d = d;
- };
- L.Transformation.prototype = {
- transform: function (point, scale) { // (Point, Number) -> Point
- return this._transform(point.clone(), scale);
- },
- // destructive transform (faster)
- _transform: function (point, scale) {
- scale = scale || 1;
- point.x = scale * (this._a * point.x + this._b);
- point.y = scale * (this._c * point.y + this._d);
- return point;
- },
- untransform: function (point, scale) {
- scale = scale || 1;
- return new L.Point(
- (point.x / scale - this._b) / this._a,
- (point.y / scale - this._d) / this._c);
- }
- };
- /*
- * L.DomUtil contains various utility functions for working with DOM.
- */
- L.DomUtil = {
- get: function (id) {
- return (typeof id === 'string' ? document.getElementById(id) : id);
- },
- getStyle: function (el, style) {
- var value = el.style[style];
- if (!value && el.currentStyle) {
- value = el.currentStyle[style];
- }
- if ((!value || value === 'auto') && document.defaultView) {
- var css = document.defaultView.getComputedStyle(el, null);
- value = css ? css[style] : null;
- }
- return value === 'auto' ? null : value;
- },
- getViewportOffset: function (element) {
- var top = 0,
- left = 0,
- el = element,
- docBody = document.body,
- docEl = document.documentElement,
- pos,
- ie7 = L.Browser.ie7;
- do {
- top += el.offsetTop || 0;
- left += el.offsetLeft || 0;
- //add borders
- top += parseInt(L.DomUtil.getStyle(el, 'borderTopWidth'), 10) || 0;
- left += parseInt(L.DomUtil.getStyle(el, 'borderLeftWidth'), 10) || 0;
- pos = L.DomUtil.getStyle(el, 'position');
- if (el.offsetParent === docBody && pos === 'absolute') { break; }
- if (pos === 'fixed') {
- top += docBody.scrollTop || docEl.scrollTop || 0;
- left += docBody.scrollLeft || docEl.scrollLeft || 0;
- break;
- }
- if (pos === 'relative' && !el.offsetLeft) {
- var width = L.DomUtil.getStyle(el, 'width'),
- maxWidth = L.DomUtil.getStyle(el, 'max-width'),
- r = el.getBoundingClientRect();
- if (width !== 'none' || maxWidth !== 'none') {
- left += r.left + el.clientLeft;
- }
- //calculate full y offset since we're breaking out of the loop
- top += r.top + (docBody.scrollTop || docEl.scrollTop || 0);
- break;
- }
- el = el.offsetParent;
- } while (el);
- el = element;
- do {
- if (el === docBody) { break; }
- top -= el.scrollTop || 0;
- left -= el.scrollLeft || 0;
- // webkit (and ie <= 7) handles RTL scrollLeft different to everyone else
- // https://code.google.com/p/closure-library/source/browse/trunk/closure/goog/style/bidi.js
- if (!L.DomUtil.documentIsLtr() && (L.Browser.webkit || ie7)) {
- left += el.scrollWidth - el.clientWidth;
- // ie7 shows the scrollbar by default and provides clientWidth counting it, so we
- // need to add it back in if it is visible; scrollbar is on the left as we are RTL
- if (ie7 && L.DomUtil.getStyle(el, 'overflow-y') !== 'hidden' &&
- L.DomUtil.getStyle(el, 'overflow') !== 'hidden') {
- left += 17;
- }
- }
- el = el.parentNode;
- } while (el);
- return new L.Point(left, top);
- },
- documentIsLtr: function () {
- if (!L.DomUtil._docIsLtrCached) {
- L.DomUtil._docIsLtrCached = true;
- L.DomUtil._docIsLtr = L.DomUtil.getStyle(document.body, 'direction') === 'ltr';
- }
- return L.DomUtil._docIsLtr;
- },
- create: function (tagName, className, container) {
- var el = document.createElement(tagName);
- el.className = className;
- if (container) {
- container.appendChild(el);
- }
- return el;
- },
- hasClass: function (el, name) {
- return (el.className.length > 0) &&
- new RegExp('(^|\\s)' + name + '(\\s|$)').test(el.className);
- },
- addClass: function (el, name) {
- if (!L.DomUtil.hasClass(el, name)) {
- el.className += (el.className ? ' ' : '') + name;
- }
- },
- removeClass: function (el, name) {
- el.className = L.Util.trim((' ' + el.className + ' ').replace(' ' + name + ' ', ' '));
- },
- setOpacity: function (el, value) {
- if ('opacity' in el.style) {
- el.style.opacity = value;
- } else if ('filter' in el.style) {
- var filter = false,
- filterName = 'DXImageTransform.Microsoft.Alpha';
- // filters collection throws an error if we try to retrieve a filter that doesn't exist
- try {
- filter = el.filters.item(filterName);
- } catch (e) {
- // don't set opacity to 1 if we haven't already set an opacity,
- // it isn't needed and breaks transparent pngs.
- if (value === 1) { return; }
- }
- value = Math.round(value * 100);
- if (filter) {
- filter.Enabled = (value !== 100);
- filter.Opacity = value;
- } else {
- el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';
- }
- }
- },
- testProp: function (props) {
- var style = document.documentElement.style;
- for (var i = 0; i < props.length; i++) {
- if (props[i] in style) {
- return props[i];
- }
- }
- return false;
- },
- getTranslateString: function (point) {
- // on WebKit browsers (Chrome/Safari/iOS Safari/Android) using translate3d instead of translate
- // makes animation smoother as it ensures HW accel is used. Firefox 13 doesn't care
- // (same speed either way), Opera 12 doesn't support translate3d
- var is3d = L.Browser.webkit3d,
- open = 'translate' + (is3d ? '3d' : '') + '(',
- close = (is3d ? ',0' : '') + ')';
- return open + point.x + 'px,' + point.y + 'px' + close;
- },
- getScaleString: function (scale, origin) {
- var preTranslateStr = L.DomUtil.getTranslateString(origin.add(origin.multiplyBy(-1 * scale))),
- scaleStr = ' scale(' + scale + ') ';
- return preTranslateStr + scaleStr;
- },
- setPosition: function (el, point, disable3D) { // (HTMLElement, Point[, Boolean])
- // jshint camelcase: false
- el._leaflet_pos = point;
- if (!disable3D && L.Browser.any3d) {
- el.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(point);
- // workaround for Android 2/3 stability (https://github.com/CloudMade/Leaflet/issues/69)
- if (L.Browser.mobileWebkit3d) {
- el.style.WebkitBackfaceVisibility = 'hidden';
- }
- } else {
- el.style.left = point.x + 'px';
- el.style.top = point.y + 'px';
- }
- },
- getPosition: function (el) {
- // this method is only used for elements previously positioned using setPosition,
- // so it's safe to cache the position for performance
- // jshint camelcase: false
- return el._leaflet_pos;
- }
- };
- // prefix style property names
- L.DomUtil.TRANSFORM = L.DomUtil.testProp(
- ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
- // webkitTransition comes first because some browser versions that drop vendor prefix don't do
- // the same for the transitionend event, in particular the Android 4.1 stock browser
- L.DomUtil.TRANSITION = L.DomUtil.testProp(
- ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);
- L.DomUtil.TRANSITION_END =
- L.DomUtil.TRANSITION === 'webkitTransition' || L.DomUtil.TRANSITION === 'OTransition' ?
- L.DomUtil.TRANSITION + 'End' : 'transitionend';
- (function () {
- var userSelectProperty = L.DomUtil.testProp(
- ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
- var userDragProperty = L.DomUtil.testProp(
- ['userDrag', 'WebkitUserDrag', 'OUserDrag', 'MozUserDrag', 'msUserDrag']);
- L.extend(L.DomUtil, {
- disableTextSelection: function () {
- if (userSelectProperty) {
- var style = document.documentElement.style;
- this._userSelect = style[userSelectProperty];
- style[userSelectProperty] = 'none';
- } else {
- L.DomEvent.on(window, 'selectstart', L.DomEvent.stop);
- }
- },
- enableTextSelection: function () {
- if (userSelectProperty) {
- document.documentElement.style[userSelectProperty] = this._userSelect;
- delete this._userSelect;
- } else {
- L.DomEvent.off(window, 'selectstart', L.DomEvent.stop);
- }
- },
- disableImageDrag: function () {
- if (userDragProperty) {
- var style = document.documentElement.style;
- this._userDrag = style[userDragProperty];
- style[userDragProperty] = 'none';
- } else {
- L.DomEvent.on(window, 'dragstart', L.DomEvent.stop);
- }
- },
- enableImageDrag: function () {
- if (userDragProperty) {
- document.documentElement.style[userDragProperty] = this._userDrag;
- delete this._userDrag;
- } else {
- L.DomEvent.off(window, 'dragstart', L.DomEvent.stop);
- }
- }
- });
- })();
- /*
- * L.LatLng represents a geographical point with latitude and longitude coordinates.
- */
- L.LatLng = function (rawLat, rawLng) { // (Number, Number)
- var lat = parseFloat(rawLat),
- lng = parseFloat(rawLng);
- if (isNaN(lat) || isNaN(lng)) {
- throw new Error('Invalid LatLng object: (' + rawLat + ', ' + rawLng + ')');
- }
- this.lat = lat;
- this.lng = lng;
- };
- L.extend(L.LatLng, {
- DEG_TO_RAD: Math.PI / 180,
- RAD_TO_DEG: 180 / Math.PI,
- MAX_MARGIN: 1.0E-9 // max margin of error for the "equals" check
- });
- L.LatLng.prototype = {
- equals: function (obj) { // (LatLng) -> Boolean
- if (!obj) { return false; }
- obj = L.latLng(obj);
- var margin = Math.max(
- Math.abs(this.lat - obj.lat),
- Math.abs(this.lng - obj.lng));
- return margin <= L.LatLng.MAX_MARGIN;
- },
- toString: function (precision) { // (Number) -> String
- return 'LatLng(' +
- L.Util.formatNum(this.lat, precision) + ', ' +
- L.Util.formatNum(this.lng, precision) + ')';
- },
- // Haversine distance formula, see http://en.wikipedia.org/wiki/Haversine_formula
- // TODO move to projection code, LatLng shouldn't know about Earth
- distanceTo: function (other) { // (LatLng) -> Number
- other = L.latLng(other);
- var R = 6378137, // earth radius in meters
- d2r = L.LatLng.DEG_TO_RAD,
- dLat = (other.lat - this.lat) * d2r,
- dLon = (other.lng - this.lng) * d2r,
- lat1 = this.lat * d2r,
- lat2 = other.lat * d2r,
- sin1 = Math.sin(dLat / 2),
- sin2 = Math.sin(dLon / 2);
- var a = sin1 * sin1 + sin2 * sin2 * Math.cos(lat1) * Math.cos(lat2);
- return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
- },
- wrap: function (a, b) { // (Number, Number) -> LatLng
- var lng = this.lng;
- a = a || -180;
- b = b || 180;
- lng = (lng + b) % (b - a) + (lng < a || lng === b ? b : a);
- return new L.LatLng(this.lat, lng);
- }
- };
- L.latLng = function (a, b) { // (LatLng) or ([Number, Number]) or (Number, Number)
- if (a instanceof L.LatLng) {
- return a;
- }
- if (L.Util.isArray(a)) {
- return new L.LatLng(a[0], a[1]);
- }
- if (a === undefined || a === null) {
- return a;
- }
- if (typeof a === 'object' && 'lat' in a) {
- return new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon);
- }
- return new L.LatLng(a, b);
- };
- /*
- * L.LatLngBounds represents a rectangular area on the map in geographical coordinates.
- */
- L.LatLngBounds = function (southWest, northEast) { // (LatLng, LatLng) or (LatLng[])
- if (!southWest) { return; }
- var latlngs = northEast ? [southWest, northEast] : southWest;
- for (var i = 0, len = latlngs.length; i < len; i++) {
- this.extend(latlngs[i]);
- }
- };
- L.LatLngBounds.prototype = {
- // extend the bounds to contain the given point or bounds
- extend: function (obj) { // (LatLng) or (LatLngBounds)
- if (!obj) { return this; }
- if (typeof obj[0] === 'number' || typeof obj[0] === 'string' || obj instanceof L.LatLng) {
- obj = L.latLng(obj);
- } else {
- obj = L.latLngBounds(obj);
- }
- if (obj instanceof L.LatLng) {
- if (!this._southWest && !this._northEast) {
- this._southWest = new L.LatLng(obj.lat, obj.lng);
- this._northEast = new L.LatLng(obj.lat, obj.lng);
- } else {
- this._southWest.lat = Math.min(obj.lat, this._southWest.lat);
- this._southWest.lng = Math.min(obj.lng, this._southWest.lng);
- this._northEast.lat = Math.max(obj.lat, this._northEast.lat);
- this._northEast.lng = Math.max(obj.lng, this._northEast.lng);
- }
- } else if (obj instanceof L.LatLngBounds) {
- this.extend(obj._southWest);
- this.extend(obj._northEast);
- }
- return this;
- },
- // extend the bounds by a percentage
- pad: function (bufferRatio) { // (Number) -> LatLngBounds
- var sw = this._southWest,
- ne = this._northEast,
- heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
- widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
- return new L.LatLngBounds(
- new L.LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
- new L.LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));
- },
- getCenter: function () { // -> LatLng
- return new L.LatLng(
- (this._southWest.lat + this._northEast.lat) / 2,
- (this._southWest.lng + this._northEast.lng) / 2);
- },
- getSouthWest: function () {
- return this._southWest;
- },
- getNorthEast: function () {
- return this._northEast;
- },
- getNorthWest: function () {
- return new L.LatLng(this.getNorth(), this.getWest());
- },
- getSouthEast: function () {
- return new L.LatLng(this.getSouth(), this.getEast());
- },
- getWest: function () {
- return this._southWest.lng;
- },
- getSouth: function () {
- return this._southWest.lat;
- },
- getEast: function () {
- return this._northEast.lng;
- },
- getNorth: function () {
- return this._northEast.lat;
- },
- contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean
- if (typeof obj[0] === 'number' || obj instanceof L.LatLng) {
- obj = L.latLng(obj);
- } else {
- obj = L.latLngBounds(obj);
- }
- var sw = this._southWest,
- ne = this._northEast,
- sw2, ne2;
- if (obj instanceof L.LatLngBounds) {
- sw2 = obj.getSouthWest();
- ne2 = obj.getNorthEast();
- } else {
- sw2 = ne2 = obj;
- }
- return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&
- (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);
- },
- intersects: function (bounds) { // (LatLngBounds)
- bounds = L.latLngBounds(bounds);
- var sw = this._southWest,
- ne = this._northEast,
- sw2 = bounds.getSouthWest(),
- ne2 = bounds.getNorthEast(),
- latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),
- lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);
- return latIntersects && lngIntersects;
- },
- toBBoxString: function () {
- return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');
- },
- equals: function (bounds) { // (LatLngBounds)
- if (!bounds) { return false; }
- bounds = L.latLngBounds(bounds);
- return this._southWest.equals(bounds.getSouthWest()) &&
- this._northEast.equals(bounds.getNorthEast());
- },
- isValid: function () {
- return !!(this._southWest && this._northEast);
- }
- };
- //TODO International date line?
- L.latLngBounds = function (a, b) { // (LatLngBounds) or (LatLng, LatLng)
- if (!a || a instanceof L.LatLngBounds) {
- return a;
- }
- return new L.LatLngBounds(a, b);
- };
- /*
- * L.Projection contains various geographical projections used by CRS classes.
- */
- L.Projection = {};
- /*
- * Spherical Mercator is the most popular map projection, used by EPSG:3857 CRS used by default.
- */
- L.Projection.SphericalMercator = {
- MAX_LATITUDE: 85.0511287798,
- project: function (latlng) { // (LatLng) -> Point
- var d = L.LatLng.DEG_TO_RAD,
- max = this.MAX_LATITUDE,
- lat = Math.max(Math.min(max, latlng.lat), -max),
- x = latlng.lng * d,
- y = lat * d;
- y = Math.log(Math.tan((Math.PI / 4) + (y / 2)));
- return new L.Point(x, y);
- },
- unproject: function (point) { // (Point, Boolean) -> LatLng
- var d = L.LatLng.RAD_TO_DEG,
- lng = point.x * d,
- lat = (2 * Math.atan(Math.exp(point.y)) - (Math.PI / 2)) * d;
- return new L.LatLng(lat, lng);
- }
- };
- /*
- * Simple equirectangular (Plate Carree) projection, used by CRS like EPSG:4326 and Simple.
- */
- L.Projection.LonLat = {
- project: function (latlng) {
- return new L.Point(latlng.lng, latlng.lat);
- },
- unproject: function (point) {
- return new L.LatLng(point.y, point.x);
- }
- };
- /*
- * L.CRS is a base object for all defined CRS (Coordinate Reference Systems) in Leaflet.
- */
- L.CRS = {
- latLngToPoint: function (latlng, zoom) { // (LatLng, Number) -> Point
- var projectedPoint = this.projection.project(latlng),
- scale = this.scale(zoom);
- return this.transformation._transform(projectedPoint, scale);
- },
- pointToLatLng: function (point, zoom) { // (Point, Number[, Boolean]) -> LatLng
- var scale = this.scale(zoom),
- untransformedPoint = this.transformation.untransform(point, scale);
- return this.projection.unproject(untransformedPoint);
- },
- project: function (latlng) {
- return this.projection.project(latlng);
- },
- scale: function (zoom) {
- return 256 * Math.pow(2, zoom);
- }
- };
- /*
- * A simple CRS that can be used for flat non-Earth maps like panoramas or game maps.
- */
- L.CRS.Simple = L.extend({}, L.CRS, {
- projection: L.Projection.LonLat,
- transformation: new L.Transformation(1, 0, -1, 0),
- scale: function (zoom) {
- return Math.pow(2, zoom);
- }
- });
- /*
- * L.CRS.EPSG3857 (Spherical Mercator) is the most common CRS for web mapping
- * and is used by Leaflet by default.
- */
- L.CRS.EPSG3857 = L.extend({}, L.CRS, {
- code: 'EPSG:3857',
- projection: L.Projection.SphericalMercator,
- transformation: new L.Transformation(0.5 / Math.PI, 0.5, -0.5 / Math.PI, 0.5),
- project: function (latlng) { // (LatLng) -> Point
- var projectedPoint = this.projection.project(latlng),
- earthRadius = 6378137;
- return projectedPoint.multiplyBy(earthRadius);
- }
- });
- L.CRS.EPSG900913 = L.extend({}, L.CRS.EPSG3857, {
- code: 'EPSG:900913'
- });
- /*
- * L.CRS.EPSG4326 is a CRS popular among advanced GIS specialists.
- */
- L.CRS.EPSG4326 = L.extend({}, L.CRS, {
- code: 'EPSG:4326',
- projection: L.Projection.LonLat,
- transformation: new L.Transformation(1 / 360, 0.5, -1 / 360, 0.5)
- });
- /*
- * L.Map is the central class of the API - it is used to create a map.
- */
- L.Map = L.Class.extend({
- includes: L.Mixin.Events,
- options: {
- crs: L.CRS.EPSG3857,
- /*
- center: LatLng,
- zoom: Number,
- layers: Array,
- */
- fadeAnimation: L.DomUtil.TRANSITION && !L.Browser.android23,
- trackResize: true,
- markerZoomAnimation: L.DomUtil.TRANSITION && L.Browser.any3d
- },
- initialize: function (id, options) { // (HTMLElement or String, Object)
- options = L.setOptions(this, options);
- this._initContainer(id);
- this._initLayout();
- this._initEvents();
- if (options.maxBounds) {
- this.setMaxBounds(options.maxBounds);
- }
- if (options.center && options.zoom !== undefined) {
- this.setView(L.latLng(options.center), options.zoom, {reset: true});
- }
- this._handlers = [];
- this._layers = {};
- this._zoomBoundLayers = {};
- this._tileLayersNum = 0;
- this.callInitHooks();
- this._addLayers(options.layers);
- },
- // public methods that modify map state
- // replaced by animation-powered implementation in Map.PanAnimation.js
- setView: function (center, zoom) {
- this._resetView(L.latLng(center), this._limitZoom(zoom));
- return this;
- },
- setZoom: function (zoom, options) {
- return this.setView(this.getCenter(), zoom, {zoom: options});
- },
- zoomIn: function (delta, options) {
- return this.setZoom(this._zoom + (delta || 1), options);
- },
- zoomOut: function (delta, options) {
- return this.setZoom(this._zoom - (delta || 1), options);
- },
- setZoomAround: function (latlng, zoom, options) {
- var scale = this.getZoomScale(zoom),
- viewHalf = this.getSize().divideBy(2),
- containerPoint = latlng instanceof L.Point ? latlng : this.latLngToContainerPoint(latlng),
- centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),
- newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));
- return this.setView(newCenter, zoom, {zoom: options});
- },
- fitBounds: function (bounds, options) {
- options = options || {};
- bounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds);
- var paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
- paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]),
- zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR)),
- paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),
- swPoint = this.project(bounds.getSouthWest(), zoom),
- nePoint = this.project(bounds.getNorthEast(), zoom),
- center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);
- return this.setView(center, zoom, options);
- },
- fitWorld: function (options) {
- return this.fitBounds([[-90, -180], [90, 180]], options);
- },
- panTo: function (center, options) { // (LatLng)
- return this.setView(center, this._zoom, {pan: options});
- },
- panBy: function (offset) { // (Point)
- // replaced with animated panBy in Map.Animation.js
- this.fire('movestart');
- this._rawPanBy(L.point(offset));
- this.fire('move');
- return this.fire('moveend');
- },
- setMaxBounds: function (bounds) {
- bounds = L.latLngBounds(bounds);
- this.options.maxBounds = bounds;
- if (!bounds) {
- this._boundsMinZoom = null;
- this.off('moveend', this._panInsideMaxBounds, this);
- return this;
- }
- var minZoom = this.getBoundsZoom(bounds, true);
- this._boundsMinZoom = minZoom;
- if (this._loaded) {
- if (this._zoom < minZoom) {
- this.setView(bounds.getCenter(), minZoom);
- } else {
- this.panInsideBounds(bounds);
- }
- }
- this.on('moveend', this._panInsideMaxBounds, this);
- return this;
- },
- panInsideBounds: function (bounds) {
- bounds = L.latLngBounds(bounds);
- var viewBounds = this.getPixelBounds(),
- viewSw = viewBounds.getBottomLeft(),
- viewNe = viewBounds.getTopRight(),
- sw = this.project(bounds.getSouthWest()),
- ne = this.project(bounds.getNorthEast()),
- dx = 0,
- dy = 0;
- if (viewNe.y < ne.y) { // north
- dy = Math.ceil(ne.y - viewNe.y);
- }
- if (viewNe.x > ne.x) { // east
- dx = Math.floor(ne.x - viewNe.x);
- }
- if (viewSw.y > sw.y) { // south
- dy = Math.floor(sw.y - viewSw.y);
- }
- if (viewSw.x < sw.x) { // west
- dx = Math.ceil(sw.x - viewSw.x);
- }
- if (dx || dy) {
- return this.panBy([dx, dy]);
- }
- return this;
- },
- addLayer: function (layer) {
- // TODO method is too big, refactor
- var id = L.stamp(layer);
- if (this._layers[id]) { return this; }
- this._layers[id] = layer;
- // TODO getMaxZoom, getMinZoom in ILayer (instead of options)
- if (layer.options && (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom))) {
- this._zoomBoundLayers[id] = layer;
- this._updateZoomLevels();
- }
- // TODO looks ugly, refactor!!!
- if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) {
- this._tileLayersNum++;
- this._tileLayersToLoad++;
- layer.on('load', this._onTileLayerLoad, this);
- }
- if (this._loaded) {
- this._layerAdd(layer);
- }
- return this;
- },
- removeLayer: function (layer) {
- var id = L.stamp(layer);
- if (!this._layers[id]) { return; }
- if (this._loaded) {
- layer.onRemove(this);
- this.fire('layerremove', {layer: layer});
- }
- delete this._layers[id];
- if (this._zoomBoundLayers[id]) {
- delete this._zoomBoundLayers[id];
- this._updateZoomLevels();
- }
- // TODO looks ugly, refactor
- if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) {
- this._tileLayersNum--;
- this._tileLayersToLoad--;
- layer.off('load', this._onTileLayerLoad, this);
- }
- return this;
- },
- hasLayer: function (layer) {
- if (!layer) { return false; }
- return (L.stamp(layer) in this._layers);
- },
- eachLayer: function (method, context) {
- for (var i in this._layers) {
- method.call(context, this._layers[i]);
- }
- return this;
- },
- invalidateSize: function (options) {
- options = L.extend({
- animate: false,
- pan: true
- }, options === true ? {animate: true} : options);
- var oldSize = this.getSize();
- this._sizeChanged = true;
- if (this.options.maxBounds) {
- this.setMaxBounds(this.options.maxBounds);
- }
- if (!this._loaded) { return this; }
- var newSize = this.getSize(),
- offset = oldSize.subtract(newSize).divideBy(2).round();
- if (!offset.x && !offset.y) { return this; }
- if (options.animate && options.pan) {
- this.panBy(offset);
- } else {
- if (options.pan) {
- this._rawPanBy(offset);
- }
- this.fire('move');
- // make sure moveend is not fired too often on resize
- clearTimeout(this._sizeTimer);
- this._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200);
- }
- return this.fire('resize', {
- oldSize: oldSize,
- newSize: newSize
- });
- },
- // TODO handler.addTo
- addHandler: function (name, HandlerClass) {
- if (!HandlerClass) { return; }
- var handler = this[name] = new HandlerClass(this);
- this._handlers.push(handler);
- if (this.options[name]) {
- handler.enable();
- }
- return this;
- },
- remove: function () {
- if (this._loaded) {
- this.fire('unload');
- }
- this._initEvents('off');
- delete this._container._leaflet;
- this._clearPanes();
- if (this._clearControlPos) {
- this._clearControlPos();
- }
- this._clearHandlers();
- return this;
- },
- // public methods for getting map state
- getCenter: function () { // (Boolean) -> LatLng
- this._checkIfLoaded();
- if (!this._moved()) {
- return this._initialCenter;
- }
- return this.layerPointToLatLng(this._getCenterLayerPoint());
- },
- getZoom: function () {
- return this._zoom;
- },
- getBounds: function () {
- var bounds = this.getPixelBounds(),
- sw = this.unproject(bounds.getBottomLeft()),
- ne = this.unproject(bounds.getTopRight());
- return new L.LatLngBounds(sw, ne);
- },
- getMinZoom: function () {
- var z1 = this.options.minZoom || 0,
- z2 = this._layersMinZoom || 0,
- z3 = this._boundsMinZoom || 0;
- return Math.max(z1, z2, z3);
- },
- getMaxZoom: function () {
- var z1 = this.options.maxZoom === undefined ? Infinity : this.options.maxZoom,
- z2 = this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom;
- return Math.min(z1, z2);
- },
- getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
- bounds = L.latLngBounds(bounds);
- var zoom = this.getMinZoom() - (inside ? 1 : 0),
- maxZoom = this.getMaxZoom(),
- size = this.getSize(),
- nw = bounds.getNorthWest(),
- se = bounds.getSouthEast(),
- zoomNotFound = true,
- boundsSize;
- padding = L.point(padding || [0, 0]);
- do {
- zoom++;
- boundsSize = this.project(se, zoom).subtract(this.project(nw, zoom)).add(padding);
- zoomNotFound = !inside ? size.contains(boundsSize) : boundsSize.x < size.x || boundsSize.y < size.y;
- } while (zoomNotFound && zoom <= maxZoom);
- if (zoomNotFound && inside) {
- return null;
- }
- return inside ? zoom : zoom - 1;
- },
- getSize: function () {
- if (!this._size || this._sizeChanged) {
- this._size = new L.Point(
- this._container.clientWidth,
- this._container.clientHeight);
- this._sizeChanged = false;
- }
- return this._size.clone();
- },
- getPixelBounds: function () {
- var topLeftPoint = this._getTopLeftPoint();
- return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
- },
- getPixelOrigin: function () {
- this._checkIfLoaded();
- return this._initialTopLeftPoint;
- },
- getPanes: function () {
- return this._panes;
- },
- getContainer: function () {
- return this._container;
- },
- // TODO replace with universal implementation after refactoring projections
- getZoomScale: function (toZoom) {
- var crs = this.options.crs;
- return crs.scale(toZoom) / crs.scale(this._zoom);
- },
- getScaleZoom: function (scale) {
- return this._zoom + (Math.log(scale) / Math.LN2);
- },
- // conversion methods
- project: function (latlng, zoom) { // (LatLng[, Number]) -> Point
- zoom = zoom === undefined ? this._zoom : zoom;
- return this.options.crs.latLngToPoint(L.latLng(latlng), zoom);
- },
- unproject: function (point, zoom) { // (Point[, Number]) -> LatLng
- zoom = zoom === undefined ? this._zoom : zoom;
- return this.options.crs.pointToLatLng(L.point(point), zoom);
- },
- layerPointToLatLng: function (point) { // (Point)
- var projectedPoint = L.point(point).add(this.getPixelOrigin());
- return this.unproject(projectedPoint);
- },
- latLngToLayerPoint: function (latlng) { // (LatLng)
- var projectedPoint = this.project(L.latLng(latlng))._round();
- return projectedPoint._subtract(this.getPixelOrigin());
- },
- containerPointToLayerPoint: function (point) { // (Point)
- return L.point(point).subtract(this._getMapPanePos());
- },
- layerPointToContainerPoint: function (point) { // (Point)
- return L.point(point).add(this._getMapPanePos());
- },
- containerPointToLatLng: function (point) {
- var layerPoint = this.containerPointToLayerPoint(L.point(point));
- return this.layerPointToLatLng(layerPoint);
- },
- latLngToContainerPoint: function (latlng) {
- return this.layerPointToContainerPoint(this.latLngToLayerPoint(L.latLng(latlng)));
- },
- mouseEventToContainerPoint: function (e) { // (MouseEvent)
- return L.DomEvent.getMousePosition(e, this._container);
- },
- mouseEventToLayerPoint: function (e) { // (MouseEvent)
- return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));
- },
- mouseEventToLatLng: function (e) { // (MouseEvent)
- return this.layerPointToLatLng(this.mouseEventToLayerPoint(e));
- },
- // map initialization methods
- _initContainer: function (id) {
- var container = this._container = L.DomUtil.get(id);
- if (!container) {
- throw new Error('Map container not found.');
- } else if (container._leaflet) {
- throw new Error('Map container is already initialized.');
- }
- container._leaflet = true;
- },
- _initLayout: function () {
- var container = this._container;
- L.DomUtil.addClass(container, 'leaflet-container' +
- (L.Browser.touch ? ' leaflet-touch' : '') +
- (L.Browser.retina ? ' leaflet-retina' : '') +
- (this.options.fadeAnimation ? ' leaflet-fade-anim' : ''));
- var position = L.DomUtil.getStyle(container, 'position');
- if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') {
- container.style.position = 'relative';
- }
- this._initPanes();
- if (this._initControlPos) {
- this._initControlPos();
- }
- },
- _initPanes: function () {
- var panes = this._panes = {};
- this._mapPane = panes.mapPane = this._createPane('leaflet-map-pane', this._container);
- this._tilePane = panes.tilePane = this._createPane('leaflet-tile-pane', this._mapPane);
- panes.objectsPane = this._createPane('leaflet-objects-pane', this._mapPane);
- panes.shadowPane = this._createPane('leaflet-shadow-pane');
- panes.overlayPane = this._createPane('leaflet-overlay-pane');
- panes.markerPane = this._createPane('leaflet-marker-pane');
- panes.popupPane = this._createPane('leaflet-popup-pane');
- var zoomHide = ' leaflet-zoom-hide';
- if (!this.options.markerZoomAnimation) {
- L.DomUtil.addClass(panes.markerPane, zoomHide);
- L.DomUtil.addClass(panes.shadowPane, zoomHide);
- L.DomUtil.addClass(panes.popupPane, zoomHide);
- }
- },
- _createPane: function (className, container) {
- return L.DomUtil.create('div', className, container || this._pan