制作動畫效果離不開動畫運動函數,而我們用得最多的無疑就是Tween.js。根據不同的數學公式原理,Tween.js划分出了不同的動畫類型,每種動畫類型里面都包含以下的緩動類型:
- ease in 先慢后快
- ease out 先塊后慢
- ease in out 先慢后快再慢
關於緩動函數,我們在 css3 動畫里已經用得太多了,不再細講。Tween.js 源代碼請看:Tween.js
繪制動畫曲線
我們可以根據實際情況選擇對應的動畫函數,但問題是有十幾個動畫函數,一個個試過去也太麻煩了。有沒有一種直觀的方式讓我們一目了然的知道每種動畫的運動效果呢?當然有,那就是把動畫函數繪制出來,渲染方式多種多樣,css,svg,canvas,從效果和便攜考慮,我選擇用canvas實現。實現原理其實非常簡單,基本就是調用canvas的基礎api,demo的效果請看: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請看:自定義動畫公式
這里固定了起始點和結束點,剩余兩個控制點可以鼠標拖動,原理無非就是檢測鼠標的位置是否在控制點上,如果在控制點上,就將鼠標坐標值設為對應控制點,同時繪制曲線,也就達到了曲線實時繪制的效果了。
有了可視化的曲線,接着還要用公式將它表達出來,也就是傳入某個時間點,返回對應的運動位置。這里面用到了如下的公式,只需要將當前時間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;
}
最后也就實現了鼠標拖動控制點,即實時調整曲線形狀,同時生成曲線對應的運動函數。