d3js的事件绑定能这么简单!!!

1,205 阅读3分钟

前言

d3js的事件绑定也是非常重要的。他可以像咱们给dom绑定事件一样方便。

常用的events如下

  • click
  • dblclick
  • mouseover
  • mouseout
  • mousemove
  • mouseleave
  • mousedown
  • mouseup
  • contextmenu

先用小demo绘制一些图形

绘制几个基础的小方块, 看不懂的翻前面几节文章 效果图如下:

1656255350733.png

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    #container {
      width: 500px;
      margin: 50px auto 0;
    }
  </style>
</head>

<body>
  <div id="container">
  </div>
</body>

</html>
<script src="https://d3js.org/d3.v5.min.js"></script>

<script>
  const svg = d3.select('#container')
    .append('svg')
    .attr('width', 500)
    .attr('height', 500);

  const data = [
    { id: 1, fill: 'black', x: 10, y: 10 },
    { id: 2, fill: 'black', x: 50, y: 50 },
    { id: 3, fill: 'black', x: 100, y: 70 },
    { id: 4, fill: 'black', x: 20, y: 100 }
  ];

  draw(); // 绘制
  function draw() {
    const update = svg.selectAll('rect')
      .data(data, d => d.id);

    //修改层
    update.attr('x', (d, idx) => d.x)
      .attr('y', (d, idx) => d.y)
      .attr('fill', (d) => d.fill)

    //渲染层
    const enter = update.enter();

    //删除层
    const exit = update.exit();

    enter.append('rect')
      .attr('width', 20)
      .attr('height', 20)
      .attr('id', d => d.id)
      .attr('x', (d, idx) => d.x)
      .attr('y', (d, idx) => d.y)
      .attr('fill', (d) => d.fill)
      .attr('stroke', 'blue')
      .attr('strokeWidth', 1)

    exit.remove()
  }
</script>

使用d3js绑定事件

咱们先用click绑定给咱们的小方块

code

bindEvent();

 function bindEvent() {
    svg.selectAll('rect') // 获取所有得rect
      .on('click', (d, i) => { // 使用on 关键函数绑定, 后面回调函数参数d 当前数据 i 索引
        console.log(d, i, 'data'); // 输出的是前面绑定的每一项 也就是点击到得数据{}
      })
      .on('mousemove', (d) => { }) // 同上
      .on('mouseleave', (d) => { });// 同上
  }

不难看出来我们绑定事件还是蛮方便得使用关键字on即可

点击到得小方框变个颜色

前面给rect都绑定了一个click事件了,下面咱们改变点击到方块得颜色(如果已经改变过得再被点击就更改回原来得)

code

const selected = [];
 bindEvent();

 function bindEvent() {
    svg.selectAll('rect') // 获取所有得rect
      .on('click', (d, i) => { // 使用on 关键函数绑定, 后面回调函数参数d 当前数据 i 索引
        console.log(d, i, 'data'); // 输出的是前面绑定的每一项 也就是点击到得数据{}
        undateSelect(d.id);
        updateColor();
      })
      .on('mousemove', (d) => { }) // 同上
      .on('mouseleave', (d) => { });// 同上
  }


  function undateSelect(id) { // 更新selected
    const index = selected.findIndex(item => item === id);
    if (index !== -1) { // 有的话就删除、没有得话添加
      selected.splice(index, 1);
    } else {
      selected.push(id);
    }
  }

  function updateColor() {
    data.forEach((item) => {
      if (selected.includes(item.id)) {  //根据selected 改变颜色
        item.fill = 'red';
      } else {
        item.fill = 'black';
      }
    });
    draw(); // 数据绑定函数 会根据数据更改做更新, 不懂得可以翻下前面几章
  };

效果图如下:

w4123w.gif

实现点击画布空白处事件

实现点击画布空白处所有方块恢复原来得颜色, 关键点怎么判断是不是点到了画布空白?看下面代码

code


function clearColor() { // 清空颜色函数
    selected = [];
    updateColor();
}

function bindEvent() {
    svg.selectAll('rect')
      .on('click', (d, i) => {
        console.log(d, i, 'data');
        undateSelect(d.id);
        updateColor();
      })
      .on('mousemove', (d) => { })
      .on('mouseleave', (d) => { });

    svg.on('click', () => { // 给画布绑定click
      const { event } = d3;
      const target = event.srcElement; // 当前点击到得元素
      const info = d3.select(target).datum(); // 获取到当前点击到图形得绑定数据
      if (info?.id) return; //用数据判断是不是点击到了小方块
      clearColor();
      d3.event.preventDefault(); // 阻止事件向后传递
    });
}

效果图如下:

w41233w.gif

源码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    #container {
      width: 500px;
      margin: 50px auto 0;
    }
  </style>
</head>

<body>
  <div id="container">
  </div>
</body>

</html>
<script src="https://d3js.org/d3.v5.min.js"></script>

<script>
  let selected = [];
  const svg = d3.select('#container')
    .append('svg')
    .attr('width', 500)
    .attr('height', 500);

  const data = [
    { id: 1, fill: 'black', x: 10, y: 10 },
    { id: 2, fill: 'black', x: 50, y: 50 },
    { id: 3, fill: 'black', x: 100, y: 70 },
    { id: 4, fill: 'black', x: 20, y: 100 }
  ];

  draw(); // 绘制
  bindEvent(); // 绑定event
  function draw() {
    const update = svg.selectAll('rect')
      .data(data, d => d.id);

    //修改层
    update.attr('x', (d, idx) => d.x)
      .attr('y', (d, idx) => d.y)
      .attr('fill', (d) => d.fill)

    //渲染层
    const enter = update.enter();

    //删除层
    const exit = update.exit();

    enter.append('rect')
      .attr('width', 20)
      .attr('height', 20)
      .attr('id', d => d.id)
      .attr('x', (d, idx) => d.x)
      .attr('y', (d, idx) => d.y)
      .attr('fill', (d) => d.fill)
      .attr('stroke', 'blue')
      .attr('strokeWidth', 1)

    exit.remove()
  }

  function bindEvent() {
    svg.selectAll('rect')
      .on('click', (d, i) => {
        console.log(d, i, 'data');
        undateSelect(d.id);
        updateColor();
      })
      .on('mousemove', (d) => { })
      .on('mouseleave', (d) => { });

    svg.on('click', () => {
      const { event } = d3;
      const target = event.srcElement; // 当前点击到得元素
      const info = d3.select(target).datum(); // 获取到当前点击到图形得绑定数据
      if (info?.id) return; //用数据判断是不是点击到了小方块
      clearColor();
      d3.event.preventDefault(); // 阻止事件向后传递
    });
  }

  function undateSelect(id) {
    const index = selected.findIndex(item => item === id);
    if (index !== -1) {
      selected.splice(index, 1);
    } else {
      selected.push(id);
    }
  }

  function updateColor() {
    data.forEach((item) => {
      if (selected.includes(item.id)) {
        item.fill = 'red';
      } else {
        item.fill = 'black';
      }
    });
    draw();
  };


  function clearColor() {
    selected = [];
    updateColor();
  }
</script>

往期推荐

结束语

事件绑定就到这里了 相信大家对事件绑定有了一个新得认识

  • 大家好 我是三原,多谢您的观看,我会更加努力(๑•̀ㅂ•́)و✧多多总结。
  • 每个方法都是敲出来验证过通过的,有需要可以放心复制。
  • 如果您给帮点个赞👍就更好了 谢谢您~~~~~
  • 期待您的关注