前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >D3库实践笔记之图表交互 |可视化系列36

D3库实践笔记之图表交互 |可视化系列36

作者头像
蛰虫始航
发布2020-11-25 15:06:22
5.3K0
发布2020-11-25 15:06:22
举报
文章被收录于专栏:蛰虫始航蛰虫始航

对于前端可视化库来说,交互效果是其基本功能,需要有优雅的效果和简洁的API才能出彩,而如果一个前端可视化工具只能生成静态图表,绝对会显得格格不入,因为在前端拥有交互功能并不复杂。与图表的交互,是指图表元素能根据用户的键盘鼠标操作做出相应的反应,例如悬停高亮、缩放、漫游、拖动节点、点击涟漪效果等等。

对于HTML元素来说,要响应用户的行为,可以在图形元素上添加一个或多个事件监听器,当监测到对应行为时,执行某些响应代码。

事件监听器

JavaScript 有一个事件模型,在这个模型中,“事件”由发生的事情来触发,比如用户通过键鼠或触摸屏输入信息。大多数情况下,没人监听事件,事件就自生自灭,我们就无感知。而如果我们添加事件监听器后,触发对应的事件就能调用这个监听器的设置,具体来说就是执行某些代码。

D3的选择集有一个方法on(),用来设定事件的监听器。在可视化绘制时我们普遍用了var svg=d3.select("body").append("svg")或类似的代码,就可以使用以下代码给元素绑定事件监听器:

代码语言:javascript
复制
var rect=svg.selectAll("rect").data(ds).enter().append("rect")
            .on("mouseover", function() {
                //触发事件后执行一些操作
                 d3.select(this).style("fill","#BA5C25");
                })
            .on("mouseout", function(d) {
                 d3.select(this).style("fill","#1EAFAE");
                });

以上代码可以给柱状图添加悬停高亮的交互效果,mouseover是事件名称,function()是监听器函数。当鼠标移动到某个柱子上时,触发一个mouseover事件,调用function()将d3所选中的柱的填充色修改为设置的颜色。演示如下:

d3交互之悬停高亮

为图表赋予交互能力只要两步:

•给选择集绑定事件监听器;•定义响应行为。

键鼠事件

在交互中最常见的行为当然要属鼠标触发的,经典的鼠标行为有单机、双击、选中拖动等。常用的事件如下:

•click:单击事件,鼠标单击某个元素触发,相当于mousedown和mouseup组合在一起;•dblclick:鼠标双击事件;•mouseover:鼠标的光标放在某元素上(悬停在元素上);•mouseout:光标从某元素上移出来时;•mousedown:鼠标按钮被按下;•mouseup:鼠标按钮被松开;

以下代码为图表标题添加了一个单击事件的监听器,当点击标题元素,会将标题加粗并在控制台输出当前标题文本;而如果当前是加粗的效果,点击后是变成非加粗文本,也就是点击会切换加粗和正常文本两种效果;

代码语言:javascript
复制
// var svg=d3.select("body").append("svg")  等等
svg.append("text").attr("x",200).attr("y",20)
.text("D3绘制柱状图").on("click", function() {
    if (d3.select(this).style("font-weight")=="bold"){
        d3.select(this).text("D3绘制柱状图").style("font-weight","normal");
    }else{
        d3.select(this).text("D3绘制柱状图-click").style("font-weight","bold");
    }
    console.log(d3.select(this).text());//输出标题文本
    });

d3-click-title

键盘事件也很实用,特别是可以结合一些控制鼠标按键的自动化程序。键盘事件有三种:

•keydown:当用户按下任意键时触发,按住不放会重复触发此事件,这一事件不会区分字母的大小写,例如“A”和“a”被视为一致;•keypress:当用户按下字符键(大小写字母、数字、加号、等号、回车等)时触发,按住不放会重复触发此事件,该事件就会区分字母的大小写;•keyup:当用户松开按键时触发,该事件不区分字母的大小写;

