d3.js入门教程之数据绑定详解


Posted in Javascript onApril 28, 2017

前言

d3.js 是一款上手容易的js类库,专门用于绘制svg图形图表,其关键理念为data-join 意即数据绑定.搞清这个概念非常重要,它将以简洁优雅的形式体现数据驱动编程.

以下是Thinking with Joins的拙译 ,原作者Mike Bostock

假设你要用D3画一副散点图,因此需要生成一些 SVG circle 元素来直观地展现数据. 你会惊讶地发现D3没有提供原生的产生多个DOM元素的接口,

是的,只有一个 append 方法,用于产生单个DOM元素:

svg.append("circle") 
 .attr("cx", d.x) 
 .attr("cy", d.y) 
 .attr("r", 2.5);

但那只是单个圆,而你想要更多: 最好data*中每个元素对应一个圆. 在你用蛮力写循环把圆画出来之前,让我们看看D3中的一个例子:

svg.selectAll("circle") 
 .data(data) 
 .enter().append("circle") 
 .attr("cx", function(d) { return d.x; }) 
 .attr("cy", function(d) { return d.y; }) 
 .attr("r", 2.5);

*此处 data是一个 JSON 数组,其每个元素 由 x 和 y属性构成, 例如: [{"x": 1.0, "y":1.1},{"x": 2.0, "y":2.5}, …]. 另,SVG circle元素用cx,cy表达圆心坐标,r表达半径长度.

这份代码符合你的需求,即每个元素产生一个圆 , 通过x和y属性表达圆心的坐标.

selectAll("circle")是什么意思,为什么要在产生所有圆之前去选中根本不存在的元素呢?

原来事情是这样的:告诉D3你的目标,而不要告诉它具体怎么做. 在这个例子中,D3知道我们的意图是,要让选中的"circle"元素来响应数据的变化, selectAll即描述了这个目标;而无需一步步指挥D3产生多个圆.这个概念即data-join.

data-join的背后执行了以下步骤:

  • selectAll("circle") 返回了一个空的选择
  • 空的选择通过 data()方法将数据和DOM元素绑定,并产生三个虚拟的子集: enter, update and exit. enter()方法包含了待添加的数据及相应的DOM元素的占位符;update()包含了已与数据绑定的现有元素.剩下待移除的部分被包含在 exit ()方法中
  • 一开始选择的结果是空的,因此所有数据都是待添加,将全部出现在enter的结果中.
  • 无需循环,通过.enter().append("circle")将待添加的元素一次性加入到SVG容器.

为什么要这么麻烦呢? 为什么不直接提供原生接口? data-join的优雅之处在于抽象和解耦.上述代码在enter()里只是专心处理新增的元素,而update and exit分别专注于处理更新和待删除部分.这意味着你不用把所有DOM元素删了重绘,因此得以轻松应对实时变化的数据,甚至支持一些交互(如拖动)与渐变的效果!

这里是一个处理三种状态(增改删)的例子:

var circle = svg.selectAll("circle") 
 .data(data); 
 
circle.enter().append("circle") 
 .attr("r", 2.5); 
 
circle 
 .attr("cx", function(d) { return d.x; }) 
 .attr("cy", function(d) { return d.y; }); 
 
circle.exit().remove();

如果我们重复运行代码,它会每次重新计算 data-join. 如果新的数据集比原来的少,多余元素会出现在 exit 中并被remove()删除.反之亦然,新增的数据出现在enter()中通过append()添加DOM元素.若新老数据集大小不变,则所有数据只是更新坐标.(译注:上文中介于enter和exit之间的代码,update()会被隐式调用)

以joins的方式思考同时让你的代码更直观: 处理这三种状态的代码无需条件(if)和循环(for)分支,只需简单描述让图形去响应数据的变化即可.如果给定的enter, update 或 exit 的选择结果为空,则会自动跳过相应的代码块,以降低性能开销.

Joins 支持在特定状态(增/删/改)下执行操作.例如,可以在enter而非update代码块中,指定静态的attributes(例如圆的半径,用 "r" attribute指定) . 仰赖于精确改动目标元素和最小化DOM变更,你已经极大地提升了浏览器渲染的表现! 类似地,你可以在特定状态下表现渐变等动画效果. 例如新增的圆可以从无到有渐变(半径从0到2.5):

circle.enter().append("circle") 
 .attr("r", 0) 
 .transition() 
 .attr("r", 2.5);

待删除的圆也可以逐渐收缩直至消失:

circle.exit().transition() 
 .attr("r", 0) 
 .remove();

