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. React课程学习

    http://guoyongfeng.github.io/idoc/index.html

  2. drupal7使用数据库api db_query需要注意的地方

    写自定义module时候需要从数据库检索数据,用到了数据库的api,用了下面的sql: $record = db_query("SELECT 'sampledate', 'time' FRO ...

  3. CNN 各layer汇总

    Flattening:类型为:Flatten 基于某个axis进行偏平的意思,如 axis = 1 ,fattens an input of shape n * c * h * w to a simp ...

  4. AWS系列-申请Redis

    1.1 打开aws控制台,可以直接搜索redis 1.2 进入redis控制面板 点击启动缓存集群(这个只是启动创建的意思,不是启动下面创建好的node.我也不懂为啥翻译过来是这个意思...) 1.3 ...

  5. Bootstrap的js插件之側边栏停靠(affix)

    以下是一个比較常见的側边栏停靠的样例: <!DOCTYPE html> <html lang="en"> <head> <meta cha ...

  6. 【BZOJ4379】[POI2015]Modernizacja autostrady 树形DP

    [BZOJ4379][POI2015]Modernizacja autostrady Description 给定一棵无根树,边权都是1,请去掉一条边并加上一条新边,定义直径为最远的两个点的距离,请输 ...

  7. Spring Security OAuth2 授权失败(401) 问题整理

    Spring Cloud架构中采用Spring Security OAuth2作为权限控制,关于OAuth2详细介绍可以参考 http://www.ruanyifeng.com/blog/2014/0 ...

  8. HTTP协议包分析(小马上传大马)

    最近工作内容是分析防火墙日志,看日志是正确,本地实验小马上传大马  抓取http包如下.可以在分析过程中进行借鉴. 该http请求的行为是通过小马,在小马的当前目录创建一个dama.php的文件,文件 ...

  9. centos7 docker镜像加速器配置

    CentOS的配置方式略微复杂,需要先将默认的配置文件复制出来 /lib/systemd/system/docker.service -> /etc/systemd/system/docker. ...

  10. Android主页导航:fragment+viewpager

    简单实现Fragment+ViewPager实现主页导航控制,效果如下: 一.activity_main.xml布局文件: <?xml version="1.0" encod ...