这部分对原先的缓动函数进行抽象化,并结合缓动公式进行强化。成品的效果非常惊人逆天。走过路过不要错过。

好了,打诨到此为止。普通的加速减速是难以让人满意的,为了实现弹簧等让人眼花缭乱的效果必须动用缓动公式。我见过两套缓动公式,一套是早期Robert Penner大神的缓动公式,内置到tween类中,不过现在人们越来越推荐tweenlite这个新秀了。另一套是script.aculo.us与mootools里面的,由于mootools可称之为prototype的升级版,script.aculo.us则是基于prototype,我们就把它们并称为prototype流派。与flash流派最大的不同是,它们封装得更好,并只需传入一个参数(0~1的小数),并且拥有严密的队列机制来调用各种回调函数。如在回调函数设置元素的长宽,就弄成Scale特效,利用它我们进一步制作SlideUp,SlideDown,Squish等复合特效。

我们先来看flash流派的缓动公式,它们基本都有如下四个参数。

  • t:timestamp,指缓动效果开始执行到当前帧开始执行时经过的时间段,单位ms
  • b:beginning position,起始位置
  • c:change,要移动的距离,就是终点位置减去起始位置。
  • d: duration ,缓和效果持续的时间。

我们把这四个参数传入Robert Penner大神的缓动公式,它就会计算出当前帧物体移动的位置。我们对比原来的函数来改写。

var transition = function(el){
transition.linear = function(t,b,c,d){ return c*t/d + b; };//免费提供一个缓动公式(匀速运动公式)
el.style.position = "absolute";
var options = arguments[1] || {},
begin = getCoords(el).left,//开始位置
change = parseFloat(getStyle(_("taxiway"),"width")) - parseFloat(getStyle(el,"width")),//要移动的距离
duration = options.duration || 500,//缓动效果持续时间
ease = options.ease || transition.linear,//要使用的缓动公式
end = begin + change,//结束位置
startTime = new Date().getTime();//开始执行的时间
(function(){
setTimeout(function(){
var newTime = new Date().getTime(),//当前帧开始的时间
timestamp = newTime - startTime;//逝去时间
el.style.left = ease(timestamp,begin,change,duration) + "px";//移动
if(duration <= timestamp){
el.style.left = end + "px";
}else{
setTimeout(arguments.callee,25);//每移动一次停留25毫秒
}
},25)
})()
}

接着是各种缓动公式大阅兵,共分为十一大类,除了linear。其他类又分为三种。

  • easeIn方法控制补间如何从开始到最高速度。
  • easeOut 方法控制补间减速并停在目标位置
  • easeInOut方法同时控制上述两者。

具体公式见下面(共31种)。

//***********@author:Robert Penner and cloudgamer*************
//http://www.cnblogs.com/cloudgamer/archive/2009/01/06/Tween.html
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;
}
}
}
<div id="taxiway">
<div id="move" onclick="transition(this,{ease:Tween.Bounce.easeOut})"></div>
</div>

但我不喜欢flash流派的缓动公式,为了使用prototype流派的缓动公式,我进一步改进与抽象化我的缓动函数

//******************@author : 司徒正美************
var transition = function(el){
el.style.position = "absolute";
var options = arguments[1] || {},
begin = options.begin,//开始位置
change = options.change,//变化量
duration = options.duration || 500,//缓动效果持续时间
field = options.field,//必须指定,基本上对top,left,width,height这个属性进行设置
ftp = options.ftp || 50,
onStart = options.onStart || function(){},
onEnd = options.onEnd || function(){},
ease = options.ease,//要使用的缓动公式
end = begin + change,//结束位置
startTime = new Date().getTime();//开始执行的时间
onStart();
(function(){
setTimeout(function(){
var newTime = new Date().getTime(),//当前帧开始的时间
timestamp = newTime - startTime,//逝去时间
delta = ease(timestamp / duration);
el.style[field] = Math.ceil(begin + delta * change) + "px"
if(duration <= timestamp){
el.style[field] = end + "px";
onEnd();
}else{
setTimeout(arguments.callee,1000/ftp);
}
},1000/ftp)
})()
}
参数 类型 说明
el element 必需,为页面元素
begin number 必需,开始的位置
change number 必需,要移动的距离
duration number 可选,缓动效果持续时间,默认是500ms。建议取300~1000ms。
field string 必需,要发生变化的样式属性。请在top,left,bottom,right,width与height中选择。
ftp number 可选,每秒进行多少帧动画,默认50帧,保证流畅播放。一些参考资料,日本动画1秒36帧,中国卡通24帧,赛车游戏60帧。
ease function 必需,缓动公式,参数为0~1之间的数。可参考我下面给出的45条公式。
onStart function 可选,在开始时执行。
onEnd function 可选,在结束时执行。

