6

如何使用Tween.js各类原生动画运动缓动算法

 2 years ago
source link: https://www.zhangxinxu.com/wordpress/2016/12/how-use-tween-js-animation-easing/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

by zhangxinxu from http://www.zhangxinxu.com/wordpress/?p=5828
本文可全文转载,但需要保留原作者姓名和可直接点击访问的原出处。

一、速战速决

昨天有事回了趟江苏,一来一回还堵车,1天基本上就在路上了,下午又当司机送夫人去买东西,周末工作时间严重不足,原本要早产的文章估计又要晚产了,为了争取2点前写完,我就尽量少废话了。

二、关于Tween.js

Tween.js是一个包含各种经典动画算法的JS资源,之前在多篇文章有提到过,例如之前写的“JavaScript与元素间的抛物线轨迹运动”,AS中甚至有专门的Tween类。

我在自己的Github上放了有3年了,地址为:https://github.com/zhangxinxu/Tween

我自己悄悄瞅了一看,就一个JS文件,连个描述都没有的的项目居然有147个star,看来今年用力一把,上500 star指日可待。

代码截图如下:

tween.js缓动代码截图

Quad, Cubic等等都是经典的动画运动算法名称,完整列表如下:

  1. Linear:线性匀速运动效果;
  2. Quadratic:二次方的缓动(t^2);
  3. Cubic:三次方的缓动(t^3);
  4. Quartic:四次方的缓动(t^4);
  5. Quintic:五次方的缓动(t^5);
  6. Sinusoidal:正弦曲线的缓动(sin(t));
  7. Exponential:指数曲线的缓动(2^t);
  8. Circular:圆形曲线的缓动(sqrt(1-t^2));
  9. Elastic:指数衰减的正弦曲线缓动;
  10. Back:超过范围的三次方缓动((s+1)*t^3 – s*t^2);
  11. Bounce:指数衰减的反弹缓动。

每个效果都分三个缓动方式,分别是:

  • easeIn:从0开始加速的缓动,也就是先慢后快;
  • easeOut:减速到0的缓动,也就是先快后慢;
  • easeInOut:前半段从0开始加速,后半段减速到0的缓动。

很多小伙伴easeIneaseOut哪个先快,哪个先慢一直记不清楚,我这里再给大家传授一遍我独门的邪恶记法,想想我们第一次OOXX,是不是进去(easeIn)的时候都是先慢,等进去了就快了;然后出来(easeOut)的时候,开始很快,都要出来了恋恋不舍速度就慢了。跟我们这里的动画效果是完全匹配的。

所有的这些缓动算法都离不开下面4个参数,t, b, c, d,含义如下:

/*
 * t: current time(当前时间);
 * b: beginning value(初始值);
 * c: change in value(变化量);
 * d: duration(持续时间)。
*/

只看上面字面意思其实不好理解,我们套用最简单的线性匀速运动来解释下:

Tween.Linear = function(t, b, c, d) { 
    return c*t/d + b; 
}

比方说我们要从位置0的地方运动到100,时间是10秒钟,此时,b, c, d三个参数就已经确认了,b初始值就是0,变化值c就是100-0就是100,最终的时间就是10,此时,只要给一个小于最终时间10的值,Tween.Linear就会返回当前时间应该的坐标,例如,假设此时动画进行到第5秒,也就是t为5,则得到(截图自Chrome控制台):
线性匀速运动结果

跟我们心中所想的值是一样的,这就是这些缓动算法的运算原理。

对了,貌似ElasticBack有其他可选参数,但我还没时间去研究,所以,这里暂不做相关介绍。

三、如何实际使用Tween.js中的缓动算法?

上面示意的Tween.js中的线性匀速运动案例实际上只是某一个静态数值,是无法构建动画的,如果要想实现连续的具有明显轨迹的动画效果,我们需要不停地修改t的数值,一般来讲都是一直往d的数值线性靠拢即可。

这里有个动词“不停地修改”,换句话说就是不停地绘制,于是,想到了HTML5中的requestAnimationFrame,关于requestAnimationFrame之前专门有文章介绍,如果浏览器不支持requestAnimationFrame,我们使用传统的setTimeout定时器兼容实现即可。

// requestAnimationFrame的兼容处理
if (!window.requestAnimationFrame) {
    requestAnimationFrame = function(fn) {
        setTimeout(fn, 17);
    };	
}

因此,我们要显示一个动画效果,例如,还是拿上面的线性效果举例,则代码可以变成:

