leaflet
Version:
JavaScript library for mobile-friendly interactive maps
94 lines (72 loc) • 2.78 kB
JavaScript
// @namespace Map
// @section Methods for modifying map state
L.Map.include({
// @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this
// Sets the view of the map (geographical center and zoom) performing a smooth
// pan-zoom animation.
flyTo: function (targetCenter, targetZoom, options) {
options = options || {};
if (options.animate === false || !L.Browser.any3d) {
return this.setView(targetCenter, targetZoom, options);
}
this._stop();
var from = this.project(this.getCenter()),
to = this.project(targetCenter),
size = this.getSize(),
startZoom = this._zoom;
targetCenter = L.latLng(targetCenter);
targetZoom = targetZoom === undefined ? startZoom : targetZoom;
var w0 = Math.max(size.x, size.y),
w1 = w0 * this.getZoomScale(startZoom, targetZoom),
u1 = (to.distanceTo(from)) || 1,
rho = 1.42,
rho2 = rho * rho;
function r(i) {
var s1 = i ? -1 : 1,
s2 = i ? w1 : w0,
t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1,
b1 = 2 * s2 * rho2 * u1,
b = t1 / b1,
sq = Math.sqrt(b * b + 1) - b;
// workaround for floating point precision bug when sq = 0, log = -Infinite,
// thus triggering an infinite loop in flyTo
var log = sq < 0.000000001 ? -18 : Math.log(sq);
return log;
}
function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }
function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }
function tanh(n) { return sinh(n) / cosh(n); }
var r0 = r(0);
function w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); }
function u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; }
function easeOut(t) { return 1 - Math.pow(1 - t, 1.5); }
var start = Date.now(),
S = (r(1) - r0) / rho,
duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8;
function frame() {
var t = (Date.now() - start) / duration,
s = easeOut(t) * S;
if (t <= 1) {
this._flyToFrame = L.Util.requestAnimFrame(frame, this);
this._move(
this.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),
this.getScaleZoom(w0 / w(s), startZoom),
{flyTo: true});
} else {
this
._move(targetCenter, targetZoom)
._moveEnd(true);
}
}
this._moveStart(true);
frame.call(this);
return this;
},
// @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
// Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
// but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
flyToBounds: function (bounds, options) {
var target = this._getBoundsCenterZoom(bounds, options);
return this.flyTo(target.center, target.zoom, options);
}
});