相信现在你已经学会用joins的方式思考了!

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
一份老外写的XMLHttpRequest代码多浏览器支持兼容性
Jan 11 Javascript
提高网站信任度的技巧
Oct 17 Javascript
Js实现手机发送验证码时按钮延迟操作
Jun 20 Javascript
jQuery点击按钮弹出遮罩层且内容居中特效
Dec 14 Javascript
BootstrapTable与KnockoutJS相结合实现增删改查功能【一】
May 10 Javascript
基于JS快速实现导航下拉菜单动画效果附源码下载
Oct 27 Javascript
基于javascript实现数字英文验证码
Jan 25 Javascript
bootstrap表单示例代码分享
May 18 Javascript
详解react如何在组件中获取路由参数
Jun 15 Javascript
JS二分查找算法详解
Nov 01 Javascript
微信小程序内拖动图片实现移动、放大、旋转的方法
Sep 04 Javascript
vue项目中使用Svg的方法
Oct 24 Javascript
jQuery tip提示插件(实例分享)
Apr 28 #jQuery
JS实现动态添加DOM节点和事件的方法示例
Apr 28 #Javascript
jQuery自定义元素右键点击事件(实现案例)
Apr 28 #jQuery
详解angularJs模块ui-router之状态嵌套和视图嵌套
Apr 28 #Javascript
vue基于Vue2.0和高德地图的地图组件实例
Apr 28 #Javascript
d3.js实现立体柱图的方法详解
Apr 28 #Javascript
JS基于正则表达式的替换操作(replace)用法示例
Apr 28 #Javascript
You might like
深入PHP magic quotes的详解
2013/06/17 PHP
PHP中CURL的CURLOPT_POSTFIELDS参数使用细节
2014/03/17 PHP
php计划任务之ignore_user_abort函数实现方法
2015/01/08 PHP
PHP实现对png图像进行缩放的方法(支持透明背景)
2015/07/15 PHP
Laravel5.5新特性之友好报错以及展示详解
2017/08/13 PHP
TP5框架简单登录功能实现方法示例
2019/10/31 PHP
JS 动态加载脚本的4种方法
2009/05/05 Javascript
document.createElement()用法及注意事项(ff下不兼容)
2013/03/13 Javascript
jQuery form插件之formDdata参数校验表单及验证后提交
2016/01/23 Javascript
深入理解JavaScript创建对象的多种方式以及优缺点
2017/06/01 Javascript
nodeJS实现路由功能实例代码
2017/06/08 NodeJs
极简主义法编写JavaScript类
2017/11/02 Javascript
jQuery除指定区域外点击任何地方隐藏DIV功能
2017/11/13 jQuery
react-navigation 如何判断用户是否登录跳转到登录页的方法
2017/12/01 Javascript
Webpack中publicPath路径问题详解
2018/05/03 Javascript
基于vue cli 通过命令行传参实现多环境配置
2018/07/12 Javascript
手淘flexible.js框架使用和源代码讲解小结
2018/10/15 Javascript
详解@angular/cli 改变默认启动端口两种方式
2018/11/29 Javascript
详解vue+axios给开发环境和生产环境配置不同的接口地址
2019/08/16 Javascript
layerui代码控制tab选项卡,添加,关闭的实例
2019/09/04 Javascript
JavaScript设计模式之策略模式实现原理详解
2020/05/29 Javascript
[02:59]DOTA2完美大师赛主赛事第三日精彩集锦
2017/11/25 DOTA
[01:38]女王驾到——至宝魔廷新尊技能&特效展示
2020/06/16 DOTA
python 实现堆排序算法代码
2012/06/05 Python
Django的数据模型访问多对多键值的方法
2015/07/21 Python
python读取csv文件并把文件放入一个list中的实例讲解
2018/04/27 Python
linux下安装python3和对应的pip环境教程详解
2019/07/01 Python
在 Python 中接管键盘中断信号的实现方法
2020/02/04 Python
pandas处理csv文件的方法步骤
2020/10/16 Python
HTML5触摸事件实现移动端简易进度条的实现方法
2018/05/04 HTML / CSS
什么是动态端口(Dynamic Ports)?动态端口的范围是多少?
2014/12/12 面试题
什么是符号链接,什么是硬链接?符号链接与硬链接的区别是什么?
2014/01/19 面试题
小学敬老月活动方案
2014/02/11 职场文书
2014年班组长工作总结
2014/11/20 职场文书
2015年南京大屠杀纪念日活动总结
2015/03/24 职场文书
创业计划书之宠物店
2019/09/19 职场文书