前言
d3.js作为目前最专业的可视化工具之一,可以实现极高自由度的可视化需求。但其上手难度较大,版本迭代变动大,资料零碎,导致以前的资料学起来困难(v3升级至v4进行了模块化)。
本文(甚至可能本系列)将分享我个人的实践经验,用CodePen举出代码示例,希望能有用处🎨也欢迎大家交流、指正✨
2019.7.29:d3.js v5.9.7
本文目录结构如下
- d3.js介绍
- d3特点介绍
- 可视化过程(布局)
- d3.selection操作元素
- 链式写法
- 数据驱动
- 使用d3与html创建条形图
- 参考资料
d3.js介绍
d3.js是一个遵循web标准,用于数据可视化的JavaScript库,帮助我们通过SVG,Canvas,HTML可视化数据。d3结合可视化布局(比如各种layout算法,用于处理原始数据,方便绘制图表等等)和协作工具(比如比例尺等等),通过数据驱动(data-driven)操作节点,提高了编撑效率及灵活性。
d3特点介绍
d3到底哪里与众不同?以下是我实践中总结的d3特点。
可视化过程(布局)
d3的绘图过程不同于Echarts等开箱即用的框架,对比如下(图自十二月咖啡馆):

对于布局的理解和demo我写在了另一篇文章里:d3.js 布局(layout)是什么
d3.selection操作元素
d3可以通过d3.select()与d3.selectAll()选中元素,返回selection对象
同时selection对象也有对应方法,即selection.select()与selection.selectAll()
通过selection对应的方法可以很方便的操作元素,比如:
let fatherNodes = d3.selectAll('.father');//选中文档中所有class名为father的元素
fatherNodes.append('div');//在所有这些元素中添加div
链式写法
之前看过d3代码的同学可能对d3这种写法感到困惑,举例:
let node = d3.select('#example')
.style('background-color', 'black')
.style('width', '100px')
.style('height', '100px')
为什么能这样写?如果不这样写会怎样?
先第一个问题:为什么能这样写
这里拿.style()方法举例说明:此方法会返回当前操作的selection,所以这段代码拆解等同后如下
let node = d3.select('#example');
node.style('background-color', 'black');
node.style('width', '100px');
let nodeTest = node.style('height', '100px')
console.log(node === nodeTest); //返回true
CodePen打开
因此可以继续对此对象进行操作
此时也可以解释第二个问题了:不这样写会怎样
效果上不会怎样,就是代码丑🤖,写起来很累很烦,不好维护
不过在使用链式写法时要注意返回的到底是哪个元素,比如一个父元素使用append()方法插入子元素,返回的是子元素
let father = d3.select('#father');
let son = father.append('p').text('son')
console.log(son);

数据驱动(data driven)
数据绑定是d3的最大特色,开发者通过绑定数据即可完成相应的绘图操作,大家会在接下来的demo实践中体验到
同时,对于数据驱动几个方法(enter、update、exit、join)的阐述我也写了一篇文章(正在重构中)
使用d3与html创建条形图
我猜测愿意看我此篇文章的人多数是新手😅所以先使用html标签制作条形图,一般情况下多数图表都是使用svg
demo效果如下:

接下来分步骤说明代码
1.初始化
// html
<div id="container">
</div>
// css
div{
margin:10px 0 10px 0; //使每一个条形图之间有空隙
color:white
}
// js
const exampleData = [200, 300, 250, 100]; //样例数据
const container = d3.select('#container');//选择div元素
2.数据绑定、绘制图形
此demo效果非常简单,同时是介绍及概览文章,所以先不使用d3的layout(布局)算法及各种工具函数(比如比例尺)
container.selectAll('div') //选择container中的div元素(可以container中没有div元素,后面有数据驱动)
.data(exampleData) //data()进行数据绑定
.enter() //这是数据绑定的几个核心api之一,在代码后用图片对此API进行简单的说明
.append('div') //根据enter返回插入div
.style('width', (d) =>{return d + 'px'}) //为这些div设置宽度,(d)=>{},d表示对应元素绑定的数据,箭头函数return的值赋值给对应的'width'属性
.style('height', '30px')//同理赋值,这里所有高度一致
.style('background-color', 'pink')
.text((d)=>{return d});//传如text()的参数为函数,d同样表示绑定的数据,return的值表示插入的值
圆形表示数据,三角形表示元素

