cubic-bezier 模擬實現

cubic-bezier 曲線css3 動畫的一個重要基石。另一個爲 steps (ease 等都是 cubic-bezier 的特殊形式),css3 中的 cubic_bezier 曲線限制了首尾兩控制點的位置,通過調整中間兩控制點的位置可以靈活得到常用的動畫效果,同時 canvas 也進行了相應的支持,也存在相應的工具可以根據想要的曲線得到對應 cubic bezier 曲線的控制點參數。

 

而 ie(6-9) 卻沒有相應的支持,爲了能在各個平臺得到一致的動畫效果,則不可避免要在 ie 上通過定時器沿着指定控制點參數的 cubic bezier 曲線來手動更新動畫對象的數值.

模擬實現

公式

cubic-bezier 公式不是簡單的 y= x 公式,而是引入了第三個變量 t,由於動畫中關鍵在於計算比例,即在總時間的某個時間點百分比得到相應的值相對於最終值的比例,那麼只需要得到 0,1 區間的曲線即可。 而 [x,y] -> [0,1] 內的曲線則是通過 t 在 0,1 內連續變化而得到:

 

 

 

其中 P0, P1 ,P2, P3 都爲兩維 xy 向量

 

將向量拆開表示即爲:

 

y= (1-t)^3*p0y + 3*(1-t)^2*t*p1y + 3*(1-t)*t^2p2y + t^3p3y


x= (1-t)^3*p0x + 3*(1-t)^2*t*p1x + 3*(1-t)*t^2p2x + t^3p3x
  

而 css3 所用的 cubic bezier 已經限定死 p0 = (0,0) , p3= (1,1) ,因此公式可簡化爲

 

var ax = 3 * p1x - 3 * p2x + 1,
      bx = 3 * p2x - 6 * p1x,
      cx = 3 * p1x;

var ay = 3 * p1y - 3 * p2y + 1,
      by = 3 * p2y - 6 * p1y,
      cy = 3 * p1y;

y= ((ay * t + by) * t + cy ) * t

x= ((ax * t + bx) * t + cx ) * t
  

爲了提高效率以及減少計算精度丟失公式進一步經過了 Horner 's method 變化。

計算

css3 中某個限定了特定控制參數的 cubic -bezier 曲線如下所示:

 

 

動畫所做的事情就是把 x 軸當做時間比例,根據曲線得到 y 軸對應的值,並更新到動畫對象中去.

即轉化爲以下問題:如何根據上述公式在已知 x 的情況下如何得到 y.

求 t

首先需要根據公式

 

var ax = 3 * p1x - 3 * p2x + 1,
      bx = 3 * p2x - 6 * p1x,
      cx = 3 * p1x;

x= ((ax * t + bx) * t + cx ) * t
  

在已知 x 的情況下求 t,即經典的多項式求參問題,首先可以通過 newton method 嘗試求出 t 的值,若不行(可能性很小)則可通過可靠但慢速的二分法求值.

求 y

上步得到 t 後則可以帶入另一個 y 公式求得最終值 y

 

var ay = 3 * p1y - 3 * p2y + 1,
      by = 3 * p2y - 6 * p1y,
      cy = 3 * p1y;

y= ((ay * t + by) * t + cy ) * t
  

上述解法也是源自 webkit webcore c++ 原生實現.

使用對比

在傳入動畫的 easing 設置時,可以傳入 css3 cubic-bezier 的語法格式或者直接傳入特定的曲線設置(ease-in ease-out).

 

$('#xx').animate({
   left:500
},{
  duration: 2,
  easing: 'cubic-bezier(1,0.22,0,0.84)' // 'ease-in'
});

 

效果對比:

 

cubic-bezier in kissy

 

通過對比即可發現,ease-out 和以前 js 實現的簡單二次曲線 easeOut 還是有明顯的不同,並且 js 實現和 css3 原生幾乎效果完全一樣(效率可能稍微低了些),更多自帶曲線對比可見:

 

easing for kissy

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章