var t = 0, b = 0, c = 100, d = 10;
var step = function () {
    // value就是当前的位置值
    // 例如我们可以设置DOM.style.left = value + 'px'实现定位
    var value = Tween.Linear(t, b, c, d);
    t++;
    if (t <= d) {
         // 继续运动
         requestAnimationFrame(step);
    } else {
        // 动画结束
    }
};

基本上,所有的动画使用都是这个套路。

然后,为了让大家可以直观体验Tween.js中所有缓动算法的效果是怎样的,我特意制作了一个包含完整效果的演示页面,您可以狠狠地点击这里:Tween.js动画算法使用示意demo

点击demo页面颜色不太好看的小圆球,就会看到各自的运动速率和缓动状态了,例如,Bounce.easeOut的效果就是小球像皮球落地一样弹几下:

Bounce.easeOut点击截图

demo页面上展示的源代码就是处理后相当精简的使用Tween.js的核心JS代码,如果大家对完整的效果实现感兴趣,可以右键页面→查看页面源代码。

四、基于Tween.js更简单调用的animation.js

Tween.js虽然原始且效果强大,但是,唯一的问题就是使用不方便,每次一个动画我都要弄个requestAnimationFrame,而且4个参数有点多,不好记忆,顺序什么的一旦弄错就很麻烦,有没有什么简单的方法调用的,就像jQuery的animation()方法一样。

出于这需求,我就手不停蹄弄出了一个更容易调用的animation.js,目前已经一起放在了https://github.com/zhangxinxu/Tween这个项目上,语法如下:

Math.animation(form, to, duration, easing, callback);
  • formto是必须参数,表示动画起始数值和结束数值;
  • durationeasingcallback理论上都是可选参数,但是实际上callback肯定是要使用的,因为实时变化的数值就是通过callback返回的。然后,durationeasingcallback这3个参数的顺序是任意的。具体来讲:
    • duration为动画持续时间,默认300,默认单位是毫秒,建议使用数值,例如600,也支持带单位,例如600ms或者0.6s
    • easing为缓动的类型,字符串类型,源自Tween.js。例如:'Linear''Quad.easeIn''Bounce.easeInOut'等等,需要注意大小写。 其中,默认值是'Linear'
    • callback为回调函数,支持2个参数(value, isEnding),其中value表示实时变化的计算值,isEnding是布尔值,表示动画是否完全停止。

所以,如果我们使用Math.animation()方法实现上面的线性运动效果则是:

Math.animation(0, 100, 170, function (value) {
    // value就是当前的位置值
});

是不是更容易理解和记忆了!

示意demo页面也有animation.js使用示意,其代码如下:

Math.animation(0, 800 - 42, function (value) {
    ball.style.transform = 'translateX(' + value + 'px)';
}, 'Bounce.easeInOut', 600);    

补充于2017-01-22
基于animation.js实现了一个更复杂的动画交互效果,名为“小兔子,跳火球;腿儿短,眼泪流”,gif截屏动画如下:

兔子跳火球gif

亲自感受您可以狠狠地点击这里:兔子跳火球动画demo

代码细节参见上demo页面源代码。

五、结束语

Tween.js的强大之处在于,其本质上是一个算法,也就是在任何地方其实都是可以使用的,比方说canvas中或者SVG动画实现等等,可以很好弥补CSS3 animation不太方便使用的场景,以及一些与动态位置打交道的交互效果,位置是不确定的,只能借助JS实现,此时配合动画算法,各种效果实现都不在话下。

有了上面的Math.animation()方法,实现不要太简单,且不依赖任何jQuery, Zepto之类的工具类JS,我们悄悄地实现,让设计师和产品经理惊讶下,喜出望外一下,岂不美哉!

比方说返回顶部效果,虽然说,直接瞬间到顶部也能满足功能,但是效果而言太干了,都如果我们主动加个动画效果,岂不是可以好好装逼一把,例如,在本文的demo演示页面,滚动到合适位置,然后打开控制台中粘贴下面JS代码然后回车:

Math.animation(document.documentElement.scrollTop, 0, function (value) {
    document.documentElement.scrollTop = value;
}, 'Quart.easeOut', 600);

就会发现页面滚动条好像自带了刹车平滑滚动到了顶部。

animation.js写得相当匆忙,时间有限,也并未详尽测试,因此如果在使用时候发现问题,欢迎及时反馈,也更加欢迎共同建设,项目地址是:https://github.com/zhangxinxu/Tween

比方说,增加loop循环控制之类的~

恩,就这些,还有13分钟2点,写个摘要差不多赶在计划前完成,速度还算不错。

最后,感谢阅读!

(本篇完)1f44d.svg 是不是学到了很多?可以分享到微信
1f44a.svg 有话要说?点击这里


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK