D3.js简介
- D3.js是一个强大的数据可视化js语言,可以利用svg在网页上展示各种精美的矢量图.
- D3 提供了各种简单易用的函数,大大简化了 JavaScript 操作数据的难度。由于它本质上是 JavaScript ,所以用 JavaScript 也是可以实现所有功能的,但它能大大减小你的工作量,尤其是在数据可视化方面,D3 已经将生成可视化的复杂步骤精简到了几个简单的函数,你只需要输入几个简单的数据,就能够转换为各种绚丽的图形。
D3.js的官方
官网:https://d3js.org/
官方API:https://github.com/d3/d3/blob/master/API.md
适合人群
适合需要在网页前端做数据可视化图表开发、对数据可视化感兴趣、为图形痴狂,以及想了解并学习D3.js的读者 😄.
最基础内容
选择元素和绑定数据
选择元素和绑定数据是 D3 最基础的内容

- 如何选择元素 ?
在 D3 中,用于选择元素的函数有两个:
d3.select()
:是选择所有指定元素的第一个
d3.selectAll()
:是选择指定元素的全部
这两个函数返回的结果称为选择集。
- 如何绑定数据 ?
D3 有一个很独特的功能:能将数据绑定到 DOM 上,也就是绑定到文档上。
D3 中是通过以下两个函数来绑定数据的:
datum()
:绑定一个数据到选择集上
data()
:绑定一个数组到选择集上,数组的各项值分别与选择集的各元素绑定,相对而言,data() 比较常用。
插入、删除元素

