Skip to content

D3.js - 定时器 API

D3 定时器 API 模块 (d3-timer) 用于管理动画和其他基于时间的任务。它利用浏览器的 requestAnimationFrame API 来实现高效、同步的动画,这些动画在页面不活跃时表现良好并节省资源。

window.requestAnimationFrame() 是一个浏览器方法,它告诉浏览器你希望执行一个动画。它请求浏览器为下一个动画帧调度一次窗口重绘。浏览器会在下一次重绘之前调用你指定的 callback 函数来更新动画。D3 的定时器模块为这个机制提供了一个更高层级的接口。

如果你使用完整的 D3 包,则包含定时器 API。对于模块化使用,你需要导入 d3-timer。

<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<script>
// Example: A simple timer
const myTimer = d3.timer(function(elapsed) {
console.log("Elapsed time:", elapsed, "ms");
if (elapsed > 2000) {
myTimer.stop(); // Stop the timer after 2 seconds
console.log("Timer stopped.");
}
});
</script>
</body>
</html>

在模块化环境中使用:

import { timer, now, timeout, interval } from 'd3-timer';

d3-timer 模块提供了以下关键方法:

返回当前时间,优先使用 performance.now()(如果可用),否则使用 Date.now()。这是定时器使用的高精度时间。

调度一个新的定时器,重复调用指定的 callback 函数。callback 函数会接收一个参数,表示自定时器开始以来(或自指定的 time 以来)经过的时间。

  • delay (可选,数字):第一次调用前的初始延迟(毫秒)。默认为零。
  • time (可选,数字):定时器应该开始的时间点(基于 d3.now())。默认为 d3.now() 加上 delay。 定时器会一直运行,直到调用 timer.stop() 方法。返回定时器对象。

用新的 callback 函数和可选的 delay 及 time 重新启动一个现有的定时器。这对于重用定时器对象很有用。

停止定时器,阻止后续调用其 callback 函数。

类似于 d3.timer,但定时器在第一次调用 callback 函数后会自动停止。这是使用 requestAnimationFrame 实现 setTimeout 行为的一种方便的简写方式。callback 函数会接收经过的时间作为参数。

调度一个定时器,以指定的 delay 间隔重复调用 callback 函数。

  • delay (可选,数字):两次调用之间的间隔(毫秒)。如果未指定,定时器最初的行为类似于 d3.timer,在每一帧都调用。常见用法是 d3.interval(callback, 1000),表示每秒运行一次。
  • time (可选,数字):定时器应该开始的时间点。 callback 函数会接收经过的时间作为参数。返回定时器对象。

创建一个 HTML 文件,命名为 timer_example.html,并添加以下脚本。此示例演示了 d3.timer、d3.timeout 和 d3.interval。

<!DOCTYPE html>
<html>
<head>
<title>D3.js Timer API Example</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body { font-family: sans-serif; }
.log { margin-bottom: 10px; padding: 5px; border: 1px solid #eee; }
</style>
</head>
<body>
<h3>D3.js Timer API Demonstration</h3>
<div id="output"></div>
<script>
const outputDiv = d3.select("#output");
outputDiv.append("p").attr("class", "log").text("Starting d3.timer (stops after 150ms elapsed from its start)");
const continuousTimer = d3.timer(function(elapsed) {
outputDiv.append("p").text(`d3.timer: ${elapsed.toFixed(2)} ms`);
if (elapsed > 150) {
continuousTimer.stop();
outputDiv.append("p").attr("class", "log").text("d3.timer stopped.");
}
}, 50); // Start after 50ms delay
outputDiv.append("p").attr("class", "log").text("Starting d3.timeout (runs once after 500ms)");
d3.timeout(function(elapsed) {
outputDiv.append("p").text(`d3.timeout: Ran after ${elapsed.toFixed(2)} ms`);
}, 500);
outputDiv.append("p").attr("class", "log").text("Starting d3.interval (runs every 300ms, 3 times)");
let intervalCount = 0;
const repeatingInterval = d3.interval(function(elapsed) {
intervalCount++;
outputDiv.append("p").text(`d3.interval (call ${intervalCount}): ${elapsed.toFixed(2)} ms`);
if (intervalCount >= 3) {
repeatingInterval.stop();
outputDiv.append("p").attr("class", "log").text("d3.interval stopped.");
}
}, 300); // Run every 300ms
</script>
</body>
</html>

在浏览器中打开这个 HTML 文件。当每个定时器触发和停止时,你会在页面上看到相应的日志消息,这展示了它们的不同行为。如果遇到问题,请检查浏览器的控制台,查看是否有错误或额外的 D3 日志。