var oldL = window.L,
L = {};
-L.version = '0.6';
+L.version = '0.6.3';
// define Leaflet for Node module pattern loaders, including Browserify
if (typeof module === 'object' && typeof module.exports === 'object') {
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 () {
+ L.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault);
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 () {
+ L.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault);
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);
- }
+ L.DomEvent.on(window, 'dragstart', L.DomEvent.preventDefault);
},
enableImageDrag: function () {
- if (userDragProperty) {
- document.documentElement.style[userDragProperty] = this._userDrag;
- delete this._userDrag;
- } else {
- L.DomEvent.off(window, 'dragstart', L.DomEvent.stop);
- }
+ L.DomEvent.off(window, 'dragstart', L.DomEvent.preventDefault);
}
});
})();
return this.fire('moveend');
},
- setMaxBounds: function (bounds) {
+ setMaxBounds: function (bounds, options) {
bounds = L.latLngBounds(bounds);
this.options.maxBounds = bounds;
if (this._loaded) {
if (this._zoom < minZoom) {
- this.setView(bounds.getCenter(), minZoom);
+ this.setView(bounds.getCenter(), minZoom, options);
} else {
this.panInsideBounds(bounds);
}
removeLayer: function (layer) {
var id = L.stamp(layer);
- if (!this._layers[id]) { return; }
+ if (!this._layers[id]) { return this; }
if (this._loaded) {
layer.onRemove(this);
- this.fire('layerremove', {layer: layer});
}
delete this._layers[id];
+
+ if (this._loaded) {
+ this.fire('layerremove', {layer: layer});
+ }
+
if (this._zoomBoundLayers[id]) {
delete this._zoomBoundLayers[id];
this._updateZoomLevels();
var oldSize = this.getSize();
this._sizeChanged = true;
+ this._initialCenter = null;
if (this.options.maxBounds) {
this.setMaxBounds(this.options.maxBounds);
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);
+ this.fire('move').fire('moveend');
}
return this.fire('resize', {
getCenter: function () { // (Boolean) -> LatLng
this._checkIfLoaded();
- if (!this._moved()) {
+ if (this._initialCenter && !this._moved()) {
return this._initialCenter;
}
return this.layerPointToLatLng(this._getCenterLayerPoint());
},
getMinZoom: function () {
- var z1 = this.options.minZoom || 0,
- z2 = this._layersMinZoom || 0,
- z3 = this._boundsMinZoom || 0;
-
- return Math.max(z1, z2, z3);
+ var z1 = this._layersMinZoom === undefined ? -Infinity : this._layersMinZoom,
+ z2 = this._boundsMinZoom === undefined ? -Infinity : this._boundsMinZoom;
+ return this.options.minZoom === undefined ? Math.max(z1, z2) : this.options.minZoom;
},
getMaxZoom: function () {
- var z1 = this.options.maxZoom === undefined ? Infinity : this.options.maxZoom,
- z2 = this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom;
-
- return Math.min(z1, z2);
+ return this.options.maxZoom === undefined ?
+ (this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :
+ this.options.maxZoom;
},
getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
},
_onMouseClick: function (e) {
- // jshint camelcase: false
- if (!this._loaded || (!e._simulated && this.dragging && this.dragging.moved()) || e._leaflet_stop) { return; }
+ if (!this._loaded || (!e._simulated && this.dragging && this.dragging.moved()) ||
+ L.DomEvent._skipped(e)) { return; }
this.fire('preclick');
this._fireMouseEvent(e);
},
_fireMouseEvent: function (e) {
- // jshint camelcase: false
- if (!this._loaded || e._leaflet_stop) { return; }
+ if (!this._loaded || L.DomEvent._skipped(e)) { return; }
var type = e.type;
lng = point.x * d / r,
tmp = r2 / r,
eccent = Math.sqrt(1 - (tmp * tmp)),
- ts = Math.exp(- point.y / r2),
+ ts = Math.exp(- point.y / r),
phi = (Math.PI / 2) - 2 * Math.atan(ts),
numIter = 15,
tol = 1e-7,
var className = 'leaflet-tile-container leaflet-zoom-animated';
this._bgBuffer = L.DomUtil.create('div', className, this._container);
- this._bgBuffer.style.zIndex = 1;
-
this._tileContainer = L.DomUtil.create('div', className, this._container);
- this._tileContainer.style.zIndex = 2;
} else {
this._tileContainer = this._container;
},
redraw: function () {
+ if (this._map) {
+ this._reset({hard: true});
+ this._update();
+ }
+
for (var i in this._tiles) {
this._redrawTile(this._tiles[i]);
}
if (newShadow !== this._shadow) {
this._removeShadow();
addShadow = true;
+ }
- if (newShadow) {
- L.DomUtil.addClass(newShadow, classToAdd);
- }
+ if (newShadow) {
+ L.DomUtil.addClass(newShadow, classToAdd);
}
this._shadow = newShadow;
if (this._map) {
this._updateOpacity();
}
+
+ return this;
},
_updateOpacity: function () {
L.DomEvent.disableClickPropagation(wrapper);
this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper);
- L.DomEvent.on(this._contentNode, 'wheel', L.DomEvent.stopPropagation);
+ L.DomEvent.on(this._contentNode, 'mousewheel', L.DomEvent.stopPropagation);
+ L.DomEvent.on(this._contentNode, 'MozMousePixelScroll', L.DomEvent.stopPropagation);
L.DomEvent.on(wrapper, 'contextmenu', L.DomEvent.stopPropagation);
this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container);
this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer);
},
removeLayer: function (layer) {
+ if (!this.hasLayer(layer)) {
+ return this;
+ }
if (layer in this._layers) {
layer = this._layers[layer];
}
// how much to extend the clip area around the map view
// (relative to its size, e.g. 0.5 is half the screen in each direction)
// set it so that SVG element doesn't exceed 1280px (vectors flicker on dragend if it is)
- CLIP_PADDING: L.Browser.mobile ?
- Math.max(0, Math.min(0.5,
- (1280 / Math.max(window.innerWidth, window.innerHeight) - 1) / 2)) : 0.5
+ CLIP_PADDING: (function () {
+ var max = L.Browser.mobile ? 1280 : 2000,
+ target = (max / Math.max(window.outerWidth, window.outerHeight) - 1) / 2;
+ return Math.max(0, Math.min(0.5, target));
+ })()
},
options: {
}
return this;
+ },
+
+ getLatLngs: function () {
+ var latlngs = [];
+
+ this.eachLayer(function (layer) {
+ latlngs.push(layer.getLatLngs());
+ });
+
+ return latlngs;
}
});
}
addData: function (geojson) {
var features = L.Util.isArray(geojson) ? geojson : geojson.features,
- i, len;
+ i, len, feature;
if (features) {
for (i = 0, len = features.length; i < len; i++) {
// Only add this if geometry or geometries are set and not null
- if (features[i].geometries || features[i].geometry || features[i].features) {
+ feature = features[i];
+ if (feature.geometries || feature.geometry || feature.features || feature.coordinates) {
this.addData(features[i]);
}
}
*/
L.DomEvent = {
- WHEEL:
- 'onwheel' in document ? 'wheel' :
- 'onmousewheel' in document ? 'mousewheel' :
- 'MozMousePixelScroll',
-
/* inspired by John Resig, Dean Edwards and YUI addEvent implementations */
addListener: function (obj, type, fn, context) { // (HTMLElement, String, Function[, Object])
this.addDoubleTapListener(obj, handler, id);
}
- if (type === 'wheel' || type === 'mousewheel') {
- type = L.DomEvent.WHEEL;
- }
-
if ('addEventListener' in obj) {
- if ((type === 'mouseenter') || (type === 'mouseleave')) {
+ if (type === 'mousewheel') {
+ obj.addEventListener('DOMMouseScroll', handler, false);
+ obj.addEventListener(type, handler, false);
+
+ } else if ((type === 'mouseenter') || (type === 'mouseleave')) {
originalHandler = handler;
newType = (type === 'mouseenter' ? 'mouseover' : 'mouseout');
if (!handler) { return this; }
- if (type === 'wheel' || type === 'mousewheel') {
- type = L.DomEvent.WHEEL;
- }
-
if (L.Browser.msTouch && type.indexOf('touch') === 0) {
this.removeMsTouchListener(obj, type, id);
} else if (L.Browser.touch && (type === 'dblclick') && this.removeDoubleTapListener) {
} else if ('removeEventListener' in obj) {
- if ((type === 'mouseenter') || (type === 'mouseleave')) {
+ if (type === 'mousewheel') {
+ obj.removeEventListener('DOMMouseScroll', handler, false);
+ obj.removeEventListener(type, handler, false);
+
+ } else if ((type === 'mouseenter') || (type === 'mouseleave')) {
obj.removeEventListener((type === 'mouseenter' ? 'mouseover' : 'mouseout'), handler, false);
} else {
obj.removeEventListener(type, handler, false);
getMousePosition: function (e, container) {
- var body = document.body,
+ var ie7 = L.Browser.ie7,
+ body = document.body,
docEl = document.documentElement,
- x = e.pageX ? e.pageX : e.clientX + body.scrollLeft + docEl.scrollLeft,
- y = e.pageY ? e.pageY : e.clientY + body.scrollTop + docEl.scrollTop,
- pos = new L.Point(x, y);
+ x = e.pageX ? e.pageX - body.scrollLeft - docEl.scrollLeft: e.clientX,
+ y = e.pageY ? e.pageY - body.scrollTop - docEl.scrollTop: e.clientY,
+ pos = new L.Point(x, y),
+ rect = container.getBoundingClientRect(),
+ left = rect.left - container.clientLeft,
+ top = rect.top - container.clientTop;
+
+ // 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 += container.scrollWidth - container.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(container, 'overflow-y') !== 'hidden' &&
+ L.DomUtil.getStyle(container, 'overflow') !== 'hidden') {
+ left += 17;
+ }
+ }
- return (container ? pos._subtract(L.DomUtil.getViewportOffset(container)) : pos);
+ return pos._subtract(new L.Point(left, top));
},
getWheelDelta: function (e) {
+
var delta = 0;
- if (e.type === 'wheel') {
- delta = -e.deltaY / (e.deltaMode ? 1 : 120);
- } else if (e.type === 'mousewheel') {
+ if (e.wheelDelta) {
delta = e.wheelDelta / 120;
- } else if (e.type === 'MozMousePixelScroll') {
- delta = -e.detail;
}
-
+ if (e.detail) {
+ delta = -e.detail / 3;
+ }
return delta;
},
- _fakeStop: function stop(e) {
- // fakes stopPropagation by setting a special event flag checked in Map mouse events handler
- // jshint camelcase: false
- e._leaflet_stop = true;
+ _skipEvents: {},
+
+ _fakeStop: function (e) {
+ // fakes stopPropagation by setting a special event flag, checked/reset with L.DomEvent._skipped(e)
+ L.DomEvent._skipEvents[e.type] = true;
+ },
+
+ _skipped: function (e) {
+ var skipped = this._skipEvents[e.type];
+ // reset when checking, as it's only used in map container and propagates outside of the map
+ this._skipEvents[e.type] = false;
+ return skipped;
},
// check if element really left/entered the event target (for mouseenter/mouseleave)
if (L.Draggable._disabled) { return; }
L.DomUtil.disableImageDrag();
+ L.DomUtil.disableTextSelection();
var first = e.touches ? e.touches[0] : e,
el = first.target;
this._startPos = L.DomUtil.getPosition(this._element).subtract(offset);
if (!L.Browser.touch) {
- L.DomUtil.disableTextSelection();
L.DomUtil.addClass(document.body, 'leaflet-dragging');
}
}
_onUp: function () {
if (!L.Browser.touch) {
- L.DomUtil.enableTextSelection();
L.DomUtil.removeClass(document.body, 'leaflet-dragging');
}
}
L.DomUtil.enableImageDrag();
+ L.DomUtil.enableTextSelection();
if (this._moved) {
// ensure drag is not fired after dragend
if (map.options.worldCopyJump) {
this._draggable.on('predrag', this._onPreDrag, this);
map.on('viewreset', this._onViewReset, this);
+
+ this._onViewReset();
}
}
this._draggable.enable();
L.Map.DoubleClickZoom = L.Handler.extend({
addHooks: function () {
- this._map.on('dblclick', this._onDoubleClick);
+ this._map.on('dblclick', this._onDoubleClick, this);
},
removeHooks: function () {
- this._map.off('dblclick', this._onDoubleClick);
+ this._map.off('dblclick', this._onDoubleClick, this);
},
_onDoubleClick: function (e) {
- this.setZoomAround(e.containerPoint, this._zoom + 1);
+ var map = this._map,
+ zoom = map.getZoom() + 1;
+
+ if (map.options.doubleClickZoom === 'center') {
+ map.setZoom(zoom);
+ } else {
+ map.setZoomAround(e.containerPoint, zoom);
+ }
}
});
L.Map.ScrollWheelZoom = L.Handler.extend({
addHooks: function () {
- L.DomEvent.on(this._map._container, 'wheel', this._onWheelScroll, this);
+ L.DomEvent.on(this._map._container, 'mousewheel', this._onWheelScroll, this);
+ L.DomEvent.on(this._map._container, 'MozMousePixelScroll', L.DomEvent.preventDefault);
this._delta = 0;
},
removeHooks: function () {
- L.DomEvent.off(this._map._container, 'wheel', this._onWheelScroll);
+ L.DomEvent.off(this._map._container, 'mousewheel', this._onWheelScroll);
+ L.DomEvent.off(this._map._container, 'MozMousePixelScroll', L.DomEvent.preventDefault);
},
_onWheelScroll: function (e) {
if (!delta) { return; }
- map.setZoomAround(this._lastMousePos, zoom + delta);
+ if (map.options.scrollWheelZoom === 'center') {
+ map.setZoom(zoom + delta);
+ } else {
+ map.setZoomAround(this._lastMousePos, zoom + delta);
+ }
}
});
if (!L.Browser.touch) {
L.DomEvent.disableClickPropagation(container);
- L.DomEvent.on(container, 'wheel', L.DomEvent.stopPropagation);
+ L.DomEvent.on(container, 'mousewheel', L.DomEvent.stopPropagation);
} else {
L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
}
},
_onStep: function () {
+ var stepPos = this._getPos();
+ if (!stepPos) {
+ this._onTransitionEnd();
+ return;
+ }
// jshint camelcase: false
// make L.DomUtil.getPosition return intermediate position value during animation
- this._el._leaflet_pos = this._getPos();
+ this._el._leaflet_pos = stepPos;
this.fire('step');
},
if (L.Browser.any3d) {
matches = style[L.DomUtil.TRANSFORM].match(this._transformRe);
- left = matches ? parseFloat(matches[1]) : 0;
- top = matches ? parseFloat(matches[2]) : 0;
+ if (!matches) { return; }
+ left = parseFloat(matches[1]);
+ top = parseFloat(matches[2]);
} else {
left = parseFloat(style.left);
top = parseFloat(style.top);
}
},
+ _nothingToAnimate: function () {
+ return !this._container.getElementsByClassName('leaflet-zoom-animated').length;
+ },
+
_tryAnimatedZoom: function (center, zoom, options) {
if (this._animatingZoom) { return true; }
options = options || {};
// don't animate if disabled, not supported or zoom difference is too large
- if (!this._zoomAnimated || options.animate === false ||
+ if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||
Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }
// offset is the pixel coords of the zoom origin relative to the current center
L.TileLayer.include({
_animateZoom: function (e) {
- var firstFrame = false;
-
if (!this._animating) {
this._animating = true;
- firstFrame = true;
- }
-
- if (firstFrame) {
this._prepareBgBuffer();
}
- var bg = this._bgBuffer;
-
- if (firstFrame) {
- //prevent bg buffer from clearing right after zoom
- clearTimeout(this._clearBgBufferTimer);
-
- // hack to make sure transform is updated before running animation
- L.Util.falseFn(bg.offsetWidth);
- }
-
- var transform = L.DomUtil.TRANSFORM,
+ var bg = this._bgBuffer,
+ transform = L.DomUtil.TRANSFORM,
initialTransform = e.delta ? L.DomUtil.getTranslateString(e.delta) : bg.style[transform],
scaleStr = L.DomUtil.getScaleString(e.scale, e.origin);
bg = this._bgBuffer;
front.style.visibility = '';
- front.style.zIndex = 2;
-
- bg.style.zIndex = 1;
+ front.parentNode.appendChild(front); // Bring to fore
// force reflow
L.Util.falseFn(bg.offsetWidth);
bg = this._bgBuffer = front;
this._stopLoadingImages(bg);
+
+ //prevent bg buffer from clearing right after zoom
+ clearTimeout(this._clearBgBufferTimer);
},
_getLoadedTilesPercentage: function (container) {
var data = {
latlng: latlng,
- bounds: bounds,
+ bounds: bounds
};
for (var i in pos.coords) {