摘要:
- 将条形图分解为独立组件:容器、坐标轴和条形。
- 使用SVG和D3.js绘制这些组件。
- 使用React的callback ref在DOM中渲染它们。
使用D3绘制图表像搭建乐高
使用D3.js绘制图表时,你处理各种独立组件 —— 很像乐高积木。你单独建造组件,然后将它们组装在一起创建最终图表。这适用于所有类型的图表。
我们来看看以条形图为例。我们可以将其分解为几个组件:
- 轴Y:垂直刻度尺
- 轴X:水平刻度尺
- 条形:数据的可视化表示
- 容器:所有元素汇聚的绘图板
对于折线图,组件包括轴X、轴Y、折线路径本身,当然还有容器。
现在,我们分解绘制条形图的步骤,这是最常见的图表类型之一,使用D3.js和React。
- 在React组件中设置
在React中操作DOM有几种方法,可以通过原生JS访问DOM节点,或者在React中使用useRef。还可以使用callback refs的方法,配合useCallback hook。这种方法可以避免组件重复渲染的问题。
// callback ref
const plotChart = () => {
// 绘制图表
return node
}
const ref = useCallback((node) => {
if(node !== null) {
const plot = plotChart()
node.append(plot)
}
}, [])
return <div ref={ref} />
现在我们开始在plotChart()函数中添加绘制图表的逻辑。
- 容器
首先需要一个容器作为图表的绘图板,使用SVG并设置宽高为500px。可以使用viewBox属性使容器响应viewport。
const WIDTH = 500
const HEIGHT = 500
const svg = d3.create('svg')
.attr('viewBox', `0 0 ${WIDTH} ${HEIGHT}`)
.style('width', '100%')
如果数据量大,可以使用canvas元素以获取更好的性能。
- 比例尺
需要理解D3中的域、范围和比例函数的概念:
- 域:可能的输入值集合
- 范围:可能的输出值的最小和最大值
- 比例函数:将域的值映射到范围内的视觉输出值
例如,对于条形图的X轴和Y轴比例尺:
// X轴
xScale = d3.scaleBand()
.domain(["Red","Green","Blue"])
.range([40, 460])
// Y轴
yScale = d3.scaleLinear()
.domain([0, 8])
.range([460, 40])
还可以设置一个颜色的序数比例尺,将分类映射到颜色。
- 条形
绘制好坐标轴后,绑定数据到条形组件,设置它们的位置和大小:
selection
.data(data)
.enter()
.append('rect')
.attr('x', (d) => xScale(d.category))
.attr('y', (d) => yScale(d.value))
添加动画效果,实现条形从下向上增长。
- 自定义配置
可以通过空间、网格线、刻度标记等的自定义,对图表进行美化。
// 条形之间的间距
xScale.padding(0.2)
// 隐藏轴线
g.select('.domain').remove()
// 动画
selection
.transition()
.duration(1000)
.attr('y', (d) => yScale(d.value))
最后将不同组件组合在一起,形成最终效果。
- 结论
总结而言,使用D3制作图表就像组装乐高积木,将不同部分放在一个容器内,关键是用比例尺和数据绑定正确连接,使其对齐。D3非常灵活,可以进行各种定制。