如何使用Tween.js各類原生動畫運動緩動算法

xiaosen 8年前發布 | 11K 次閱讀 算法 JavaScript開發

一、速戰速決

昨天有事回了趟江蘇,一來一回還堵車,1天基本上就在路上了,下午又當司機送夫人去買東西,周末工作時間嚴重不足,原本要早產的文章估計又要晚產了,為了爭取2點前寫完,我就盡量少廢話了。

二、關于Tween.js

Tween.js是一個包含各種經典動畫算法的JS資源,之前在多篇文章有提到過,例如之前寫的“ JavaScript與元素間的拋物線軌跡運動 ”,AS中甚至有專門的Tween類。

我自己悄悄瞅了一看,就一個JS文件,連個描述都沒有的的項目居然有147個star,看來今年用力一把,上500 star指日可待。

代碼截圖如下:

Quad , Cubic 等等都是經典的動畫運動算法名稱,完整列表如下:

  1. Linear :線性勻速運動效果;
  2. Quadratic :二次方的緩動(t^2);
  3. Cubic :三次方的緩動(t^3);
  4. Quartic :四次方的緩動(t^4);
  5. Quintic :五次方的緩動(t^5);
  6. Sinusoidal :正弦曲線的緩動(sin(t));
  7. Exponential :指數曲線的緩動(2^t);
  8. Circular :圓形曲線的緩動(sqrt(1-t^2));
  9. Elastic :指數衰減的正弦曲線緩動;
  10. Back :超過范圍的三次方緩動((s+1)*t^3 – s*t^2);
  11. Bounce :指數衰減的反彈緩動。

每個效果都分三個緩動方式,分別是:

  • easeIn :從0開始加速的緩動,也就是先慢后快;
  • easeOut :減速到0的緩動,也就是先快后慢;
  • easeInOut :前半段從0開始加速,后半段減速到0的緩動。

很多小伙伴 easeIn 和 easeOut 哪個先快,哪個先慢一直記不清楚,我這里再給大家傳授一遍我獨門的邪惡記法,想想我們第一次OOXX,是不是進去( easeIn )的時候都是先慢,等進去了就快了;然后出來( easeOut )的時候,開始很快,都要出來了戀戀不舍速度就慢了。跟我們這里的動畫效果是完全匹配的。

所有的這些緩動算法都離不開下面4個參數, t , b , c , d ,含義如下:

/*

  • t: current time(當前時間);
  • b: beginning value(初始值);
  • c: change in value(變化量);
  • d: duration(持續時間)。 */</code></pre>

    只看上面字面意思其實不好理解,我們套用最簡單的線性勻速運動來解釋下:

    Tween.Linear = function(t, b, c, d) { 
     return c*t/d + b; 
    }

    比方說我們要從位置 0 的地方運動到 100 ,時間是 10 秒鐘,此時, b , c , d 三個參數就已經確認了, b 初始值就是 0 ,變化值 c 就是 100-0 就是 100 ,最終的時間就是 10 ,此時,只要給一個小于最終時間 10 的值, Tween.Linear 就會返回當前時間應該的坐標,例如,假設此時動畫進行到第5秒,也就是 t 為5,則得到(截圖自Chrome控制臺):

    跟我們心中所想的值是一樣的,這就是這些緩動算法的運算原理。

    對了,貌似 Elastic 和 Back 有其他可選參數,但我還沒時間去研究,所以,這里暫不做相關介紹。

    三、如何實際使用Tween.js中的緩動算法?

    上面示意的Tween.js中的線性勻速運動案例實際上只是某一個靜態數值,是無法構建動畫的,如果要想實現連續的具有明顯軌跡的動畫效果,我們需要不停地修改 t 的數值,一般來講都是一直往 d 的數值線性靠攏即可。

    這里有個動詞“不停地修改”,換句話說就是不停地繪制,于是,想到了HTML5中的 requestAnimationFrame ,關于 requestAnimationFrame 我之前專門有文章介紹,如果瀏覽器不支持 requestAnimationFrame ,我們使用傳統的 setTimeout 定時器兼容實現即可。

    // requestAnimationFrame的兼容處理
    if (!window.requestAnimationFrame) {
     requestAnimationFrame = function(fn) {
         setTimeout(fn, 17);
     };  
    }

    因此,我們要顯示一個動畫效果,例如,還是拿上面的線性效果舉例,則代碼可以變成:

    var t = 0, b = 0, c = 100, d = 10;
    var step = function () {
     // value就是當前的位置值
     // 例如我們可以設置DOM.style.left = value + 'px'實現定位
     var value = Tween.Linear(t, b, c, d);
     t++;
     if (t <= d) {
          // 繼續運動
          requestAnimationFrame(step);
     } else {
         // 動畫結束
     }
    };

    基本上,所有的動畫使用都是這個套路。

    然后,為了讓大家可以直觀體驗Tween.js中所有緩動算法的效果是怎樣的,我特意制作了一個包含完整效果的演示頁面,您可以狠狠地點擊這里: Tween.js動畫算法使用示意demo

    點擊demo頁面顏色不太好看的小圓球,就會看到各自的運動速率和緩動狀態了,例如, Bounce.easeOut 的效果就是小球像皮球落地一樣彈幾下:

    demo頁面上展示的源代碼就是處理后相當精簡的使用Tween.js的核心JS代碼,如果大家對完整的效果實現感興趣,可以右鍵頁面→查看頁面源代碼。

    四、基于Tween.js更簡單調用的animation.js

    Tween.js雖然原始且效果強大,但是,唯一的問題就是使用不方便,每次一個動畫我都要弄個 requestAnimationFrame ,而且4個參數有點多,不好記憶,順序什么的一旦弄錯就很麻煩,有沒有什么簡單的方法調用的,就像jQuery的 animation() 方法一樣。

    出于這需求,我就手不停蹄弄出了一個更容易調用的animation.js,目前已經一起放在了 https://github.com/zhangxinxu/Tween 這個項目上,語法如下:

    Math.animation(form, to, duration, easing, callback);

    其中:

    • form 和 to 是必須參數,表示動畫起始數值和結束數值;
    • duration , easing , callback 理論上都是可選參數,但是實際上 callback 肯定是要使用的,因為實時變化的數值就是通過 callback 返回的。然后, duration , easing , callback 這3個參數的順序是任意的。具體來講:
      • duration 為動畫持續時間,默認 300 ,默認單位是毫秒,建議使用數值,例如 600 ,也支持帶單位,例如 600ms 或者 0.6s ;
      • easing 為緩動的類型,字符串類型,源自Tween.js。例如: 'Linear' , 'Quad.easeIn' , 'Bounce.easeInOut' 等等,需要注意大小寫。 其中,默認值是 'Linear' ;
      • callback 為回調函數,支持2個參數(value, isEnding),其中 value 表示實時變化的計算值, isEnding 是布爾值,表示動畫是否完全停止。

    所以,如果我們使用 Math.animation() 方法實現上面的線性運動效果則是:

    Math.animation(0, 100, 170, function (value) {
     // value就是當前的位置值
    });

    是不是更容易理解和記憶了!

    示意demo頁面也有animation.js使用示意,其代碼如下:

    Math.animation(0, 800 - 42, function (value) {
     ball.style.transform = 'translateX(' + value + 'px)';
    }, 'Bounce.easeInOut', 600);

    五、結束語

    Tween.js的強大之處在于,其本質上是一個算法,也就是在任何地方其實都是可以使用的,比方說canvas中或者SVG動畫實現等等,可以很好彌補CSS3 animation 不太方便使用的場景,以及一些與動態位置打交道的交互效果,位置是不確定的,只能借助JS實現,此時配合動畫算法,各種效果實現都不在話下。

    有了上面的 Math.animation() 方法,實現不要太簡單,且不依賴任何jQuery, Zepto之類的工具類JS,我們悄悄地實現,讓設計師和產品經理驚訝下,喜出望外一下,豈不美哉!

    比方說返回頂部效果,雖然說,直接瞬間到頂部也能滿足功能,但是效果而言太干了,都如果我們主動加個動畫效果,豈不是可以好好裝逼一把,例如,在本文的demo演示頁面,滾動到合適位置,然后打開控制臺中粘貼下面JS代碼然后回車:

    Math.animation(document.documentElement.scrollTop, 0, function (value) {
     document.documentElement.scrollTop = value;
    }, 'Quart.easeOut', 600);

    就會發現頁面滾動條好像自帶了剎車平滑滾動到了頂部。

    animation.js寫得相當匆忙,時間有限,也并未詳盡測試,因此如果在使用時候發現問題,歡迎及時反饋,也更加歡迎共同建設,項目地址是: https://github.com/zhangxinxu/Tween

    比方說,增加loop循環控制之類的~

    恩,就這些,還有13分鐘2點,寫個摘要差不多趕在計劃前完成,速度還算不錯。

     

     

    來自:http://www.zhangxinxu.com/wordpress/2016/12/how-use-tween-js-animation-easing/

     

 本文由用戶 xiaosen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!