smeijer / leaflet-geosearch

A geocoding/address-lookup library supporting various api providers.
https://smeijer.github.io/leaflet-geosearch/
MIT License
1.04k stars 273 forks source link

Performing a smooth pan-zoom animation , like leaflet flyTo not panTo #308

Closed dolorain closed 1 year ago

dolorain commented 2 years ago

As the title

Thanks

dolorain commented 2 years ago

@smeijer This is a function copy from leaflet.js, and it took me some time to understand. I think it replacing some of the code in the centerMap function (line 437) of SearchControl may achieve it. But I didn't try it, because I didn't figure out the correspondence between the if else functions of thecenterMap.

`

    // @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 || !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 = toLatLng(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 = 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, options.noMoveStart);

    frame.call(this);
    return this;
},

`

smeijer commented 2 years ago

If we want this functionality, we can simply call the flyTo method on the map instance. We don't need to copy all that code.

It should definitely be an option though. Not everyone prefers the long animation.