程式設計雜筆

[程設雜筆] 增進canvas上動畫效能

最近在寫一個程式,需要在canvas上畫出大量的點點,而且是以動畫的形式呈現,所以當要畫的點多起來時,瀏覽器就會變得很當。htop了一下,發現瀏覽器繪圖吃太多CPU資源了。於是就研究一下,如何把CPU的使用率壓下去。

首先,之前寫前端的動畫時,我都會用setInterval或setTimeout,但是後來發現,我的動畫好像都會漏格,於是就研究了一下,發現只要把這兩個方法都換成requestAnimFrame即可。而各家瀏覽器在這方面的名稱都不一樣,所以要自己定義自己的方法。

window.requestAnimFrame = (function(){
    return window.requestAnimationFrame || //Chromium
        window.webkitRequestAnimationFrame || //Webkit
        window.mozRequestAnimationFrame || //Mozilla
        window.oRequestAnimationFrame || //Opera
        window.msRequestAnimationFrame || //IE
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        };
})();

    drawAnim(){//畫動畫
        .
        .
        .
        .
        window.requestAnimFrame(this.drawAnim.bind(this));
    }

此外,這個方法預設的fps是60,也就是每秒刷畫面60次。我的動畫來說,這樣吃的資源太多了,所以把fps下降到30,也就是一次畫,一次不畫,吃的CPU馬上顯著下降。

可是我覺得效能降的還不是很滿意,於是打開google chrome 按F12得到下面這個畫面,就可以開始測我們的網頁到底吃了多少CPU。
chrome-profile

本來的程式碼長下面這個樣子,也就是每畫一個點都beginpath(), fill(), closepath()一次。

//point collection.draw()
this.draw=function(){
        for(let i=0;i<this.points.length;i++){
            points[i].draw();
        }
    };

//points.draw
this.draw=function(){
        ctx.fillStyle=color;
        ctx.beginPath();
        ctx.arc(this.curPos.x,this.curPos.y,radius,0,Math.PI*2,true);
        ctx.fill();
        ctx.closePath();
    };

可是看了一下cpu profile,發現大部分的資源都花在fill這裡,於是就改了一下程式呼叫的先後。變成全部的點點都設好後,再一次fill(),也就是下面這樣。

//point collection.draw()
this.draw=function(){
        ctx.beginPath();
        for(let i=0;i<this.points.length;i++)
                this.points[i].draw();
        ctx.fill();
        ctx.closePath();
    };
//points.draw
this.draw=function(){
        ctx.fillStyle=color;
        ctx.moveTo(this.curPos.x,this.curPos.y);
        ctx.arc(this.curPos.x,this.curPos.y,radius,0,Math.PI*2,true);
    };

再看一下CPU的profile,馬上顯著的下降。如下圖

canvascpu1
優化前
canvascpu2
優化後

但是,在fill的時候,如果fillstyle有改變,就要先fill,然後再closepath,beginpath,否則會以最後設定的fillstyle為主。所以最好的狀況,就是把所有相同的fillstyle,全部都一次指定好,一次fill,就不用一直切換fillstyle,然後重複的執行最耗資源的fill()

參考資料:
http://blog.tonycube.com/2012/03/html5-canvas-6.html

https://msdn.microsoft.com/zh-tw/library/hh920765(v=vs.85).aspx

http://www.html5rocks.com/en/tutorials/canvas/performance/

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 變更 )

Twitter picture

You are commenting using your Twitter account. Log Out / 變更 )

Facebook照片

You are commenting using your Facebook account. Log Out / 變更 )

Google+ photo

You are commenting using your Google+ account. Log Out / 變更 )

連結到 %s