Calculating fractional zoom using Leaflet

325 Views Asked by At

I'm working on getting deck.gl to work alongside Leaflet (https://github.com/visgl/deck.gl/issues/5588).

Basically, when the Leaflet map pans or zooms, the deck.gl view needs to be synced so that things render in the right places. This seems to be working okay here: https://codepen.io/clebal/pen/rNjdzzr

It's using the map bounds to update deck.gl. As is apparent in the codepen, this doesn't work well during zoom (deck.gl doesn't animate alongside Leaflet).

My understanding is that Leaflet animates using CSS so there really aren't any intermediate states to tap into.

A workaround I've seen is to override the internal _animateMove method and call and use timers to update deck.gl periodically throughout the 250ms Leaflet takes to finish the zoom animation.

This part is all relatively straightforward, the challenge I'm facing is how to actually calculating what the bounding box would be at a fractional zoom. e.g. 25ms into the animation (making the simplifying assumption that the CSS animation is linear which isn't actually the case), I'd need to be able to calculate what the bounding box for a map at zoom 11.10 would be (the map itself doesn't need to update). I can hopefully then use this bounding box to perform the calculations on the deck.gl side.

Does Leaflet support this calculation out of the box? Is there any code in the Leaflet codebase I can reference to help achieve this (or even using external tools like turf, etc)?

1

There are 1 best solutions below

1
On

My understanding is that Leaflet animates using CSS so there really aren't any intermediate states to tap into.

That's right. Leaflet expects its layers to redraw in full once the CSS zoom animation has ended.

So the Leaflet-y way of approaching this problem is to not update your deck.gl canvas during a CSS zoom animation; and the way to do that is to have two paths of updating the center & bounds of your canvas: one during zoom events and one during animzoom events.

The key to understanding how that works is on this fragment of code from L.Renderer:

_onAnimZoom: function (ev) {
    this._updateTransform(ev.center, ev.zoom);
},

_onZoom: function () {
    this._updateTransform(this._map.getCenter(), this._map.getZoom());
},

So, in one case you trust the map's center and zoom, and in the other case you trust a cached center+zoom, and you let the CSS transform resize your deck.gl canvas.

Does Leaflet support this calculation out of the box? Is there any code in the Leaflet codebase I can reference to help achieve this ?

No; but do look at https://github.com/mapbox/unitbezier instead.

You probably want to instantiate a unitbezier curve like unitBezier(0, 0, 0.25, 1) (note the similarity to the transition: cubic-bezier(0,0,0.25,1); CSS code), and then solve that curve for values within 0 and 1, depending on how far into the animation you are.

Be aware that this technique might lag your graphics one frame after/behind the Leaflet CSS animation.