在上一篇《基於HT for Web矢量實現3D葉輪旋轉》一文中,我略微提了下HT for Web基礎動畫的相關用法,可是講得不深刻,今天就來和你們分享下HT for Web基礎動畫的相關介紹及用法。html
先上一段枯燥的理論知識,你們混個眼熟。node
在HT的數據模型驅動圖形組件的設計架構下,動畫可理解爲將某些屬性由起始值逐漸變到目標值的過程, HT提供了ht.Default.startAnim的動畫函數,其示例代碼以下。瀏覽器
ht.Default.startAnim({ frames: 12, // 動畫幀數 interval: 10, // 動畫幀間隔毫秒數 easing: function(t){ return t * t; }, // 動畫緩動函數,默認採用`ht.Default.animEasing` finishFunc: function(){ console.log('Done!') }, // 動畫結束後調用的函數。 action: function(v, t){ // action函數必須提供,實現動畫過程當中的屬性變化。 node.setPosition( // 此例子展現將節點`node`從位置`p1`動畫到位置`p2`。 p1.x + (p2.x - p1.x) * v, p1.y + (p2.y - p1.y) * v ); } });
ht.Default.startAnim支持Frame-Based和Time-Based兩種方式的動畫,以上代碼爲Frame-Based方式, 這種方式用戶經過指定frames動畫幀數,以及interval動畫幀間隔參數控制動畫效果。架構
如下代碼爲Time-Based方式,該方式用戶只須要指定duration的動畫週期的毫秒數便可,HT將在指定的時間週期內完成動畫, 不一樣於Frame-Based方式有明確固定的幀數,即action函數被調用多少次,Time-Based方式幀數或action函數被調用次數取決於系統環境, 通常來講系統配置更好的機器,更高效的瀏覽器則調用幀數越多,動畫過程更平滑。因爲js語言沒法精確控制interval時間間隔, 採用Frame-Based不能精確控制動畫時間週期,即便相同的frames和interval參數在不一樣的環境,可能會出現動畫週期差別較大的問題, 所以HT默認採用Time-Based的方式,若是不設置duration和frames參數,則duration參數將被系統自動設置爲ht.Default.animDuration值。函數
ht.Default.startAnim({ duration: 500, // 動畫週期毫秒數,默認採用`ht.Default.animDuration` action: function(v, t){ ... } });
startAnim函數會返回一個anim對象,可調用anim.stop(true)終止動畫,其中的參數shouldBeFinished表明是否徹底未達到的目標改變, 若是爲true則會調用anim.action(anim.easing(1))。同時anim還具備anim.pause()和anim.resume()可中斷和繼續動畫功能, 以及anim.isRunning()函數判斷動畫是否正在進行。動畫
action函數的第一個參數v表明經過easing(t)函數運算後的值,t表明當前動畫進行的進度[0~1],通常屬性變化根據v參數進行。spa
ht.Default.startAnim中得easing參數是用於讓用戶定義函數,經過數學公式控制動畫, 如勻速變化、先慢後快等效果,可參考http://easings.net/.net
介紹就到這裏,接下來咱們來作一個簡單的例子,先練練手,具體的頁面效果以下設計
沒錯。它就是一個球,咱們要作的就是點擊瀏覽器的某個位置,而後它平滑地滑到點擊位置,點擊自身的話,就作旋轉收縮,而後再旋轉還原,整個過程都是經過HT for Web的基礎動畫來完成的。3d
建立拓撲及建立節點的代碼我再這裏就很少囉嗦了,咱們直接上基礎動畫的內容:
首先咱們須要在拓撲上監聽點擊事件,由於咱們的Demo涉及到兩個動畫,因此在點擊事件的內部處理須要作些簡單的判斷,咱們先來看下監聽改如何添加:
var type = "ontouchend" in document ? 'touchstart' : 'mousedown'; view.addEventListener(type, function(e){ e.preventDefault(); … }, false);
如下是圖元的平移動畫的處理:
var p2 = graphView.getLogicalPoint(e); var p1 = toy.getPosition(); anim = ht.Default.startAnim({ duration: 500, easing: easing, finishFunc: finishFunc, action: function(v){ toy.setPosition( p1.x + (p2.x - p1.x) * v, p1.y + (p2.y - p1.y) * v ); } });
經過事件對象獲取到當前點擊的位置,做爲終點,而後獲取圖元的位置座標做爲起點,而後經過ht.Default.startAnim()方法建立一個基礎動畫,在action函數內部不斷地改變圖元的position位置屬性,令其從起點運動到終點,整個過程歷時500毫秒。
接下來看下自身動畫該如何設計:
var size = toy.getSize(); ht.Default.startAnim({ frames: 30, interval: 16, easing: easing, finishFunc: finishFunc, action: function(v){ toy.setRotation(Math.PI * v); var r = Math.abs(v - 0.5) * 2; toy.setSize(size.width * r, size.height * r); } });
點擊圖元時觸發圖元圍繞自身中心旋轉一週,同時圖元由大變小再恢復原尺寸,該邏輯經過設置frames爲30幀和interval爲16毫秒間隔的 Frame-Based方式完成動畫。
咱們兩個動畫都有了,那麼接下來就是將兩個動畫拼接到一塊兒,在監聽裏面該如何出來才能將連個動畫串接起來呢?其實很簡單,咱們只須要判斷當前點擊的對象就能夠很容易分辨出到底要播放哪一個動畫,如下的代碼就是具體的點擊事件邏輯處理:
if(isAnimating || !ht.Default.isLeftButton(e)){ return; } isAnimating = true; var data = graphView.getDataAt(e); var easing = function (t) { return ( 2 - t) * t; }; var finishFunc = function(){ isAnimating = false; }; if(data === toy){ // 自身動畫 … }else{ // 平移動畫 … }
這個Demo到這裏就算結束了,這個Demo是在2D上的應用,接下來咱們來看一個3D上的應用:
本次要設計的3D應用是一個在頁面初始化後,圖元從遠到近呈如今屏幕上,而後緩慢地作360度的旋轉,令圖元的各個視角都呈如今眼前。
哈哈,飛機又和你們見面了,在上一章節的Demo中,加載obj文件完成操做後的finishFunc函數中添加如下代碼:
fromEye = [0, 900*5, 1200*5]; toEye = [0, 100, 600]; g3d.setEye(fromEye); ht.Default.startAnim({ duration: 1000, action: function(t){ g3d.setEye([ fromEye[0] + (toEye[0] - fromEye[0]) * t, fromEye[1] + (toEye[1] - fromEye[1]) * t, fromEye[2] + (toEye[2] - fromEye[2]) * t ]); }, finishFunc: function(){ setInterval(function(){ g3d.rotate(Math.PI/360, 0); }, 30); } });
代碼的邏輯也很簡單,經過設置視角就可以實現圖元由遠到近的感受,當圖元呈如今眼先後,咱們經過定時器旋轉拓撲組件,令圖元水平360度呈現。
在這個例子中,我並無操做圖元的屬性值,都是在操做拓撲的屬性值,因此效果的呈現有可能會有多種實現方式,關鍵是要懂得思考和運用,那麼這個飛機的Demo,經過直接改變圖元屬性來達到以上相同效果該如何實現呢?感興趣的朋友不妨嘗試下。
如下是本次介紹涉及到的Demo源碼及相關視頻: