canvas簡(jiǎn)介以及常用性能優(yōu)化

1团滥、Canvas和SVG

1)Canvas

HTML5 的 Canvas 元素使用 JavaScript 在網(wǎng)頁上繪制圖像脏嚷。
畫布是一個(gè)矩形區(qū)域赁炎,您可以控制其每一像素是尖。
Canvas 擁有多種繪制路徑意系、矩形、圓形饺汹、字符以及添加圖像的方法蛔添。
Canvas 是逐像素進(jìn)行渲染的。
在 Canvas 中兜辞,一旦圖形被繪制完成迎瞧,它就不會(huì)繼續(xù)得到瀏覽器的關(guān)注。如果其位置發(fā)生變化逸吵,那么整個(gè)場(chǎng)景也需要重新繪制凶硅,包括任何或許已被圖形覆蓋的對(duì)象。

2)SVG

SVG 基于 XML扫皱,這意味著 SVG DOM 中的每個(gè)元素都是可用的足绅。您可以為某個(gè)元素附加 JavaScript 事件處理器。
在 SVG 中韩脑,每個(gè)被繪制的圖形均被視為對(duì)象氢妈。如果 SVG 對(duì)象的屬性發(fā)生變化,那么瀏覽器能夠自動(dòng)重現(xiàn)圖形段多。

3)Canvas和SVG的優(yōu)缺點(diǎn)

Canvas

-依賴分辨率
-不支持事件處理器
-弱的文本渲染能力
-能夠以 .png 或 .jpg 格式保存結(jié)果圖像
-最適合圖像密集型的游戲首量,其中的許多對(duì)象會(huì)被頻繁重繪

SVG

-不依賴分辨率
-支持事件處理器
-最適合帶有大型渲染區(qū)域的應(yīng)用程序(比如谷歌地圖)
-復(fù)雜度高會(huì)減慢渲染速度(任何過度使用 DOM 的應(yīng)用都不快)
-不適合游戲應(yīng)用

2、創(chuàng)建 Canvas 元素

<canvas id="myCanvas" width="200" height="100"></canvas>

3、基本的canvas用法

當(dāng)我們?cè)诶L制的一個(gè)元素(文字加缘、圖形)的時(shí)候粥航,首先要對(duì)這個(gè)元素規(guī)定它的顏色,文字字體生百,然后在進(jìn)行繪制,不然不會(huì)生效柄延。

<script type="text/javascript">
var canvasEle = document.getElementById("myCanvas");
var cxt = canvasEle.getContext("2d");
cxt.fillStyle = "#FF0000";
cxt.fillRect(0,0,150,75);
</script>

4蚀浆、Canvas常用優(yōu)化點(diǎn)

1)使用多層畫布去畫一個(gè)復(fù)雜的場(chǎng)景

場(chǎng)景:假設(shè)您有一個(gè)游戲,其UI位于頂部搜吧,中間是游戲性動(dòng)作市俊,底部是靜態(tài)背景。

方法:可以將游戲分成三個(gè)<canvas>層滤奈。 UI將僅在用戶輸入時(shí)發(fā)生變化摆昧,游戲?qū)与S每個(gè)新框架發(fā)生變化,并且背景通常保持不變

<div id="stage">
  <canvas id="ui-layer" width="480" height="320"></canvas>
  <canvas id="game-layer" width="480" height="320"></canvas>
  <canvas id="background-layer" width="480" height="320"></canvas>
</div>

<style>
  #stage {
    width: 480px;
    height: 320px;
    position: relative;
    border: 2px solid black
  }
  canvas { position: absolute; }
  #ui-layer { z-index: 3 }
  #game-layer { z-index: 2 }
  #background-layer { z-index: 1 }
</style>

好處:避免了固定組件的重復(fù)渲染蜒程。

2)使用window.devicePixelRatio對(duì)畫布進(jìn)行高清處理

設(shè)備屏幕上的像素(邏輯像素)绅你,我們可以當(dāng)做是正常的像素(css中設(shè)置的像素),你可以正常使用它昭躺。如果你畫一個(gè)100px的東西忌锯,他也就是一個(gè)100px的東西。但是领炫,在出現(xiàn)了一些高分辨率屏幕的手機(jī)之后偶垮,一個(gè)屬性devicePixelRatio就一起出現(xiàn)了。它允許我們?nèi)ゲ樵冊(cè)O(shè)備像素比帝洪。在這里我們需要拋出一個(gè)名詞邏輯像素似舵,也就是在css設(shè)置的100px時(shí),在iphone6/7/8(devicePixelRatio為3)上葱峡,實(shí)際渲染的是300px的物理像素砚哗。比例為3:1

