javascript运动系列第二篇——变速运动

javascript运动系列第二篇——变速运动原文地址 http www cnblogs com xiaohuochai p 5973556 html 前面的话 前面介绍过匀速运动的实现及注意事项 本文在匀速运动的基础上 更进一步 实现各种变速运动 包括加速运动 减速运动 缓冲运动 重力运动和弹性运动 nbsp 准备工作匀速运动 在原生 javascript 中实现运动的主要工具是定时器 通过设置固定的间隔时间 使元素在确定的间隔时间内实

原文地址:http://www.cnblogs.com/xiaohuochai/p/5973556.html

前面的话

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

 

准备工作

匀速运动

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

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

setInterval(function(){ s = s + step },30)

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

s = v * t;

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

复制代码
  
   
复制代码

小数解析

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

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

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

 
   

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

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

复制代码
function getCSS(obj,style){ if(window.getComputedStyle){ return getComputedStyle(obj)[style]; } return obj.currentStyle[style]; } 
复制代码

 

加速运动

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

v = v0 + a*t; s = (v0+v)*t/2 = v0*t + 1/2*a*t*t;

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

s1 = v0*t1 + 1/2*a*t1*t1; s2 = v0*t2 + 1/2*a*t2*t2; s2 - s1 = (t2-t1)(v0+ 1/2*a*(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(100*v0+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.6*37.8*100px = 36288px

  step = 0.02(v0+a*(0.02n+0.01)) = 2/10000(100*v0+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(100*v0+a(2n+1))

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

v = v0 - a*t s = (v0+v)/2*t

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

复制代码
  
   
复制代码

加减速运动

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

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

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

  所以a = v*v/(2*s) = 5000/s = 25

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

  在加速运动中,s=1/2*a*t*t;

  所以加速运动总时间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

复制代码
function getCSS(obj,style){ if(window.getComputedStyle){ return getComputedStyle(obj)[style]; } return obj.currentStyle[style]; } function varMove(json){ var obj = json.obj; var attr = json.attr; var target = json.target; var type = json.type; var value = json.value; var fn = json.fn; //如果没有建立定时器对象,则在obj下建立定时器对象 if(!obj.timers){obj.timers = {};} //清除定时器 if(obj.timers[attr]){return;} //声明定时器运行次数 var index=-1; //声明当前值变量cur var cur = parseFloat(getCSS(obj,attr)); //声明距离为distance var distance= target - cur; //声明运动的次数,一个方向的加速和减速运动总共算一个运动 var num=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 = (4*distance/(value*value*10000))*(2*index+1) break; //如果type设置为'gravity',则为重力运动 case 'gravity': step = 0.072576*(2*index+1); break; //如果type设置为'speeddown',则为减速运动 //'speeddown'的value值为初始速度v0 case 'speeddown': value = Number(value) || 100; step = (2/10000)*(100*value-(value*value)/(2*distance)*(2*index+1)) break; //如果type设置为'speedupAndDown',则为先加速后减速运动 //'speedupAndDown'的value值为总时间t case 'speedupAndDown': value = Number(value) || 2; //当index为25*value时,说明进行完一次运动,则将index置0 if(index == 25*value){ index = 0; }; //加速运动 if(cur < distance/2){ step =8*distance/(10000*value*value)*(2*index+1); }else{ //减速运动 step = distance/(25*value)-8*distance/(10000*value*value)*(2*index+1); } break; //如果type设置为'repeat',则为往复运动 //'repeat'的value值为一次运动(一次加速和一次减速)的时间 case 'repeat': value = Number(value) || 2; //当index为25*value时,说明进行完一次运动,则将index置0 if(index == 25*value){ index = 0; num += 0.5; }; if(Math.floor(num)%2 == 0){ //加速运动 if(cur < distance/2){ step =8*distance/(10000*value*value)*(2*index+1); }else{ //减速运动 step = distance/(25*value)-8*distance/(10000*value*value)*(2*index+1); } }else{ //加速运动 if(cur > distance/2){ step =-8*distance/(10000*value*value)*(2*index+1); }else{ //减速运动 step = 8*distance/(10000*value*value)*(2*index+1)-distance/(25*value); } } 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 
     
    

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/209444.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 上午9:13
下一篇 2026年3月19日 上午9:14


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号