D3学习之动画和变换

(17.02.27-02.28)


主要学习到了D3对动画和缓动函数的一些应用,结合前面的选择器、监听事件、自定义插值器等,拓展了动画的效果和样式。

主要内容

  • 单元素动画
  • 多元素动画
  • 使用缓动函数
  • 使用中间帧函数
  • 使用级联过渡
  • 使用选择器过渡
  • 监听过渡事件
  • 自定义插值器
  • 使用计时器

为什么需要动画?

人类视觉系统是一个精妙的信息处理器,因此推向可以传递海量信息,并且移动的图像更能在短时间内传达更多的信息。的确,在世界不断的演变过程中,人类的视觉系统也在不断地进化,对于移动的物体,它能够更好地聚焦。 -Parent R.2012

D3的动画与过渡

D3过渡使我们可以在网页上使用HTML或SVG创造计算机动画。D3过渡实现了一种基于插值的动画(Interpolation-based Animation)。所以D3动画的基础是插值。

单元素动画

body.append("div")
.classed("box", true)
.style("background-color", "#e9967a")
.transition() //使用d3.selection.transition函数来定义一个过渡
.duration(duration) //使用duration函数来设置过渡效果的持续时间
.style("background-color", "#add8e6")
.style("margin-left", "600px")
.style("width", "100px")
.style("height", "100px")
.transition() //要实现单元素连续动画就直接加在后面
.duration(duration)
.style("background-color", "#19e549")
.style("margin-top", "100px")
.style("margin-left","100px")
.style("width", "500px")
.style("height", "50px");

因为是动画所以不好截图显示,从代码上也可以看出是一个长方形变成正方形再变成长方形,同时伴随着颜色的变化的过程。

多元素动画

原理和单元素类似,但是操作对象变成了一个集合而不是单一的元素:

 selection   //selection是元素的集合
.transition().duration(duration) // <-D
.style("top", function (d) {
return chartHeight - barHeight(d) + "px"; //top是距离顶的距离
})
.style("left", function (d, i) { //更新left值和height值
return barLeft(i) + "px";
})
.style("height", function (d) {
return barHeight(d) + "px";
})
.style("background-color",randomColor())
.select("span")
.text(function (d) {
return d.value;
}); //d.value,d是字典

缓动函数

过渡是和时间相关的函数,它将时间进度映射到数值的变化,形成了对象的运动(如果数值代表位置)或者形变(如果数值描述视觉属性)。时间是均匀变化的,换句话说时间是均匀的,然而结果并不总是需要均匀的。缓动正是控制这一映射,并提供灵活性的典型技术。当一个过渡生成均匀的值变化时,我们称之为线性缓动。

D3内部已经实现了一部分缓动函数及其过渡效果(linear线性,cubic立方,sin正弦等),同时支持自定义函数(代码内的B处)。

var data = [ // <-A
"linear", "cubic", "cubic-in-out",
"sin", "sin-out", "exp", "circle", "back",
"bounce",
function(t){ // <-B
return t * t;
}
]

ease( )的传入参数是一个字符串,D3会找到同名的缓动函数,否则默认使用线性缓动。而在实现上,需要注意的有一点:

 d3.selectAll("div").each(function(d){
d3.select(this)
.transition().ease(d) //这里ease()函数不能用上面each()这种方式
.duration(5000)
.style("left", "10px");
});

ease()函数不支持以下这种方式,即使用一个函数来定义不同的缓动效果:

d3.selectAll("div").ease(function(d){
return d;})
.duration(5000)
.style("left", "10px");
});

D3还提供了缓动模式修饰符,它能够和任意缓动函数结合起来,形成特殊的效果,例如sin-out或者quad-out-in。现有的模式修饰符有如下几个:

  • in:默认
  • out:反向
  • in-out:镜像
  • out-in:反向镜像

使用中间帧计算

中间帧一词源于“inbetween”,inbetween是传统动画行业的一种通用实践,当时主设计师创建完关键帧后,再由工作人员在其中插入一些中间帧。这一概念被引入现代计算机动画中,用来代表插入中间帧的各种技术和算法。

以下函数创建了一个自定义中间帧计算函数:

body.append("div").append("input")
.attr("type", "button")
.attr("class", "countdown")
.attr("value", "0")
.transition().duration(duration).ease("linear")
.styleTween("width", widthTween)
.attrTween("value", valueTween); //valueTween即中间帧计算函数

来看看valueTween():通过量化尺度对传入的时间参数插值,最终生成了跳跃的整数效果。

function valueTween(){
var interpolate = d3.scale.quantize() // 定义了量化尺度,设置了定义域和值域
.domain([0, 1])
.range([1, 2, 3, 4, 5, 6, 7, 8, 9]); return function(t){ // <-D
return interpolate(t);
};
}

效果如下:

级联过滤

