canvas性能優(yōu)化篇

轉(zhuǎn)自博客原文連接:https://tong-h.github.io/2019/03/18/canvas-3/#more

看了很多大佬的文章萨螺,自己也對項目做了一些優(yōu)化镰绎,其實有很多地方平常碼代碼的時候稍微注意一下就能節(jié)約很多性能開銷

1.離屏渲染

在離屏canvas上預(yù)渲染相似的圖形或重復(fù)的對象,通俗的解釋是將離屏canvas當(dāng)成預(yù)渲染唁桩,在離屏canvas上繪制好一整塊圖形巴碗,繪制好后在放到視圖canvas中,適合每一幀畫圖運算復(fù)雜的圖形

比如你想把一張圖片放到canvas上扣癣,使用drawImage()方法惰帽,有三種寫法

// 將image放到目標(biāo)canvas指定位置
void ctx.drawImage(image, dx, dy); 
// 將image放到目標(biāo)canvas指定位置,指定寬高渲染
void ctx.drawImage(image, dx, dy, dWidth, dHeight);
// 將image裁剪之后放到目標(biāo)canvas指定位置搏色,指定寬高渲染
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

第一種只是把圖片原樣放到canvas里善茎,第二章指定寬高就意味著放大或者縮小圖片后再放進(jìn)去,帶三種是裁剪后再放大或者縮小放到canvas中频轿,這三種寫法操作依次增加垂涯,性能開銷也是依次提高
而離屏渲染就可以讓我們先把圖片裁剪成想要的尺寸內(nèi)容保存起來烁焙,繪制的時候就可以使用第一種寫法簡單的把圖片放進(jìn)去就完了

// 在離屏 canvas 上繪制
var offscreencanvas = document.createElement('canvas');
// 寬高賦值為想要的圖片尺寸
offscreencanvas.width = dWidth;
offscreencanvas.height = dHeight;
// 裁剪
offscreencanvas.getContext('2d').drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
// 在視圖canvas中繪制
viewcontext.drawImage(canvas, x, y);

2.分層畫布

多個相互重疊的canvas根據(jù)變化程度分開渲染,越復(fù)雜的場景越適合

比如一個簡單的游戲場景耕赘,游戲背景始終不變或者變化次數(shù)較少但是人物游戲的主體是一直在根據(jù)玩家的指揮不停的改變骄蝇,

場景:最近寫的一個畫板,比如這樣一個簡單的畫圓操骡,可以看到有原來的繪畫的痕跡九火,那就要 渲染沒畫圓之前的畫布 -> 再畫圓,鼠標(biāo)移動的時候不斷的執(zhí)行這個渲染過程

canvas-3.gif

這個時候就可以使用分層畫布册招,畫畫在一個上層canvas上岔激,原來繪畫痕跡在下層canvas上,那么畫圓的過程就是清空 -> 畫圓是掰,畫好之后再放到下層canvas上虑鼎,這樣就不需要去渲染之前的畫布,就能節(jié)約性能開銷

3.一次性繪制

繪制操作的性能開銷較高键痛,可以創(chuàng)建一個包含所有線條的路徑炫彩,然后通過單個繪制路徑調(diào)用進(jìn)行繪制

從這樣

for (var i = 0; i < points.length - 1; i++) {
  var p1 = points[i];
  var p2 = points[i+1];
  context.beginPath();
  context.moveTo(p1.x, p1.y);
  context.lineTo(p2.x, p2.y);
  context.stroke();
}

變成這樣,在繪制復(fù)雜路徑時絮短,最好將所有點都放入路徑中江兢,而不是分別呈現(xiàn)各個片段

context.beginPath();
for (var i = 0; i < points.length - 1; i++) {
  var p1 = points[i];
  var p2 = points[i+1];
  context.moveTo(p1.x, p1.y);
  context.lineTo(p2.x, p2.y);
}
context.stroke();

4.使用requestAnimationFrame執(zhí)行動畫

