diff --git a/src/dom/DomUtil.js b/src/dom/DomUtil.js index d161b9dd..873b9557 100644 --- a/src/dom/DomUtil.js +++ b/src/dom/DomUtil.js @@ -1,5 +1,5 @@ /* - * L.DomUtil contains various utility functions for working with DOM + * L.DomUtil contains various utility functions for working with DOM. */ L.DomUtil = { @@ -8,48 +8,51 @@ L.DomUtil = { }, getStyle: function (el, style) { + var value = el.style[style]; + if (!value && el.currentStyle) { value = el.currentStyle[style]; } + if (!value || value === 'auto') { var css = document.defaultView.getComputedStyle(el, null); value = css ? css[style] : null; } - return (value === 'auto' ? null : value); + + return value === 'auto' ? null : value; }, getViewportOffset: function (element) { + var top = 0, left = 0, el = element, - docBody = document.body; + docBody = document.body, + pos; do { top += el.offsetTop || 0; left += el.offsetLeft || 0; + pos = L.DomUtil.getStyle(el, 'position'); - if (el.offsetParent === docBody && - L.DomUtil.getStyle(el, 'position') === 'absolute') { - break; - } - if (L.DomUtil.getStyle(el, 'position') === 'fixed') { - top += docBody.scrollTop || 0; + if (el.offsetParent === docBody && pos === 'absolute') { break; } + + if (pos === 'fixed') { + top += docBody.scrollTop || 0; left += docBody.scrollLeft || 0; break; } - el = el.offsetParent; + } while (el); el = element; do { - if (el === docBody) { - break; - } + if (el === docBody) { break; } - top -= el.scrollTop || 0; + top -= el.scrollTop || 0; left -= el.scrollLeft || 0; el = el.parentNode; @@ -59,15 +62,19 @@ L.DomUtil = { }, create: function (tagName, className, container) { + var el = document.createElement(tagName); el.className = className; + if (container) { container.appendChild(el); } + return el; }, disableTextSelection: function () { + if (document.selection && document.selection.empty) { document.selection.empty(); } @@ -94,12 +101,12 @@ L.DomUtil = { }, removeClass: function (el, name) { + function replaceFn(w, match) { - if (match === name) { - return ''; - } + if (match === name) { return ''; } return w; } + el.className = el.className .replace(/(\S+)\s*/g, replaceFn) .replace(/(^\s+|\s+$)/, ''); @@ -130,6 +137,7 @@ L.DomUtil = { }, testProp: function (props) { + var style = document.documentElement.style; for (var i = 0; i < props.length; i++) { @@ -141,7 +149,7 @@ L.DomUtil = { }, getTranslateString: function (point) { - // On webkit browsers (Chrome/Safari/MobileSafari/Android) using translate3d instead of translate + // 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 @@ -153,6 +161,7 @@ L.DomUtil = { }, getScaleString: function (scale, origin) { + var preTranslateStr = L.DomUtil.getTranslateString(origin), scaleStr = ' scale(' + scale + ') ', postTranslateStr = L.DomUtil.getTranslateString(origin.multiplyBy(-1)); @@ -160,8 +169,10 @@ L.DomUtil = { return preTranslateStr + scaleStr + postTranslateStr; }, - setPosition: function (el, point, disable3D) { + setPosition: function (el, point, disable3D) { // (HTMLElement, Point[, Boolean]) + el._leaflet_pos = point; + if (!disable3D && L.Browser.any3d) { el.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(point); @@ -176,14 +187,21 @@ L.DomUtil = { }, getPosition: function (el) { + // this method is only used for elements previously positioned using setPosition, + // so it's safe to cache the position for performance return el._leaflet_pos; } }; -L.Util.extend(L.DomUtil, { - TRANSITION: L.DomUtil.testProp(['transition', 'webkitTransition', 'OTransition', 'MozTransition', 'msTransition']), - TRANSFORM: L.DomUtil.testProp(['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']) -}); -L.DomUtil.TRANSITION_END = (L.DomUtil.TRANSITION === 'webkitTransition' || L.DomUtil.TRANSITION === 'OTransition' ? - L.DomUtil.TRANSITION + 'End' : 'transitionend'); +// prefix style property names + +L.DomUtil.TRANSFORM = L.DomUtil.testProp( + ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']); + +L.DomUtil.TRANSITION = L.DomUtil.testProp( + ['transition', 'webkitTransition', 'OTransition', 'MozTransition', 'msTransition']); + +L.DomUtil.TRANSITION_END = + L.DomUtil.TRANSITION === 'webkitTransition' || L.DomUtil.TRANSITION === 'OTransition' ? + L.DomUtil.TRANSITION + 'End' : 'transitionend'; diff --git a/src/geometry/Point.js b/src/geometry/Point.js index 7980e1af..318c0dff 100644 --- a/src/geometry/Point.js +++ b/src/geometry/Point.js @@ -8,10 +8,17 @@ L.Point = function (/*Number*/ x, /*Number*/ y, /*Boolean*/ round) { }; 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; @@ -22,35 +29,36 @@ L.Point.prototype = { return this.clone()._subtract(L.point(point)); }, - // destructive subtract (faster) _subtract: function (point) { this.x -= point.x; this.y -= point.y; return this; }, - divideBy: function (num, round) { - return new L.Point(this.x / num, this.y / num, round); + divideBy: function (num) { + return this.clone()._divideBy(num); }, - multiplyBy: function (num, round) { - return new L.Point(this.x * num, this.y * num, round); + _divideBy: function (num) { + this.x /= num; + this.y /= num; + return this; }, - distanceTo: function (point) { - point = L.point(point); + multiplyBy: function (num) { + return this.clone()._multiplyBy(num); + }, - var x = point.x - this.x, - y = point.y - this.y; - - return Math.sqrt(x * x + y * y); + _multiplyBy: function (num) { + this.x *= num; + this.y *= num; + return this; }, round: function () { return this.clone()._round(); }, - // destructive round _round: function () { this.x = Math.round(this.x); this.y = Math.round(this.y); @@ -67,8 +75,13 @@ L.Point.prototype = { return this; }, - clone: function () { - return new L.Point(this.x, this.y); + 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); }, toString: function () { diff --git a/src/layer/ImageOverlay.js b/src/layer/ImageOverlay.js index feac515c..74d463a0 100644 --- a/src/layer/ImageOverlay.js +++ b/src/layer/ImageOverlay.js @@ -94,10 +94,11 @@ L.ImageOverlay = L.Class.extend({ scale = map.getZoomScale(e.zoom), nw = this._bounds.getNorthWest(), se = this._bounds.getSouthEast(), + topLeft = map._latLngToNewLayerPoint(nw, e.zoom, e.center), - size = map._latLngToNewLayerPoint(se, e.zoom, e.center).subtract(topLeft), - currentSize = map.latLngToLayerPoint(se).subtract(map.latLngToLayerPoint(nw)), - origin = topLeft.add(size.subtract(currentSize).divideBy(2)); + size = map._latLngToNewLayerPoint(se, e.zoom, e.center)._subtract(topLeft), + currentSize = map.latLngToLayerPoint(se)._subtract(map.latLngToLayerPoint(nw)), + origin = topLeft._add(size._subtract(currentSize)._divideBy(2)); image.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(origin) + ' scale(' + scale + ') '; }, @@ -105,7 +106,7 @@ L.ImageOverlay = L.Class.extend({ _reset: function () { var image = this._image, topLeft = this._map.latLngToLayerPoint(this._bounds.getNorthWest()), - size = this._map.latLngToLayerPoint(this._bounds.getSouthEast()).subtract(topLeft); + size = this._map.latLngToLayerPoint(this._bounds.getSouthEast())._subtract(topLeft); L.DomUtil.setPosition(image, topLeft); diff --git a/src/layer/vector/Path.js b/src/layer/vector/Path.js index d1d6ce1f..c53948f9 100644 --- a/src/layer/vector/Path.js +++ b/src/layer/vector/Path.js @@ -104,8 +104,8 @@ L.Map.include({ var p = L.Path.CLIP_PADDING, size = this.getSize(), panePos = L.DomUtil.getPosition(this._mapPane), - min = panePos.multiplyBy(-1)._subtract(size.multiplyBy(p)), - max = min.add(size.multiplyBy(1 + p * 2)); + min = panePos.multiplyBy(-1)._subtract(size.multiplyBy(p)._round()), + max = min.add(size.multiplyBy(1 + p * 2)._round()); this._pathViewport = new L.Bounds(min, max); } diff --git a/src/layer/vector/Polyline.Edit.js b/src/layer/vector/Polyline.Edit.js index 78490495..ba2738ae 100644 --- a/src/layer/vector/Polyline.Edit.js +++ b/src/layer/vector/Polyline.Edit.js @@ -205,6 +205,6 @@ L.Handler.PolyEdit = L.Handler.extend({ p1 = map.latLngToLayerPoint(marker1.getLatLng()), p2 = map.latLngToLayerPoint(marker2.getLatLng()); - return map.layerPointToLatLng(p1._add(p2).divideBy(2)); + return map.layerPointToLatLng(p1._add(p2)._divideBy(2)); } }); diff --git a/src/map/Map.js b/src/map/Map.js index cd1a6cc8..a7c487e9 100644 --- a/src/map/Map.js +++ b/src/map/Map.js @@ -211,7 +211,7 @@ L.Map = L.Class.extend({ if (!this._loaded) { return this; } - var offset = oldSize.subtract(this.getSize()).divideBy(2, true); + var offset = oldSize._subtract(this.getSize())._divideBy(2)._round(); if (animate === true) { this.panBy(offset); @@ -318,7 +318,7 @@ L.Map = L.Class.extend({ this._sizeChanged = false; } - return this._size; + return this._size.clone(); }, getPixelBounds: function () { @@ -620,7 +620,7 @@ L.Map = L.Class.extend({ }, _getNewTopLeftPoint: function (center, zoom) { - var viewHalf = this.getSize().divideBy(2); + var viewHalf = this.getSize()._divideBy(2); // TODO round on display, not calculation to increase precision? return this.project(center, zoom)._subtract(viewHalf)._round(); }, @@ -631,7 +631,7 @@ L.Map = L.Class.extend({ }, _getCenterLayerPoint: function () { - return this.containerPointToLayerPoint(this.getSize().divideBy(2)); + return this.containerPointToLayerPoint(this.getSize()._divideBy(2)); }, _getCenterOffset: function (center) { diff --git a/src/map/anim/Map.ZoomAnimation.js b/src/map/anim/Map.ZoomAnimation.js index e36b7e6d..62bb1f02 100644 --- a/src/map/anim/Map.ZoomAnimation.js +++ b/src/map/anim/Map.ZoomAnimation.js @@ -17,7 +17,7 @@ L.Map.include(!L.DomUtil.TRANSITION ? {} : { if (!this.options.zoomAnimation) { return false; } var scale = this.getZoomScale(zoom), - offset = this._getCenterOffset(center).divideBy(1 - 1 / scale); + offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale); // if offset does not exceed half of the view if (!this._offsetIsWithinView(offset, 1)) { return false; } diff --git a/src/map/handler/Map.Drag.js b/src/map/handler/Map.Drag.js index be2dbb59..1344853a 100644 --- a/src/map/handler/Map.Drag.js +++ b/src/map/handler/Map.Drag.js @@ -80,7 +80,7 @@ L.Map.Drag = L.Handler.extend({ }, _onViewReset: function () { - var pxCenter = this._map.getSize().divideBy(2), + var pxCenter = this._map.getSize()._divideBy(2), pxWorldCenter = this._map.latLngToLayerPoint(new L.LatLng(0, 0)); this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x; diff --git a/src/map/handler/Map.ScrollWheelZoom.js b/src/map/handler/Map.ScrollWheelZoom.js index 905a1c54..329c0caf 100644 --- a/src/map/handler/Map.ScrollWheelZoom.js +++ b/src/map/handler/Map.ScrollWheelZoom.js @@ -41,17 +41,17 @@ L.Map.ScrollWheelZoom = L.Handler.extend({ if (!delta) { return; } var newZoom = zoom + delta, - newCenter = this._getCenterForScrollWheelZoom(this._lastMousePos, newZoom); + newCenter = this._getCenterForScrollWheelZoom(newZoom); map.setView(newCenter, newZoom); }, - _getCenterForScrollWheelZoom: function (mousePos, newZoom) { + _getCenterForScrollWheelZoom: function (newZoom) { var map = this._map, scale = map.getZoomScale(newZoom), - viewHalf = map.getSize().divideBy(2), - centerOffset = mousePos.subtract(viewHalf).multiplyBy(1 - 1 / scale), - newCenterPoint = map._getTopLeftPoint().add(viewHalf).add(centerOffset); + viewHalf = map.getSize()._divideBy(2), + centerOffset = this._lastMousePos._subtract(viewHalf)._multiplyBy(1 - 1 / scale), + newCenterPoint = map._getTopLeftPoint()._add(viewHalf)._add(centerOffset); return map.unproject(newCenterPoint); } diff --git a/src/map/handler/Map.TouchZoom.js b/src/map/handler/Map.TouchZoom.js index db9b4d13..b74c468c 100644 --- a/src/map/handler/Map.TouchZoom.js +++ b/src/map/handler/Map.TouchZoom.js @@ -24,7 +24,7 @@ L.Map.TouchZoom = L.Handler.extend({ p2 = map.mouseEventToLayerPoint(e.touches[1]), viewCenter = map._getCenterLayerPoint(); - this._startCenter = p1.add(p2).divideBy(2, true); + this._startCenter = p1._add(p2)._divideBy(2); this._startDist = p1.distanceTo(p2); this._moved = false; @@ -48,7 +48,7 @@ L.Map.TouchZoom = L.Handler.extend({ p2 = map.mouseEventToLayerPoint(e.touches[1]); this._scale = p1.distanceTo(p2) / this._startDist; - this._delta = p1.add(p2).divideBy(2, true).subtract(this._startCenter); + this._delta = p1._add(p2)._divideBy(2)._subtract(this._startCenter); if (this._scale === 1) { return; }