级联过滤的作用就是将复杂的过渡效果进行封装,从而可以重复使用,保证了复杂过渡效果的可重用性,这一特性很好地实现了DRY原则(Don't repeat yourself)。

function teleport(s) {  //复杂的过渡效果
s.transition().duration(300)
.style("width", "200px")
.style("height", "1px")
.transition().duration(100)
.style("left", "600px")
.transition().duration(300)
.style("left", "800px")
.style("height", "80px")
.style("width", "80px")
.transition().duration(300)
.style("left", "680px")
.style("height", "1px")
.style("width", "200px")
.style("top", "80px")
.transition().duration(100)
.style("left", "10px")
.transition().duration(300)
.style("height", "80px")
.style("width", "80px")
.style("top", "10px");
}

调用这一函数:

body.append("div")
.attr("class", "dong")
.style("position", "fixed")
.style("background-color", "steelblue")
.style("left", "10px")
.style("width", "80px")
.style("height", "80px")
.call(teleport); //通过call函数来调用级联过滤

使用选择性过渡

选择性过渡用于对特定选集的部分子集应用过渡效果。以下选择器限定了data值为“cat”的对象才会移动。

 .transition() // <- A
.duration(duration)
.style("left", "10px")
.filter(function(d){return d == "Cat";}) // <- B d就是数据值 选择器
.transition() // <- C
.duration(duration)
.style("left", "500px");

效果如图:

级联过滤

级联过滤的作用就是将复杂的过渡效果进行封装,从而可以重复使用,保证了复杂过渡效果的可重用性,这一特性很好地实现了DRY原则(Don't repeat yourself)。

function teleport(s) {  //复杂的过渡效果
s.transition().duration(300)
.style("width", "200px")
.style("height", "1px")
.transition().duration(100)
.style("left", "600px")
.transition().duration(300)
.style("left", "800px")
.style("height", "80px")
.style("width", "80px")
.transition().duration(300)
.style("left", "680px")
.style("height", "1px")
.style("width", "200px")
.style("top", "80px")
.transition().duration(100)
.style("left", "10px")
.transition().duration(300)
.style("height", "80px")
.style("width", "80px")
.style("top", "10px");
}

调用这一函数:

body.append("div")
.attr("class", "dong")
.style("position", "fixed")
.style("background-color", "steelblue")
.style("left", "10px")
.style("width", "80px")
.style("height", "80px")
.call(teleport); //通过call函数来调用级联过滤

使用选择性过渡

选择性过渡用于对特定选集的部分子集应用过渡效果。以下选择器限定了data值为“cat”的对象才会右移。

 .transition() // <- A
.duration(duration)
.style("left", "10px")
.filter(function(d){return d == "Cat";}) // <- B d就是数据值 选择器
.transition() // <- C
.duration(duration)
.style("left", "500px");

效果如图:

监听过渡事件

监听用于在触发特定动作后进行相应的操作或者在过渡时进行不同的处理。

.transition().duration(duration)
.delay(1000)
.each("start", function(){ // 在过渡开始(start)时触发,修改text值
console.log(arguments);
d3.select(this).text(function (d, i) {
return "transitioning";
});
})
.each("end", function(){ // 在过渡动画结束时修改text值为done
d3.select(this).text(function (d, i) {
return "done";
});
})

效果如下:





实现自定义插值器

先看看自定义插值器的实现:

 d3.interpolators.push(function(a, b) { // <-A
var re = /^([a-z])$/, ma, mb;
if ((ma = re.exec(a)) && (mb = re.exec(b))) {
a = a.charCodeAt(0);
var delta = a - b.charCodeAt(0);
return function(t) {
return String.fromCharCode(Math.ceil(a - delta * t));
};
}
}); //自定义差值器自动加入全局,并且优先被选取(类似栈结构)

这里定义的是一个a-z的插值器,设定了检查和范围,那么在调用时只要符合参数的范围(a-z),D3会调用相应的插值器。

countdown.attr("type", "button")
.attr("class", "countdown")
.attr("value", "a") //a
.transition().ease("linear")
.duration(25000).delay(1000)
.attr("value", "z"); //z

效果如图:

使用定时器

D3定时器函数作为实现D3过渡的底层结构,可以帮助我们更灵活地创建自定义动画。

在下面这个例子中,我们构造一个自定义动画,用来显示不断变化的从0到100的数字。

 function countup(target){
d3.timer(function(){
var value = countdown.attr("value");
if(value == target) return true;
countdown.attr("value", ++value);
});
}

d3.timer()函数接受一个自定义函数,并且立即反复调用这一函数,直到该函数返回true为止,因此当value等于target(也就是100)时,才会返回true,否则就会一直自加。

最后

已掌握了对过渡和动画的初步使用,在以后具体实现中应多思考来实现更复杂的效果。

D3学习之动画和变换的更多相关文章

  1. iOS学习——核心动画之Layer基础

    iOS学习——核心动画之Layer基础 1.CALayer是什么? CALayer我们又称它叫做层.在每个UIView内部都有一个layer这样一个属性,UIView之所以能够显示,就是因为它里面有这 ...

  2. 纯干货:深度学习实现之空间变换网络-part2

    https://www.jianshu.com/p/854d111670b6 纯干货:深度学习实现之空间变换网络-part1 在第一部分中,我们主要介绍了两个非常重要的概念:仿射变换和双线性插值,并了 ...

  3. iOS学习——核心动画

    iOS学习——核心动画 1.什么是核心动画 Core Animation(核心动画)是一组功能强大.效果华丽的动画API,无论在iOS系统或者在你开发的App中,都有大量应用.核心动画所在的位置如下图 ...

  4. ECCV 2018 | 旷视科技提出GridFace:通过学习局部单应变换实现人脸校正

    全球计算机视觉三大顶会之一 ECCV 2018(European Conference on Computer Vision)即将于 9 月 8 -14 日在德国慕尼黑拉开帷幕,旷视科技有多篇论文被此 ...

  5. D3学习笔记一

    D3学习笔记一 什么是D3? D3(全称Data Driven Documents)是一个用来做Web数据可视化的JavaScript函数库.D3也称之为D3.js. D3是2011年由Mike Bo ...

  6. D3学习之地图

    D3学习之地图 (2017.03.09-03.11) 地图的意义 在可视化领域中,将数据点投影和关联到地理区域上,是一个非常关键的内容(体现了可视化中利用读者自身知识常识从而加速吸收信息的原则). G ...

  7. D3 学习

    D3 学习笔记 D3简介 D3全称是Data-Driven Documents数据驱动文档,是一个开源的javascript库,可以用于数据可视化图形的创建,但不仅仅只是这些.可以查看d3帮助文档还有 ...

  8. d3学习之路

    d3学习历程: 轻量化编译器:HbuiderXHbuiderX使用教程   理解HTMl js CSS 三者关系   学习html js css :1)w3school           2)moo ...

  9. ReactNative学习实践--动画初探之加载动画

    学习和实践react已经有一段时间了,在经历了从最初的彷徨到解决痛点时的兴奋,再到不断实践后遭遇问题时的苦闷,确实被这一种新的思维方式和开发模式所折服,react不是万能的,在很多场景下滥用反而会适得 ...

