d3-selection
前言
D3.js 用了一种与 jQuery 一样的 链式语法,这样通过 . 就把多个操作链接起来,执行逻辑上更加清晰,链式语法的关键就是每个操作函数都有返回值,这个返回值可以执行当前操作的对象,也可以是其他对象,在 D3.js 中要注意 .append('path')
方法的返回值是新创建的元素对象,而不是调用这个方法的元素对象
选择集方法
一、选择方法
1..select()
选取符合条件的第一个元素,返回选取的元素
js
d3.selectAll('p').on('click', function () {
d3.select(this).style('color', 'red')
})
d3 选择集也可以调用
select()
方法,也就是在当前选择集下边继续选择元素。这个时候除了传入选择器字符串外,还可以传入一个函数, 这个函数中的this 表示当前的元素,函数会被传入三个参数 d: 元素数据 i: 元素索引 nodes 元素集
js
// 不能用箭头函数 () => {} 否则 this 指向 window
d3.selectAll('p').select(function (d, i, nodes) {
console.log(this, d, i, nodes);
console.log(this === nodes[i]); // true
return this;
})
2. .selectAll()
选取符合条件的所有元素元素顺序按照其在文档中的顺序排列,如果没有元素则返回空集,和 .select()
用法类似
DOM操作方法
1. .append()
添加元素,返回值是添加的元素对象
js
d3.select('#container') .append('div')
2..insert()
插入元素到选择集中每个选中的元素前部
有两个参数,第一个参数定义要插入的元素标签名,第二个定义了一个选择器,指定在那个元素前添加
js
d3.select('#container')
.append('p')
.text('blue')
.style('color', 'blue')
.append('mark')
.text('mark')
.classed('blue', true);
d3.select('#container')
.selectAll('p')
.insert('span', '.blue') // 被插入到 类名为 blue 的 mark 标签前
.text('嘻嘻嘻嘻嘻')
3. .remove()
移除元素
移除当前选择集
js
d3.select('.blue')
.remove()
.clone()
克隆当前选择集并添加到当前选择集后边
有一个可选参数 deep 表示是否 将所选元素的子元素页克隆了
js
d3.select('#container')
.append('p')
.text('blue')
.style('color', 'blue')
.append('mark')
.text('mark')
.classed('blue', true)
.clone(true)
8. .text()
添加文本
参数是一段文本字符串或者是动态更新的函数,提供 d, i, nodes 三个参数,返回值即为文本值, 没有参数时则返回选择集第一个元素的文本值
js
d3.select('#container')
.append('div')
.text('this is div')
9. .attr()
给元素添加属性 返回添加属性的元素
有两个参数 分别是 属性名和属性值,表示设置属性,如果参数只有属性名则表示获取属性值
js
d3.select('#container')
.append('div')
.attr('id', 'box')
.attr('id'); // box
属性值也可以是一个函数,接受 d: 数据 i: 索引 nodes 组节点 三个参数,函数中 this 指向当前元素,函数返回值就是属性值,设置为 null 会将其移除
js
d3.select('#container')
.selectAll('p')
.data(data)
.enter()
.append('p')
.text((d, i) => `index: ${i}; org: ${d.org}; value: ${d.value};`)
.append('span')
.attr('class', 'to')
.attr('class', function (d, i, nodes) {
console.log(d, i, nodes, this);
return this.className;
})
10. .classed()
添加或者删除类名
classed() 有两个参数,第一个参数是一个或多个类名用空格链接的字符串,表示要操作的类名,第二个参数可以是一个布尔值或者返回值为布尔值的函数,同样获得 d, i, nodes 三个参数
用来判断操作的类名是添加(true)还是删除(false)
js
d3.select('#container')
.selectAll('p')
.data(data)
.enter()
.append('p')
.text((d, i) => `index: ${i}; org: ${d.org}; value: ${d.value};`)
.append('span')
.attr('class', 'to')
.attr('class', 'post')
.classed('to get', false)
.attr('class', function () {
console.log(this); // 只剩 post class
return this.className;
})
11. .style()
给元素添加样式
两个参数,样式名和样式值,表示设置样式,如果参数只有 样式名,表示获取指定的样式值
对于SVG 元素设置 style 的属性是要加上单位的,因为有些浏览器不支持默认单位
js
d3.select('#container')
.append('p')
.attr('class', 'blusse')
.text('blue')
.style('color', 'blue')
.style('color'); // blue
12. .data()
将数据绑定到元素上
将指定数组的数据 data 与已经选中的元素进行绑定并返回一个新的选择集,新的选择集使用 update 表示:此时数据已经成功与元素绑定,并且定义了 enter 和 exit 方法用来返回需要加入元素和移除元素的选择集,参数 data 可以是一个数组,也可以是一个返回数组的函数
js
var matrix = [
[11975, 5871, 8916, 2868],
[ 1951, 10048, 2060, 6171],
[ 8010, 16145, 8090, 8045],
[ 1013, 990, 940, 6907]
];
const p = d3.select('#container')
.selectAll('p')
.data(matrix)
.enter()
.append('p')
.text((d, i) => `index: ${i}; d:`)
p.selectAll('span')
.data(function (d, i, nodes) {
console.log(d, i); // 这个时候 d 是 matrix 的每一行 [11975, 5871, 8916, 2868]
return d
})
.enter()
.append('span')
.text(d => '--' + d + '--')
14. .exit()
返回没有对应数据的,曾经存在的DOM节点选择集
exit 选择集通常用来移除多余的元素
js
const data = [
{name: 'xxx1', age: 19, id: 123},
{name: 'xxx2', age: 21, id: 124},
{name: 'xxx3', age: 34, id: 125},
{name: 'xx4x', age: 12, id: 126},
{name: 'xxx5', age: 1, id: 127}
];
d3.select('#container')
.selectAll('p')
.data(data, d => d.id)
.enter()
.append('p')
.text((d, i) => `F index: ${i}; d: ${JSON.stringify(d)}`)
const newData = [
{name: 'xxx2', age: 21, id: 124},
{name: 'xx4x', age: 80, id: 126}, // 这里实际修改了数据,但是是否更新的标准是 key(id) 是否一致,所以旧的没有被更新
{name: 'xxx7', age: 212, id: 129},
{name: 'xx48', age: 122, id: 128},
];
// 按照新数据重新渲染
const selectP = d3.select('#container')
.selectAll('p')
.data(newData, d => d.id); // 指定 按照 key 索引,这样旧的数据 key 没有对应上的就会被清除到 exit 的集合
// 将新的数据补上
selectP.enter()
.append('p')
.text((d, i) => `S index: ${i}; d: ${JSON.stringify(d)}`);
// 清除不用的数据
selectP.exit().remove();
15. .datum()
获取或者 设置每个选中元素上绑定的数据
与 data()
方法不同,这个方法不会进行数据链式计算,不影响索引,不影响 enter 和 exit 选择集,参数为要设置的值,或者一个函数,返回要设置的值
js
// 按照新数据重新渲染
const selectP = d3.select('#container')
.selectAll('p')
.data(newData, d => d.id); // 指定 按照 key 索引,这样旧的数据 key 没有对应上的就会被清除到 exit 的集合
// 将新的数据补上
selectP.enter()
.append('p')
.datum((d, i) => `name: ${d.name}`)
.text((d, i) => `S index: ${i}; d: ${JSON.stringify(d)}`)
// 清除不用的数据
selectP.exit().remove();
监听和分派事件
1. 常用事件类型
D3 支持所有标准的 DOM 事件,例如:
- click :点击事件
- mouseover :鼠标悬停事件
- mouseout :鼠标移出事件
- mousemove :鼠标移动事件
- dblclick :双击事件
- keydown :按键按下事件
- keyup :按键松开事件
2. 添加事件监听器
使用 .on() 方法为选择集添加事件监听器:
javascript
d3.select("circle")
.on("click", function(event) {
// 事件处理逻辑
d3.select(this).attr("fill", "red"); // this 指向当前元素
});
3. 移除事件监听器
通过传递 null 作为回调函数来移除事件监听器:
javascript
d3.select("circle").on("click", null);
4. 触发自定义事件
使用 .dispatch() 方法手动触发事件:
javascript
d3.select("circle").dispatch("click");
5. 事件对象
事件处理函数会接收到一个 event 对象,包含以下常用属性:
- event.target :触发事件的元素
- event.type :事件类型(如 "click")
- event.clientX / event.clientY :鼠标位置
示例
js
d3.select("svg")
.append("circle")
.attr("cx", 50)
.attr("cy", 50)
.attr("r", 30)
.attr("fill", "blue")
.on("mouseover", function() {
d3.select(this).attr("fill", "green");
})
.on("mouseout", function() {
d3.select(this).attr("fill", "blue");
})
.on("click", function() {
d3.select(this).attr("r", 40);
});
控制流
1. .each(function)
为选择集中的每个元素执行指定的函数,函数参数为 (d, i, nodes),this 指向当前 DOM 元素。
js
d3.select('#container')
.selectAll('p')
.each(function(d, i) {
console.log(d, i); // 打印数据 d 和索引 i
});
2. .call(function, arguments)
调用指定函数,第一个参数是当前选择集,其余参数为传入的 arguments。
js
d3.select('#container')
.selectAll('p')
.call(function(selection, a, b) {
selection.append('span')
.text(a + b); // 在每个 <p> 中添加 <span>,内容为 'aaa' + 'bbb'
}, 'aaa', 'bbb');
3. .filter()
过滤并返回新的选择集,参数可以是字符串或者函数
js
d3.selectAll('p').filter('.none').style('color', 'red')
d3.selectAll('p').filter(function (d, i) {
console.log(d,i)
})
3. .empty()
返回选择集是否为空(布尔值)。
js
const empty = d3.select('#container')
.selectAll('div')
.empty(); // 检查是否有 <div> 元素
console.log(empty); // 输出 true 或 false
4. .nodes()
返回选择集中的元素数组。
javascript
const nodes = d3.select('#container')
.selectAll('p')
.nodes(); // 获取所有 <p> 元素的数组
console.log(nodes); // 输出 DOM 元素数组
5. .size()
返回选择集中的元素个数。
javascript
const size = d3.select('#container')
.selectAll('p')
.size(); // 获取 <p> 元素的数量
console.log(size); // 输出数量