原文(持续更新):datavis-note.benbinbin.com/article/d3/…
系列文章可以查看《数据可视化》专栏
这个系列的文章主要是学习 D3 在 Observable 中的官方样例,逐行 line-by-line 解读样例代码,并在 Codepen 中复现这些基础、常见的图表。在对原始例子的代码解读后,可能进行适度的简化,让实现代码更精简和通用。此外也可能对样例进行拓展,对于静态图表可能会尝试添加交互功能。
主要参考:
💡 由于 Observable 类似于 Jupyter Notebook,其代码是分为一个个 Cell,而且代码不仅仅包含 JavaScript(有一些方法并不是 D3 模块的 API,而是 Observable 平台内置的专属方法,例如导入文件的方法,并不是使用 d3-fetch 模块)还有一些类似于 HTML 的模板语法,而且存在跨页面的函数、数据引用,所以代码不能直接复制搬运,在系列文章中一般会先基于原始的代码进行修改再解读。
配置
首先最基本的一个操作是要在项目中引入 D3。
在 Observable 中提供了一个标准库 standard library,便于实现一些基础功能。其中一个常用的功能是监听页面的大小调整,同步更新图表的宽度,这是实现响应式图表的基础,参考其源码写出一个类似的方法:
// 获取页面宽度
let width = document.documentElement.clientWidth;
console.log("init width: ", width);
// 为了优化性能,在核心代码外包了一层防抖函数
// 默认延迟时间是 300 毫秒
let timer = null;
function debounce(delay = 300) {
if (timer) {
// (如果倒计时的时间未到,而再次触发 debounce 函数)阻止计时器执行回调函数
clearTimeout(timer);
}
// 重新设置计时器,倒计时重新计算
timer = setTimeout(function () {
// 经过延迟后,执行核心代码
// 修改变量 width(存储当前页面的宽度信息)
const w = document.documentElement.clientWidth; // 也可以是 SVG 元素的宽度,可以将该元素的宽度设置为 width: 100%,让它随页面缩放而变换
if (w !== width) width = w;
console.log(width);
// 执行完核心代码后,清空计时器 timer
timer = null;
}, delay);
}
function resized() {
// 实际使用防抖函数时,可以设置延迟时间
// 这里设置为延迟 500 毫秒
debounce(500);
}
// 监听页面调整大小时分发的 resize 事件
function setListener() {
window.addEventListener("resize", resized);
return function removeListener() {
window.removeEventListener("resize", resized);
};
}
const removeListener = setListener();
// 当需要时调用方法注销监听器(例如移除图表时)
// removeListener()
⚙️ 代码具体演示效果可以查看这个 Codepen
在进行数据可视化前,需要有数据文件。该系列文章的数据来源于相应的官方示例的附件,对于小型的数据文件,我一般会从 Observable 下载下来后,再上传到 Github Gist 进行托管,而不是直接将数据内嵌到 JS 脚本中(可以模拟真实的开发环境,使用 d3-fetch 模块来读取数据文件,让代码更通用);由于 Github Gist 的限制,较大的文件(大于 10Mb)会采取其他方式导入项目中。