随机推荐

  1. @classmethod装饰器

    当一个类中有多条用例,我们在执行的时候每执行一条用例就要重新打开一次浏览器操作,例如下: start test1 quit start test2 start 若我们使用@classmethod装饰器 ...

  2. GitHub上整理的一些工具【转】

    技术站点 Hacker News:非常棒的针对编程的链接聚合网站 Programming reddit:同上 MSDN:微软相关的官方技术集中地,主要是文档类 infoq:企业级应用,关注软件开发领域 ...

  3. 自己根据java的LinkedList源码编写的一个简单的LinkedList实现

    自己实现了一个简单的LinkedList /** * Create by andy on 2018-07-03 11:44 * 根据 {@link java.util.LinkedList}源码 写了 ...

  4. Oracle Instant Client的安装和使用

    转自:https://www.cnblogs.com/chinalantian/archive/2011/09/09/2172145.html 根据自己需求到Oracle网站(http://www.o ...

  5. zookeeper 事务日志与快照日志

    zookeeper日志各类日志简介 zookeeper服务器会产生三类日志:事务日志.快照日志和log4j日志. 在zookeeper默认配置文件zoo.cfg(可以修改文件名)中有一个配置项data ...

  6. Spring容器初始化的时候如何添加一个定时器?

    昨天遇到这个问题,在项目启动的时候添加一个定时器隔一段时间扫描有没有定时发送的邮件(当然也可以是你自己的业务逻辑),也在网上找了资料,加上自己的修改,终于成功了.所以来做个记录. 1.ServletC ...

  7. Spoken English Practice(If you fail to do as I say, I will take you suffer.)

    绿色:连读:                  红色:略读:               蓝色:浊化:               橙色:弱读     下划线_为浊化 口语蜕变(2017/6/29) ...

  8. Spoken English Practice( Nobody have the guts to tell Paul what a mistake he was taking.(call,come,gut,fortune,when it comes to))

    音标复习 绿色:连读:                  红色:略读:               蓝色:浊化:               橙色:弱读 口语蜕变(2017/6/24) If your ...

  9. Android 点击电话号码之间拨号

    点击电话号码之间拨打电话,可用通过下面的方式实现: 假设电话号码以TextView的方式显示 1.Intent方式 在TextView的响应事件中 : String phone = tvphone.g ...

  10. 用java求一个整数各位数字之和

    /* * 用java求一个整数各位数字之和 */ public class Test02 { public static void main(String[] args) { System.out.p ...