配色: 字号:
javascript运动系列第二篇——变速运动
2017-01-14 | 阅:  转:  |  分享 
  
javascript运动系列第二篇——变速运动



前面介绍过匀速运动的实现及注意事项,本文在匀速运动的基础上,更进一步,实现各种变速运动,包括加速运动、减速运动、缓冲运动、重力运动和弹性运动







准备工作

匀速运动



在原生javascript中实现运动的主要工具是定时器,通过设置固定的间隔时间,使元素在确定的间隔时间内实现距离的变化。而运动变化的主要表现形式是距离的变化



例如,定时器频率可如下列代码所示,设置为30ms。每30ms对s的值进行更新,使其增加一个步长step的距离,来实现视觉上的元素运动效果



setInterval(function(){

s=s+step

},30)

而step的值如何变化就决定了何种运动形式



s=vt;

当step是一个恒定的值(如10),则说明相同时间间隔内,距离变化相同,说明速度是一个恒定的值,该运动为匀速运动



复制代码

开始运动

还原







复制代码





小数解析



在CSS解析中,是可以识别小数的;但在javascript中,不同的解析方式对于小数识别有区别



如果使用getComputedStyle或currentStyle是可以识别小数的,但是使用offset值,则返回对应的四舍五入值



[注意]IE7-浏览器不支持小数







在上面的代码中,元素以100.7px的宽度进行渲染;但是,通过offsetWidth获取的值是100.7四舍五入后的值101;通过getComputedStyle计算样式获取的值是实际渲染值100.7px



所以,为了保证结果准备尽量使用计算样式,而不要使用offset值



复制代码

functiongetCSS(obj,style){

if(window.getComputedStyle){

returngetComputedStyle(obj)[style];

}

returnobj.currentStyle[style];

}

复制代码





加速运动

说到加速运动,必须要提到一个物理名词——加速度



v=v0+at;

s=(v0+v)t/2=v0t+1/2att;

如果v0是初始速度,v1是定时器第n次经过20ms之后元素变化后的速度,v2是定时器第n+1次经过20ms之后元素变化后的速度



s1=v0t1+1/2at1t1;

s2=v0t2+1/2at2t2;

s2-s1=(t2-t1)(v0+1/2a(t2+t1))=0.02(v0+a(0.02n+0.01))

所以,下列代码中的步长step值是0.02(v0+a(0.02n+0.01))



step=0.02(v0+a(0.02n+0.01))=2/10000(100v0+a(2n+1))

v0代表初始速度,a代表加速度,n代表定时器执行的次数



由于n的值是以+1的形式递增,当a为正数时,step值不断增加,则为加速运动;当a为负数时,step值不断减小,则为减速运动



假设初始速度v0等于0,加速度a等于200,则step=0.04(2n+1)



setInterval(function(){

s=s+step

},20)

复制代码

开始运动

还原







复制代码





重力运动

重力运动是加速运动的特殊情况,相当于初始速度为0,加速度为9.8m/s2的特值情况



这时,涉及到长度单位m变换为像素单位px的过程



1cm=37.8px

1m=100cm

所以9.6m=9.637.8100px=36288px



step=0.02(v0+a(0.02n+0.01))=2/10000(100v0+a(2n+1))



当v0=0,a=36288时,step=7.2576(2n+1)



这里,我们把运动的距离设置为300px,实际上,转换为常用长度单位时,只有8cm。如果,我们要以300px模拟8m的重力效果,则可以粗略地将加速度缩小为原来的1/100



此时,修正过的step值为0.072576(2n+1)



复制代码

开始运动

还原







复制代码





减速运动

相当于加速运动来说,减速运动有一个临界点的问题。如果元素运动到指定的位置前,速度已经减到0,则停到当前速度为0的位置



同样以定时器20ms的频率为例,位移变化的step值是0.02(v0+a(0.02n+0.01))



假设初始速度v0为100px/s,加速度为-10,则step=0.02(99.9-0.2n)



复制代码

开始运动

还原







复制代码





缓冲运动

缓冲运动是减速运动的一种特殊形式,指元素做减速运动,速度减到0时,恰好停在目标点位置



以定时器20ms的频率为例



step=0.02(v0+a(0.02n+0.01))=2/10000(100v0+a(2n+1))

假设初始速度v0为100px/s,最终的v为0



v=v0-at

s=(v0+v)/2t

所以,a=-5000/s,step=2-(2n+1)/s



复制代码

开始运动

还原







复制代码





加减速运动

加减速运动是加速运动和减速运动的结合。前半段运动时,做加速运动。到达指定点时,做减速运动,最终到达终点停止



step=0.02(v0+a(0.02n+0.01))=2/10000(100v0+a(2n+1))



假设v0=0,最终速度v=100,距离s=200



所以a=vv/(2s)=5000/s=25



