需要了解的几个概念
数据可视化
基于Web的数据可视化指的是在网页中显示数据统计报表,从而可以更直观地了解数据的走向和趋势,如图表、图谱、地图、关系图、立体图。
数据可视化的展现方式从以往的 Flash 技术、IE 的 vml 语言发展至如今规范统一的 HTML5 技术点——Canvas 和 SVG。
SVG
可缩放矢量图形,基于 XML。
D3.js
简介
Data Driven Documents,基于数据驱动文档的 JavaScript 库,用于网页作图、生成互动图形,是一个优秀的可视化库。D3.js 不需要你使用哪个特定的框架,也就是说只要能写 JavaScript 就能使用 D3.js,当然是要在浏览器兼容的前提下了。
优势
堪称 SVG 中的 jQuery,操作 SVG 极为方便,当然 Canvas 也支持
截止目前来说,D3 是操作 SVG 最为方便的一个库,堪比 jQuery 和 JavaScript 的关系,当然这不是说 D3 只能操作 SVG,在 v3 之后的 v4 版本开始 D3 就已经支持 Canvas 了,但是支持不代表擅长,主要的处理目标还是 SVG。
相比于 Echarts 这种框架式工具来说,D3.js 的自由度更高,但相对的学习成本也会变高
chart 类的工具(Highchart、Echarts)固然简单易上手,但是这类都是“框架式工具”,和“库”区别还是比较大的。举个例子,你需要装修自家房子,一种方式是提供给你装修会用到所有工具并教会你所有装修方法,装修风格就任君发挥了,还有一种方式就是给你出几个样本房,自己从中选择,这就是“库”和“框架式工具”的区别了,所以,玩转 D3 后限制图形样式的就只有你的想象力了。
操作DOM极其强大
毫不夸张的说,如果你学习过 jQuery,D3 你已经会了⅓。甚至网上有人说 D3 可以替代 jQuery,虽然不现实,但这个说法确实得益于 D3 极强的操作 DOM能力。
入门实例——直方图
1. 新建一个 HTML5 文件
|
|
2. 引入 D3.js
|
|
3. 创建 div 用来展示 SVG
|
|
4. 使用 D3.js 的语法绘制 SVG
|
|
⚠️注意:
- 矩形的 x、y 坐标以矩形的左上角为中心点
- SVG 填充背景颜色使用的是
fill
属性- 矩形之间的间隔为 x 轴的差值
涉及的API:
API | 含义 | 示例 |
---|---|---|
.select | 选择元素 | d3.select("#id") |
.selectAll | 选择多个元素 | d3.selectAll("#id") |
.append | 添加元素 | .append("svg") |
.attr | 添加属性 | .attr("width","400") |
.data | 绑定数据 | .data([45,64]) |
.enter | 当DOM元素数量少于data的数量时,自动创建元素 | .enter() |
.text | 设置文本内容 | .text(d => d) |
比例尺和坐标轴
比例尺
先来回顾一下上次直方图中是怎样设置“柱子”的高度的:
|
|
对的,这里是直接使用数值的大小来表示“柱子”的高度,你可能会表示:显示的高度肯定是和数值的大小有关系啊!对!问题就在这个关系上,如果一定是这样一对一的关系,那数值是这样呢:[ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ]
,这样呢:[ 2500, 2100, 1700, 1300, 900 ]
。
这样的数据可视化是毫无可读性、也是绝不可取的,所以需要一种计算关系,能够将某一区域的值映射到另一区域,其大小关系不变,这就是 D3 中的一个重要概念——比例尺。
scaleLinear()
线性比例尺
线性比例尺中,定义域和值域都是连续的一一对应关系。
例子
|
|
需求
- 将最小的值映射为0,将最大的值映射为300。
定义比例尺:
1 2 3 4
const linear = d3 .scaleLinear() .domain([d3.min(dataset), d3.max(dataset)]) .range([0, 300])
结果
1 2 3
linear(0.9) // 输出:0 linear(2.3) // 输出:175 linear(3.3) // 输出:300
解释
.domain()
为定义域,.range()
为值域d3.min()
和d3.max()
返回数组中的最小值和最大值
scaleOrdinal()
序数比例尺
输入域和输出域都是离散的数据,不连续,其数据是序数关系。
例子
|
|
需求
- 45对应 pink,34对应 blue,以此类推。
定义比例尺
1 2 3 4
const ordinal = d3 .scaleOrdinal() .domain(dataset) .range(color)
结果
1 2 3
ordinal(45) // 输出:color ordinal(145) // 输出:yellow ordinal(78) // 输出:green
v3 以下版本和 v3 以上版本比例尺的写法不同,详情请参阅官方文档。
坐标轴
基本每种图表都需要坐标轴,但是 SVG 中并没有现成的元素,而是需要由其它图形来组成——刻度 和 直线。
|
|
用户交互与力导向图
交互式操作
用户交互指的是用户输入了某种指令,程序接收到后做出了某种响应,而 D3.js 中的用户交互当然指的是用户与可视化图表的交互操作了。
例如鼠标移动至图形上时候图形的变色、变形、文字提示,或是点击变大缩小等等,而最经典的运用就是力导向图了。
添加交互
D3 中使用事件监听函数.on(type, function)
为元素添加交互事件。
参数 type 为事件类型,下表为常见的事件,参数 function 为事件处理函数
事件名 含义 鼠标操作 click 鼠标单击 mouseover 鼠标进入 mouseout 鼠标移出 mousemove 鼠标移动(需节流处理) mousedown 鼠标按下 mouseup 鼠标松开 dblclick 鼠标双击 键盘操作 按住不放会持续触发 keydown 键盘按下 keyup 键盘释放 keypress 键盘按下字符键 触屏操作 touchstart 触摸屏幕 touchmove 触摸点移动 touchend 离开屏幕 d3.select(this)
可以直接选择触发事件的元素,但前提是事件处理函数不使用箭头函数每个
select
的元素都可以添加.on()
事件监听函数
布局
布局的作用是将不适合用于绘图的数据转换为适合用于绘图的数据,简而言之——数据转换。
- D3(v4 以上版本)提供了以下12种布局:
布局( v3 与 v4以上版本写法不同) API 饼状图(Pie) d3.layout.pie 力导向图(Force) d3.forceSimulation 弦图(Chord) d3.layout.chord 树状图(Tree) d3.tree 集群图(Cluster) d3.cluster 捆图(Bundle) d3.layout.bundle 打包图(Pack) d3.pack 直方图(Histogram) d3.layout.histogram 分区图(Partition) d3.partition 堆栈图(Stack) d3.layout.stack 矩阵树图(Treemap) d3.treemap 层级图(Hierarchy) d3.hierarchy
力导向图
建立在力学模型基础上的一种特殊的图表,常用来呈现复杂的关系网络。由节点和连线组成,节点和连线都被施加了力的作用,根据力来计算节点和连线的运动轨迹。
实现
整体思路
定义数据(节点数据和连线数据)
定义SVG画布
设置力导向图布局
绘制节点(
circle
)、连线(line
)、描述文字(text
)和关系文字(text
)监听力导向图的
tick
事件,每运动一帧重新设置节点坐标、连线起始结尾坐标、描述文字坐标和关系文字坐标
核心代码
|
|
绘制热点图
没事儿画啥地图?
- 比如现有一需求:
- 在吃鸡地图中标示出哪里跳伞的人多及哪里跳伞的人少,然后就可以根据这个图大概分析出跳哪里落地成盒的几率更小🌚。
正经点儿,实际业务需求:
- 在中国地图上显示出百星23个自有制作中心、16个驻场制作中心、39个外包服务站点所在的地理位置(实力打广告🤨),并通过点的大小、亮度等体现出不同制作中心的业务量高低。
没错,热点图(又称地图散点图)是这类需求的标准解决方案,其可通过在地图上不同区域使用不同的标志来呈现不同区域的关注程度,使数据清晰明了地呈现在人眼前。
准备工作
1. 中国地理信息文件——GeoJSON
GeoJSON是用于描述地理空间信息的数据格式,包括地图上的所有要素,如经纬度、点、线、面、特征等,格式为 JSON 格式。
网上搜索 china.json 一大堆😏,但是要注意格式要符合 GeoJSON 标准
2. 球形➡️平面投影——d3-geo
经纬度不能直接用于绘图,需要转换为平面坐标,D3 中提供了丰富的投影函数来处理球面坐标和经纬度运算。
安装:npm install d3-geo d3-array --save
3. 配色方案
安装:npm install d3-scale-chromatic --save
绘制地图
1. 按需导入类库
|
|
|
|
2. 定义 SVG 画布和投影函数
|
|
3. 创建路径生成器和颜色比例尺
|
|
4. 获取 GeoJSON 数据,生成地图
此处为重中之重,要使用 D3.js 提供的d3.json()
方法获取地理信息文件,官方文档表明此方法根据指定的 url 创建一个 JSON 文件请求,这就要求不能使用本地的 JSON 文件而要搭建服务器返回数据。本案例使用 Express + MongoDB 搭建了简单的服务器返回地理信息数据。
|
|
使用
append("path")
的话 DOM 结构中 path 元素会处于 g 元素之前,导致 path 覆盖 g 元素,原因是 D3 中元素的层级是由元素创建的先后顺序来决定的。
定位城市坐标
1. 定义城市坐标数据
|
|
2. 标点并绘制
|
|
3. 加入动画
|
|
🎱案例 GitHub 地址:https://github.com/Xuezenghuigithub/D3.js_china_map