D3简介
D3 是一个 Javascript 库,用于创建数据可视化图形,全称 Data-Driven Documents 也就是数据驱动文档,文档指的就是基于 web 的文档,代表可以在浏览器中展示的一切,包括 SVG 以及 一般的 HTML , D3扮演的是一个驱动程序的角色,联系着数据和文档。
与 ECharts 图表相比,D3.js给我们提供了一些方法,用来生成带数据的标签,绑定可视化的属性,而如何制作图表则由我们自己定义。D3.js 还提供很多数据处理的方法,用来生成可以更好的显示的数据模型。也就是说,ECharts图表可以作为满足基本需求的图表插件来使用,而如果需要自己定制,或是更有个性的图表,就可以使用D3.js。
而这部分的学习,只会总结一些常用的API,且学习的版本为v3.x.x版本。该注意的是D3.js从v4开始,和之前版本有很大不同,所以后续深入学习时,注意去查询一下新旧版本的不同!
注意去查询一下新旧版本的不同!
注意去查询一下新旧版本的不同!
注意去查询一下新旧版本的不同!
(三遍不会忘)
d3选择器API
选择元素
一个选择就是从当前文档中抽取的一组元素。D3使用CSS3来选择页面元素。例如,你可以使用的选择方式有标签 ("div")、类(“.awesome”)、唯一标识符(“#foo”)、属性(“[color=red]”)、或者包含(“parent child”)。选择器可以是交叉(".this.that" 表示逻辑与)的也可以是联合的(".this, .that" 表示逻辑或)。
d3提供了两种方法来选择元素:
- .select():返回匹配的第一个元素;
- .selectAll():返回匹配的所有元素;
这两个方法可以接受节点。
d3.select()
接受字符串:
d3.select('#container')
接受一个节点的引用:
这里的this指向当前元素,且不可以在这里使用箭头函数,因为如果你这么做了,那么this将指向window
d3.selectAll('p').on('click',function(){
d3.select(this).style('coler','red')
})
除了d3对象外,选择集也可以调用select(),用来继续选择元素,这个时候除了传入字符串外,还可以传入一个函数。
d3.selectAll('p').select(function(d,i,nodes) {
console.log(this,d,i,nodes); // this表示当前元素,d为与元素数据,i 为当前元素索引,nodes为元素集
console.log(this === nodes(i)); // true
return this;
})
d3.selectAll()
和select()一样,可以和接收字符串,也可以接收节点数组。
除了d3对象外,选择集也可以调用selectAll(),用来继续选择符合条件的后代元素
d3.selectAll('p').selectAll('span').selectAll(function(d,i,nodes) {
console.log(d,i,nodes);
})
操作选择
当选择完元素之后你可以添加操作。这些操作可以设置或者获取属性、样式、特性、选择器和文本内容。
选择是一组元素。D3绑定额外的方法到数组上。所以你可以在选中的元素上应用操作,例如为所有选中的元素设置属性值。一个细微的差别是选择结果是分组的,而不是一个一维数组。每一个选择都是元素数组中的一个数组。这保留了自选择的层次结果,大多数情况下你可以忽略这个细节,这就是为什么一个单一的元素选择看起来像 [[node]] 而不是 [node]
d3-selection 是 D3.js 的一系列选择集 API,这些方法都有返回值,有的返回的是当前的选择集,有的则返回新的选择集。
selection.filter() 过滤选择集
过滤并返回新的选择集
d3.selectAll('p')
.filter('.con')
.style('coler','red');
selection.append() 添加元素
参数为要被添加的新元素的标签名,在这个选择集中添加新的元素,并将这个新元素返回
d3.selectAll('#container')
.append('p');
selection.insert() 插入一个新元素到匹配的元素前面
接收两个参数,第一个参数为要插入的元素,第二个参数定义一个选择器。
// 在类名为'.con'的p标签前添加span标签
d3.select('#container')
.selectAll('p')
.insert('span','.con');
selection.remove() 移除当前选择集
d3.select('#container').remove();
selection.clone() 克隆当前选择集并放到当前选择集后面
有一个可选参数 deep 表示是否 将所选元素的子元素页克隆了
selection.text() 添加文本
接收的参数是一段文本字符串或者是动态更新的函数,提供三个参数d,i,nodes,返回值为文本值
d3.select('div').text('this is a div');
(存在待解决的例子)selection.attr() 给元素添加属性
接受两个参数,一个为属性名,一个为属性值。选择集中通过指定的name(属性名)添加指定的value(属性值)。如果value是一个常数,那就为选择集所有元素设置同样的属性;如果value为一个函数,那么这个函数会为每个选中的元素计算。
如果只有属性名,没有设置属性值,则返回选择中第一个非空元素的属性值。
d3.select('#container')
.select('div')
.attr('id','box')
.attr('id'); // 'box'
// 属性值为函数
// 这个例子感觉不对的,先留个疑问,学到之后回来看我写的这个什么鬼
d3.select('#container')
.selectAll('div')
.attr('class',function(d,i,nodes) {
return this.className;
})
(存在待解决问题)selection.classed() 添加或删除类名
接受两个参数,第一个参数为字符串,可以为一个类名或者多个类名(多个类名之间用空格隔开),这个参数表示要操作的类名,第二个参数为布尔值或者返回值为布尔值的函数,true表示添加,flase表示删除。
d3.select('#container')
.selectAll('p')
.classed('con', flase)
d3.select('#container')
.append('p')
.text('blue')
.style('color', 'blue')
.append('mark')
.text('mark')
.classed('blue', true)
.clone(true)
selection.style() 给元素添加样式
d3.select('.con').style('coler','red');
selection.data() 将数据绑定到元素上
将指定数组的数据 data 与已经选中的元素进行绑定并返回一个新的选择集,新的选择集使用 update 表示:此时数据已经成功与元素绑定,并且定义了 enter 和 exit 方法用来返回需要加入元素和移除元素的选择集,参数 data 可以是一个数组,也可以是一个返回数组的函数。
var matrix = [
[11975, 5871, 8916, 2868],
[ 1951, 10048, 2060, 6171],
[ 8010, 16145, 8090, 8045],
[ 1013, 990, 940, 6907]
];
var tr = d3.select("body").append("table").selectAll("tr")
.data(matrix)
.enter().append("tr");
var td = tr.selectAll("td")
.data(function(d) { return d; })
.enter().append("td")
.text(function(d) { return d; });
selection.enter() 返回输入(enter)选择:当前选择中存在但是当前DOM元素中还不存在的每个数据元素的占位符节点。
在enter()方法前调用data()方法,会创建data数据所需要的DOM占位符,通常用enter()方法来创建数据比节点多时的缺失节点
d3.select("body").selectAll("div")
.data([4, 8, 15, 16, 23, 42])
.enter().append("div")
.text(function(d) { return d; });
假设body是空的,则上面的代码会创建六个新的div,并将它们按顺序添加到body里
<div>4</div>
<div>8</div>
<div>15</div>
<div>16</div>
<div>23</div>
<div>42</div>
selection.exit() 返回退出(exit)选择:找出在当前选择存在的DOM元素中没有新的数据元素时
exit()通常用来移除多余的元素
一个简单的例子,考虑更新在上面的例子中的enter操作符创建的六个DIV元素。在这里,我们把这些元素和一个含有一些新的,一些旧数据的新数组绑定:
var div = d3.select("body").selectAll("div")
.data([1, 2, 4, 8, 16, 32], function(d) { return d; });
现在div--data操作符的结果--指的是更新的选择。因为我们指定的key函数使用标识函数,并且将新数据数组包含数字[4,8,16],它也存在旧的数据数组中,这个更新选择包含3 个DIV元素。比方说,我们离开这些元素原样。我们可以实例化并使用enter选择添加新的元素[1,2,32]:
div.enter().append("div")
.text(function(d) { return d; });
同样,我们可以删除退出的元素[15, 23, 42]:
div.exit().remove();
现在,文档body如下:
<div>4</div>
<div>8</div>
<div>16</div>
<div>1</div>
<div>2</div>
<div>32</div>
selection.datum() 获取或者设置每个选中元素上绑定的数据
与 data() 方法不同,这个方法不会进行数据链式计算,不影响索引,不影响 enter 和 exit 选择集,参数为要设置的值,或者一个函数,返回要设置的值
选择集事件
添加事件监听器 .on(type,listener,capture)
-
为元素添加或移除指定的事件监听器
-
如果listener为null,则表示移除监听器
-
同一个元素注册同一个类型事件监听器,则前面的被覆盖
-
为了不被覆盖,可以在事件名后面加
.指定分类 -
capture是一个布尔值,表示是否启动事件捕获
d3.select('#container') .selectAll('p') .on('click.foo', function(d) { console.log('foo click' , d) }) .on('click.bar', function(d) { console.log('bar click', d) })
返回触摸事件的坐标 .touches(container[,touches])
d3.select('#container')
.selectAll('p')
.on('touchstart', function (d) {
const touches = d3.touches(document.getElementById('container')); // [Array(2)]
console.log(touches)
})