则加速运动的step=(2n+1)/s=(2n+1)/200



在加速运动中,s=1/2att;



所以加速运动总时间t=s/50=4,定时器运行次数n=t/0.02=200次



减速运动的step=0.02(v0-(2n+1)),此时的v0相应于加速运动结束时的瞬时速度100,a=-5000/s=-25



所以,减速运动的step=2-(2n+1)/s=2-(2n+1)/200



复制代码

开始运动

还原









复制代码





往复运动

往复运动相当于加减速运动的升级版。元素先加速后减速,当减速到0时,元素并不停止,而是做反向的先加速后减速运动,如此反复



加速运动和减速运动的公式与加减速运动的公式相同



加速运动:step=(2n+1)/s=(2n+1)/200



减速运动:step=2-(2n+1)/s=2-(2n+1)/200



复制代码

开始运动

还原











复制代码





变速函数

以上介绍的各种变速运动其中大部分代码相同,只是步长公式不同而已。所以,我们可以把变速运动也封装成一个函数形式,命名为varMove.js



复制代码

functiongetCSS(obj,style){

if(window.getComputedStyle){

returngetComputedStyle(obj)[style];

}

returnobj.currentStyle[style];

}

functionvarMove(json){

varobj=json.obj;

varattr=json.attr;

vartarget=json.target;

vartype=json.type;

varvalue=json.value;

varfn=json.fn;

//如果没有建立定时器对象,则在obj下建立定时器对象

if(!obj.timers){obj.timers={};}

//清除定时器

if(obj.timers[attr]){return;}

//声明定时器运行次数

varindex=-1;

//声明当前值变量cur

varcur=parseFloat(getCSS(obj,attr));

//声明距离为distance

vardistance=target-cur;

//声明运动的次数,一个方向的加速和减速运动总共算一个运动

varnum=0;

//开启定时器

obj.timers[attr]=setInterval(function(){

//更新定时器的工作次数

index++;

//获取样式当前值并赋值给cur

cur=parseFloat(getCSS(obj,attr));

//根据不同的type值来设置步长

switch(type){

//如果type设置为''linear'',则为匀速运动

case''linear'':

//linear的value值为步长step

step=Number(value)||10;

break;

//如果type设置为''speedup'',则为加速运动

case''speedup'':

//''speedup''的value值为总时间t

value=Number(value)||2;

step=(4distance/(valuevalue10000))(2index+1)

break;

//如果type设置为''gravity'',则为重力运动

case''gravity'':

step=0.072576(2index+1);

break;

//如果type设置为''speeddown'',则为减速运动

//''speeddown''的value值为初始速度v0

case''speeddown'':

value=Number(value)||100;

step=(2/10000)(100value-(valuevalue)/(2distance)(2index+1))

break;

//如果type设置为''speedupAndDown'',则为先加速后减速运动

//''speedupAndDown''的value值为总时间t

case''speedupwww.baiyuewang.netAndDown'':

value=Number(value)||2;

//当index为25value时,说明进行完一次运动,则将index置0

if(index==25value){

index=0;

};

//加速运动

if(cur
step=8distance/(10000valuevalue)(2index+1);

}else{

//减速运动

step=distance/(25value)-8distance/(10000valuevalue)(2index+1);

}

break;

//如果type设置为''repeat'',则为往复运动

//''repeat''的value值为一次运动(一次加速和一次减速)的时间

case''repeat'':

value=Number(value)||2;

//当index为25value时,说明进行完一次运动,则将index置0

if(index==25value){

index=0;

num+=0.5;

};

if(Math.floor(num)%2==0){

//加速运动

if(cur
step=8distance/(10000valuevalue)(2index+1);

}else{

//减速运动

step=distance/(25value)-8distance/(10000valuevalue)(2index+1);

}

}else{

//加速运动

if(cur>distance/2){

step=-8distance/(10000valuevalue)(2index+1);

}else{

//减速运动

step=8distance/(10000valuevalue)(2index+1)-distance/(25value);

}

}

break;

//如果没有设置,则默认为''linear''匀速运动

default:

step=10;

}

//若步长设置值使得元素超过目标点时,将步长设置值更改为目标点值-当前值

if(((cur+step-target)step>0)&&type!=''repeat''){

step=target-cur;

}

//将合适的步长值赋值给元素的样式

obj.style[attr]=cur+step+''px'';

//当元素到达目标点后,停止定时器

if((step==target-cur)&&type!=''repeat''){

clearInterval(obj.timers[attr]);

obj.timers[attr]=0;

fn&&fn.call(obj);

}

},20);

}

复制代码

下面以varMove函数为基础,进行一些简单应用



复制代码









Document









匀速运动

加速运动

减速运动

加减速运动

往复运动

还原























献花(0)
+1
(本文系thedust79首藏)