prototype流派的缓动公式,只需一个参数(增至45种)

var tween = {
easeInQuad: function(pos){
return Math.pow(pos, 2);
}, easeOutQuad: function(pos){
return -(Math.pow((pos-1), 2) -1);
}, easeInOutQuad: function(pos){
if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,2);
return -0.5 * ((pos-=2)*pos - 2);
}, easeInCubic: function(pos){
return Math.pow(pos, 3);
}, easeOutCubic: function(pos){
return (Math.pow((pos-1), 3) +1);
}, easeInOutCubic: function(pos){
if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,3);
return 0.5 * (Math.pow((pos-2),3) + 2);
}, easeInQuart: function(pos){
return Math.pow(pos, 4);
}, easeOutQuart: function(pos){
return -(Math.pow((pos-1), 4) -1)
}, easeInOutQuart: function(pos){
if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,4);
return -0.5 * ((pos-=2)*Math.pow(pos,3) - 2);
}, easeInQuint: function(pos){
return Math.pow(pos, 5);
}, easeOutQuint: function(pos){
return (Math.pow((pos-1), 5) +1);
}, easeInOutQuint: function(pos){
if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,5);
return 0.5 * (Math.pow((pos-2),5) + 2);
}, easeInSine: function(pos){
return -Math.cos(pos * (Math.PI/2)) + 1;
}, easeOutSine: function(pos){
return Math.sin(pos * (Math.PI/2));
}, easeInOutSine: function(pos){
return (-.5 * (Math.cos(Math.PI*pos) -1));
}, easeInExpo: function(pos){
return (pos==0) ? 0 : Math.pow(2, 10 * (pos - 1));
}, easeOutExpo: function(pos){
return (pos==1) ? 1 : -Math.pow(2, -10 * pos) + 1;
}, easeInOutExpo: function(pos){
if(pos==0) return 0;
if(pos==1) return 1;
if((pos/=0.5) < 1) return 0.5 * Math.pow(2,10 * (pos-1));
return 0.5 * (-Math.pow(2, -10 * --pos) + 2);
}, easeInCirc: function(pos){
return -(Math.sqrt(1 - (pos*pos)) - 1);
}, easeOutCirc: function(pos){
return Math.sqrt(1 - Math.pow((pos-1), 2))
}, easeInOutCirc: function(pos){
if((pos/=0.5) < 1) return -0.5 * (Math.sqrt(1 - pos*pos) - 1);
return 0.5 * (Math.sqrt(1 - (pos-=2)*pos) + 1);
}, easeOutBounce: function(pos){
if ((pos) < (1/2.75)) {
return (7.5625*pos*pos);
} else if (pos < (2/2.75)) {
return (7.5625*(pos-=(1.5/2.75))*pos + .75);
} else if (pos < (2.5/2.75)) {
return (7.5625*(pos-=(2.25/2.75))*pos + .9375);
} else {
return (7.5625*(pos-=(2.625/2.75))*pos + .984375);
}
}, easeInBack: function(pos){
var s = 1.70158;
return (pos)*pos*((s+1)*pos - s);
}, easeOutBack: function(pos){
var s = 1.70158;
return (pos=pos-1)*pos*((s+1)*pos + s) + 1;
}, easeInOutBack: function(pos){
var s = 1.70158;
if((pos/=0.5) < 1) return 0.5*(pos*pos*(((s*=(1.525))+1)*pos -s));
return 0.5*((pos-=2)*pos*(((s*=(1.525))+1)*pos +s) +2);
}, elastic: function(pos) {
return -1 * Math.pow(4,-8*pos) * Math.sin((pos*6-1)*(2*Math.PI)/2) + 1;
}, swingFromTo: function(pos) {
var s = 1.70158;
return ((pos/=0.5) < 1) ? 0.5*(pos*pos*(((s*=(1.525))+1)*pos - s)) :
0.5*((pos-=2)*pos*(((s*=(1.525))+1)*pos + s) + 2);
}, swingFrom: function(pos) {
var s = 1.70158;
return pos*pos*((s+1)*pos - s);
}, swingTo: function(pos) {
var s = 1.70158;
return (pos-=1)*pos*((s+1)*pos + s) + 1;
}, bounce: function(pos) {
if (pos < (1/2.75)) {
return (7.5625*pos*pos);
} else if (pos < (2/2.75)) {
return (7.5625*(pos-=(1.5/2.75))*pos + .75);
} else if (pos < (2.5/2.75)) {
return (7.5625*(pos-=(2.25/2.75))*pos + .9375);
} else {
return (7.5625*(pos-=(2.625/2.75))*pos + .984375);
}
}, bouncePast: function(pos) {
if (pos < (1/2.75)) {
return (7.5625*pos*pos);
} else if (pos < (2/2.75)) {
return 2 - (7.5625*(pos-=(1.5/2.75))*pos + .75);
} else if (pos < (2.5/2.75)) {
return 2 - (7.5625*(pos-=(2.25/2.75))*pos + .9375);
} else {
return 2 - (7.5625*(pos-=(2.625/2.75))*pos + .984375);
}
}, easeFromTo: function(pos) {
if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,4);
return -0.5 * ((pos-=2)*Math.pow(pos,3) - 2);
}, easeFrom: function(pos) {
return Math.pow(pos,4);
}, easeTo: function(pos) {
return Math.pow(pos,0.25);
}, linear: function(pos) {
return pos
}, sinusoidal: function(pos) {
return (-Math.cos(pos*Math.PI)/2) + 0.5;
}, reverse: function(pos) {
return 1 - pos;
}, mirror: function(pos, transition) {
transition = transition || tween.sinusoidal;
if(pos<0.5)
return transition(pos*2);
else
return transition(1-(pos-0.5)*2);
}, flicker: function(pos) {
var pos = pos + (Math.random()-0.5)/5;
return tween.sinusoidal(pos < 0 ? 0 : pos > 1 ? 1 : pos);
}, wobble: function(pos) {
return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
}, pulse: function(pos, pulses) {
return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
}, blink: function(pos, blinks) {
return Math.round(pos*(blinks||5)) % 2;
}, spring: function(pos) {
return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
}, none: function(pos){
return 0
}, full: function(pos){
return 1
}
}
<!doctype html>
<html dir="ltr" lang="zh-CN">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=8">
<style type="text/css">
.taxiway{
width:800px;
height:100px;
background:#E8E8FF;
}
.move{
width:100px;
height:100px;
background:#a9ea00;
}
#panel {
float:left;
width:810px
}
#panel div{
float:left;
width:88px;
border:1px solid #333;
height:20px;
font-size:11px;
}
div.transition {
margin-top: 30px;
width: 200px;
height: 200px;
position: relative;
margin-bottom:10px;
} div.transition div {
position: absolute;
height: 1px;
width: 1px;
background: #000;
} div.transition span {
display: block;
position: absolute;
border-bottom: 1px solid #dadada;
font-size: 10px;
color: #888;
width: 200px;
left: 0px;
}
div.transition div#indicator {
position:absolute;
background-color:#a9ea00;
height: 200px;
top: 0px;
left: 0px;
} div.transition div#marker {
background-color: #f00;
height: 6px;
width: 6px;
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
left: 0px;
margin-bottom: -3px;
margin-left: -3px;
}
div.transition div#label {
background: transparent;
color: #ABD474;
font-size: 20px;
height: 20px;
width: 200px;
text-align: center;
top: 80px;
left: 0px;
z-index: -1;
} </style>
<script type="text/javascript">
var getCoords = function(el){
var box = el.getBoundingClientRect(),
doc = el.ownerDocument,
body = doc.body,
html = doc.documentElement,
clientTop = html.clientTop || body.clientTop || 0,
clientLeft = html.clientLeft || body.clientLeft || 0,
top = box.top + (self.pageYOffset || html.scrollTop || body.scrollTop ) - clientTop,
left = box.left + (self.pageXOffset || html.scrollLeft || body.scrollLeft) - clientLeft
return { 'top': top, 'left': left };
}; var getStyle = function(el, style){
if(!+"\v1"){
style = style.replace(/\-(\w)/g, function(all, letter){
return letter.toUpperCase();
});
var value = el.currentStyle[style];
(value == "auto")&&(value = "0px" );
return value;
}else{
return document.defaultView.getComputedStyle(el, null).getPropertyValue(style)
}
}
var tween = {
easeInQuad: function(pos){
return Math.pow(pos, 2);
}, easeOutQuad: function(pos){
return -(Math.pow((pos-1), 2) -1);
}, easeInOutQuad: function(pos){
if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,2);
return -0.5 * ((pos-=2)*pos - 2);
}, easeInCubic: function(pos){
return Math.pow(pos, 3);
}, easeOutCubic: function(pos){
return (Math.pow((pos-1), 3) +1);
}, easeInOutCubic: function(pos){
if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,3);
return 0.5 * (Math.pow((pos-2),3) + 2);
}, easeInQuart: function(pos){
return Math.pow(pos, 4);
}, easeOutQuart: function(pos){
return -(Math.pow((pos-1), 4) -1)
}, easeInOutQuart: function(pos){
if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,4);
return -0.5 * ((pos-=2)*Math.pow(pos,3) - 2);
}, easeInQuint: function(pos){
return Math.pow(pos, 5);
}, easeOutQuint: function(pos){
return (Math.pow((pos-1), 5) +1);
}, easeInOutQuint: function(pos){
if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,5);
return 0.5 * (Math.pow((pos-2),5) + 2);
}, easeInSine: function(pos){
return -Math.cos(pos * (Math.PI/2)) + 1;
}, easeOutSine: function(pos){
return Math.sin(pos * (Math.PI/2));
}, easeInOutSine: function(pos){
return (-.5 * (Math.cos(Math.PI*pos) -1));
}, easeInExpo: function(pos){
return (pos==0) ? 0 : Math.pow(2, 10 * (pos - 1));
}, easeOutExpo: function(pos){
return (pos==1) ? 1 : -Math.pow(2, -10 * pos) + 1;
}, easeInOutExpo: function(pos){
if(pos==0) return 0;
if(pos==1) return 1;
if((pos/=0.5) < 1) return 0.5 * Math.pow(2,10 * (pos-1));
return 0.5 * (-Math.pow(2, -10 * --pos) + 2);
}, easeInCirc: function(pos){
return -(Math.sqrt(1 - (pos*pos)) - 1);
}, easeOutCirc: function(pos){
return Math.sqrt(1 - Math.pow((pos-1), 2))
}, easeInOutCirc: function(pos){
if((pos/=0.5) < 1) return -0.5 * (Math.sqrt(1 - pos*pos) - 1);
return 0.5 * (Math.sqrt(1 - (pos-=2)*pos) + 1);
}, easeOutBounce: function(pos){
if ((pos) < (1/2.75)) {
return (7.5625*pos*pos);
} else if (pos < (2/2.75)) {
return (7.5625*(pos-=(1.5/2.75))*pos + .75);
} else if (pos < (2.5/2.75)) {
return (7.5625*(pos-=(2.25/2.75))*pos + .9375);
} else {
return (7.5625*(pos-=(2.625/2.75))*pos + .984375);
}
}, easeInBack: function(pos){
var s = 1.70158;
return (pos)*pos*((s+1)*pos - s);
}, easeOutBack: function(pos){
var s = 1.70158;
return (pos=pos-1)*pos*((s+1)*pos + s) + 1;
}, easeInOutBack: function(pos){
var s = 1.70158;
if((pos/=0.5) < 1) return 0.5*(pos*pos*(((s*=(1.525))+1)*pos -s));
return 0.5*((pos-=2)*pos*(((s*=(1.525))+1)*pos +s) +2);
}, elastic: function(pos) {
return -1 * Math.pow(4,-8*pos) * Math.sin((pos*6-1)*(2*Math.PI)/2) + 1;
}, swingFromTo: function(pos) {
var s = 1.70158;
return ((pos/=0.5) < 1) ? 0.5*(pos*pos*(((s*=(1.525))+1)*pos - s)) :
0.5*((pos-=2)*pos*(((s*=(1.525))+1)*pos + s) + 2);
}, swingFrom: function(pos) {
var s = 1.70158;
return pos*pos*((s+1)*pos - s);
}, swingTo: function(pos) {
var s = 1.70158;
return (pos-=1)*pos*((s+1)*pos + s) + 1;
}, bounce: function(pos) {
if (pos < (1/2.75)) {
return (7.5625*pos*pos);
} else if (pos < (2/2.75)) {
return (7.5625*(pos-=(1.5/2.75))*pos + .75);
} else if (pos < (2.5/2.75)) {
return (7.5625*(pos-=(2.25/2.75))*pos + .9375);
} else {
return (7.5625*(pos-=(2.625/2.75))*pos + .984375);
}
}, bouncePast: function(pos) {
if (pos < (1/2.75)) {
return (7.5625*pos*pos);
} else if (pos < (2/2.75)) {
return 2 - (7.5625*(pos-=(1.5/2.75))*pos + .75);
} else if (pos < (2.5/2.75)) {
return 2 - (7.5625*(pos-=(2.25/2.75))*pos + .9375);
} else {
return 2 - (7.5625*(pos-=(2.625/2.75))*pos + .984375);
}
}, easeFromTo: function(pos) {
if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,4);
return -0.5 * ((pos-=2)*Math.pow(pos,3) - 2);
}, easeFrom: function(pos) {
return Math.pow(pos,4);
}, easeTo: function(pos) {
return Math.pow(pos,0.25);
}, linear: function(pos) {
return pos
}, sinusoidal: function(pos) {
return (-Math.cos(pos*Math.PI)/2) + 0.5;
}, reverse: function(pos) {
return 1 - pos;
}, mirror: function(pos, transition) {
transition = transition || tween.sinusoidal;
if(pos<0.5)
return transition(pos*2);
else
return transition(1-(pos-0.5)*2);
}, flicker: function(pos) {
var pos = pos + (Math.random()-0.5)/5;
return tween.sinusoidal(pos < 0 ? 0 : pos > 1 ? 1 : pos);
}, wobble: function(pos) {
return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
}, pulse: function(pos, pulses) {
return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
}, blink: function(pos, blinks) {
return Math.round(pos*(blinks||5)) % 2;
}, spring: function(pos) {
return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
}, none: function(pos){
return 0
}, full: function(pos){
return 1
}
} var _ = function(id){
return document.getElementById(id);
}
var transition = function(el){
el.style.position = "absolute";
var options = arguments[1] || {},
begin = options.begin,//开始位置
change = options.change,//变化量
duration = options.duration || 500,//缓动效果持续时间
field = options.field,//必须指定,基本上对top,left,width,height这个属性进行设置
ftp = options.ftp || 50,
onEnd = options.onEnd || function(){},
ease = options.ease,//要使用的缓动公式
end = begin + change,//结束位置
startTime = new Date().getTime();//开始执行的时间
(function(){
setTimeout(function(){
var newTime = new Date().getTime(),//当前帧开始的时间
timestamp = newTime - startTime,//逝去时间
delta = ease(timestamp / duration);
el.style[field] = Math.ceil(begin + delta * change) + "px"
if(duration <= timestamp){
el.style[field] = end + "px";
onEnd();
}else{
setTimeout(arguments.callee,1000/ftp);
}
},1000/ftp)
})()
} if (typeof Array.prototype['max'] == 'undefined') {
Array.prototype.map = function(fn, thisObj) {
var scope = thisObj || window;
var a = [];
for ( var i=0, j=this.length; i < j; ++i ) {
a.push(fn.call(scope, this[i], i, this));
}
return a;
};
Array.prototype.max = function(){
return Math.max.apply({},this)
}
Array.prototype.min = function(){
return Math.min.apply({},this)
}
} var range = function(start,end){
var _range = []
for(var i = start,l=end-start;i<l;i++){
_range.push(i)
}
return _range
} var draw = function(ease){
var demo = _("transition");
demo.innerHTML = "";//还原!
//***********绘制控制台********************
var values = range(0,200).map(function(v){
return tween[ease](v/200) * 200;
}),
max = Math.max(200, values.max()),
min = Math.min(0, values.min());
if (min==max) {
min = 0;
max = 200;
}
var factor = 200/(max-min),
grid = '<span style="bottom:'+Math.round((0-min)*factor)+'px">0</span>'+
'<span style="bottom:'+Math.round((200-min)*factor)+'px">1</span>',
graph = range(0,200).map(function(v){
return '<div style="left:'+v+'px;bottom:'+Math.round((values[v]-min)*factor)+'px;height:1px"></div>';
}).join('') + '<div id="indicator" style="display:none">'
+'</div><div id="marker" style="display:none"></div><div id="label"></div>';
demo.innerHTML = grid + graph;
var indicator = _("indicator"),
marker = _("marker"),
label = _("label"),
demoTransition = function(pos){
var value = tween[ease](pos);
indicator.style.display = "block";
marker.style.display = "block";
marker.style.left = Math.round(pos*200)+'px';
marker.style.bottom = Math.round((value*200-min)*factor)+'px';
label.innerHTML = Math.round(pos*200)+'px';
return value;
}
transition(indicator,{field:"left",begin:parseFloat(getCoords(demo).left),change:200,
ease:demoTransition})
} window.onload = function(){
var panelHTML = function(){
var builder = [];
var _temp = 'Back Circ Cubic Expo Quad Quart Quint Sine'.split(' ');
var ease = _temp.map(function(v){
return 'easeIn'+v;
});
ease = ease.concat(_temp.map(function(v){
return 'easeOut'+v;
}));
ease = ease.concat(_temp.map(function(v){
return 'easeInOut'+v;
}));
ease = ease.concat('blink bounce bouncePast easeFrom easeFromTo easeOutBounce easeTo elastic'.split(' '));
ease = ease.concat('flicker full linear mirror none pulse reverse sinusoidal spring swingTo swingFrom swingFromTo wobble'.split(' '))
for(var i =0,l=ease.length;i<l;i++){
builder.push("<div onclick='draw(this.innerHTML)'>");
builder.push(ease[i]);
builder.push("</div>");
}
return builder.join('');
}
var panel = document.createElement("div");
panel.id = "panel"
panel.innerHTML = panelHTML();
_("transition").parentNode.insertBefore(panel,_("transition").nextSibling); }
</script>
<title>缓动BY司徒正美</title>
</head>
<body>
<div class="taxiway">
<div class="move" onclick="transition(this,{field:'left',begin:parseFloat(getCoords(this).left),change:700,ease:tween.bouncePast})"></div>
</div>
<div class="taxiway">
<div class="move" onclick="transition(this,{field:'width',begin:parseFloat(getStyle(this,'width')),change:300,ease:tween.spring})"></div>
</div>
<span class="clear"></span>
<h2>请点击下表的格子</h2>
<div id="transition" class="transition"> </div> </body>
</html>

