本篇大纲:transition( ) 移动、变换颜色、transition.delay( )、transition.ease( )、transition.on( )
今天要来讲讲我觉得 D3.js 最有趣的部分啦!动画效果基本上是酷炫前端网站必不可少的功能,D3 也知道这一点,并开发出一系列处理动画效果的 API 们
一般主要是使用 selection.transition( ) 这个 API 来处理动画,.transition() 归类在selection 底下是因为它的设计逻辑是由d3.selection延伸而来,因此要先用select() 的方法选定 DOM 元素後,才能将动画绑定到回传的 selection 实体上。
一旦把所选的 DOM 元素加上 transition( ) 之後,就能建立d3的动画效果。特别的是,这个动画效果还多了动画执行时间
、动画生命周期
这些特性,因此我们就可以用其他 transition( ) 旗下的 API 来调整动画的时长、动画方式、延迟时间等等。我们能使用的 API 包含:
transition() 的用法也非常简单,只要选定要加动画的DOM元素之後,加上.transition(),接着在後方接上想用动画完成的项目,这些项目就会被加上动画啦~这边要特别说一下,因为下一篇才会讲到d3的事件触发,所以这篇的范例我们都先用JS原生的on click事件去触发动画,下一篇开始再跟大家说要如何使用d3方便的事件触发 API 们~
移动
以下就用这个例子来示范,目前画面上[0,0]的位置有一个方块,按下移动的按钮後,这个方块会被移动到[140,60]的位置
// html
<svg class="move"></svg>
<button type="button" class="btn btn-primary moveBtn">移动</button>
// js
// 方块大小
const rect = d3.select('.move')
.append('rect')
.attr('width', 40)
.attr('height', 40)
.attr('stroke', 'black')
// 移动事件触发
document.querySelector('.moveBtn').addEventListener('click', function(){
rect.attr('transform', 'translate(140, 60)')
})
没有加上动画时,按下移动的按钮会发现正方型很生硬地直接跳到[140,60]的位置
救命!!谁想要这麽生硬蛮横地跳转啊!?快点加上动画缓和一下
// 移动事件触发
document.querySelector('.moveBtn').addEventListener('click', function(){
rect.transition() // 加上动画
.attr('transform', 'translate(140, 60)')
})
总算好多了~~这个就是我们要的平滑转换动画效果
但我觉得这个动画有点太快了,想进行一些特别设定,例如:我想要设定动画的时长是五秒钟!这时就可以派出 .duration( ) 啦~
// 移动事件触发
document.querySelector('.moveBtn').addEventListener('click', function(){
rect.transition()
.duration(5000) // 设定动画时间持续5秒钟
.attr('transform', 'translate(140, 60)')
})
完成的效果就像这样
变换颜色
除了移动之外,颜色的变化、边框粗细等等也都可以用动画来调整
// html
<svg class="changeColor"></svg>
<br>
<button type="button" class="btn btn-primary changeBtn">改变颜色</button>
// 改变颜色
const round = d3.select('.changeColor')
.append('circle')
.attr('cx', 100)
.attr('cy', 50)
.attr('r', 25)
.attr('fill', 'orange')
.attr('stroke-width', '0.5px')
.attr('stroke', 'black')
document.querySelector('.changeBtn').addEventListener('click', function(){
round.transition()
.duration(1000)
.attr('fill', 'green')
.attr('stroke-width', '6px')
.attr('stroke', 'red')
})
大功告成~transition( ) 是不是很简单呀?但要特别注意的是,想加上动画的项目一定要放在 transition( ) 之後,如果放在 transition( ) 之前的话,就无法绑定动画效果
.delay( ) 动画延迟
我自己觉得 transition.delay( ) 这个方法很有趣,它的参数是填入想秒数,但也可以填入方法去各别设定每个元素的延迟秒数,达到元素一个接一个进行动画的效果,就像这样:
那具体该怎麽做呢?话不多说直接上程序码吧!
一开始一样先设定我们的资料,并把资料绑定到 DOM 上
// html
<svg class="delay"></svg>
<button type="button" class="btn btn-primary mt-3 delayBtn">delay开始</button>
// js
const dataDelay = [160, 140, 120, 100, 80, 60 ,40 ,20]
const delay = d3.select('.delay')
.selectAll('circle')
.data(dataDelay)
.enter()
.append('circle')
.attr('cx', d => d)
.attr('cy', 30)
.attr('r', 15)
.attr('fill', 'blue')
.attr('opacity', '0.5')
接着设定按下按钮时触发的动画事件,并且设定 .delay( ) 要一一进行
document.querySelector('.delayBtn').addEventListener('click', function(){
delay.transition()
.delay((d,i)=> i*200) // 分别延迟
.attr('cx', d => d+120) // 位移距离
})
这样就完成啦~~
.ease( ) 动画效果
我们接着看到另外一个有趣的API,transition.ease( ) 的参数必须是一个方法,用来设定动画每一帧的时长,藉此达到不同的动画效果。但设定动画运作方式其实蛮复杂的,还好 D3.js 已经帮我们设定好多种不同的动画方法了!这些方法有:
我们只要找到想要的方法并带入就可以~想更深入了解这些方法的人可以看官网对於每个方法的的详细解说
但光看官方文件实在很难理解这些动画效果,所以我们直接用画面来展示一下吧!首先,一样先在画面上画个圆
// html
<svg class="ease"></svg>
<select name="ease" id="ease">
<option value=""></option>
</select>
<button type="button" class="btn btn-primary mt-3 easeBtn" onClick="updateEast();">Ease开始</button>
// js
const easeDot = d3.select('.ease')
.append('circle')
.attr('cx', 40)
.attr('cy', 40)
.attr('r', 30)
.attr('fill', 'blue')
接着,我们把d3所有的API 叫出来,并抓出属於 ease 的 API 带入< option > 中让我们能够选取想要的动画效果
const easeNames = Object.keys(d3).filter(d=>{
return d.slice(0,4) === 'ease' // 抓出所有方法中,名称内有ease的方法
})
console.log(easeNames)
d3.select('#ease')
.selectAll('option')
.data(easeNames)
.join('option')
.attr('value', function(d) { return d; })
.text(function(d) { return 'd3.' + d; });
最後,我们设定按下按钮时,要运行目前选到的动画效果
function updateEast(){
let easeName = d3.select('#ease').node().value;
console.log(easeName)
easeDot.attr('cx', 40) // 回原点
.transition()
.ease(d3[easeName]) // 设定动画效果
.attr('cx', 200)
}
完成!!我们来玩玩看吧~
transition.on( ) 动画的生命周期
前面示范的动画效果都是被特定指令触发止後只执行一次,但如果想制作重复执行、不停循环的动画
该怎麽办呢?这时我们就可以利用 transition.on( ) 产生的四个事件来进行设计。
transition.on( ) 会产生四种事件:
我们使用 start 这个事件来制作一个无限循环的动画。 首先,一样先在画面上建立一个蓝色圆点点
// html
<svg class="loopAnimation"></svg>
//js
const loop = d3.select('.loopAnimation')
.append('circle')
.attr('cx', 50)
.attr('cy', 50)
.attr('r', 25)
.attr('fill', 'blue')
接着,将这个圆点加上transition.on( ),并设定要触发的动画事件为"start",它的callback function 叫做 goRight。这边的意思就是:每当动画开始时,我要执行 goRight 这个方法
const loop = d3.select('.loopAnimation')
.append('circle')
.attr('cx', 50)
.attr('cy', 50)
.attr('r', 25)
.attr('fill', 'blue')
.transition()
.duration(2000)
.on('start', goRight)
然後我们来设定 goRight 方法吧!
function goRight(){
d3.active(this)
.attr('cx', 200)
.transition()
.on("start", goLeft);
}
接着我们一样来设定 goLeft 方法
function goLeft (){
d3.active(this)
.attr('cx', 50)
.transition()
.on("start", goRight)
}
我们利用 transition() start 的事件,设定了 goRight、goLeft 两个方法,并让这两个方法互相呼叫,这样一来就能成功做出无限循环的动画啦!
看完上面的例子,是不是觉得d3.transition( ) 很有趣呢?最後我们实际示范一个常见的图表动画:当资料变动时,图表要搭配动画去改变颜色跟高度吧!
// html
<h5 class="mt-5">3.完整图表动画</h5>
<div class="chartContainer"></div>
<button type="button" id="start" class="btn btn-primary">动画开始</button>
//js
//定义两个资料,都是Y值,x值就用阵列索引即可
let data1 = [150, 122, 133, 161, 116, 139, 143, 115, 193, 137, 122, 141];
let data2 = [180, 146, 180, 172, 133, 149, 152, 138, 188, 192, 117, 146];
let n = data1.length, //资料点的数量
mx = d3.max(d3.merge([data1, data2])) //抓两个阵列的最大值
// svg
const svg = d3.select('.chartContainer').append('svg');
svg.attr('width', 500)
.attr('height', 300);
svg.selectAll('rect')
.data(data1)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', (d, i) => i * 30)
.attr('width', (d, i) => d)
.attr('height', 20)
.attr('fill', 'orange')
// 动画开始
d3.select('#start')
.on('click', function () {
svg.selectAll('rect')
.data(data2) // 资料变化
.transition() // 加上动画
.duration(1000) //点击之後每个 bar 会在1秒内到达更新位置
.delay((d, i) => 200 * i) //每个bar在分别delay後才开始动画,
// delay 时间乘上index,做出从上至下更新的动画效果
.attr('width', (d, i) => d)
.attr('fill', '#66f9ff')
});
实际呈现是这样子
这就是 d3.js 的动画效果啦~有兴趣的人也可以自己做一次看看!明天我们就要进入另一个有趣的领域罗~
这边附上本章的程序码与图表 Github 、 Github,需要的人请自行取用~
<<: Day 7 - Function 时空旅行 (2) - 拆解与命名
>>: 【Day06】生命周期 Lifecycle(Class Component)
在辅导客户中多数都是外销公司的辅导顾问案件,尤於外销市场不同於内销市场在操作 业务开发 的确有难度。...
前情提要 艾草:「我们今天来提升一下吧!」 「不是每天都在提升魔力总量了吗?」 艾草:「不一样唷,今...
Biometric Biometric让用户不必每次打开APP时都记住帐户用户名和密码,只需使用生物...
嗨呦大家好我是 Jasmine~脑袋总是胡思乱想停不下来的设计师一枚\(✪ω✪)/ 来到连假最後一天...
-虚拟机和容器部署(来源:NIST SP 800-190) 虚拟机器监视器(Hypervisor)...