var oldL = window.L,
L = {};
-L.version = '0.7';
+L.version = '0.7.7';
// define Leaflet for Node module pattern loaders, including Browserify
if (typeof module === 'object' && typeof module.exports === 'object') {
}
return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
},
-
- compileTemplate: function (str, data) {
- // based on https://gist.github.com/padolsey/6008842
- str = str.replace(/"/g, '\\\"');
- str = str.replace(/\{ *([\w_]+) *\}/g, function (str, key) {
- return '" + o["' + key + '"]' + (typeof data[key] === 'function' ? '(o)' : '') + ' + "';
- });
- // jshint evil: true
- return new Function('o', 'return "' + str + '";');
- },
-
template: function (str, data) {
- var cache = L.Util._templateCache = L.Util._templateCache || {};
- cache[str] = cache[str] || L.Util.compileTemplate(str, data);
- return cache[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: Array.isArray || function (obj) {
gecko = ua.indexOf('gecko') !== -1,
mobile = typeof orientation !== undefined + '',
- msPointer = window.navigator && window.navigator.msPointerEnabled &&
- window.navigator.msMaxTouchPoints && !window.PointerEvent,
- pointer = (window.PointerEvent && window.navigator.pointerEnabled && window.navigator.maxTouchPoints) ||
+ msPointer = !window.PointerEvent && window.MSPointerEvent,
+ pointer = (window.PointerEvent && window.navigator.pointerEnabled) ||
msPointer,
retina = ('devicePixelRatio' in window && window.devicePixelRatio > 1) ||
('matchMedia' in window && window.matchMedia('(min-resolution:144dpi)') &&
doc = document.documentElement,
ie3d = ie && ('transition' in doc.style),
- webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()),
+ webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23,
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.Pointer) or WebKit, etc.
- if (pointer || (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;
- }());
-
+ var touch = !window.L_NO_TOUCH && !phantomjs && (pointer || 'ontouchstart' in window ||
+ (window.DocumentTouch && document instanceof window.DocumentTouch));
L.Browser = {
ie: ie,
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';
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),
+ zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
+
+ zoom = (options.maxZoom) ? Math.min(options.maxZoom, zoom) : zoom;
+
+ var 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);
- zoom = options && options.maxZoom ? Math.min(options.maxZoom, zoom) : zoom;
-
return this.setView(center, zoom, options);
},
},
invalidateSize: function (options) {
+ if (!this._loaded) { return this; }
+
options = L.extend({
animate: false,
pan: true
this._sizeChanged = true;
this._initialCenter = null;
- if (!this._loaded) { return this; }
-
var newSize = this.getSize(),
oldCenter = oldSize.divideBy(2).round(),
newCenter = newSize.divideBy(2).round(),
var loading = !this._loaded;
this._loaded = true;
+ this.fire('viewreset', {hard: !preserveMapOffset});
+
if (loading) {
this.fire('load');
this.eachLayer(this._layerAdd, this);
}
- this.fire('viewreset', {hard: !preserveMapOffset});
-
this.fire('move');
if (zoomChanged || afterZoomAnim) {
}
if (options.bounds) {
- var tileSize = options.tileSize,
+ var tileSize = this._getTileSize(),
nwPoint = tilePoint.multiplyBy(tileSize),
sePoint = nwPoint.add([tileSize, tileSize]),
nw = this._map.unproject(nwPoint),
/*
Chrome 20 layouts much faster with top/left (verify with timeline, frames)
Android 4 browser has display issues with top/left and requires transform instead
- Android 2 browser requires top/left or tiles disappear on load or first drag
- (reappear after zoom) https://github.com/CloudMade/Leaflet/issues/866
(other browsers don't currently care) - see debug/hacks/jitter.html for an example
*/
- L.DomUtil.setPosition(tile, tilePos, L.Browser.chrome || L.Browser.android23);
+ L.DomUtil.setPosition(tile, tilePos, L.Browser.chrome);
this._tiles[tilePoint.x + ':' + tilePoint.y] = tile;
_getWrapTileNum: function () {
var crs = this._map.options.crs,
size = crs.getSize(this._map.getZoom());
- return size.divideBy(this.options.tileSize);
+ return size.divideBy(this._getTileSize())._floor();
},
_adjustTilePoint: function (tilePoint) {
update: function () {
if (this._icon) {
- var pos = this._map.latLngToLayerPoint(this._latlng).round();
- this._setPos(pos);
+ this._setPos(this._map.latLngToLayerPoint(this._latlng).round());
}
-
return this;
},
if (options.title) {
icon.title = options.title;
}
-
+
if (options.alt) {
icon.alt = options.alt;
}
if (content instanceof L.Popup) {
L.setOptions(content, options);
this._popup = content;
+ content._source = this;
} else {
this._popup = new L.Popup(options, this)
.setContent(content);
layer = this._layers[layer];
}
- layer.off(L.FeatureGroup.EVENTS, this._propagateEvent, this);
+ if ('off' in layer) {
+ layer.off(L.FeatureGroup.EVENTS, this._propagateEvent, this);
+ }
L.LayerGroup.prototype.removeLayer.call(this, layer);
},
_propagateEvent: function (e) {
- e = L.extend({}, e, {
+ e = L.extend({
layer: e.target,
target: this
- });
+ }, e);
this.fire(e.type, e);
}
});
},
_fireMouseEvent: function (e) {
- if (!this.hasEventListeners(e.type)) { return; }
+ if (!this._map || !this.hasEventListeners(e.type)) { return; }
var map = this._map,
containerPoint = map.mouseEventToContainerPoint(e),
}
this._requestUpdate();
-
+
+ this.fire('remove');
this._map = null;
},
if (options.fill) {
this._ctx.fillStyle = options.fillColor || options.color;
}
+
+ if (options.lineCap) {
+ this._ctx.lineCap = options.lineCap;
+ }
+ if (options.lineJoin) {
+ this._ctx.lineJoin = options.lineJoin;
+ }
},
_drawPath: function () {
if (options.fill) {
ctx.globalAlpha = options.fillOpacity;
- ctx.fill();
+ ctx.fill(options.fillRule || 'evenodd');
}
if (options.stroke) {
_initEvents: function () {
if (this.options.clickable) {
- // TODO dblclick
this._map.on('mousemove', this._onMouseMove, this);
- this._map.on('click', this._onClick, this);
+ this._map.on('click dblclick contextmenu', this._fireMouseEvent, this);
}
},
- _onClick: function (e) {
+ _fireMouseEvent: function (e) {
if (this._containsPoint(e.layerPoint)) {
- this.fire('click', e);
+ this.fire(e.type, e);
}
},
* and polylines (clipping, simplification, distances, etc.)
*/
-/*jshint bitwise:false */ // allow bitwise oprations for this file
+/*jshint bitwise:false */ // allow bitwise operations for this file
L.LineUtil = {
if (this._popup && this._popup._isOpen) {
this._popup.setLatLng(latlng);
}
+ return this;
},
setRadius: function (radius) {
},
getMousePosition: function (e, container) {
- var body = document.body,
- docEl = document.documentElement,
- //gecko makes scrollLeft more negative as you scroll in rtl, other browsers don't
- //ref: https://code.google.com/p/closure-library/source/browse/closure/goog/style/bidi.js
- x = L.DomUtil.documentIsLtr() ?
- (e.pageX ? e.pageX - body.scrollLeft - docEl.scrollLeft : e.clientX) :
- (L.Browser.gecko ? e.pageX - body.scrollLeft - docEl.scrollLeft :
- 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);
-
if (!container) {
- return pos;
+ return new L.Point(e.clientX, e.clientY);
}
- var rect = container.getBoundingClientRect(),
- left = rect.left - container.clientLeft,
- top = rect.top - container.clientTop;
+ var rect = container.getBoundingClientRect();
- return pos._subtract(new L.Point(left, top));
+ return new L.Point(
+ e.clientX - rect.left - container.clientLeft,
+ e.clientY - rect.top - container.clientTop);
},
getWheelDelta: function (e) {
var timeStamp = (e.timeStamp || e.originalEvent.timeStamp),
elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick);
- // are they closer together than 1000ms yet more than 100ms?
+ // are they closer together than 500ms yet more than 100ms?
// Android typically triggers them ~300ms apart while multiple listeners
// on the same event should be triggered far faster;
// or check if click is simulated on the element, and if it is, reject any non-simulated events
- if ((elapsed && elapsed > 100 && elapsed < 1000) || (e.target._simulatedClick && !e._simulated)) {
+ if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) {
L.DomEvent.stop(e);
return;
}
offset = newPoint.subtract(this._startPoint);
if (!offset.x && !offset.y) { return; }
+ if (L.Browser.touch && Math.abs(offset.x) + Math.abs(offset.y) < 3) { return; }
L.DomEvent.preventDefault(e);
this._startPos = L.DomUtil.getPosition(this._element).subtract(offset);
L.DomUtil.addClass(document.body, 'leaflet-dragging');
- L.DomUtil.addClass((e.target || e.srcElement), 'leaflet-drag-target');
+ this._lastTarget = e.target || e.srcElement;
+ L.DomUtil.addClass(this._lastTarget, 'leaflet-drag-target');
}
this._newPos = this._startPos.add(offset);
this.fire('drag');
},
- _onUp: function (e) {
+ _onUp: function () {
L.DomUtil.removeClass(document.body, 'leaflet-dragging');
- L.DomUtil.removeClass((e.target || e.srcElement), 'leaflet-drag-target');
+
+ if (this._lastTarget) {
+ L.DomUtil.removeClass(this._lastTarget, 'leaflet-drag-target');
+ this._lastTarget = null;
+ }
for (var i in L.Draggable.MOVE) {
L.DomEvent
L.DomUtil.enableImageDrag();
L.DomUtil.enableTextSelection();
- if (this._moved) {
+ if (this._moved && this._moving) {
// ensure drag is not fired after dragend
L.Util.cancelAnimFrame(this._animRequest);
pointers = this._pointers;
var cb = function (e) {
-
- L.DomEvent.preventDefault(e);
+ if (e.pointerType !== 'mouse' && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) {
+ L.DomEvent.preventDefault(e);
+ }
var alreadyInArray = false;
for (var i = 0; i < pointers.length; i++) {
center = map.layerPointToLatLng(origin),
zoom = map.getScaleZoom(this._scale);
- map._animateZoom(center, zoom, this._startCenter, this._scale, this._delta);
+ map._animateZoom(center, zoom, this._startCenter, this._scale, this._delta, false, true);
},
_onTouchEnd: function () {
onRemove: function (map) {
map
- .off('layeradd', this._onLayerChange)
- .off('layerremove', this._onLayerChange);
+ .off('layeradd', this._onLayerChange, this)
+ .off('layerremove', this._onLayerChange, this);
},
addBaseLayer: function (layer, name) {
L.Map.include(!L.DomUtil.TRANSITION ? {} : {
- _catchTransitionEnd: function () {
- if (this._animatingZoom) {
+ _catchTransitionEnd: function (e) {
+ if (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) {
this._onZoomTransitionEnd();
}
},
return true;
},
- _animateZoom: function (center, zoom, origin, scale, delta, backwards) {
+ _animateZoom: function (center, zoom, origin, scale, delta, backwards, forTouchZoom) {
- this._animatingZoom = true;
+ if (!forTouchZoom) {
+ this._animatingZoom = true;
+ }
// put transform transition on all layers with leaflet-zoom-animated class
L.DomUtil.addClass(this._mapPane, 'leaflet-zoom-anim');
L.Draggable._disabled = true;
}
- this.fire('zoomanim', {
- center: center,
- zoom: zoom,
- origin: origin,
- scale: scale,
- delta: delta,
- backwards: backwards
- });
+ L.Util.requestAnimFrame(function () {
+ this.fire('zoomanim', {
+ center: center,
+ zoom: zoom,
+ origin: origin,
+ scale: scale,
+ delta: delta,
+ backwards: backwards
+ });
+ // horrible hack to work around a Chrome bug https://github.com/Leaflet/Leaflet/issues/3689
+ setTimeout(L.bind(this._onZoomTransitionEnd, this), 250);
+ }, this);
},
_onZoomTransitionEnd: function () {
+ if (!this._animatingZoom) { return; }
this._animatingZoom = false;
L.DomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim');
- this._resetView(this._animateToCenter, this._animateToZoom, true, true);
+ L.Util.requestAnimFrame(function () {
+ this._resetView(this._animateToCenter, this._animateToZoom, true, true);
- if (L.Draggable) {
- L.Draggable._disabled = false;
- }
+ if (L.Draggable) {
+ L.Draggable._disabled = false;
+ }
+ }, this);
}
});
// force reflow
L.Util.falseFn(bg.offsetWidth);
+ var zoom = this._map.getZoom();
+ if (zoom > this.options.maxZoom || zoom < this.options.minZoom) {
+ this._clearBgBuffer();
+ }
+
this._animating = false;
},