除了这45条公式外,我们还可以制定自己的缓动公式。正如我在上面表格中提到, 它在运行过程是不执行回调函数时,但你们可以在运行框中看到,我可以实现一边移动一边记录点的坐标。这是怎样实现的呢? 我们只要把上面的缓动公式的任何一条塞进一个只有一个参数的函数就行了。当然此函数要有返回,供继续向下调用。以下就是一个模板:

var myTween = function(pos){ //缓动公式
var value = tween[ease](pos);
//***********这上面是固定的**************
indicator.style.display = "block";
marker.style.display = "block";
marker.style.left = Math.round((pos*200))+'px';
marker.style.bottom = Math.round(((value*200)-min)*factor)+'px';
label.innerHTML = Math.round((pos*200))+'px';
//************这下面是固定的*************
return value;
}
<div class="taxiway">
<div class="move" onclick="transition(this,{field:'left',begin:parseFloat(getCoords(this).left),change:700,ease:tween.bouncePast})"></div>
</div>
<div class="taxiway">
<div class="move" onclick="transition(this,{field:'width',begin:parseFloat(getStyle(this,'width')),change:300,ease:tween.spring})"></div>
</div>

http://www.cnblogs.com/rubylouvre/archive/2009/09/17/1567607.html

javascript的缓动效果的更多相关文章

  1. javascript 45种缓动效果BY司徒正美

    javascript 45种缓动效果 参数 类型 说明 el element 必需,为页面元素 begin number 必需,开始的位置 change number 必需,要移动的距离 durati ...

  2. 《JavaScript 实战》:Tween 算法及缓动效果

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

  3. animation js控制 缓动效果

    <!DOCTYPE html><html><head><meta charset="utf-8" /><title>缓动 ...

  4. 过渡与动画 - 缓动效果&基于贝塞尔曲线的调速函数

    难题 给过渡和动画加上缓动效果是一种常见的手法(比如具有回弹效果的过渡过程)是一种流行的表现手法,可以让界面显得更加生动和真实:在现实世界中,物体A点到B点往往也是不完全匀速的 以纯技术的角度来看,回 ...

  5. [ActionScript 3.0] AS3 用于拖动对象时跟随鼠标的缓动效果

    package com.fylibs.components.effects { import flash.display.DisplayObject; import flash.events.Even ...

  6. Adobe Edge Animate –弹性的方块-使用tweenmax缓动效果

    Adobe Edge Animate –弹性的方块-使用tweenmax缓动效果 版权声明: 本文版权属于 北京联友天下科技发展有限公司. 转载的时候请注明版权和原文地址. 此前有Edge爱好者提出一 ...

  7. 软件项目技术点(1)——Tween算法及缓动效果

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 Tween算法及缓动效果 软件里在切换步序时需要有过渡动画效果,从当前位置的画面缓动到目标位置的画面.动画效果可重新查看文章系列第一篇 ...

  8. quick-cocos2dx 之transition.execute()的缓动效果

    注:本文图片来源(http://hosted.zeh.com.br/tweener/docs/en-us/misc/transitions.html. 侵权请告知,即刻删除) 什么是缓动, 缓动(ea ...

  9. WPF中ListBox滚动时的缓动效果

    原文:WPF中ListBox滚动时的缓动效果 上周工作中遇到的问题: 常规的ListBox在滚动时总是一格格的移动,感觉上很生硬. 所以想要实现类似Flash中的那种缓动的效果,使ListBox滚动时 ...

随机推荐

  1. Nginx反向代理的工作方式

    如图所示: 当客户端发来HTTP请求时,Nginx并不会立刻转发到上游服务器,而是先把用户的请求(包括HTTP包体)完整地接收到Nginx所在服务器的硬盘或者内存中,然后再向上游服务器发起连接,把缓存 ...

  2. 第六届福建省大学生程序设计竞赛(FZU2213—FZU2221)

    from:piaocoder Common Tangents(两圆之间的公公切线) 题目链接: http://acm.fzu.edu.cn/problem.php?pid=2213 解题思路: 告诉你 ...

  3. Swift中的一些关键字

    以下关键字关于引用传参.属性.修改成员变量.静态变量.索引和构造函数重载 读过The Swift Programming Language的人都能看得出,我上面的这几个说法全不是apple的习惯用语. ...

  4. 在SQL SERVER中实现RSA加解密函数(第一版)

    /*************************************************** 作者:herowang(让你望见影子的墙) 日期:2010.1.1 注:   转载请保留此信息 ...

  5. 2015ACM/ICPC亚洲区长春站

    5532 Almost Sorted Array 题目大意:给你一个序列,如果它拿掉其中一个数后,可以是该序列成为非递减或非递增序列,则输出YES. 有两种思路,第一种代码比较简单,是LIS,复杂度n ...

  6. CodeForces 444C 分块

    题目链接:http://codeforces.com/problemset/problem/444/C 题意:给定一个长度为n的序列a[].起初a[i]=i,然后还有一个色度的序列b[],起初b[i] ...

  7. SOAPUI使用教程-验证SOAP服务

    当soapUI创建一个功能性TestCase 一个很常见的场景是你想一些SOAP / WSDL服务验证响应检查返回正确的结果. 一旦你导入了您想要测试的WSDL服务这样做很容易: 添加一个新的SOAP ...

  8. Leetcode N-Queens

    The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens ...

  9. 【PostgreSQL】PostGreSQL数据库,时间数据类型

    ---"17:10:13.236"time without time zone:时:分:秒.毫秒 ---"17:10:13.236+08"time with t ...

  10. google jquery用不了啦,你准备好了吗

    今天,相信很多网站开发人员都有这感觉,明明正常的页面却无法工作了,莫名其妙的错误,笔者也遇到这种错误,细查之下才发现google jquery用不了啦,通过firefox调试发现找不到jquery了, ...