動畫函式的繪製及自定義動畫函式

Jeff.Zhong發表於2019-01-03

製作動畫效果離不開動畫運動函式,而我們用得最多的無疑就是Tween.js。根據不同的數學公式原理,Tween.js劃分出了不同的動畫型別,每種動畫型別裡面都包含以下的緩動型別:

  1. ease in 先慢後快
  2. ease out 先塊後慢
  3. ease in out 先慢後快再慢

關於緩動函式,我們在 css3 動畫裡已經用得太多了,不再細講。Tween.js 原始碼請看:Tween.js

繪製動畫曲線

我們可以根據實際情況選擇對應的動畫函式,但問題是有十幾個動畫函式,一個個試過去也太麻煩了。有沒有一種直觀的方式讓我們一目瞭然的知道每種動畫的運動效果呢?當然有,那就是把動畫函式繪製出來,渲染方式多種多樣,csssvgcanvas,從效果和便攜考慮,我選擇用canvas實現。實現原理其實非常簡單,基本就是呼叫canvas的基礎api,demo的效果請看:TweenJS動畫運動函式繪製
TweenJS

這裡解釋一下座標介面,X軸是運動時間,Y軸則是運動的距離。點選tween型別和ease型別選擇框,就可以看到對應運動曲線的繪製動畫,以及右邊小球的實際運動效果。核心程式碼如下:

    function orbit(){
        ctx.save();
        ctx.translate(10,450);
        ctx.strokeStyle ='hsl(30,100%,50%)';
        ctx.beginPath();
        ctx.clearRect(0,1,500,150);
        ctx.moveTo(0,0);
        pos.forEach(function(n,i){
            ctx.lineTo(n.x,n.y);
        });
        ctx.stroke();
        ctx.restore();
    }

    function ball(y){
        ctx.save();
        ctx.clearRect(520,0,90,600);
        ctx.translate(540,450-y);
        ctx.fillStyle = gradient;
        ctx.beginPath();
        ctx.arc(0,0,15,0,Math.PI*2,false);
        ctx.fill();
        ctx.restore();
    }

    ~function animate(){
        isRunning = true;
        t = new Date() - start;
        if(t > duration) {
            pos.push({x:xLen,y:-yLen});
            orbit();
            ball(yLen);
            isRunning = false;
            return;
        }
        y = fn(t,0,yLen,duration);
        pos.push({x:t*space,y:-y})
        orbit();
        ball(y);
        requestAnimationFrame(animate); 
    }();

自定義動畫函式

有了這個小工具,選擇動畫函式就非常方便了。仔細觀察這些運動曲線,它們的形狀都像什麼?像貝塞爾曲線呀,應該說大部分像。而剛好canvas也有繪製貝塞爾曲線的api,那麼使用三次貝塞爾曲線繪製方法bezierCurveTo() 就可以視覺化的自定義自己想要的運動曲線。

繪製原理和拖動原理在之前的文章canvas圖形編輯器 有詳細介紹(編輯器裡面繪製貝塞爾曲線同時還要檢測移動起始點,結束點,控制點,中心點,比這裡的功能還要複雜)。
實現的demo請看:自定義動畫公式
bazier function
這裡固定了起始點和結束點,剩餘兩個控制點可以滑鼠拖動,原理無非就是檢測滑鼠的位置是否在控制點上,如果在控制點上,就將滑鼠座標值設為對應控制點,同時繪製曲線,也就達到了曲線實時繪製的效果了。

有了視覺化的曲線,接著還要用公式將它表達出來,也就是傳入某個時間點,返回對應的運動位置。這裡面用到了如下的公式,只需要將當前時間t 和 起始點,結束點,控制點的y座標傳入(y對應距離),就可獲得當前時間t對應的位置。

/**
 * 獲取三次貝塞爾曲線座標
 * @param  {Number} p0 [起始點]
 * @param  {Number} p1 [控制點1]
 * @param  {Number} p2 [控制點2]
 * @param  {Number} p3 [結束點]
 * @param  {Number} t  [取值範圍:0~1]
 * @return {Number}    
 */
function BezierPos(p0,p1,p2,p3,t){
    return p0*Math.pow(1-t,3)+3*p1*t*Math.pow(1-t,2)+3*p2*Math.pow(t,2)*(1-t)+p3*Math.pow(t,3);
}

根據上面的公式,再結合Tween.js裡面的函式呼叫格式,就可以實現生成程式碼的功能了。

function showCode(){
    var code = `function bezierFun(t,b,c,d){\n`+
        `\tt = t/d;\n`+
        `\tvar y = ${start.y}*Math.pow(1-t,3)+3*${controls[0].y}*t*Math.pow(1-t,2)+3*${controls[1].y}*Math.pow(t,2)*(1-t)+${end.y}*Math.pow(t,3);\n`+
        `\treturn b+(300-y)/200*c;\n}`;
    txt.value = code;
}

最後也就實現了滑鼠拖動控制點,即實時調整曲線形狀,同時生成曲線對應的運動函式。

相關文章