D3(四)

一、d3中的交互操作

与图表的交互,指的是在图形元素上设置一个或多个监听器,当事件发生时,做出相应的反应。

什么是交互

交互 : 指的是用户输入了某种指令,程序接受到指令之后必须做出某种响应。对可视化图表来说,交互能使图表更加生动,能表现更多内容。

例如,拖动图表中某些图形、鼠标滑到图形上出现提示框、用触屏放大或缩小图形等等。

用户用于交互的工具一般有三种:鼠标键盘触屏

如何添加交互?

对某一元素添加交互操作十分简单,代码如下:

var circle = svg.append("circle");
circle.on("click", function(){
    //在这里添加交互内容
});

在 D3 中,每一个选择集都有 on() 函数,用于添加事件监听器。on() 的第一个参数是监听的事件,第二个参数是监听到事件后响应的内容,是一个函数。

  • 鼠标常用的事件有:

    click :鼠标单击某元素时触发。

    mouseover :光标放在某元素上。

    mouseout :光标从某元素上移出来时。

    mousemove :鼠标被移动的时候。

    mousedown :鼠标按钮被按下。

    mouseup :鼠标按钮被松开。

    dblclick :鼠标双击。

  • 键盘事件:

    keydown :当用户按下任意键时触发,按住不放会重复触发此事件。该事件不会区分字母的大小写。

    keypress :当用户按下任意字符键时触发,按住不放会重复触发此事件。该事件区分字母的大小写。

    keyup :当用户释放键时触发,不区分字母的大小写。

  • 触屏事件:

    touchstart : 当触摸点被放在触摸屏上时。

    touchmove : 当触摸点在触摸屏上移动时。

    touchend : 当触摸点从触摸屏上拿开时。

可视化图形

层级结构:树, 最直接、最直观的可视化方案。 数据格式为JSON格式,节点可以包含“属性”。


绘制树状图

树状图用于表示层级、上下级、包含与被包含关系。

绘制一个树状图主要分为四步:

  1. 选中页面设置的svg绘制区域的宽高
  2. 生成树状布局,设置尺寸
  3. 对角线生成器
  4. 请求数据,渲染数据
    • 获取节点数组和连线数组
    • 绘制连线和节点
    • 给节点添加圆圈设置半径
    • 给节点添加文本 设置文本样式 位置

一、使用SVG绘制区域的宽高,设置元素的位置

 <svg id="mainsvg" class="svgs" width="1000" height="900"></svg>
  <script src="https://d3js.org/d3.v6.min.js"></script>
  <script>
    // 获得画布
    const svg = d3.select('#mainsvg');
    // 定义比例尺
    const width = +svg.attr('width');
    const height = +svg.attr('height');
    // 用来控制表格边框线的位置
    const margin = {
      top: 50,
      right: 150,
      bottom: 50,
      left: 60
    };
    const innerWidth = width - margin.left - margin.right;
    const innerHeight = height - margin.top - margin.bottom;
    const g = svg.append('g')
      .attr('transform', `translate(${margin.left},${margin.top})`);
    let root;//全局变量root
    let color;

二、设置数据,并且读取数据

  1. 由于层级的数据本质就是JSON,而且D3支持从web服务读取json数据,或者从外部文件如.json, .csv文件中直接读取。因此这里我们把数据放在data文件夹下的province.json中,数据格式如下:


  2. 使用第三方的json来读取数据。使用d3.hierarchy进行层级数据的预处理,它会保持数据的原始结构,并将输入层级数据转换成D3中的hierarchy对象,同时引入:height、depth、data等。d3.hierarchy可作为一个“中间结果”,继续输入到更多D3.js提供的数据预处理接口中。

d3.json('./data/province.json').then(data => {
      //使用hierarchy将数据转换成d3中自己的数据格式
      root = d3.hierarchy(data);
      //调用d3.tree()对层级结构进行空间上的划分,此时每个节点就会多出来一个x和y的值,这两个值就是每个节点对应到画布上的位置
      root = d3.tree().size([innerHeight, innerWidth])(root);
      render()
    })