keydown和keypress事件的区别在于keydown用于任意键的事件,而keypress用于字符键,如果只需要处理字母数字类的响应,或是要对大小写字母分别处理的时候,使用keypress;如果要处理上下左右(↑→)、Shift、Ctrl等特殊键的输入,使用keydown。

随着各种移动设备的普及,触屏有着广泛的使用场景,无论是我们的手机还是触屏的显示器,触屏离我们很近。常用的触屏事件有以下三种:

•touchstart:当触摸点被放在触摸屏上时,也就是触摸到某个元素;•touchmove:当触摸点在触摸屏上移动时;•touchend:当触摸点从触摸屏上拿开时;

我们可以为触摸事件配置点击事件以及拖动事件,也就是触摸有选中并拖动的效果。

缩放

通过d3.zoom().on("zoom", zoomed)配置缩放的交互,具体用法如下。需要说明的是在v3.x版本中是使用d3.behavior.zoom()创建缩放行为,而v5.x及之后的版本是d3.zoom(),不再有behavior这一层抽象;

给矩形和坐标轴添加缩放交互响应:

代码语言:javascript
复制
var zoom = d3.zoom()
    .scaleExtent([0.1, 90])
    //.translateExtent([[-100, -100], [60+ 90, 60+ 100]])
    .on("zoom", zoomed);
    svg.call(zoom);
    function zoomed() {
            var rects=svg.selectAll("rect");
            rects.attr("transform", d3.event.transform);
            tt.attr("transform", d3.event.transform);
            gX.call(xAxis.scale(d3.event.transform.rescaleX(x)));
        }

绑定d3.zoom()的行为后,就具备了漫游的交互,zoom不仅仅可以放大缩小,还可以拖动元素进行漫游。

漫游是一种拖拽效果,但在力导向图等的交互中,我们希望有更纯粹的拖拽元素效果,因此d3也有d3.drag()用于创建拖拽行为。和zoom一样的,在v5.x版本中是使用d3.drag()而v3.x版本是使用d3.behavior.drag()。drag没有缩放功能。

drag和zoom一般通过call调用,写在svg.append("rect")语句中变成svg.append("rect").call(zoom),或者写svg.call(zoom)

代码语言:javascript
复制
drag = simulation => {
  function dragstarted(event) {
    if (!event.active) simulation.alphaTarget(0.3).restart();
    event.subject.fx = event.subject.x;
    event.subject.fy = event.subject.y;
  }

  function dragged(event) {
    event.subject.fx = event.x;
    event.subject.fy = event.y;
  }

  function dragended(event) {
    if (!event.active) simulation.alphaTarget(0);
    event.subject.fx = null;
    event.subject.fy = null;
  }

  return d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended);
};
var node = svg.append("g").attr("stroke", "#fff").attr("stroke-width", 1.5)
      .selectAll("circle").data(nodes).join("circle")
      .attr("r", 5).attr("fill", "#CAE9E0")
      .call(drag(simulation));

d3力导向图拖动效果

悬停文本标签

要实现鼠标悬停在图形元素上时显示其标签的tooltip效果,仍然使用选择集的on监听mouseover和mouseout事件,只是把响应的代码从修改选定的rect元素变成了增加文本标签元素,具体实现是可以选择加svg的<text>标签或者加HTML的<div>标签,按需使用。

代码语言:javascript
复制
svg.selectAll("rect").data(dataset).enter().append("rect")
   .attr("class","bar").style("fill","#1EAFAE")
   .attr("x",function(d,i){return i*75+75 +"px";})
   .attr("y",function(d){return (375-d*3.5) +"px";})
   .attr("width",50).attr("height",d=>d*3.5 +"px")
   .on("mouseover", function() {
      d3.select(this).append("title").attr("id", "tooltip")
        .text(function(d) {
              return "Value of this bar: " + d;
         });
    })
   .on("mouseout", function(d) {
           d3.select("#tooltip").remove();
});

过渡动画

