transition、animation是CSS3中制做DOM元素动画的重要属性,但其仅仅只能应对一些常规的需求,针对非DOM元素的属性过渡时就显得无能为力了,因此接下来经过js简单实现其动画原理(说白了也就是经过JavaScript间接操做目标过渡属性值,每隔一段时间更新一次)让动画变得更加灵活可控,而不是对可恶的pm说这效果有啥用、砍掉这类的话,固然还得看需求使用场景css
先给个demo: 针对这样的需求怎么实现呢? html
纯css显然已没法作到(图片有点失真,在线众筹换mac, 意思到位了就行~)前端
简单概述下上面的gif,布局采用了d3实现,针对这种需求常规的可视化图形插件(如ECharts、ichartjs等),经过简单的配置可能已没法作到,就算能实现灵活度也必然受到了限制。熟悉d3的同窗实现起来也不会太复杂,图中主要是数字的变化以及弧形的颜色渐变的效果应如何实现,以及总体的联动。下面经过js来描述动画原理,使得更易于掌握css过渡transition及动画animationcss3
html代码git
<div id="motionPath"></div>
复制代码
css代码github
#motionPath {
width: 20px;
height: 100px;
color:#333;
background-color: red;
}
复制代码
在实现以前,先简单了解下贝塞尔曲线的原理参考贝塞尔曲线扫盲,了解了原理以后推荐一个实现三次贝塞尔曲线的js库CubicBezier,也是下文中使用的动画函数,等价CSS transition-timing-function、animation-timing-functionbash
首先定义过渡动画的几个参数:函数
var BezierEasing = require('bezier-easing')
var tween = {
paused: false,
duration: 6000,
easing: BezierEasing(0, 0, 1, 0.5),
update: function (v) {
// anim 是下文定义的一个描述动画的对象
anim.target.innerHTML = v
}
}
复制代码
定义一个动画开始函数play()布局
var raf = null
function play() {
raf = requestAnimationFrame(function (t) {
step(t);
})
function step(t) {
if (!tween.paused) {
setInstanceProgress(t);
play();
} else {
raf = cancelAnimationFrame(raf);
}
}
}
复制代码
step() 为动画的入口,这里使用requestAnimationFrame关键帧动画函数,固然也可用setTimeout来模拟实现,但更推荐使用requestAnimationFrame,推荐阅读深刻理解requestAnimationFrame。在每个动画关键帧周期内会调用setInstanceProgress() 函数,下面来看下setInstanceProgress() 函数的实现post
function setInstanceProgress(engineTime) {
var insTime = engineTime;
if (insTime > tween.duration) {
tween.paused = true;
}
var currentTime = Math.min(Math.max(insTime, 0), tween.duration);
setAnimationsProgress(currentTime);
}
复制代码
setInstanceProgress() 函数对动画时间进行了修正,同时会判断动画是否应该结束,并将修正的时间传给了setAnimationsProgress() 函数,一样再来看看setAnimationsProgress()函数的实现,咱们知道动画实际上是“位移”关于“时间”的函数:s=f(t)将动画函数与时间关联起来,计算 t 时刻动画属性值 f(t)
接下来再定义一个描述动画的对象 以下各参数的含义:
var anim = {
target: document.getElementById('motionPath'),
type: 'css',
property: 'width',
fromNumber: 20,
toNumber: 200
}
复制代码
setAnimationsProgress() 函数
function setAnimationsProgress(insTime) {
var elapsed = insTime / tween.duration;
var eased = tween.easing(elapsed);
var value = anim.fromNumber + (eased * (anim.toNumber - anim.fromNumber))
setProgressValue[anim.type](anim.target, anim.property, value);
tween.update(value);
}
复制代码
setAnimationsProgress() 函数也就是动画的核心,把时间和过渡函数相结合,计算t
时刻对应的value值,再把value值设置到过渡的目标对象属性中去,接下来就是setProgressValue的实现,针对DOM元素,设置width属性也就是设置style对应的属性
var setProgressValue = {
css: function (t, p, v) {
t.style[p] = v + 'px'
},
plainkey: function (t, p, v) {
t[p] = v
}
}
复制代码
最后只须要运行play()函数,一个简单的动画也就实现了,效果以下:
若是说咱们要过渡一个对象plain={key: 0}中的key属性值从 0 到 100 是否是修改一下anim参数就能够了,以下:
var plain = {key: 0}
var anim = {
target: plain,
type: 'plainkey',
property: 'key',
fromNumber: 0,
toNumber: 200
}
复制代码
key值的变化我就不给效果图了,总之经过这样简单的配置就解决了css不能实现相似的需求了,文章开头所说的数字变化的效果就完美的给解决了
最后一个问题了,文章开头的扇形的颜色渐变效果又应该如何实现呢,其实也很简单扇形是经过多份小扇形拼接而成的,而后设置相应的颜色,那每一个小扇形应该设置什么样色来达到渐变的效果呢?
举例:从颜色#e8cf22 变化到 #48b532,应用上面所讲的过渡动画原理,#e8cf22对应的rgb格式为rgb(232, 207, 34),#48b532对应的rgb格式为rgb(72, 181, 50),那么分别对R、G、B各值按照对应的起始值和对应的终点值进行过渡(R:从232到72,G:从207到181,B:从34到50),过渡过程当中再次组合对应的rgb值就是其过渡对应的颜色值,这就是颜色的过渡渐变原理,下面使用animejs这个库来实现,原理是同样的
html代码
<div id="motionPath"></div>
复制代码
css代码
#motionPath {
color: blue;
height: 100px;
}
复制代码
js代码
var oDev = document.getElementById('motionPath')
anime({
targets: '#motionPath',
duration: 6000,
backgroundColor: ['rgb(232, 207, 34)', 'rgb(72, 181, 50)']
easing: 'easeInOutQuad',
update: function (instance) {
oDev.innerHTML = instance.animations[0].currentValue;
}
});
复制代码
效果以下:
综上:了解了js如何实现动画以后,接下来看个使用css3 animation的例子,效果图就不粘出来了。 以下示例代码:
// div
<div class="animation"></div>
// css
.animation
{
width: 100px;
height: 100px;
background: red;
position: relative;
animation: myfirst 4s;
animation-timing-function: cubic-bezier(0.42,0,0.58,1);
}
@keyframes myfirst
{
0% {background:red; left:0px; top:0px;}
25% {background:yellow; left:200px; top:0px;}
50% {background:blue; left:200px; top:200px;}
75% {background:green; left:0px; top:200px;}
100% {background:red; left:0px; top:0px;}
}
/*
效果表现为:让一个长宽都是100px的div元素,在不一样的时间阶段,结合过渡函数cubic-bezier(0.42,0,0.58,1)来进行颜色和位置的过渡变化,
那么我想问0%、25%、50%、75%、100%指什么呢,过渡函数cubic-bezier(0.42,0,0.58,1)是应用到整个4s的过渡周期仍是每一个阶段应用一次完整的过渡?
答案:n%指的是所占过渡时间duration的百分数,0%~25%也就是从0s到1s阶段,而后结合时间t关于过渡函数cubic-bezier(0.42,0,0.58,1)来计算相应的位置点值和颜色值
*/
复制代码
上文中的实现过程,读者你若是使用过animejs 这个动画函数库,也view过源代码,你会发现我只是参考其实现讲了一个大概,具体该函数库中一系列优秀的功能感兴趣的同窗能够参考学习,很是值得推荐,目前GitHub上star已到达了30k+
在应对pm提出的一些需求中,只要清晰的知道要过渡那个具体属性,须要从某个起始状态变化到某个指定状态,而后以什么样的方式(过渡函数)来进行过渡,再结合过渡时间 duration
,相信有这样的思路必然需求也会迎刃而解
快狗打车前端团队专一前端技术分享,按期推送高质量文章,欢迎关注点赞。