D3 Note - Basis

D3 (Data-Driven Documents) 是一个 JavaScript Library,用来做 Web 端的数据可视化实现以及各种绘图。

D3.js is a JavaScript library for manipulating documents based on data. D3 helps you bring data to life using HTML, SVG, and CSS.

学习 D3 需要很多预备知识:

HTML / DOM CSS JavaScript (better with jQuery) SVG

HTML / CSS 不必多说,因为 D3 含有大量链式操作函数以及选择器等,因此如果有 jQuery 基础将轻松很多。此外,由于一般采用 SVG 方式进行绘图,所以 SVG 基础知识也需要掌握。

虽然必须的预备知识如此之多,但 D3 的定位其实是 Web 前端绘图的底层工具,所谓底层,即是操作复杂而功能强大者。

关于 SVG 🔗

SVG (Scalable Vector Graphics) 是一种绘图标准,已经被绝大多数的现代浏览器所支持。SVG 采用 XML 语法定义图像,可直接嵌入 HTML 中使用。

SVG 的特点是矢量绘图(与 Canvas 不同),除了预设样式以外同时也支持 CSS 样式。

比如,画一个园圈,坐标为 (100, 50),半径为 40px,拥有 2px 的黑色 border,以及红色填充:

<svg>
    <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
</svg>

SVG 有一些预定义的形状元素,可被开发者使用和操作:

矩形 圆形 椭圆 线 折线 多边形 路径

其中,path 是功能最强大者,使用 path 可以构成所有图形。

选择器 🔗

选择元素 🔗

D3 使用与 jQuery 类似的选择器来获取 HTML 元素。常用的方法有:

d3.select(selector) d3.selectAll(selector)

(参数既可以传 selector 也可以直接传 HTML Element )

顾名思义,selectAll 就是选择所有符合条件的元素了,那么 select 选择的是符合条件的第一个元素。如:

d3.select('body') //选择 body 元素

d3.selectAll('p') //选择所有 p 元素

d3.selectAll('.className') //选择所有 class 包含 className 的元素

更多就不说了。

操作选择 🔗

选择器返回的是一组选择(selection),这组选择可以进行一些操作,如:

在此选择的基础上继续选择; 改变属性; 改变样式; 绑定事件; 插入、删除; 绑定数据。

大多数操作都与 jQuery 十分类似,同时也支持链式操作,不再赘述。只是这个“绑定数据”操作稍有特别。

数据绑定 🔗

通过 D3 可以把数据“绑定”到 HTML 元素上,绑定的目的主要是为了方便一些需要相应数据才能进行的元素操作(如:更改元素大小、位置等)。

绑定数据有两个方法:

datum: 将一个数据绑定到选择上; data: 将一个数组绑定到选择上,数组的各项分别与选择的各项一一对应。

下面引用一个例子来说明这二者的不同。假设有如下三个节点:

<p>Apple</p>
<p>Pear</p>
<p>Banana</p>

datum 🔗

执行以下代码:

let str = 'datum';
let p = d3.selectAll('p');

p.datum(str);
p.text((d, i) => `Element ${i} bind with ${d}`);

将得到:

Element 0 bind with datum
Element 1 bind with datum
Element 2 bind with datum

在对选择进行操作时,传入的值可以是值,也可以是函数。当传入函数时,D3 会向函数注入两个参数,分别是 d (data) 与 i (index),代表当前元素绑定的数据与其索引。

data 🔗

执行以下代码:

let strArr = ['data0', 'data1', 'data2'];
let p = d3.selectAll('p');

p.data(strArr);
p.text((d, i) => `Element ${i} bind with ${d}`);

将得到:

Element 0 bind with data0
Element 1 bind with data1
Element 2 bind with data2

可以看到,数组中的 3 个项分别与 3 个 p 元素绑定到了一起。因此,可以将 datum 看作是 data 函数的一个特例,实际开发中使用更多的是 data 函数。

实践:简单柱状图 🔗

先定义一个 SVG 画布,并将它插入到 HTML 的 body 中去:

let width = 300,
  height = 300;

let svg = d3.select('body')
  .append('svg')
  .attr('width', width)
  .attr('height', height);

在这里,画布的宽高都为 300 像素。

然后,定义一组数据:

let data = [250, 210, 170, 100, 190];

最后使用以上数据画出柱状图,柱子使用 SVG 预定义的 rect 元素:

let rectWidth = 25;

svg.selectAll('rect')
 .data(data)
 .enter()
 .append('rect')
 .attr('y', (d, i) => height - d)
 .attr('x', (d, i) => i * rectWidth)
 .attr('height', d => d)
 .attr('width', rectWidth - 2)
 .attr('fill', 'steelblue');

rectWidth 表示柱子的宽度,至于坐标、宽高则分别通过 x / y 以及 height / width 属性来控制,效果如下:

可以发现,这里并没有指定需要插入的 rect 个数,但 D3 却根据数据量自动地把图画出来了,这个工作是通过 enter 语句完成的。关于其工作原理,下回分解。

文章来源:

Author:wxsm's blog
link:https://blog.wxsm.space/p/d3-note-basis