上一章:《【D3.js 入门系列一】从零开始绘制一个柱形图》 html
声明:本教程针对D3.js v3版本进行讲解。git
Update、Enter、Exit 是 D3 中三个很是重要的概念,它处理的是当选择集和数据的数量关系不肯定的状况。github
前面章里,反复出现了形如如下的代码。api
svg.selectAll("rect") //选择svg内全部的矩形
.data(dataset) //绑定数组
.enter() //指定选择集的enter部分
.append("rect") //添加足够数量的矩形元素
复制代码
前面提到,这段代码使用的状况是当如下状况出现的时候:数组
有数据,而没有足够图形元素的时候,使用此方法能够添加足够的元素。app
当时并无深究这段代码是什么意思,本章将对此进行讲解。可是,因为此问题相对复杂,本章只进行最初步的介绍。less
假设,在 body 中有三个 p 元素,有一数组 [3, 6, 9],则能够将数组中的每一项分别与一个 p 元素绑定在一块儿。可是,有一个问题:当数组的长度与元素数量不一致(数组长度 > 元素数量 or 数组长度 < 元素数量)时呢?这时候就须要理解 Update、Enter、Exit 的概念。dom
若是数组为 [3, 6, 9, 12, 15],将此数组绑定到三个 p 元素的选择集上。能够想象,会有两个数据没有元素与之对应,这时候 D3 会创建两个空的元素与数据对应,这一部分就称为 Enter。而有元素与数据对应的部分称为 Update。若是数组为 [3],则会有两个元素没有数据绑定,那么没有数据绑定的部分被称为 Exit。示意图以下所示。 svg
看到这,我想你们能体会到为何本节最开始处的代码可以给 SVG 内添加足够数量的元素了吧。它的意思实际上是:函数
此时 SVG 里没有 rect 元素,即元素数量为 0。有一数组 dataset,将数组与元素数量为 0 的选择集绑定后,选择其 Enter 部分(请仔细看上图),而后添加(append)元素,也就是添加足够的元素,使得每个数据都有元素与之对应。
当对应的元素不足时 ( 绑定数据数量 > 对应元素 ),须要添加元素(append)。
如今 body 中有三个 p 元素,要绑定一个长度大于 3 的数组到 p 的选择集上,而后分别处理 update 和 enter 两部分。
var dataset = [ 3 , 6 , 9 , 12 , 15 ];
//选择body中的p元素
var p = d3.select("body").selectAll("p");
//获取update部分
var update = p.data(dataset);
//获取enter部分
var enter = update.enter();
//update部分的处理:更新属性值
update.text(function(d){
return "update " + d;
});
//enter部分的处理:添加元素后赋予属性值
enter.append("p")
.text(function(d){
return "enter " + d;
});
复制代码
结果以下图,update 部分和 enter 部分被绑定的数据很清晰地表示了出来。
请你们记住:
当对应的元素过多时 ( 绑定数据数量 < 对应元素 ),须要删掉多余的元素。
如今 body 中有三个 p 元素,要绑定一个长度小于 3 的数组到 p 的选择集上,而后分别处理 update 和 exit 两部分。
var dataset = [ 3 ];
//选择body中的p元素
var p = d3.select("body").selectAll("p");
//获取update部分
var update = p.data(dataset);
//获取exit部分
var exit = update.exit();
//update部分的处理:更新属性值
update.text(function(d){
return "update " + d;
});
//exit部分的处理:修改p元素的属性
exit.text(function(d){
return "exit";
});
//exit部分的处理一般是删除元素
// exit.remove();
复制代码
结果以下,请你们区分好 update 部分和 exit 部分。这里为了代表哪一部分是 exit,并无删除掉多余的元素,但实际上 exit 部分的绝大部分操做是删除。
请你们记住:
D3 支持制做动态的图表。有时候,图表的变化须要缓慢的发生,以便于让用户看清楚变化的过程,也能给用户不小的友好感。
前面一章制做的图表是一蹴而就地出现,而后绘制完成后再也不发生变化的,这是静态的图表。
动态的图表,是指图表在某一时间段会发生某种变化,多是形状、颜色、位置等,并且用户是能够看到变化的过程的。
例如,有一个圆,圆心为 (100, 100)。如今咱们但愿圆的 x 坐标从 100 移到 300,而且移动过程在 2 秒的时间内发生。
这种时候就须要用到动态效果,在 D3 里咱们称之为过渡(transition)。
D3 提供了 4 个方法用于实现图形的过渡:从状态 A 变为状态 B。
transition()
启动过渡效果。
其先后是图形变化先后的状态(形状、位置、颜色等等),例如:
.attr("fill","red") //初始颜色为红色
.transition() //启动过渡
.attr("fill","steelblue") //终止颜色为铁蓝色
复制代码
D3 会自动对两种颜色(红色和铁蓝色)之间的颜色值(RGB值)进行插值计算,获得过渡用的颜色值。咱们无需知道中间是怎么计算的,只须要享受结果便可。
duration()
指定过渡的持续时间,单位为毫秒。
如 duration(2000) ,指持续 2000 毫秒,即 2 秒。
ease()
指定过渡的方式,经常使用的有:
调用时,格式形如: ease(“bounce”)。
delay()
指定延迟的时间,表示必定时间后才开始转变,单位一样为毫秒。此函数能够对总体指定延迟,也能够对个别指定延迟。
例如,对总体指定时:
.transition()
.duration(1000)
.delay(500)
复制代码
如此,图形总体在延迟 500 毫秒后发生变化,变化的时长为 1000 毫秒。所以,过渡的总时长为1500毫秒。
又如,对一个一个的图形(图形上绑定了数据)进行指定时:
.transition()
.duration(1000)
.delay(funtion(d,i){
return 200*i;
})
复制代码
如此,假设有 10 个元素,那么第 1 个元素延迟 0 毫秒(由于 i = 0),第 2 个元素延迟 200 毫秒,第 3 个延迟 400 毫秒,依次类推….整个过渡的长度为 200 * 9 + 1000 = 2800 毫秒。
下面将在 SVG 画布里添加三个圆,圆出现以后,当即启动过渡效果。
第一个圆,要求移动 x 坐标。
var circle1 = svg.append("circle")
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 45)
.style("fill","green");
//在1秒(1000毫秒)内将圆心坐标由100变为300
circle1.transition()
.duration(1000)
.attr("cx", 300);
复制代码
第二个圆,要求既移动 x 坐标,又改变颜色。
var circle2 = svg.append("circle")... //与第一个圆同样,省略部分代码
//在1.5秒(1500毫秒)内将圆心坐标由100变为300,
//将颜色从绿色变为红色
circle2.transition()
.duration(1500)
.attr("cx", 300)
.style("fill","red");
复制代码
第三个圆,要求既移动 x 坐标,又改变颜色,还改变半径。
var circle3 = svg.append("circle")... //与第一个圆同样,省略部分代码
//在2秒(2000毫秒)内将圆心坐标由100变为300
//将颜色从绿色变为红色
//将半径从45变成25
//过渡方式采用bounce(在终点处弹跳几回)
circle3.transition()
.duration(2000)
.ease("bounce")
.attr("cx", 300)
.style("fill","red")
.attr("r", 25);
复制代码
在上一章完整柱形图的基础上稍做修改,便可作成一个带动态效果的、有意思的柱形图。
在添加文字元素和矩形元素的时候,启动过渡效果,让各柱形和文字缓慢升至目标高度,而且在目标处跳动几回。
对于文字元素,代码以下:
.attr("y",function(d){
var min = yScale.domain()[0];
return yScale(min);
})
.transition()
.delay(function(d,i){
return i * 200;
})
.duration(2000)
.ease("bounce")
.attr("y",function(d){
return yScale(d);
});
复制代码
文字元素的过渡先后,发生变化的是 y 坐标。其起始状态是在 y 轴等于 0 的位置(但要注意,不能在起始状态直接返回 0,要应用比例尺计算画布中的位置)。终止状态是目标值。
对于矩形元素,思想与文字元素同样,只是在计算起始状态时要稍微复杂一些,请读者自行研读页面底部的示例代码地址中的代码。
与图表的交互,指在图形元素上设置一个或多个监听器,当事件发生时,作出相应的反应。
交互,指的是用户输入了某种指令,程序接受到指令以后必须作出某种响应。对可视化图表来讲,交互能使图表更加生动,能表现更多内容。例如,拖动图表中某些图形、鼠标滑到图形上出现提示框、用触屏放大或缩小图形等等。
用户用于交互的工具通常有三种:鼠标、键盘、触屏。
对某一元素添加交互操做十分简单,代码以下:
var circle = svg.append("circle");
circle.on("click", function(){
//在这里添加交互内容
});
复制代码
这段代码在 SVG 中添加了一个圆,而后添加了一个监听器,是经过 on() 添加的。在 D3 中,每个选择集都有 on() 函数,用于添加事件监听器。
on() 的第一个参数是监听的事件,第二个参数是监听到事件后响应的内容,第二个参数是一个函数。
鼠标经常使用的事件有:
键盘经常使用的事件有三个:
触屏经常使用的事件有三个:
当某个事件被监听到时,D3 会把当前的事件存到 d3.event 对象,里面保存了当前事件的各类参数,请你们好好参详。若是须要监听到事件后马上输出该事件,能够添加一行代码:
circle.on("click", function(){
console.log(d3.event);
});
复制代码
将【D3.js 入门系列一】的部分代码修改为以下代码。
var rects = svg.selectAll(".MyRect")
.data(dataset)
.enter()
.append("rect")
.attr("class","MyRect") //把类里的 fill 属性清空
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.attr("x", function(d,i){
return xScale(i) + rectPadding/2;
} )
.attr("y",function(d){
return yScale(d);
})
.attr("width", xScale.rangeBand() - rectPadding )
.attr("height", function(d){
return height - padding.top - padding.bottom - yScale(d);
})
.attr("fill","steelblue") //填充颜色不要写在CSS里
.on("mouseover",function(d,i){
d3.select(this)
.attr("fill","yellow");
})
.on("mouseout",function(d,i){
d3.select(this)
.transition()
.duration(500)
.attr("fill","steelblue");
});
复制代码
这段代码添加了鼠标移入(mouseover),鼠标移出(mouseout)两个事件的监听器。监听器函数中都使用了 d3.select(this),表示选择当前的元素,this 是当前的元素,要改变响应事件的元素时这么写就好。
mouseover 监听器函数的内容为:将当前元素变为黄色
mouseout 监听器函数的内容为:缓慢地将元素变为原来的颜色(蓝色)
代码示例地址:github.com/legend-li/D…
未完待续~
参考资料:www.ourd3js.com/
D3.js(v3)中文api:github.com/d3/d3/wiki/…