canvas動畫的本質(zhì)是不斷地擦除和重繪,再結(jié)合一些時間控制的方法達(dá)到動畫的目的
顯示器刷新頻率是60Hz丁频,最平滑動畫的最佳循環(huán)間隔是1000ms/60杉允,約等于16.6ms
而requestAnimationFrame就是根據(jù)顯示器刷新頻率來的,這是瀏覽器專門為動畫提供的API席里,在運行時瀏覽器會自動優(yōu)化方法的調(diào)用夺颤,節(jié)省系統(tǒng)資源,提高系統(tǒng)性能胁勺,如果頁面不是激活狀態(tài)下的話世澜,requestAnimationFrame() 會被暫停調(diào)用以提升性能和電池壽命

詳細(xì)看這兒

5.清空畫布

三種方法性能,性能依次提高

context.fillRect()
context.clearRect()
canvas.width = canvas.width; // 一種畫布專用的技巧

6.減少調(diào)用canvas的api

比如像背景可以使用css屬性設(shè)置或者img標(biāo)簽加一些定位什么的

畫布的縮放可以使用CSS transforms署穗,不要將小畫布放大寥裂,而是去將大畫布縮小

var scaleX = canvas.width / window.innerWidth;
var scaleY = canvas.height / window.innerHeight;

var scaleToFit = Math.min(scaleX, scaleY);
var scaleToCover = Math.max(scaleX, scaleY);

stage.style.transformOrigin = '0 0'; //scale from top left
stage.style.transform = 'scale(' + scaleToFit + ')';

其他注意點

  • 盡可能使用計算代替canvas渲染,通常情況下案疲,渲染比計算的開銷大很多(3~4 個量級)
  • 減少改變 context 的狀態(tài)以及不要賦一些亂七八糟類型的值封恰,比如人家要一個number你要給一個string,瀏覽器會用一些額外時間來處理這些非法輸入褐啡,可能會造成三四倍的時間開銷
  • 避免使用浮點數(shù)坐標(biāo)诺舔,使用非整數(shù)的坐標(biāo)繪制內(nèi)容,系統(tǒng)會自動使用抗鋸齒功能,嘗試對線條進(jìn)行平滑處理低飒,這又是一種性能消耗许昨。可以調(diào)用 Math.round 四舍五入取整
  • 減少使用 shadowBlur 效果褥赊,和很多圖像環(huán)境渲染一樣糕档,陰影渲染的性能開銷通常比較高

參考文章

https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas
https://www.html5rocks.com/zh/tutorials/canvas/performance/
http://taobaofed.org/blog/2016/02/22/canvas-performance/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拌喉,隨后出現(xiàn)的幾起案子速那,更是在濱河造成了極大的恐慌,老刑警劉巖尿背,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件端仰,死亡現(xiàn)場離奇詭異,居然都是意外死亡田藐,警方通過查閱死者的電腦和手機(jī)榆俺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坞淮,“玉大人,你說我怎么就攤上這事陪捷』鼐剑” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵市袖,是天一觀的道長啡直。 經(jīng)常有香客問我,道長苍碟,這世上最難降的妖魔是什么酒觅? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮微峰,結(jié)果婚禮上舷丹,老公的妹妹穿的比我還像新娘。我一直安慰自己蜓肆,他們只是感情好颜凯,可當(dāng)我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著仗扬,像睡著了一般症概。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上早芭,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天彼城,我揣著相機(jī)與錄音,去河邊找鬼。 笑死募壕,一個胖子當(dāng)著我的面吹牛调炬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播司抱,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼筐眷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了习柠?” 一聲冷哼從身側(cè)響起匀谣,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎资溃,沒想到半個月后武翎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡溶锭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年宝恶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趴捅。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡垫毙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拱绑,到底是詐尸還是另有隱情综芥,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布猎拨,位于F島的核電站膀藐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏红省。R本人自食惡果不足惜额各,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吧恃。 院中可真熱鬧虾啦,春花似錦、人聲如沸痕寓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽厂抽。三九已至需频,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間筷凤,已是汗流浹背昭殉。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工苞七, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挪丢。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓蹂风,卻偏偏與公主長得像,于是被迫代替她去往敵國和親乾蓬。 傳聞我的和親對象是個殘疾皇子惠啄,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容