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