d3js enter/exit深入了解
在 Data joins 章节我们演示了当data和dom element个数相同时的情况
<div id="content">
<div></div>
<div></div>
<div></div>
</div>
给定下面的数据
var myData = [ 10, 40, 20 ];
当我们对div元素join上数据时
d3.select('#content')
.selectAll('div')
.data(myData);
myData
数据的个数和div元素的个数是相同的。
但是,如果数据和dom元素的个数如果不相同的话,会怎样呢?
- 如果数据个数多于dom元素个数那么说明有DOM元素的缺口,我们需要 add elements
- 如果数据个数少于dom元素个数,那么说明DOM元素有剩余,我们需要 remove elements
幸运的是D3可以帮助我们非常方便地管理这两种情况,分别通过 .enter来添加
而通过.exit来删除
.
.enter
.enter
指明了所有和data相比dom元素的缺口,enter和exit都是定义在update selection上的 (the selection returned by .data
):
d3.select('#content')
.selectAll('div')
.data(myData)
.enter();
.enter
返回代表需要增加的那些元素(已经绑定了数据)的selection. 通常跟随.enter的都是 .append
操作
d3.select('#content')
.selectAll('div')
.data(myData)
.enter()
.append('div');
再看一个例子,有下面的div元素
<divid="content">
<div></div>
<div></div>
<div></div>
</div>
var myData = ['A', 'B', 'C', 'D', 'E'];
我们使用.enter和 .append
来add div
elements for D and E:
d3.select('#content')
.selectAll('div')
.data(myData)
.enter()
.append('div');
需要说明的是我们可以join一个数组到空的selection上去,并接着使用.enter().append()这个pattern
.exit
.exit返回未能绑定到数据的dom元素,一般来说紧跟着的是 .remove操作:
d3.select('#content')
.selectAll('div')
.data(myData)
.exit()
.remove();
再来重复上面的例子,只是把数据改为只有一个元素的数组
var myData = ['A'];
这里我们使用 .exit
紧跟 .remove
来删除那些多余没有绑定上数据的元素:
d3.select('#content')
.selectAll('div')
.data(myData)
.exit()
.remove();
Putting it all together
我们可以对以下selection中的元素执行修改操作:
- the existing elements(update section)
- the entering elements(enter section)
- both existing and entering elements
大多数情况下我们修改属性的操作可以直接使用(enter+update)一起来操作,但是有的时候我们可能希望对enter,update来分开设置不同的styling.
我们看看update section(dom依然是前面的有三个子div)
<div id="content">
</div> <div id="menu">
<button onClick="doUpdate();">Add elements using .enter and .append</button>
</div>
</div>
var myData = ['A', 'B', 'C', 'D', 'E']; function doUpdate() {
var u = d3.select('#content')
.selectAll('div')
.data(myData); u.enter()
.append('div'); u.text(function(d) {
return d;
});
}
注意这段代码,当点击button后,新的元素将被加进来(绑定上D,E),但是由于.text函数调用仅仅在update selection上起作用,因此只有existing elements(in update section)才被添加了对应的A,B,C文字。但是注意:如果再次点击button,则会全部添加上文字哦!原因是D和E div元素已经被插入dom,因此再次执行click函数时update section已经包含了所有5个div元素!!
我们也可以对.enter section调用text()方法这样就直接把D,E文字打印出来了。
如果我们希望一次性地把upate和enter section的div都打印上对应的data,还有一种方法是先merge两个section,再执行text()方法:
var myData = ['A', 'B', 'C', 'D', 'E']; var u = d3.select('#content')
.selectAll('div')
.data(myData); u.enter()
.append('div')
.merge(u) // 先merge, 随后对enter和update两个section中的dom元素执行text()方法!
.text(function(d) {
return d;
});
General update pattern
d3社区通用的update pattern:
function update(data) {
var u = d3.select('#content')
.selectAll('div')
.data(data); u.enter()
.append('div')
.merge(u)
.text(function(d) {
return d;
}); u.exit().remove();
}
当数据发生变化时,我们调用update(data)函数来完成DOM的更新
function update(data) {
var u = d3.select('#content')
.selectAll('div')
.data(data); u.enter()
.append('div')
.classed('new', true)
.text(function(d) {
return d;
}); u.text(function(d) {
return d;
})
.classed('new', false); u.exit().remove();
}
Data join key function
When we do a data join D3 binds the first array element to the first element in the selection, the second array element to the second element in the selection and so on.
当我们执行data join操作时,d3将data数组的value默认一对一地和dom元素绑定,也就是第一个数据对应第一个dom元素,第二个数据对应第二个dom元素,。。。
然而,如果数据数组顺序如果发生了变化(比如在数据data数组sort, add, remove时),那么data可能会join到不同的dom元素上去。
这时,我们可以通过给.data提供一个key function来解决这个问题。这个key function将针对每一个数据元素返回一个唯一的id,这样D3就能确保相同的数据总是绑定到相同的dom元素!
我们来看一个例子:
var letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var i = 25; function doInsert() {
if(i < 0)
return; var myData = letters.slice(i).split('');
i--;
update(myData);
} function update(data) {
var u = d3.select('#content')
.selectAll('div')
.data(data, function(d) {
return d;
}); u.enter()
.append('div')
.merge(u)
.transition()
.style('left', function(d, i) {
return i * 32 + 'px';
})
.text(function(d) {
return d;
});
} doInsert();
<div id="content">
</div> <div id="menu">
<button onClick="doInsert();">Insert element</button>
</div>
以下是带key和不带key两种方式插入的不同表现
d3js enter/exit深入了解的更多相关文章
- D3中数据与DOM element绑定之data() enter() exit()浅析
几个非常有用的links: [1] three little circles. http://bost.ocks.org/mike/circles/ [2] How selection works. ...
- 【 D3.js 入门系列 --- 7 】 理解 update, enter, exit 的使用
在前面几节中反复出现了如下代码: svg.selectAll("rect") .data(dataset) .enter() .append("rect") 当 ...
- with 重写enter exit 方法
- D3中动画(transition函数)的使用
关于transition的几个基本点: 1. transition()是针对与每个DOM element的,每个DOM element的transition并不会影响其他DOM element的tra ...
- d3可视化实战02:理解d3数据驱动的真正含义
前文中已经提到,SVG从诞生之初起就可以非常方便地使用javascript脚本语言来进行其DOM对象的控制.当然,控制的方法有很多,有直接控制SVG对象的方法,例如使用原生js:有帮你封装一下图形接口 ...
- D3、EChart、HighChart绘图demol
1.echarts: <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...
- D3 JS study notes
如何使用d3来解析自定义格式的数据源? var psv = d3.dsvFormat("|"); // This parser can parse pipe-delimited t ...
- Coroutine in Java - Quasar Fiber实现--转载
转自 https://segmentfault.com/a/1190000006079389?from=groupmessage&isappinstalled=0 简介 说到协程(Corout ...
- Linux下命令行安装weblogic10.3.6
Linux下命令行安装weblogic10.3.6 一.安装前准备工作: 1.创建用户useradd weblogic;创建用户成功linux系统会自动创建一个和用户名相同的分组,并将该用户分到改组中 ...
随机推荐
- 使用大白菜安装Windows Server 2012 r2
依照往常安装win10的习惯操作,结果发现无GUI界面.重装时注意到了两个问题: 1. 启动时有两个U盘启动选项,请选择无UEFI的模式启动: 2. 一键安装系统时,一定要点一下系统文件来源的地方,因 ...
- Linux系统编程:线程控制
一.提出问题 问1.线程存在的意义是什么?什么时候适合使用多线程? 答1.在单进程环境中实现多任务,线程可访问其所在进程的资源,例如内存.描述符等.对于单进程,如果要完成多项任务,这些任务只能依次执行 ...
- $scope作用域与依赖注入
一.$scope与$rootscope作用域 $scope下的数据作为该控制器下的数据moduel,只有在该控制器下才能够访问:而$rootScope则可以可以再任何有效的地方访问到,这个有效的地方指 ...
- Linux-socket使用
socket 产生的原因 进程通信的概念最初来源于单机系统.由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进程之间既互不干扰又协调一致工作,操作系统为进程通信提供了相应设施,如 UNIX ...
- FocusBI:MDX检索多维模型
微信公众号:FocusBI关注可了解更多的商业智能.数据仓库.数据库开发.爬虫知识及沪深股市数据推送.问题或建议,请关注公众号发送消息留言;如果你觉得FocusBI对你有帮助,欢迎转发朋友圈或在文章末 ...
- Spring多线程编程
在Spring框架下如何保证线程安全,如何很happy顺畅地并发编程. 常见的如下面的这坨代码,在Spring中,默认是单例的,也就是说,在同一时刻只有一个SpringOrdinaryClass的单实 ...
- Angular 4+ 修仙之路
Angular 4.x 快速入门 Angular 4 快速入门 涉及 Angular 简介.环境搭建.插件表达式.自定义组件.表单模块.Http 模块等 Angular 4 基础教程 涉及 Angul ...
- ajax 传递数组给后台.net MVC 控制器
数组结构为: [ "5ae92c2786f3591b2cff1be5", "5ae91bb7ca673569a8d23a6e" ] 前台代码: $.ajax({ ...
- C# 核心语法-反射(反射类型、方法、构造函数、属性,实现可配置可扩展,完成数据库访问类反射封装)
反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类.结构.委托.接口和枚举等)的成员和成员的信息.有了反射,即可对每一个类型了如指掌.另外我还可以直接创建对象,即使 ...
- Hadoop源码学习笔记(3) ——初览DataNode及学习线程
Hadoop源码学习笔记(3) ——初览DataNode及学习线程 进入了main函数,我们走出了第一步,接下来看看再怎么走: public class DataNode extends Config ...