但是這對(duì)于我們開發(fā)者的影響是什么呢?早些時(shí)候族沃,我們注意到當(dāng)我們向這種高分辨率的屏幕添加img的時(shí)候频祝,我們的圖形受到devicePixelRatio的影響變得非常模糊。
如何解決這個(gè)問題呢脆淹?如果我把img的寬和高分別與devicePixelRatio相乘常空,得到的大小畫進(jìn)屏幕中,在對(duì)齊進(jìn)行縮放devicePixelRatio的大小盖溺。Img就會(huì)以一種高清的方式呈現(xiàn)漓糙。

 createHiDPICanvas (w, h, ratio) {
      const PIXEL_RATIO = (function () {
        const c = document.getElementById('posterCanvas')
        const ctx = c.getContext('2d')
        const dpr = window.devicePixelRatio || 1
        // backingStorePixelRatio,該屬性的值決定了瀏覽器在渲染canvas之前會(huì)用幾個(gè)像素來來存儲(chǔ)畫布信息 (僅適用于chrome和safari)烘嘱,已經(jīng)廢棄昆禽。
        const bsr =
          ctx.webkitBackingStorePixelRatio ||
          ctx.mozBackingStorePixelRatio ||
          ctx.msBackingStorePixelRatio ||
          ctx.oBackingStorePixelRatio ||
          ctx.backingStorePixelRatio ||
          1

        return dpr / bsr
      })()

      if (!ratio) {
        ratio = PIXEL_RATIO
      }
      const can = document.getElementById('posterCanvas')
      can.width = w * ratio
      can.height = h * ratio
      can.style.width = w + 'px'
      can.style.height = h + 'px'
      can.getContext('2d').setTransform(ratio, 0, 0, ratio, 0, 0)
      return can
    },

但是此方法有個(gè)問題就是既然同比將畫布和內(nèi)容進(jìn)行了放大蝗蛙,然后在進(jìn)行縮放,那么繪制出來的圖片大小就會(huì)相應(yīng)的增大醉鳖。建議根據(jù)需求來判斷是否需要進(jìn)行高清操作捡硅。

3)使用requestAnimationFrame執(zhí)行動(dòng)畫

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

window.requestAnimationFrame(callback)

執(zhí)行一個(gè)動(dòng)畫惊畏,并且要求瀏覽器在下次重繪之前調(diào)用指定的回調(diào)函數(shù)更新動(dòng)畫恶耽。該方法需要傳入一個(gè)回調(diào)函數(shù)作為參數(shù),返回一個(gè) requestID颜启,該回調(diào)會(huì)在瀏覽器下一次重繪之前執(zhí)行

window. cancelAnimationFrame(requestID)

取消一個(gè)先前通過調(diào)用window. cancelAnimationFrame()方法添加到計(jì)劃中的動(dòng)畫幀請(qǐng)求驳棱,接受一個(gè) requestID
瀏覽器兼容


瀏覽器兼容.png

4)1px像素模糊情況

canvas每條線都有一條無限細(xì)的中線,線由中線兩個(gè)伸展农曲。


1px像素模糊.png

解決問題的根源起點(diǎn)應(yīng)該在0.5的地方社搅,這也是為什么x,y需要+0.5。當(dāng)x,y做過計(jì)算不一定是整數(shù)的時(shí)候可能+0.5又出現(xiàn)模糊的情況乳规。所以做一個(gè)取整可以保證不會(huì)出現(xiàn)模糊的情況

cxt.moveTo(parseInt(x)+0.5, parseInt(y)+0.5)
cxt.lineTo(parseInt(x)+0.5, parseInt(y)+0.5)

5)離屏繪制圖像

1.繪制圖像
context.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
image.png
2.繪制性能比較

