HTML5的誕生給web前端界帶來了不小轟動,像什么動畫旋轉、圖片滑塊、圖片輪播等等這些3D特效,也引發了不少朋友想要學習HTML5的好奇心。最近我一直在做canvas動畫效果,發現canvas這個東西做動畫不是不可以。相對于flash,它太底層。如果有給力的編輯器或者給力的框架的話,它就能發揮出更大的威力。
于是決定自己寫一個簡單一點的動畫框架,以便能更方便地構建出一些動畫效果。
我將分幾個章節來講述我這個小動畫框架的實現:
1.通用類的提取:動畫對象與幀對象
2.靈與肉的結合:便于拆卸的運動方程
3.進度條的實現:canvas的圖片預加載
4.demo測試:通過一個demo測試框架
這一節我們先來說說通用類的提取。
其實上一篇文章我已經用到了這種從flash借鑒來的思路:一個動畫對象(類似flash中的元件),一個幀對象(類似flash中的幀)。動畫就是在不斷在當前幀上繪制每個動畫對象來實現的。有了這兩個對象,再加上一些運動方法,我們就可以構建出動畫來。
首先我們先來看看動畫對象Aniele:
/* *Aniele動畫對象 *所有動畫對象的始祖 */ varAniele=function(){ this.img=newImage(); //定義動畫對象位置 this.loca={ x:300, y:300 } //定義動畫對象的大小(可以實現縮放) this.dw; this.dh; //動畫對象的速度屬性 this.speed={ x:0, y:0 } //設置對象的透明度 this.alpha=1; //設置圖像翻轉,1為不翻轉,-1為翻轉 this.scale={ x:1, y:1 } //定動畫對象的運動方法庫 this.motionFncs=[]; } Aniele.prototype={ //添加運動方法 addMotionFnc:function(name,fnc) { this.motionFncs[name]=fnc; }, //刪除運動方法 deleMotionFnc:function(name){ this.motionFncs[name]=null; }, //遍歷運動方法庫里的所有運動方法 countMotionFncs:function() { for(vari=0; i if(this.motionFncs[i]==null) continue; this.motionFncs[i].call(this); } }, //把自己繪制出來的方法,包括功能:水平翻轉 draw:function(canvas,ctx){ //存儲canvas狀態ctx.save(); //實現透明度的改變 ctx.globalAlpha=this.alpha; //實現水平豎直翻轉,定義drawImage的兩個位置參數dx,dy vardx=this.loca.x; vardy=this.loca.y; if(this.scale.x!=1||this.scale.y!=1){ if(this.scale.x<0){ console.log(this.img.width) dx=canvas.width-this.loca.x-this.img.width; ctx.translate(canvas.width,1); ctx.scale(this.scale.x,1); } if(this.scale.y<0){ dy=canvas.height-this.loca.y-this.img.height; ctx.translate(1,canvas.height); ctx.scale(1,this.scale.y); } } if(this.dw==null) this.dw=this.img.width; if(this.dh==null) this.dh=this.img.height; //畫出對象 ctx.drawImage(this.img,dx,dy,this.dw,this.dh); //恢復canvas狀態ctx.restore(); } }
動畫對象的主要屬性:
- this.img=newImage();我們引入一張圖片,依附在動畫對象上;
- this.loca.x等等;圖片的大小位置透明度等等,便于繪圖時調用;
- this.motionFncs=[];這個比較關鍵,我們給動畫對象定義一個運動方法庫,把動畫對象的運動規則都放在這個運動方法庫中統一管理(每個動畫對象都有自己的運動方法庫);
動畫對象的主要方法:
- addMotionFnc: 為動畫對象的運動方法庫中添加一個運動方法;
- deleMotionFnc:為動畫對象的運動方法庫中刪除一個運動方法;
- countMotionFncs:為動畫對象遍歷運動方法庫中的所有運動方法;
- draw:把動畫對象畫在畫布上,這里我們會把畫布作為參數傳到這個方法里面去,便于繪圖;
在draw方法里,我封裝了一些對圖像的簡單操作,這些操作在動畫中會經常用到:透明,縮放和翻轉。
有了這個,我們就好似獲得了flash里的一個元件,我們可以通過修改它的屬性來隨意改變它。
那么幀對象呢?
幀對象肩負著渲染的任務,并且管理所有動畫對象;
幀對象的主要屬性:
this.aniEles=[];用來存儲當前畫布上所有動畫實例的數組;
大家用過canvas載入圖片的應該知道,由于圖片的異步載入,動畫過程中圖片會出現閃爍的現象,為了避免這種現象,我采用了雙緩沖。
首先后臺創建一個畫布:
this.backBuffer=document.('canvas');
this.backBuffer.width=this.canvas.width;
this.backBuffer.height=this.canvas.height;
this.backBufferctx=this.backBuffer.getContext('2d');
我們所有繪制命令都執行在這個后臺畫布上,最后把后臺畫布畫在前臺畫布上:
this.ctx.drawImage(this.backBuffer,0,0);
這種先把圖繪在后臺畫布,再把后臺畫布復制到前臺的方法就叫做雙緩沖技術。
幀屬性的主要方法:
- int:用于初始化畫布;
- begin:開始動畫渲染的方法;
- render:主渲染的方法;
- addAniEle:為當前幀添加動畫對象;
- deleAniEle:為當前幀刪除動畫;
我們利用幀對象的流程是:先為當前幀添加動畫對象,然后讓當前幀開始渲染。
來源:藍鷗大連中心