重点强调d3.tree().size([innerHeight, innerWidth])
这个代码会返回一个函数,函数接受的参数为d3.hierarchy(data),函数会根据设置的size将树形结构的每个节点映射到空间中“合适”的位置。

  1. 有了x和y的值就可以进行渲染,首先先渲染出线条关系图。我们使用d3.linkHorizontal()来添加线条,这条线的本质上是一个path。
  const render = function (data) {
      g.selectAll('path')
        // root.links 它返回一个数组,包括source和target,这就是两个根结点
        .data(root.links())
        .join('path')
        //填充设置为空
        .attr('fill', 'none')
        //定义边框颜色为黑色的
        .attr('stroke', 'black')
        //边框的宽度为1.5
        .attr('stroke-width', 1.5)
        // x和y表示要对source和target的每一个x和y要如何取值,这里由于是横向显示,所以把x和y的位置反过来写
        .attr('d', d3.linkHorizontal().x(d => d.y).y(d => d.x))
    }




4. 绘画小圆点,data().join(‘circle’)中data()接收的是一个list。d3提供给我们一个root.descendants(),它可以把包括root节点在内的其他的所有子节点压平成一个list,返回给data,然后就可以进行join()

g.selectAll('circle').data(root.descendants()).join('circle')
        // 设置圆的位置
        .attr('cx', d => d.y)
        .attr('cy', d => d.x)
        //填充一个颜色
        .attr('fill', 'red')
        .attr('stroke-width', 3)
        //设置半径
        .attr('r', 6)



  1. 但是这样设置的颜色都是一样的,我们可以将red修改为一个参数,然后在上面去定义它。
const fill = d => {
      //如果是根结点
      if (d.dept === 0) {
        return color(d.data.name)
      }
      //如果不是根结点
      while (d.dept > 1) {
        d = d.parent;
      }
      return color(d.data.name)
    }

然后我们就去render中定义color:

color = d3.scaleOrdinal(d3.schemeCategory10)

定义比例尺的时候我们就要设置domain()和range(),在定义scaleOrdinal的时候range(d3.schemeCategory10),这个是d3提供的默认的配色方案。domain的设置是很麻烦的,在这里就可以省略,scaleOrdinal看到这里没有设置domain,它就会从Category里面找一个颜色进行渲染,就是自动配色。

  1. 进行字体的渲染,这里要注意的是,放置文字的位置。我们可以使用text-anchor来调整,如果设置成middle的时候,文字就会剧中显示。如果设置为end,就是从右向左扩张。如果是
g.selectAll('text').data(root.descendants()).join('text')
        .attr("font-size", '1em')
        // 用三元运算符去判断,它如果有子节点的话,就是true,显示形式就用end,会显示在圆点的左边。这样的话根结点就在左边,子节点在右边。
        .attr("text-anchor", d => d.children ? "end" : "start")
        //设置节点和圆点的距离,默认是以圆心来放置
        .attr('x', d => (d.children ? -7 : 7) + d.y)
        .attr('y', d => d.x + 5)
        .text(d => d.data.name)
  1. 在渲染文字和圆圈的时候添加交互效果,改变圆圈的大小,颜色的文字
 .on("mouseover", function (d) { //交互
          d3.select(this)
            .attr("r", 8)
        })
        .on("mouseout", function () {
          d3.select(this)
            .attr("r", 6)
        })

绑定数据的三个“状态”

Update、Enter、Exit 是 D3 中三个非常重要的概念,它处理的是当选择集和数据的数量关系不确定的情况。


之前写的例子中,反复出现了类似以下的代码:

svg.selectAll("rect")   //选择svg内所有的矩形
    .data(dataset)      //绑定数组
    .enter()            //指定选择集的enter部分
    .append("rect")     //添加足够数量的矩形元素
  • update()
    当对应的元素正好满足时 ( 绑定数据数量 = 对应元素 ),图元和数据条目相同。
  • enter()
    数据的条目多于图元甚至没有图元,常用于第一次绑定数据。D3会自动搞清楚哪些数据是新增的,根据新增的数据生成相应的图元。占位的内容可以使用append来添加。
 const p = main.selectAll('.class').data(data).enter().append('rect').attr()
 //.enter给不存在数据的图源一个占位符
  • exit()
    数据的条目少于图元甚至没有数据。D3会自动搞清楚哪些图元是不绑定数据的。占位的内容可以使用remove来删除。
const p = main.selectAll('.class').data(data).exit().remove()





  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值