- 插入元素涉及的函数有两个:
append()
:在选择集末尾插入元素
insert()
:在选择集前面插入元素
- 删除元素
删除一个元素时,对于选择的元素,使用 remove
即可,例如:
var p = body.select("#myid");
p.remove();
如此即可删除指定 id 的段落元素。
交互式操作
- 什么是交互 ?
交互,指的是用户输入了某种指令,程序接受到指令之后必须做出某种响应。对可视化图表来说,交互能使图表更加生动,能表现更多内容。例如,拖动图表中某些图形、鼠标滑到图形上出现提示框、用触屏放大或缩小图形等等。
用户用于交互的工具一般有三种:鼠标、键盘、触屏。
- 如何添加交互 ?
对某一元素添加交互操作十分简单,代码如下:
var circle = svg.append("circle");
circle.on("click", function(){
//在这里添加交互内容
});
这段代码在 SVG 中添加了一个圆,然后添加了一个监听器,是通过 on() 添加的。在 D3 中,每一个选择集都有 on() 函数,用于添加事件监听器。
布局
- 布局是什么 ?
布局,英文是 Layout。从字面看,可以想到有“决定什么元素绘制在哪里”的意思。布局是 D3 中一个十分重要的概念。
- 如何理解布局 ?
从上面的图可以看到,布局的作用是:将不适合用于绘图的数据转换成了适合用于绘图的数据。
因此,总的来说,布局的作用:数据转换
。
案例:
基于 D3.js 绘制动态进度条
经常使用svg或canvas来实现动态图形的绘制,但绘制过程相对较繁琐。对于直观漂亮的进度条,社区也有提供成熟的方案,例如highcharts
/ ECharts
等等,但基于配置的开发方式终究无法实现100%的自定义绘制。
绘制圆形进度条
对于一个圆形进度条,我们先对其进行任务拆分:
- 绘制嵌套圆弧
- 圆心处的实时数据展示
- 展现动画
- 美化
- 为了生成一个环形,我们需要四个参数:
开始角度(startAngle)
,结束角度(endAngle)
,内圆半径长(innerRadius)
,外圆半径长(outerRadius)
。当内圆半径为0的时候生成的图形是饼,不为0的时候则是环形。
1⃣️ :绘制嵌套圆弧
d3.arc()
返回一个圆弧构造函数,并通过链式调用设置内圆与外圆的半径大小,起始角度与结束角度。执行arc()构造函数
即可获得用于绑定在<path>
上的路径数据。
var arcGenerator = d3.arc().innerRadius(80).outerRadius(100).startAngle(0);
var picture = d3.select('svg').append('g').attr('transform','translate(480,250)');
1.生成将0度作为起点的圆弧构造器arcGenerator
2.设置transform图形偏移量,令图形在画布中央
目前画布上还没有任何元素,接下来我们实际图形的绘制。
var backGround = picture.append("path")
.datum({endAngle: 2 * Math.PI})
.style("fill", "#FDF5E6")
.attr("d", arcGenerator);
我们对画布picture添加<path>
元素,依据endAngle()
特性,使用datum()方法将{endAngle:Math.PI} 也就是终点角度2π绑定到<path>
元素上,并将圆弧构造器赋值给path路径d。
第一个圆弧画好了,那么依据svg的层级关系z-index,所谓的进度条其实就是覆盖在第一层圆弧之上的第二层圆弧。同理可得:
var upperGround = picture.append('path')
.datum({endAngle:Math.PI / 2})
.style('fill','#FFC125')
.attr('d',arcGenerator)
2⃣️:圆心处的实时数据展示
第一部分我们已经实现了基于两个path的嵌套圆。第二部分我们来实现圆心处的实时数据展示。
在进度条进行加载时,我们在圆心处添加数据来表达当前的加载进度,使用<text>
标签做展示即可:
var dataText = d3.select("g").append('text')
.text(12)
.attr('text-anchor','middle') //字符对齐方式
.attr('dominant-baseline','center') //基线
.attr('font-size','26px')
暂时将数据设置为12,并设置水平居中和垂直居中
3⃣️:展现动画
绘制进度条的实质是改变上层弧的角度
当弧度是 2π 时为整圆
,当弧度是 π 时为半圆
圆形中的数据即为当前弧度相对2π的百分比
综上我们只要改变弧度值和数值同时设定改变过程所需时长即可实现所谓"动画"。在ECharts提供的官方实例中,通过setInterval来实现每隔固定一段时间进行数据更新,其实在D3.js中同样提供了类似方法来实现类似setInterval的功能:
d3.interval(function(){
upperGround.transition().duration(750).attrTween('d',function(d){
var compute = d3.interpolate(d.endAngle,Math.random() * Math.PI * 2);
// 实现了如下插值范围:
// ["当前角度值","随机角度值"] //表达区间而非数组
return function(t){
d.endAngle = compute(t);
return arcGenerator(d);
}
})
},1000)
- d3.interval()方法提供了setInterval()的功能
- selection.transition.duration()设置了当前DOM属性过渡变化为指定DOM属性的过程所需时间,毫秒为单位
- transation.attrTween为插值功能API
t参数与d类似,是D3.js内部实现的插值,其范围为[0,1]。t参数根据设置的duration()时长自动计算在[0,1]内合适的插值数量,并返回插值结果,实现线性平稳的过渡动画效果。
代码d3.interpolate(d.endAngle,Math.random() * Math.PI * 2);实现了如下插值范围:
[“当前角度值”,“随机角度值”] //表达区间而非数组
4⃣️ : 美化
1,2,3部分我们实现了最基本的进度条样式和功能,但样式看起来还是很单调的,我们接下来我们对进度条进行线性渐变处理。我们使用D3.js提供的线性插值API:
var colorLinear = d3.scaleLinear().domain([0,100]).range(["#EEE685","#EE3B3B"]);
colorLinear同样是一个插值函数
实现了颜色取值后,我们只需在进度条变化时,将原有颜色改变即可:
d3.interval(function(){
upperGround.transition().duration(750).attrTween('d',function(d){
var compute = d3.interpolate(d.endAngle,Math.random() * Math.PI * 2);
return function(t){
d.endAngle = compute(t);
var data = d.endAngle / Math.PI / 2 * 100;
//设置数值
d3.select('text').text(data.toFixed(0) + '%');
//将新参数传入,生成新的圆弧构造器
return arcGenerator(d);
}
})
.styleTween('fill',function(d){
return function(t){
var data = d.endAngle / Math.PI / 2 * 100;
//返回数值对应的色值
return colorLinear(data);
}
})
},2000)
styleTween与attrTween类似,是实现改变样式的插值函数。采用链式调用的形式同时对进度条数值和颜色的设置即可。
⬆️ 综上我们实现了在不同数值下颜色变化的圆形进度条,可常用于告警,提醒等业务场景。