javascript动画、运动算法详细解释与分析 (二、javascript动画 时间精度问题)

三、时间精度问题

首先我们必须知道出现时间精度问题的原因。

如果你对javascript单线程机制不太熟悉,或者对setInterval、setTimeOut函数执行机制不太理解,希望你能先看一下这篇文章:How JavaScript Timers Work [Copy]。然后你可以看一下这篇文章http://icolin.org/javascript/settimeout-bug-in-ie-with-winxp.html。第一篇文章可以帮助你理解javascript单线程机制以及setInterval、setTimeOut函数的执行机制,第二篇文章中 iColin 童鞋已经对时间精度问题出现的情况作了详细的描述,他和我们在这里的问题是一样的,所以我就不再复述。最后一定要看 Omiga再谈JavaScript时钟中的16ms精度问题 这篇文章。

(希望你确实看了那三篇文章,这样你才能更加容易的理解下面的内容)

那么现在相信你对问题出现的原因已经理解的差不多了,我在这里再做一下小结:

javascript动画在浏览器中运行的过程中会产生时间误差,误差由系统环境,浏览器环境,程序运算时间,以及其他人为原因造成(我们这里排除人为错误导致的误差)。那么系统环境包括计算机硬件、计算机操作系统,浏览器环境包括浏览器内核、javascript解释引擎等,程序运算时间虽然有时可以忽略,但程序却可能由于javascript的单线程机制造成时间延迟。所以如果想把时间精确到毫秒,那是很有难度的,jQuery也考虑到了这个问题,所以她采用了消息队列机制来尽量的消除这种误差,不过效果差强人意。因为程序本身的时间精度就很难控制,所以如果使用程序本身来控制时间精度,那就好像拿油灭火。。。因为有很多不可抗力因素和外力因素影响。所以我们暂且将动画时间精确到秒。

这里对时间精度问题的讨论就先到这里,如果你有更好的解决方案,非常非常希望你能给予指导,非常非常感谢。

 

在这里我们顺便顺便解释一下上次遗留的 (这里为什么是以6px/30ms的速度等下解释) 这个问题。

首先要说一下Tween算法,我是从 cloudgamerhttp://www.cnblogs.com/cloudgamer/archive/2009/01/06/tween.html这篇文章中看到了Tween算法,进而在 robertpenner 的《Flash_MX编程与创意实现》中看到的非常细致的讲解。网址: http://www.robertpenner.com/easing/ 。如果想搞Flash创意和动画的朋友推荐看这本书,我看了一部分,讲得不错,网上对这本书的评论也很好,我这里有PDF中文版的,需要的跟我联系。

在Flash中,动画时长都是以帧为单位来计算的。每帧时长*帧数就是动画总时间。在我们javascript中,我们的帧时长实际上就是setInterval、setTimeOut的第二个参数。而帧数就是

   1:  Math.prototype.linearTween = function( t, b, c, d){
   2:       return t*c/d + b;
   3:  }

上面linear算法中的d和t(d表示总帧数,t表示已经经过的帧数)。

所以如果你就像最开始那样单纯的认为t是时间,可能你就会陷入像我一样的痛苦的迷茫中,半天不能自拔。我们再来复习一下这段代码。

   1:  $ = function( id ){ return typeof id == "string"?document.getElementById(id):id }
   2:   
   3:  /* des:tween算法。
   4:      t: 动画已经执行的时间(实际上时执行多少次/帧数)
   5:      b: 起始位置
   6:      c: 终止位置
   7:      d: 从起始位置到终止位置的经过时间(实际上时执行多少次/帧数)*/
   8:  tween = {
   9:      linear : function( t, b, c, d){
  10:          return t*c/d + b;
  11:      }
  12:  }
  13:   
  14:  move={
  15:      moveType : function(mvTp){return  mvTp && typeof(mvTp)== ”string” && tween[mvTp] ? mvTp: "linear" },
  16:   
  17:      startMove : function( mvObj,mvTp,t,b,c,d ){ 
  18:          t ? t : t=0; b ? b : b = 0; c ? c : c =300; d ? d : d = 50; 
  19:          $(mvObj).style.position =="relative" || $(mvObj).style.position =="absolute" 
  20:              ? 1 : $(mvObj).style.position = "relative";
  21:          //每隔30毫秒重复执行改变元素位置的函数
  22:          mvTimer = setInterval(function(){
  23:          //判断动画已经执行的时间(次数/帧数)是否小于总时间,是的话继续执行改变位置的函数,否则的话,清理该interval。
  24:              t <= d 
  25:                  ? function(){ $(mvObj).style.left = parseInt(tween[move.moveType(mvTp)](t,b,c,d))+"px"; t++;}() 
  26:                  : clearInterval(mvTimer); 
  27:          } ,30 ) 
  28:      }
  29:  }
  30:   
  31:  move.startMove("moveLinear");

在这里我们动画的帧数是d=50,经过帧数为t,当t<=d时,继续执行动画,每帧的时间间隔是30毫秒,该元素将从距离窗口左边距为0的位置移动到距离窗口左边距为300的位置(这里忽略body的默认margin)。

今天先到这里,下次将会接着分析Tween算法,我将尽最大努力来经历这个有意思的东西。

posted @ 2011-05-13 19:57  像阳光一样  阅读(2526)  评论(5编辑  收藏  举报