1. 程式人生 > >canvas的效能優化(快取問題)

canvas的效能優化(快取問題)

使用快取

使用快取就是用離屏canvas進行預渲染了。原理就是先繪製一個離屏canvas,然後再通過drawImage把離屏canvas畫到主canvas中。把離屏canvas當成一個快取區,需要重複繪製的畫面資料進行快取。減少呼叫canvas的API消耗。
例如下面的DEMO:

1、使用了快取
2、沒使用快取
看到上面的DEMO效能明顯不一樣。分析一下原因:為了實現每個圈的樣式,所以繪製圈圈時用了迴圈繪製,如果沒有啟用快取,當頁面的圈圈數量達到一定時,動畫的每一幀就要大量呼叫canvas的API,要進行大量的計算,這樣再好的瀏覽器也會被拖垮。

ctx.save();
var j=0
; ctx.lineWidth = borderWidth; for(var i=1;i<this.r;i+=borderWidth){ ctx.beginPath(); ctx.strokeStyle = this.color[j]; ctx.arc(this.x , this.y , i , 0 , 2*Math.PI); ctx.stroke(); j++; } ctx.restore();

除了建立離屏的canvas作為快取之外,下面的程式碼中有一點很關鍵,就是要設定離屏canvas的寬度和高度,canvas生成後的預設大小是300X150,對於程式碼中每個快取起來圈圈物件半徑最大也就不超過80,所以300X150的大小明顯會造成很多空白區域,會造成資源浪費,所以要設定一下離屏canvas的寬度和高度,讓他跟快取起來的元素大小一致,這樣有利於提高動畫效能。

var ball = function(x , y , vx , vy , useCache){
                this.x = x;
                this.y = y;
                this.vx = vx;
                this.vy = vy;
                this.r = getZ(getRandom(20,40));
                this.color = [];
                this.cacheCanvas = document.createElement("canvas"
); this.cacheCtx = this.cacheCanvas.getContext("2d"); this.cacheCanvas.width = 2*this.r; this.cacheCanvas.height = 2*this.r; var num = getZ(this.r/borderWidth); for(var j=0;j<num;j++){ this.color.push("rgba("+getZ(getRandom(0,255))+","+getZ(getRandom(0,255))+","+getZ(getRandom(0,255))+",1)"); } this.useCache = useCache; if(useCache){ this.cache(); } }

當例項化圈圈物件時,直接呼叫快取方法,把複雜的圈圈直接畫到圈圈物件的離屏canvas中儲存起來。

cache:function(){
                    this.cacheCtx.save();
                    var j=0;
                    this.cacheCtx.lineWidth = borderWidth;
                    for(var i=1;i<this.r;i+=borderWidth){
                        this.cacheCtx.beginPath();
                        this.cacheCtx.strokeStyle = this.color[j];
                        this.cacheCtx.arc(this.r , this.r , i , 0 , 2*Math.PI);
                        this.cacheCtx.stroke();
                        j++;
                    }
                    this.cacheCtx.restore();
                }

然後在接下來的動畫中,只需要把圈圈物件的離屏canvas畫到主canvas中,這樣,每一幀呼叫的canvasAPI就只有這麼一句話:
ctx.drawImage(this.cacheCanvas , this.x-this.r , this.y-this.r);