当前位置: 首页 > 图文教程 > 网络编程 > Javascript > JavaScript Tween算法及缓动效果

Javascript
jquery 弹出层实现代码
jQuery 扩展对input的一些操作方法
扩展jQuery 键盘事件的几个基本方法
Iframe 自适应高度并实时监控高度变化的js代码
CCPry JS类库 代码
jquery text()要注意啦
json 入门基础教程 推荐
json 实例详细说明教程
JavaScript中的JSON 中文版翻译
javascript GUID生成器实现代码
DOM 脚本编程中的兄弟节点
JavaScript Sort 表格排序
提高网站性能之 如何对待JavaScript
js 函数的执行环境和作用域链的深入解析
键盘 keycode的值 javascript时触发事件时很有用的要素
cnblogs csdn 代码运行框实现代码
简单实用的HTML到UBB转换脚本工具实现说明
Javascript结合css实现网页换肤功能
JQuery 网站换肤功能实现代码
JS OOP包机制,类创建的方法定义

Javascript 中的 JavaScript Tween算法及缓动效果


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 204 ::
收藏到网摘: n/a

Flash做动画时会用到Tween类,利用它可以做很多动画效果,例如缓动、弹簧等等。我这里要教大家的是怎么利用flash的Tween类的算法,来做js的Tween算法,并利用它做一些简单的缓动效果。

完整实例下载

运行代码框

[Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行]

效果说明

首先大家到这里下载flash的as脚本(建议看看这里的demo),1.0和2.0都可以(里面的算法都一样)。
例如打开2.0的可以看到几个as文件,每个文件对应一个Tween效果,分别有(参考里面的说明):

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

ps:以上都是自己的烂翻译,希望各位修正。

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

  • easeIn:从0开始加速的缓动;
  • easeOut:减速到0的缓动;
  • easeInOut:前半段从0开始加速,后半段减速到0的缓动。

其中Linear是无缓动效果,没有以上效果。

然后看看里面的算法,以Quadratic的easeOut为例:

static function easeOut (t:Number, b:Number, c:Number, d:Number):Number {
    return -c * ((t=t/d-1)*t*t*t - 1) + b;
}

这是as代码,四个参数分别是:

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

ps:Elastic和Back有其他可选参数,里面都有说明。

那如何在js中利用这些算法呢?可以看到,虽然是as代码,但里面的程序是可以直接放在js里使用的。
我们可以定义一个类,把它这部分放在里面:

var Tween = {
    Quad: {
        easeOut: function(t,b,c,d){
            return -c *(t/=d)*(t-2) + b;
        }
    }
}

这样,就可以用Tween.Quad.easeOut取得这个算法了,其他算法也一样处理就行了。

接下来就可以利用这个js的Tween来做一些缓动效果了。
先通过上面的坐标实例说一下算法原理:
x轴是时间,y轴是当前值,b是y轴的初始值,x轴的初始值是0,t是当前时间。当t(x轴)逐渐增加到达d时,当前值(y轴)会到达目标值(b+c)。
想详细理解的话可以找资料看看吧(貌似跟数学关系比较大)。

下面就介绍如何使用这个Tween了,首先b、c、d三个参数(即初始值,变化量,持续时间)在缓动开始前,是需要先确定好的。
举一个简单的例子,一个div要向右缓动,left初始值是50,那么b就是50,要向右移动100,那c就是100,如果知道的是目标值,例如要向右移动到150,那就把目标值150减初始值b就是变化量c了。
至于d的设置就比较灵活,只要符合t是从0向d递增(或递减)就可以了。
d跟步长配合使用来设置持续时间,例如d设置为100,如果设置步长是1,那么从0到100就有100步,即分100次来完成这个过程,步数越多那么持续时间就越长。
至于t的变化相当于时间的变化,一般是均匀变化的,每次变化都增加一个步长,当t从0递增(或递减)到d时,缓动就结束了。
要注意的是t是从0开始的,设置步长时必须确定t确实能到达d,如果上面的步长是3,那么t就永远都到不了d了。更好的处理是当t等于或超过d之后,就停止定时器并设置当前值为目标值。

了解了Tween的使用后就可以实现动画效果了。继续上面的例子,已经确定b是50,c是100,d是100,步长是1,使用Tween.Quad.easeOut算法。那么可以用以下程序实现缓动:

var b=50,c=100,d=100,t=0;
function Run(){
    div.style.left = Math.ceil(Tween.Quad.easeOut(t,b,c,d)) + "px";
    if(t<d){ t++; setTimeout(Run, 10); }
}
Run();