由于我們具備「把圖片中的某一部分繪制到 Canvas 上」的能力形葬。
在平常的html中,我們會(huì)把多個(gè)對(duì)象放在一張圖片里面暮的,以減少請(qǐng)求數(shù)量笙以。這通常被稱為「精靈圖」。然而冻辩,這實(shí)際上存在著一些潛在的性能問題猖腕。使用 drawImage 繪制同樣大小的區(qū)域,數(shù)據(jù)源是一張和繪制區(qū)域尺寸相仿的圖片的情形恨闪,和比起數(shù)據(jù)源是一張較大圖片(我們只是把數(shù)據(jù)扣下來了而已)的情形倘感,前者的開銷要小一些×剩可以認(rèn)為老玛,兩者相差的開銷正是「裁剪」這一個(gè)操作的開銷。
雖然看上去開銷相差并不多,但是 drawImage 是最常用的 API 之一蜡豹,我認(rèn)為還是有必要進(jìn)行優(yōu)化的麸粮。優(yōu)化的思路是,將「裁剪」這一步驟事先做好镜廉,保存起來弄诲,每一幀中僅繪制不裁剪。

3.離屏繪制

我們可以先把待繪制的區(qū)域裁剪好娇唯,保存起來威根,這樣每次繪制時(shí)就能輕松很多
drawImage 方法的第一個(gè)參數(shù)不僅可以接收 Image 對(duì)象,也可以接收另一個(gè) Canvas 對(duì)象视乐。而且,使用 Canvas 對(duì)象繪制的開銷與使用 Image 對(duì)象的開銷幾乎完全一致敢茁。我們只需要實(shí)現(xiàn)將對(duì)象繪制在一個(gè)未插入頁面的 Canvas 中佑淀,然后每一幀使用這個(gè) Canvas 來繪制。

// 在離屏 canvas 上繪制
var canvasOffscreen = document.createElement('canvas');
canvasOffscreen.width = dw;
canvasOffscreen.height = dh;
canvasOffscreen.getContext('2d').drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);

// 在繪制每一幀的時(shí)候彰檬,繪制這個(gè)圖形
context.drawImage(canvasOffscreen, x, y);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末伸刃,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子逢倍,更是在濱河造成了極大的恐慌捧颅,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件较雕,死亡現(xiàn)場(chǎng)離奇詭異碉哑,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)亮蒋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門扣典,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人慎玖,你說我怎么就攤上這事贮尖。” “怎么了趁怔?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵湿硝,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我润努,道長(zhǎng)关斜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任铺浇,我火速辦了婚禮蚤吹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己裁着,他們只是感情好繁涂,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著二驰,像睡著了一般扔罪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上桶雀,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天矿酵,我揣著相機(jī)與錄音,去河邊找鬼矗积。 笑死全肮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的棘捣。 我是一名探鬼主播辜腺,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼乍恐!你這毒婦竟也來了评疗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤茵烈,失蹤者是張志新(化名)和其女友劉穎百匆,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呜投,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡加匈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仑荐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矩动。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖释漆,靈堂內(nèi)的尸體忽然破棺而出悲没,到底是詐尸還是另有隱情,我是刑警寧澤男图,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布示姿,位于F島的核電站,受9級(jí)特大地震影響逊笆,放射性物質(zhì)發(fā)生泄漏栈戳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一难裆、第九天 我趴在偏房一處隱蔽的房頂上張望子檀。 院中可真熱鬧镊掖,春花似錦、人聲如沸褂痰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缩歪。三九已至归薛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間匪蝙,已是汗流浹背主籍。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逛球,地道東北人千元。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像颤绕,于是被迫代替她去往敵國(guó)和親幸海。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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

  • 一屋厘、簡(jiǎn)介 是一個(gè)可以使用腳本(通常為JavaScript)來繪制圖形的 HTML 元素.例如,它可以用于繪制圖表、...
    Adoins閱讀 2,173評(píng)論 0 2
  • 一:canvas簡(jiǎn)介 1.1什么是canvas月而? ①:canvas是HTML5提供的一種新標(biāo)簽 ②:HTML5 ...
    GreenHand1閱讀 4,667評(píng)論 2 32
  • 1.繪圖 fillRect(x, y, width, height)[https://developer.mozi...
    SnuggleE閱讀 598評(píng)論 0 0
  • @(HTML5)[canvas與SVG] [TOC] 十 汗洒、canvas canvas的基本用法 canvas是H...
    踏浪free閱讀 723評(píng)論 0 0
  • 一、圖形的組合方式 globalAlpha是一個(gè)介于0和1之間的值(包括0和1)父款,用于指定所有繪制的透明度溢谤。默認(rèn)值...
    空谷悠閱讀 1,252評(píng)論 0 0