过渡动画同样通过事件监听和缓动实现过渡效果和数据更新,实现友好的交互;还有便是用好.transition(),在方法链上,要把transition的调用插到选择元素之后,改变任何属性之前。transition()默认情况延迟(delay)为0ms,持续时长(duration)为250ms,可以自行设置这两个参数。

例如对一个矩形的变换应用过渡效果:

代码语言:javascript
复制
svg.append("rect")
.attr("fill","steelblue")
.attr("x",30)
.attr("y",30)
.attr("width",100)
.attr("height",30)
.transition() //在更新width之前调用
.attr("width",300);

和HTML元素交互

D3作为一个JavaScript库,自然可以和原生的HTML元素进行交互,例如响应按钮的点击事件,在html中配置了按钮和点击监测,<button type="button" onclick="update()"> 更新 </button>,点击按钮触发事件,在函数update里面调用d3的绘制代码,实现交互。

状态条是很实用的元素,通过状态条调节d3图表的参数,例如下面通过状态条调节绘制矩形的填充颜色,给状态条添加了onchange的事件监听器,有变化时更新矩形的颜色。

代码语言:javascript
复制
//html中需要额外引入 <script src="https://unpkg.com/d3-simple-slider"></script>
var num2hex = rgb => {
    return rgb.map(color => {
        var s = color.toString(16);
        if (s.length === 1) {
          s= '0' + s;
        }
        return s;
      }).join('');
  };

var rgb = [0,175,174];
var colors = ['red', 'green', 'blue'];

var svg = d3.select('div#d3-slider').append('svg')
    .attr('width', 600).attr('height', 400).append('g')
    .attr('transform', 'translate(30,30)');
var box = svg
    .append('rect')
    .attr('width', 160)
    .attr('height', 100)
    .attr('transform', 'translate(400,30)')
    .attr('fill', `#${num2hex(rgb)}`);

rgb.forEach((color, i) => {
    var slider = d3
      .sliderBottom()
      .min(0)
      .max(255)
      .step(1)
      .width(300)
      .default(rgb[i])
      .displayValue(false)
      .fill(colors[i])
      .on('onchange', num => {
        rgb[i] = num;
        box.attr('fill', `#${num2hex(rgb)}`);
        d3.select('p#value-color').text(`#${num2hex(rgb)}`);
      });
    svg.append('g').attr('transform', `translate(30,${60 * i})`).call(slider);
});
d3.select('p#value-color').text(`#${num2hex(rgb)}`);

d3状态条改颜色

可视化结果输出

d3绘制的图像是svg或canvas对象,要将生成的可视化结果导出可以选择直接复制svg节点数据,从DOM里直接复制 SVG 代码,然后粘贴到文本文件里,命名为chart.svg,如果觉得麻烦可以用其他工具,导出的需求挺普遍,当然有大佬造了轮子,d3-downloadable[1]是一个JavaScript库,用于下载绘制的svg图形,在html里引入后,在JavaScript代码里加入svg.call(d3.downloadable({width:w,height:h,filename: "filename"}));就可以下载svg文件了。而如果只需要图片,就可以直接用截图工具截图保存,例如在写这些笔记时,自己大部分图片都是直接截图的,部分svg图形在DOM里直接复制出来粘到文本文件里。

总结

交互是JavaScript可视化库的基本功能,一些封装的基于前端的Python库也都实现了缩放漫游、悬停文本标签等交互功能。d3实现交互效果并不复杂,只需要对选择集使用on(),设定事件的监听器,在监听器里写交互的代码,定义响应的行为。基础可视化实现挺简单,而深度交互的内容很多,如更优雅的过渡和渐变效果、更深入的适应触摸设备交互、迷你图加入悬停框等等,在之后的具体实践中深入学习。

References

[1] d3-downloadable: https://github.com/likr/d3-downloadable

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 蛰虫始航 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 事件监听器
  • 键鼠事件
  • 缩放
  • 悬停文本标签
  • 过渡动画
  • 和HTML元素交互
  • 可视化结果输出
  • 总结
  • References
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档