You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:15:27