本文详解D3.js中折线图的实现原理,重点解析x轴比例尺scalePoint与scaleBand的区别,以及d3.line和d3.area生成器的配置方法。通过代码示例展示如何定义坐标、设置曲线插值及填充区域,并探讨数据排序对图形渲染的影响,帮助开发者快速掌握D3可视化核心技巧。
本章将演示折线图的实现过程。基于此前柱状图的绘制经验,可以发现两者差异主要在于x轴比例尺的选择以及数据图形的绘制方式,而画布与坐标轴等其他元素的处理逻辑基本一致,此处不再赘述。
点击查看demo

x轴比例尺
针对折线图x轴的特征,我们需要在x轴上绘制间隔均匀的N个点,因此应当选用scalePoint。
const xScale = d3.scalePoint()
.domain(data.map((d) => d.name))
.range([0, dimensions.boundedWidth]);

若错误地使用scaleBand,则会出现刻度和数据点无法对齐的情况,如下图所示。

数据折线
D3提供了几种图形构造器,如d3.line、d3.area、d3.arc和d3.pie等。本章将重点介绍d3.line与d3.area的使用方法。
d3.line
利用点位二维数组自动生成path路径:
// 构建一个默认为直线的线条绘制器
const lineGenerator = d3.line();
// 定义一下点位
const points = [
[0, 50],
[100, 200],
[300, 100],
[400, 150],
[300, 200]
];
// 生成一条path路径
const linePath = lineGenerator(points);
// 渲染line
svg.append("path")
.attr("d", linePath)
.attr("fill", "none")
.attr("stroke-width", 1)
.attr("stroke", "red");

指定x,y的取值方式
const points = [
{ x: 0, y: 50 },
{ x: 100, y: 200 },
{ x: 300, y: 100 },
{ x: 400, y: 150 },
{ x: 300, y: 200 }
];
const lineGenerator = d3
.line()
.x((d) => d.x)
.y((d) => d.y);
const linePath = lineGenerator(points);
实际开发中,通常需借助x轴和y轴的比例尺来计算每个数据点对应的位置信息。
圆滑的曲线
const lineGenerator = d3
.line()
.x((d) => d.x)
.y((d) => d.y)
.curve(d3.curveBasis) // 曲线插值

D3提供了多种插值算法,例如curveBasis、curveCardinal、curveCatmullRom、curveStep、curveStepBefore和curveStepAfter,开发者可尝试不同效果。
初步掌握d3.line后,即可轻松绘制折线图:
const line = d3.line()
.x((d) => xScale(xValue(d)))
.y((d) => yScale(yValue(d)));
chartG.append("g")
.append("path")
.style("fill", "none")
.style("stroke", "rgb(51, 209, 243)")
.style("stroke-width", 1)
.datum(data)
.attr("d", line);
复制代码此处使用datum,因为仅需绘制一条折线,且需在该线上生成所有数据点位以构成path路径。若对datum与data的区别存疑,可回顾DataJoin相关章节。
d3.area
除绘制单条折线外,还可绘制填充的折线区域,这是常见应用场景,需使用d3.area。

d3.area用于设置坐标的属性共有六个,分别是x、y、x0、y0、x1和y1。它们通常分为两组使用:x, y0, y1和y, x0, x1,分别代表水平与垂直方向。
水平方向
const areaGenerator = d3.area()
.x((d) => d.x)
.y1((d) => d.y)
.y0(10);
const areaPath = areaGenerator(points);
svg
.append("path")
.attr("d", areaPath)
.attr("fill", "none")
.attr("stroke-width", 1)
.attr("stroke", "red");

打印areaPath的结果如下:
M0,50L100,200L300,100L400,150L400,10L300,10L100,10L0,10Z
具体含义解析:
移动至(0,50),绘制线条至(100,200),再绘制至(300,100),接着至(400,150)。
随后绘制至(400,10),再至(300,10),最后至(100,10)。
接着绘制至(0,10),并闭合路径(将起点与终点连接)。

理解起来类似于小学的拼音连线题:

垂直方向
const points = [ // y 是递增的
{ x: 20, y: 50 },
{ x: 100, y: 100 },
{ x: 300, y: 150 },
{ x: 200, y: 200 },
{ x: 300, y: 230 }
];
const areaGenerator = d3.area()
.y((d) => d.y)
.x0(10)
.x1((d) => d.x);

值得注意的是,水平方向的area与points特点在于按x递增,而垂直方向的area与points则按y递增。
若未进行排序,可能会得到出乎意料的图形效果。

最后,即可完成折线图的area模式绘制:
const area = d3.area()
.x((d) => xScale(xValue(d)))
.y1((d) => yScale(yValue(d)))
.y0(yScale(0));
chartG.append("g")
.append("path")
.style("fill", "none")
.style("fill", "green")
.style("stroke", "rgb(51, 209, 243)")
.style("stroke-width", 1)
.datum(data)
.attr("d", area);
总结
不同图表需匹配不同的比例尺,这要求根据比例尺特性与图表特征进行选择。本章仅简要介绍了line和area的部分特性,更详细的API说明请参考官方文档。建议打开demo进行调试,修改数据、样式或比例尺以观察效果。
到此这篇关于D3.js实现绘制折线图的教程详解的文章就介绍到这了,更多相关D3.js绘制折线图内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!