Skip to content

D3.js - 形状 API

D3.js 提供了一个强大的模块 d3-shape,用于生成各种图形形状(如圆弧 [用于饼图/环形图]、线 [用于折线图] 和区域 [用于面积图])的 SVG 路径数据。这些形状生成器(shape generator)接收数据,并返回 SVG <path> 元素的 d 属性所需的字符串值。

要使用 D3.js 形状 API,需要在 HTML 文件中引入 D3.js 库。最简单的方法是使用 CDN(内容分发网络)上的完整 D3 包,其中包含 d3-shape 及其依赖 d3-path。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D3.js Shapes API Example</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<svg id="visualization" width="400" height="300"></svg>
<script>
// Your D3.js code using d3-shape will go here
</script>
</body>
</html>

D3.js 提供了几种形状生成器。让我们探索一些主要的。

圆弧生成器(d3.arc())用于生成圆形或环形扇区的路径数据,常用于饼图和环形图。

  • d3.arc(): 创建一个使用默认设置的新圆弧生成器。
  • arc(dataObject): 为圆弧生成路径字符串。dataObject 通常需要 innerRadius、outerRadius、startAngle 和 endAngle 等属性。例如:
  • { innerRadius: 0, outerRadius: 100, startAngle: 0, endAngle: Math.PI / 2 } 会定义一个四分之一圆。
  • arc.innerRadius([radius]): 设置或获取内半径。radius 可以是一个常数,也可以是一个接收数据并返回值的函数。默认访问器(accessor)为:function innerRadius(d) { return d.innerRadius; }。
  • arc.outerRadius([radius]): 设置或获取外半径。默认访问器为:function outerRadius(d) { return d.outerRadius; }。
  • arc.startAngle([angle]): 设置或获取起始角度(以弧度为单位)。默认访问器为:function startAngle(d) { return d.startAngle; }。
  • arc.endAngle([angle]): 设置或获取结束角度(以弧度为单位)。默认访问器为:function endAngle(d) { return d.endAngle; }。
  • arc.padAngle([angle]): 设置或获取圆弧之间的填充角度(pad angle,用于分隔饼图扇区)。默认访问器为:function padAngle(d) { return d && d.padAngle; }。
  • arc.cornerRadius([radius]): 设置或获取圆角半径(corner radius),用于使圆弧的角变圆润。对于样式效果很有帮助。
  • arc.centroid(dataObject): 计算圆弧中心线的中心点 [x, y]。对于放置标签很有用。

示例用法:

const arcGenerator = d3.arc()
.innerRadius(50)
.outerRadius(100)
.startAngle(0)
.endAngle(Math.PI / 2); // 一个四分之一的环形扇区
const pathData = arcGenerator(); // 生成具有固定值的单个圆弧的路径字符串
// 或者,如果绑定了数据:
// const pathData = arcGenerator(dataObjectForArc);
d3.select("#visualization").append("path")
.attr("d", pathData)
.attr("transform", "translate(150, 150)") // 定位圆弧
.attr("fill", "steelblue");

饼图生成器(d3.pie())本身不绘制任何内容。它接收一个数据数组,并计算饼图每个扇区所需的起始角度(start angle)和结束角度(end angle)。d3.pie() 的输出通常会传递给 d3.arc(),用于生成每个扇区的实际路径数据。

  • d3.pie(): 构造一个使用默认设置的新饼图生成器。
  • pie(dataArray): 计算给定 dataArray 的角度。它返回一个对象数组,其中每个对象代表一个扇区,并包含:
  • data: 该扇区的原始输入数据项。
  • value: 扇区的数值(用于角度计算)。
  • index: 数据项的原始索引。
  • startAngle: 计算出的扇区起始角度。
  • endAngle: 计算出的扇区结束角度。
  • padAngle: 填充角度(如果在饼图生成器上设置)。
  • pie.value([accessor]): 设置或获取从每个数据元素中提取数值的访问器函数。默认值:function value(d) { return d; }。
  • pie.sort([comparator]): 设置或获取用于按原始数据对象对扇区进行排序的比较器(comparator)函数。设置为 null 可保留输入顺序。
  • pie.sortValues([comparator]): 设置或获取用于按计算出的数值对扇区进行排序的比较器函数。设置为 null 可保留输入顺序。默认为降序。
  • pie.startAngle([angle]): 设置或获取饼图的整体起始角度(例如,0 表示 12 点钟方向)。
  • pie.endAngle([angle]): 设置或获取饼图的整体结束角度(例如,2 * Math.PI 表示一个整圆)。
  • pie.padAngle([angle]): 设置或获取用于分隔扇区的角度。

与 d3.arc 配合使用的示例用法:

const dataset = [10, 20, 30, 40];
const pieGenerator = d3.pie();
const arcData = pieGenerator(dataset);
// arcData 现在是一个包含 startAngle, endAngle 等属性的对象数组
// 例如,[{data: 10, value: 10, index: 0, startAngle: ..., endAngle: ..., padAngle:...}, ...]
const arcGeneratorForPie = d3.arc().innerRadius(0).outerRadius(100);
d3.select("#visualization")
.selectAll(".pieSlice")
.data(arcData)
.enter()
.append("path")
.attr("class", "pieSlice")
.attr("d", arcGeneratorForPie)
.attr("fill", (d, i) => d3.schemeCategory10[i])
.attr("transform", "translate(150, 150)");

线生成器(d3.line())用于生成折线的路径数据,这对于折线图至关重要。

  • d3.line(): 创建一个新的线生成器。
  • line(dataArray): 根据数据点数组生成线的路径字符串。dataArray 中的每个点通常包含 x 和 y 分量。
  • line.x([accessor]): 设置或获取每个点 x 坐标的访问器。默认值:function x(d) { return d[0]; }(假设点是 [x, y] 数组)。
  • line.y([accessor]): 设置或获取每个点 y 坐标的访问器。默认值:function y(d) { return d[1]; }。
  • line.defined([accessor]): 设置或获取一个访问器,用于控制一个点是否被定义。如果一个点是 undefined,线将在此处断开。默认值:function defined() { return true; }。
  • line.curve([curveType]): 设置或获取用于绘制点之间线的插值策略(interpolation strategy)(例如,d3.curveLinear、d3.curveBasis、d3.curveStep)。
  • line.context([canvasContext]): 如果直接绘制到 Canvas 2D API,则设置渲染上下文(rendering context)(对于 SVG 较少使用)。

示例用法:

const lineData = [ [0, 80], [100, 100], [200, 30], [300, 50], [400, 40] ];
const lineGenerator = d3.line(); // 使用默认的 x 和 y 访问器
// 或者,如果数据是一个对象数组:
// const lineData = [ {xVal:0, yVal:80}, {xVal:100, yVal:100}, ... ];
// const lineGenerator = d3.line()
// .x(d => d.xVal)
// .y(d => d.yVal);
const pathString = lineGenerator(lineData);
d3.select("#visualization").append("path")
.attr("d", pathString)
.attr("fill", "none")
.attr("stroke", "green");

d3.lineRadial() 与 d3.line() 类似,但它生成的是极坐标(角度和半径)而不是笛卡尔坐标(x 和 y)下的线。对于雷达图或螺旋图很有用。

  • d3.lineRadial(): 创建一个新的径向线生成器。
  • lineRadial.angle([accessor]): 设置或获取角度(以弧度为单位)的访问器。
  • lineRadial.radius([accessor]): 设置或获取半径(与原点的距离)的访问器。

这些形状生成器是 D3.js 中创建常见图表类型的基本工具,它们简化了复杂 SVG 路径数据的构建。