D3.js是一个JavaScript库,其将DOM对象(HTML, SVG,或Canvas elements)和数据能很好的对应 (数据驱动),从而数据可视化非常出色。
本文简单的了解下使用,大致知道概念和能力边界,如果需要,再投入更大的精力深入研究。
选择器
类似 jQuery的选择器之后,D3的选择器直接可以设置元素属性:
<div class="box">
<p>1</p>
<p>2</p>
</div>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script>
console.dir(d3);
d3.select('.box')
.selectAll('p')
.style('color', 'red')
.style('background-color', '#f5f5f5');
</script>
动态属性
D3的强大之处是,动态属性设置,其可跟数据绑定,然后根据数据设置属性
d3.select('.box')
.selectAll('p')
// 根据索引设置颜色
.data([11, 22])
.style('color', (d, i) => (i % 2 ? '#f69' : '#69f'))
.text((d) => d + 1);
enter 和 exit
可以用enter为新的数据创建新的节点 ,用exit移除不需要的节点。
enter 的例子
使用enter的例子,假设先只有里一个 p。
<div class="box">
<p></p>
</div>
<script>
const pEnter = d3
.select('.box')
.selectAll('p')
.data([11, 22, 33, 44])
// 填充的是已存在的节点
.text((d) => d)
.enter()
.append('p');
console.log(pEnter);
// 填充的新增的节点
pEnter.text((d) => d);
</script>
这里注意,enter 会根据数据的长度,补充新的节点,也只能控制新的节点。所以填充数据的时候,一定分清旧节点和新节点,因为都需要填充。
打印了下,append('p')之后,pEnter 的组里之前的节点位置显示为empty,所以数据填充的时候会跳过。
exit 的例子
使用exit的例子,假设先有 3 个p。
<div class="box">
<p></p>
<p></p>
<p></p>
</div>
<script>
const pExit = d3
.select('.box')
.selectAll('p')
.data([11, 22])
.text((d) => d)
.exit();
console.log(pExit);
pExit.remove();
</script>
exit 会将数量相同的节点,在组里显示为empty,而多余的节点正常显示,remove 的时候,去掉的就是多余结点。
神奇的 join:简化exit和enter
enter 和 exit 会根据,数据的数量增删节点的数量,但合并或者增减节点的时候,就会增加额外的逻辑。
将上面例子的逻辑,抽离出来,假设隔段时间时间变化,那么将变成如下
<div class="box">
<p></p>
<p></p>
<p></p>
</div>
<script>
function show(dataset) {
const p = d3.select('.box').selectAll('p').data(dataset);
// 先删除多余节点,remove之后的返回的并不是原选择器节点,所以需要额外写这行
p.exit().remove();
// 已有节点填充数据
p.text((d) => d)
// 新增节点填充数据
.enter()
.append('p')
.text((d) => d);
}
// 第一次数据
show([1, 2, 3, 4]);
// 第二次数据
setTimeout(() => {
show([11, 22, 33, 44, 55]);
}, 2000);
// 第三次数据
setTimeout(() => {
show([44, 55]);
}, 4000);
</script>
用户要始终小心,数据和节点是不是一一对应,很容易出错。
join 就简化这个问题,会自动增删节点,统一节点之后,再进行统一操作。
function show(dataset) {
const p = d3.select('.box').selectAll('p').data(dataset);
// enter、update、exit统一了节点之后,再统一操作
p.join(
(enter) => enter.append('p'),
(update) => update,
(exit) => exit.remove()
).text((d) => d);
}
动画效果 transitions
css 的transition同样适用于 d3。
比如让字体颜色,有个动画效果,过渡到别的颜色
<div class="box">
<p>1</p>
<p>2</p>
</div>
<script>
d3.select('.box')
.selectAll('p')
.transition()
.duration(500)
.style('color', '#f69');
</script>
写个简单的 bar
svg我没咋学,就不秀svg画图了,当然svg是最合适的.
其实假设,上面的 p 的宽度就是数据的话,easy 啦
function show(dataset) {
const p = d3.select('.box').selectAll('p').data(dataset);
p.join(
(enter) => enter.append('p'),
(update) => update,
(exit) => exit.remove()
)
.text((d) => d)
// 写样式就行
.style('width', (d) => `${d}px`)
.style('height', '20px')
.style('background-color', 'steelblue')
.style('text-align', 'right')
.style('color', '#fff')
.style('font-size', '10px');
}
show([111, 222, 333, 444]);