如何实现D3.js中竖线的水平移动及暂停/继续功能
实现可暂停/继续的竖线移动动画
好问题!D3的transition()方法本身确实没有内置的暂停/继续功能——它是设计成一次性完成的过渡流程。不过我们可以换个思路,用手动定时器控制的方式,自己计算每帧的位置更新,这样就能完全掌控动画的启停。
下面是完整的实现代码,我会一步步解释关键部分:
<html> <head> <script src="https://d3js.org/d3.v4.min.js"></script> </head> <body> <!-- 添加控制按钮 --> <button id="pauseBtn">pause</button> <button id="continueBtn">continue</button> <svg width="500" height="150"> <line x1="100" y1="20" x2="100" y2="120" stroke="black" stroke-width="2"/> </svg> <script> // 获取DOM元素 const line = d3.select("line"); const pauseBtn = d3.select("#pauseBtn"); const continueBtn = d3.select("#continueBtn"); // 动画配置参数 const startX = 100; // 起始X位置 const targetX = 400; // 目标X位置 const totalDuration = 2000; // 总时长(毫秒) let elapsedTime = 0; // 已流逝的时间 let timer = null; // 定时器对象 let isPaused = false; // 暂停状态标记 // 计算当前位置的线性插值函数 const interpolateX = d3.interpolate(startX, targetX); // 更新线条位置的函数 function updateLinePosition(timestamp) { // 如果是第一次启动,记录初始时间 if (!elapsedTime) elapsedTime = timestamp; // 计算已过去的时间(减去初始时间) const delta = timestamp - elapsedTime; // 计算进度(0到1之间) const progress = Math.min(delta / totalDuration, 1); // 获取当前X位置 const currentX = interpolateX(progress); // 更新线条的x1和x2属性 line.attr("x1", currentX).attr("x2", currentX); // 如果进度达到1,停止动画 if (progress >= 1) { timer.stop(); timer = null; } } // 启动/继续动画的函数 function startAnimation() { if (timer) return; // 避免重复启动 // 用d3.timer创建定时器,每帧调用updateLinePosition timer = d3.timer(updateLinePosition); isPaused = false; } // 暂停动画的函数 function pauseAnimation() { if (!timer || isPaused) return; // 停止定时器 timer.stop(); timer = null; isPaused = true; } // 绑定按钮事件 pauseBtn.on("click", pauseAnimation); continueBtn.on("click", startAnimation); // 初始启动动画 startAnimation(); </script> </body> </html>
关键部分解释:
- d3.timer:这个方法会创建一个和浏览器重绘节奏同步的定时器(基于requestAnimationFrame),比setInterval更适合动画场景,能保证流畅性。
- d3.interpolate:线性插值函数,帮我们根据进度(0到1)计算当前的X位置,确保动画是匀速的,和你之前用的
d3.easeLinear效果完全一致。 - 状态控制:用
elapsedTime记录已经流逝的时间,暂停时停止定时器,继续时重新启动定时器,这样动画会从暂停时的位置继续,而不是从头开始。 - 进度限制:用
Math.min(delta / totalDuration, 1)确保进度不会超过1,避免线条超出目标位置。
为什么不用transition?
D3的transition是一个封装好的过渡流程,一旦启动就会自动运行到结束,没有提供暂停、恢复的API。虽然可以通过interrupt()中断过渡,但中断后无法从当前位置继续,只能重新开始,所以手动控制定时器是更合适的方案。
内容的提问来源于stack exchange,提问作者Marbo
相关产品推荐
相关产品推荐

