cleanup and prettify animation code, more comments

This commit is contained in:
Vladimir Agafonkin 2013-02-22 17:29:52 +02:00
parent 9c2e7cfbd4
commit a2890d6c4b
3 changed files with 56 additions and 50 deletions

View File

@ -691,12 +691,14 @@ L.Map = L.Class.extend({
return this.project(latlng, newZoom)._subtract(topLeft); return this.project(latlng, newZoom)._subtract(topLeft);
}, },
// layer point of the current center
_getCenterLayerPoint: function () { _getCenterLayerPoint: function () {
return this.containerPointToLayerPoint(this.getSize()._divideBy(2)); return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
}, },
_getCenterOffset: function (center) { // offset of the specified place to the current center in pixels
return this.latLngToLayerPoint(center).subtract(this._getCenterLayerPoint()); _getCenterOffset: function (latlng) {
return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());
}, },
_limitZoom: function (zoom) { _limitZoom: function (zoom) {

View File

@ -5,38 +5,43 @@
L.Map.include({ L.Map.include({
setView: function (center, zoom, forceReset) { setView: function (center, zoom, forceReset) {
zoom = this._limitZoom(zoom); zoom = this._limitZoom(zoom);
center = L.latLng(center); center = L.latLng(center);
var zoomChanged = (this._zoom !== zoom); if (this._panAnim) {
this._panAnim.stop();
}
if (this._loaded && !forceReset && this._layers) { var zoomChanged = (this._zoom !== zoom),
canBeAnimated = this._loaded && !forceReset && !!this._layers;
if (this._panAnim) { if (canBeAnimated) {
this._panAnim.stop();
}
var done = (zoomChanged ? // try animating pan or zoom
this._zoomToIfClose && this._zoomToIfClose(center, zoom) : var animated = zoomChanged && this.options.zoomAnimation ?
this._panByIfClose(center)); this._animateZoomIfClose && this._animateZoomIfClose(center, zoom) :
this._animatePanIfClose(center);
// exit if animated pan or zoom started if (animated) {
if (done) { // prevent resize handler call, the view will refresh after animation anyway
clearTimeout(this._sizeTimer); clearTimeout(this._sizeTimer);
return this; return this;
} }
} }
// reset the map view // animation didn't start, just reset the map view
this._resetView(center, zoom); this._resetView(center, zoom);
return this; return this;
}, },
panBy: function (offset, duration, easeLinearity, moving) { panBy: function (offset, duration, easeLinearity, noMoveStart) {
offset = L.point(offset); offset = L.point(offset).round();
if (!(offset.x || offset.y)) { // TODO add options instead of arguments to setView/panTo/panBy/etc.
if (!offset.x && !offset.y) {
return this; return this;
} }
@ -49,13 +54,14 @@ L.Map.include({
}, this); }, this);
} }
if (moving !== true) { // don't fire movestart if animating inertia
if (!noMoveStart) {
this.fire('movestart'); this.fire('movestart');
} }
L.DomUtil.addClass(this._mapPane, 'leaflet-pan-anim'); L.DomUtil.addClass(this._mapPane, 'leaflet-pan-anim');
var newPos = L.DomUtil.getPosition(this._mapPane).subtract(offset)._round(); var newPos = this._getMapPanePos().subtract(offset);
this._panAnim.run(this._mapPane, newPos, duration || 0.25, easeLinearity); this._panAnim.run(this._mapPane, newPos, duration || 0.25, easeLinearity);
return this; return this;
@ -70,22 +76,13 @@ L.Map.include({
this.fire('moveend'); this.fire('moveend');
}, },
_panByIfClose: function (center) { _animatePanIfClose: function (center) {
// difference between the new and current centers in pixels // difference between the new and current centers in pixels
var offset = this._getCenterOffset(center)._floor(); var offset = this._getCenterOffset(center)._floor();
if (this._offsetIsWithinView(offset)) { if (!this.getSize().contains(offset)) { return false; }
this.panBy(offset);
return true;
}
return false;
},
_offsetIsWithinView: function (offset, multiplyFactor) { this.panBy(offset);
var m = multiplyFactor || 1, return true;
size = this.getSize();
return (Math.abs(offset.x) <= size.x * m) &&
(Math.abs(offset.y) <= size.y * m);
} }
}); });

View File

@ -7,31 +7,39 @@ L.Map.mergeOptions({
}); });
if (L.DomUtil.TRANSITION) { if (L.DomUtil.TRANSITION) {
L.Map.addInitHook(function () { L.Map.addInitHook(function () {
// zoom transitions run with the same duration for all layers, so if one of transitionend events
// happens after starting zoom animation (propagating to the map pane), we know that it ended globally
L.DomEvent.on(this._mapPane, L.DomUtil.TRANSITION_END, this._catchTransitionEnd, this); L.DomEvent.on(this._mapPane, L.DomUtil.TRANSITION_END, this._catchTransitionEnd, this);
}); });
} }
L.Map.include(!L.DomUtil.TRANSITION ? {} : { L.Map.include(!L.DomUtil.TRANSITION ? {} : {
_zoomToIfClose: function (center, zoom) { _catchTransitionEnd: function () {
if (this._animatingZoom) {
this._onZoomTransitionEnd();
}
},
_animateZoomIfClose: function (center, zoom) {
if (this._animatingZoom) { return true; } if (this._animatingZoom) { return true; }
if (!this.options.zoomAnimation) { return false; } // offset is the pixel coords of the zoom origin relative to the current center
var scale = this.getZoomScale(zoom), var scale = this.getZoomScale(zoom),
offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale); offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale),
origin = this._getCenterLayerPoint()._add(offset);
// if offset does not exceed half of the view // only animate if the zoom origin is within one screen from the current center
if (!this._offsetIsWithinView(offset, 1)) { return false; } if (!this.getSize().contains(offset)) { return false; }
this this
.fire('movestart') .fire('movestart')
.fire('zoomstart'); .fire('zoomstart');
var origin = this._getCenterLayerPoint().add(offset);
this._animateZoom(center, zoom, origin, scale); this._animateZoom(center, zoom, origin, scale);
return true; return true;
@ -39,12 +47,16 @@ L.Map.include(!L.DomUtil.TRANSITION ? {} : {
_animateZoom: function (center, zoom, origin, scale, delta, backwards) { _animateZoom: function (center, zoom, origin, scale, delta, backwards) {
L.DomUtil.addClass(this._mapPane, 'leaflet-zoom-anim');
this._animateToCenter = center;
this._animateToZoom = zoom;
this._animatingZoom = true; this._animatingZoom = true;
// put transform transition on all layers with leaflet-zoom-animated class
L.DomUtil.addClass(this._mapPane, 'leaflet-zoom-anim');
// remember what center/zoom to set after animation
this._animateToCenter = center;
this._animateToZoom = zoom;
// disable any dragging during animation
if (L.Draggable) { if (L.Draggable) {
L.Draggable._disabled = true; L.Draggable._disabled = true;
} }
@ -59,17 +71,12 @@ L.Map.include(!L.DomUtil.TRANSITION ? {} : {
}); });
}, },
_catchTransitionEnd: function () {
if (this._animatingZoom) {
this._onZoomTransitionEnd();
}
},
_onZoomTransitionEnd: function () { _onZoomTransitionEnd: function () {
this._animatingZoom = false;
L.DomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim'); L.DomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim');
this._animatingZoom = false;
this._resetView(this._animateToCenter, this._animateToZoom, true, true); this._resetView(this._animateToCenter, this._animateToZoom, true, true);
if (L.Draggable) { if (L.Draggable) {