一个简单的缓动效果就实现了,要实现不同的缓动,只需要使用对应的Tween算法就行了,以前看来遥不可及的效果,现在这么容易就实现了(当然那些算法才是最难的地方)。

这样关于缓动的效果就介绍完了,但其实远远不止这些,我们还可以自己定义一些算法,发挥想象力,做一些好玩的效果。

运行代码框

[Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行]

ease,JavaScript,加速,减速,运动,Tween,缓动,动画,弹簧,反弹

完整Tween

var Tween = {
    Linear: function(t,b,c,d){ return c*t/d + b; },
    Quad: {
        easeIn: function(t,b,c,d){
            return c*(t/=d)*t + b;
        },
        easeOut: function(t,b,c,d){
            return -c *(t/=d)*(t-2) + b;
        },
        easeInOut: function(t,b,c,d){
            if ((t/=d/2) < 1) return c/2*t*t + b;
            return -c/2 * ((--t)*(t-2) - 1) + b;
        }
    },
    Cubic: {
        easeIn: function(t,b,c,d){
            return c*(t/=d)*t*t + b;
        },
        easeOut: function(t,b,c,d){
            return c*((t=t/d-1)*t*t + 1) + b;
        },
        easeInOut: function(t,b,c,d){
            if ((t/=d/2) < 1) return c/2*t*t*t + b;
            return c/2*((t-=2)*t*t + 2) + b;
        }
    },
    Quart: {
        easeIn: function(t,b,c,d){
            return c*(t/=d)*t*t*t + b;
        },
        easeOut: function(t,b,c,d){
            return -c * ((t=t/d-1)*t*t*t - 1) + b;
        },
        easeInOut: function(t,b,c,d){
            if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
            return -c/2 * ((t-=2)*t*t*t - 2) + b;
        }
    },
    Quint: {
        easeIn: function(t,b,c,d){
            return c*(t/=d)*t*t*t*t + b;
        },
        easeOut: function(t,b,c,d){
            return c*((t=t/d-1)*t*t*t*t + 1) + b;
        },
        easeInOut: function(t,b,c,d){
            if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
            return c/2*((t-=2)*t*t*t*t + 2) + b;
        }
    },
    Sine: {
        easeIn: function(t,b,c,d){
            return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
        },
        easeOut: function(t,b,c,d){
            return c * Math.sin(t/d * (Math.PI/2)) + b;
        },
        easeInOut: function(t,b,c,d){
            return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
        }
    },
    Expo: {
        easeIn: function(t,b,c,d){
            return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
        },
        easeOut: function(t,b,c,d){
            return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
        },
        easeInOut: function(t,b,c,d){
            if (t==0) return b;
            if (t==d) return b+c;
            if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
            return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
        }
    },
    Circ: {
        easeIn: function(t,b,c,d){
            return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
        },
        easeOut: function(t,b,c,d){
            return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
        },
        easeInOut: function(t,b,c,d){
            if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
            return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
        }
    },
    Elastic: {
        easeIn: function(t,b,c,d,a,p){
            if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
            if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
            else var s = p/(2*Math.PI) * Math.asin (c/a);
            return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
        },
        easeOut: function(t,b,c,d,a,p){
            if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
            if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
            else var s = p/(2*Math.PI) * Math.asin (c/a);
            return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
        },
        easeInOut: function(t,b,c,d,a,p){
            if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
            if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
            else var s = p/(2*Math.PI) * Math.asin (c/a);
            if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
            return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
        }
    },
    Back: {
        easeIn: function(t,b,c,d,s){
            if (s == undefined) s = 1.70158;
            return c*(t/=d)*t*((s+1)*t - s) + b;
        },
        easeOut: function(t,b,c,d,s){
            if (s == undefined) s = 1.70158;
            return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
        },
        easeInOut: function(t,b,c,d,s){
            if (s == undefined) s = 1.70158;
            if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
            return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
        }
    },
    Bounce: {
        easeIn: function(t,b,c,d){
            return c - Tween.Bounce.easeOut(d-t, 0, c, d) + b;
        },
        easeOut: function(t,b,c,d){
            if ((t/=d) < (1/2.75)) {
                return c*(7.5625*t*t) + b;
            } else if (t < (2/2.75)) {
                return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
            } else if (t < (2.5/2.75)) {
                return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
            } else {
                return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
            }
        },
        easeInOut: function(t,b,c,d){
            if (t < d/2) return Tween.Bounce.easeIn(t*2, 0, c, d) * .5 + b;
            else return Tween.Bounce.easeOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
        }
    }
}