LeafletJS 1.3.1:如何在缩放动画中获取缩放增量或进度百分比?
在Leaflet 1.3.1中缩放动画期间获取进度并重绘内容
我完全懂你的困扰——Leaflet原生的缩放相关事件确实不会在动画过程中重复触发,这对需要实时跟随缩放进度更新内容的场景来说太不友好了。不过别担心,我们可以利用Leaflet内部的动画机制,手动计算出和原生动画完全同步的缩放进度,结合requestAnimationFrame来实现流畅的实时重绘。
下面是具体的实现思路和代码:
核心思路
Leaflet在执行缩放动画时,会内部计算从起始缩放级别到目标级别的插值过程。我们可以通过zoomanim事件获取动画的关键参数(起始缩放、目标缩放、持续时长),然后用requestAnimationFrame跟踪动画进度,再用Leaflet内置的缓动函数计算出和原生动画一致的插值缩放级别,最后用这个级别来重绘你的内容。
完整代码示例
let animFrameId; let animStartTimestamp; let animStartZoom; let animEndZoom; let animDuration; // 监听缩放动画开始事件,记录关键参数 map.on('zoomanim', function(e) { animStartTimestamp = Date.now(); animStartZoom = e.startZoom; animEndZoom = e.endZoom; animDuration = e.duration; // 启动实时更新循环 updateContentDuringZoom(); }); // 监听缩放动画结束,停止循环并做最终修正 map.on('zoomend', function() { if (animFrameId) { cancelAnimationFrame(animFrameId); animFrameId = null; } // 确保内容和最终缩放级别完全匹配 updateYourContent(map.getZoom()); }); // 实时更新逻辑 function updateContentDuringZoom() { const elapsedTime = Date.now() - animStartTimestamp; let progress = elapsedTime / animDuration; // 防止进度超过1(比如动画提前结束) progress = Math.min(progress, 1); // 使用Leaflet内置的缓动函数,和原生动画曲线保持一致 const easedProgress = L.Map._ease(progress); // 计算当前的插值缩放级别 const currentZoom = animStartZoom + (animEndZoom - animStartZoom) * easedProgress; // 在这里执行你的重绘逻辑 updateYourContent(currentZoom); // 如果动画未结束,继续下一帧更新 if (progress < 1) { animFrameId = requestAnimationFrame(updateContentDuringZoom); } } // 替换成你自己的重绘函数 function updateYourContent(currentZoom) { // 示例:打印当前插值缩放级别 console.log('当前实时缩放级别:', currentZoom); // 这里写你的具体重绘逻辑,比如更新自定义图层的样式、位置等 // 例如:yourCustomLayer.update(currentZoom); }
关键细节说明
zoomanim事件:这个事件会在缩放动画启动时触发一次,它的参数里包含了我们需要的所有动画基础数据:startZoom(起始缩放级别)、endZoom(目标缩放级别)、duration(动画持续时长,单位毫秒)。- Leaflet内置缓动函数:
L.Map._ease是Leaflet原生缩放动画使用的缓动函数,用它处理进度可以保证我们的自定义重绘和原生动画的节奏完全一致,避免出现错位。 requestAnimationFrame:相比定时器,它会和浏览器的刷新频率同步,让重绘动画更流畅,不会出现卡顿或跳帧。zoomend收尾:在动画结束时停止循环,并强制用最终的实际缩放级别重绘一次,确保内容完全准确。
需要注意的是,L.Map._ease是Leaflet的私有方法,但在1.3.1版本中这个方法是稳定存在的,足以满足你的需求。
内容的提问来源于stack exchange,提问作者filimonic
相关产品推荐
相关产品推荐

