D3.js - 选择集方法(Selection Methods)

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()
  1. .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); // 输出数量
相关推荐
chenjianzhong3 小时前
vite-plugin-legacy 实战解析
前端·vue.js·vite
前端赵哈哈3 小时前
Vue I18n 完整安装与使用指南
前端·vue.js·面试
秋田君3 小时前
Vue3 + VitePress 搭建部署组件库文档平台(结合 Element Plus 与 Arco Design Vue)—— 超详细图文教程
前端·vue.js·arco design
code_Bo3 小时前
前端使用snapdom报错问题
前端·javascript·vue.js
一壶浊酒..3 小时前
什么是AJAX
前端·javascript·ajax
fruge3654 小时前
从零到一:我在 Rokid Glasses 上“画”出一个远程协作系统
前端
BumBle4 小时前
高频扫码场景下的去重与接口调用方案
前端·javascript
Mapmost4 小时前
半透明模型渲染全白?Mapmost Studio一招搞定
前端