canvas 必須懂的方法

  1. 驗證瀏覽器是否支持

    <canvas id="myCanvas" width="400" height="400"> Your browser does not support HTML5 Canvas. </canvas>
    
    function canvasAPP () { 
        var myCanvas = document.getElementById('myCanvas');
        if (!myCanvas || !myCanvas.getContext) { return; } 
        //  這里開始繪制 
        var ctx = myCanvas.getContext('2d');
        function drawScreen () { 
            //  ... 
        }
        drawScreen();
     }
    
  2. 繪制線段

    • ctx.strokeStyle 用于設置畫筆繪制路徑的顏色、漸變和模式

    • ctx.lineWidth 定義繪制線條的寬度

    • ctx.beginPath() 開始一個新的繪制路徑

    • ctx.moveTo(x,y) 移動畫筆到指定的坐標點(x,y),該點就是新的子路徑的起始點

    • ctx.lineTo(x,y) 使用直線邊接當前端點和指定的坐標點(x,y)

    • ctx.stroke() 沿著繪制路徑的坐標點順序繪制直線

    • ctx.closePath() 如果當前的繪制路徑是打開的,則關閉掉該繪制路徑

    • ctx.setLineDash([]) 繪制虛線,數組內可以傳一個元素,兩個或者三個分別表示線段,間隔大小

    • ctx.lineCap 線帽,取值有butt、round和square,其中默認的值是butt。

      線帽.png

    • ctx.lineJoin 線段的連接點,取值有round、bevel和miter,其中miter是其默認值,取值為miter時,還可以指定一個miterLimit屬性。

  3. 如果繪制一條真正1像素寬的線段,你必須將該線段繪制在某兩個像素之間的那個像素中(比如從moveTo(30.5,100.5) lineTo(50.5,120.5)),而不能將它繪制在兩個像素的交界處。

    像素邊界.png
  1. 對于save()和restore()方法,一開始有一個錯誤的理解,以為每一步都save()之后restore()就等同于command + z(或者ctrl + z),其實save()保存的只是CanvasRenderingContext2D對象的狀態以及對象的所有屬性,并不包括這個對象上繪制的圖形。官方文檔描述如下:

    save()和restore()方法允許你保存和恢復一個CanvasRenderingContext2D對象的狀態。save()把當前狀態推入到繪圖堆棧中,而restore()從繪圖堆棧中的頂端彈出最近保存的狀態,并且根據這些存儲的值來設置當前繪圖狀態。

  2. 繪制矩形api

    • fillRect(x, y, width, height):繪制一個填充的矩形
    • strokeRect(x, y, width, height):繪制一個矩形的邊框
    • clearRect(x, y, width, height):清除指定矩形區域,讓清除部分完全透明.經常用來清除干凈畫布,`ctx.clearRect(0,0,myCanvas.width,myCanvas.height);
    • rect(x, y, width, height):也是Canvas中路徑的一個方法,需要配合fill()和stroke()。
    function drawScreen () {
        ctx.strokeStyle = '#000'; 
        ctx.fillStyle = '#9f9' ;
        ctx.lineWidth = 4; 
        // 繪制
        ctx.beginPath(); 
        ctx.rect(30,30,200,200); 
        ctx.stroke(); 
        // 繪制
        ctx.beginPath(); 
        ctx.rect(300,30,200,200); 
        ctx.fill(); 
        // 繪制既有邊框又填充,注意因為lineWidth為4,fill方法的值大小
        ctx.strokeRect(240,10,100,100); 
        ctx.fillRect(242,12,96,96);
    }
    
  3. 在Canvas中,CanvasRenderingContext2D對象提供了兩個方法(arc()和arcTo())來繪制圓和圓弧。其中arc()即可繪制弧線,圓,也可以繪制扇形,但arcTo()僅能繪制出弧線。但arcTo()可以更輕易的幫助我們實現帶圓角的矩形。

    • arc(x, y, radius, startRad, endRad, [anticlockwise]) 坐標點(x,y)為圓心、半么為radius的圓上的一段弧線。這段弧線的起始弧度是startRad,結束弧度是endRad。這里的弧度是以x軸正方向為基準、進行順時針旋轉的角度來計算。其中anticlockwise表示arc()繪制圓或圓弧是以順時針還是逆時針方向開始繪制。如果其值為true表示逆時針,如果是false表示為順時針。該參數是一個可選參數,如果沒有顯式設置,其值是false(也是anticlockwise的默認值)。
    • arcTo(x1, y1, x2, y2, radius) arcTo()方法將利用當前端點、端點一(x1, y1)和端點二(x2, y2)這三點所形成的夾角,然后繪制一段與夾角的兩邊相切并且半徑為radius的圓上的弧線?;【€的起點就是當前端點所在邊與圓的切點,弧線的終點就是商端點二(x2,y2)所在邊與圓的切點,并且繪制的弧線是兩個切點之間長度最短的那個圓弧。此外,如果當前端點不是弧線起點,arcTo()方法還將添加一條當前端點到弧線起點的直線線段。
  4. Canvas坐標變換有移動、旋轉和縮放

    • ctx.translate(x, y) :translate方法接受兩個參數。x是左右偏移量,y是上下偏移量。當偏移量操作出Canvas的width或height時,坐標將會移出Canvas的畫布,這個時候你繪制的東西都將看不到。
    • ctx.rotate(angle) :rotate()方法只接受一個參數,旋轉的角度angle,它是順時針方向的,以弧度為單位的值。
    • ctx.scale(x, y) :scale()方法接受兩個參數。x和y分別是橫軸和縱軸的縮放因子。其縮放因子默認是1,如果比1小是縮小,如果比1大則放大。在繪制了某個圖形后,可以調用ctx.scale(-1, 1)來繪制其水平鏡像或者調用ctx.scale(1, -1)來繪制其垂直鏡像(這里只是把坐標系翻轉,翻轉后還需要再繪制一遍要鏡像的圖形)。
  5. Canvas中可以通過ctx.fillText("內容",x,y,maxWidth)繪制填充文本,ctx.strokeText()可以繪制描邊文本,另外通過ctx.textAlign和ctx.textBaseline設置所繪制文本的位置,并且使用ctx.measureText('text').width可以得到所繪制文本text的寬度值,雖然這個值并不精確

  6. 在Canvas中有兩個屬性globalAlpha和globalCompositeOperation來控制圖像合成操作:

    • globalAlpha:設置圖像的透明度。globalAlpha屬性默認值為1,表示完全不透明,并且可以設置從0(完全透明)到1(完全不透明)。這個值必須設置在圖形繪制之前。
    • globalCompositeOperation:該屬性的值在globalAlpha以及所有變換都生效后控制在當前Canvas位圖中繪制圖形
      // 上面是目標圖像(已有),下面是源圖像(新的);
      // source-over  默認。在目標圖像上顯示源圖像。
      // source-atop  在目標圖像頂部顯示源圖像。源圖像位于目標圖像之外的部分是不可見的。
      // source-in    在目標圖像中顯示源圖像。只有目標圖像內的源圖像部分會顯示,目標圖像是透明的。
      // source-out   在目標圖像之外顯示源圖像。只會顯示目標圖像之外源圖像部分,目標圖像是透明的。
      // destination-over 在源圖像上方顯示目標圖像。
      // destination-atop 在源圖像頂部顯示目標圖像。源圖像之外的目標圖像部分不會被顯示。
      // destination-in   在源圖像中顯示目標圖像。只有源圖像內的目標圖像部分會被顯示,源圖像是透明的。
      // destination-out  在源圖像外顯示目標圖像。只有源圖像外的目標圖像部分會被顯示,源圖像是透明的。
      // lighter  顯示源圖像 + 目標圖像。
      // copy 顯示源圖像。忽略目標圖像。
      // source-over  使用異或操作對源圖像與目標圖像進行組合。
      ctx.globalCompositeOperation = "source-over";
      
  7. clip()方法將剪切區域設置為當前剪切區域與當前路徑的交集。在第一次調用clip()方法之前,剪切區域與整個Canvas畫布大小一致。因為clip()方法會將剪切區域設置為當前剪切區域與當前路徑的交集,所以對該方法的調用一般都是嵌入save()和restore()方法之間的。否則,剪切區域將會越變越小,這通常不是我們想要的效果。

    • Canvas中的clip()方法用于從原始畫布中剪切任意形狀和尺寸。一旦剪切了某個區域,則所有之后的繪圖都會被限制在被剪切的區域內(不能訪問畫布上的其他區域)。也可以在使用clip()方法前通過使用save()方法對當前畫布區域進行保存,并在以后的任意時間通過restore()方法對其進行恢復。
    • [實現探照燈效果](https:// www.w3cplus.com/canvas/clip.html)
  8. ImageData操作,無論時getImageData還是putImageData都是針對畫布來說的,拿到畫布上的像素。一般可以結合drawIamge來用,先把圖片通過drawImage繪制到圖像上,然后再通過getImageData獲取像素數據,循環修改其中的data屬性,最后再通過putImageData,把修改后的imageData放回到畫布。

    • createImageData() 方法創建新的空白 ImageData 對象。新對象的默認像素值 transparent black。
      對于 ImageData 對象中的每個像素,都存在著四方面的信息,即 RGBA 值:
      R - 紅色 (0-255)
      G - 綠色 (0-255)
      B - 藍色 (0-255)
      A - alpha 通道 (0-255; 0 是透明的,255 是完全可見的)
      因此 ,transparent black 表示 (0,0,0,0)。
      color/alpha 以數組形式存在,并且既然數組包含了每個像素的四條信息,數組的大小是 ImageData對象的四倍。(獲得數組大小有更簡單的辦法,就是使用 ImageDataObject.data.length)。
      注意:包含 color/alpha 信息的數組存儲于 ImageData 對象的 data 屬性中。

      // 1. 以指定的尺寸(以像素計)創建新的 ImageData 對象:
      var imgData=ctx.createImageData(width,height);
      // 2. 創建與指定的另一個 ImageData 對象尺寸相同的新 ImageData 對象(不會復制圖像數據):
      var imgData=ctx.createImageData(imageData);
      
    • getImageData() 方法返回 ImageData 對象,該對象拷貝了畫布指定矩形的像素數據。

      // x    開始復制的左上角位置的 x 坐標。相對與canvas
      // y    開始復制的左上角位置的 y 坐標。
      // width    將要復制的矩形區域的寬度。
      // height 將要復制的矩形區域的高度。
      var imgData=context.getImageData(x,y,width,height);
      // 返回的 ImageData 對象中第一個像素的 color/alpha 信息,注意這里只是第一個像素,每個像素占數組的四個元素
      red=imgData.data[0];
      green=imgData.data[1];
      blue=imgData.data[2];
      alpha=imgData.data[3];
      
    • putImageData() 方法將圖像數據(從指定的 ImageData 對象)放回畫布上

      // imgData  規定要放回畫布的 ImageData 對象。
      // x    ImageData 對象左上角的 x 坐標,以像素計。
      // y    ImageData 對象左上角的 y 坐標,以像素計。
      // dirtyX   可選。水平值(x),以像素計,在畫布上放置圖像的位置。
      // dirtyY   可選。水平值(y),以像素計,在畫布上放置圖像的位置。
      // dirtyWidth   可選。在畫布上繪制圖像所使用的寬度。
      // dirtyHeight  可選。在畫布上繪制圖像所使用的高度。
      ctx.putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight);
      
    • ImageDate對象的三個屬性
      width 返回 ImageData 對象的寬度
      height 返回 ImageData 對象的高度
      data 返回一個對象,其包含指定的 ImageData 對象的圖像數據

  9. 圖像繪制,向畫布上繪制圖像、畫布或視頻

    // img  規定要使用的圖像、畫布或視頻。
    // sx   可選。開始剪切的 x 坐標位置。
    // sy   可選。開始剪切的 y 坐標位置。
    // swidth   可選。被剪切圖像的寬度。
    // sheight  可選。被剪切圖像的高度。
    // x    在畫布上放置圖像的 x 坐標位置。
    // y    在畫布上放置圖像的 y 坐標位置。
    // width    可選。把圖像繪制到畫布上的寬度。(伸展或縮小圖像)
    // height   可選。把圖像繪制到畫布上的高度。(伸展或縮小圖像)
    ctx.drawImage(img,x,y);
    ctx.drawImage(img,x,y,width,height);
    ctx.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
    
  10. 如何把canvas畫布轉換成img圖像,[更多canvas壓縮圖片操作](http:// www.zhangxinxu.com/wordpress/2017/07/html5-canvas-image-compress-upload/)

    • canvas.toDataURL()方法,注意是canvas對象調用的方法
    canvas.toDataURL(mimeType, qualityArgument)
    

    可以把圖片轉換成base64格式信息,純字符的圖片表示法。
    其中:
    mimeType表示canvas導出來的base64圖片的類型,默認是png格式,也即是默認值是'image/png',我們也可以指定為jpg格式'image/jpeg'或者webp等格式。file對象中的file.type就是文件的mimeType類型,在轉換時候正好可以直接拿來用(如果有file對象)。
    qualityArgument表示導出的圖片質量,只要導出為jpg和webp格式的時候此參數才有效果,默認值是0.92,是一個比較合理的圖片質量輸出參數,通常情況下,我們無需再設定。

    • canvas.toBlob()方法
    canvas.toBlob(callback, mimeType, qualityArgument)
    

    可以把canvas轉換成Blob文件,通常用在文件上傳中,因為是二進制的,對后端更加友好。
    和toDataURL()方法相比,toBlob()方法是異步的,因此多了個callback參數,這個callback回調方法默認的第一個參數就是轉換好的blob文件信息,本文demo的文件上傳就是將canvas圖片轉換成二進制的blob文件,然后再ajax上傳的,代碼如下:

    //  canvas轉為blob并上傳
    canvas.toBlob(function (blob) {
      //  圖片ajax上傳
      var xhr = new XMLHttpRequest();
      //  開始上傳
      xhr.open("POST", 'upload.php', true);
      xhr.send(blob);    
    });
    
  11. beginPath 的重要性,從下面代碼開始

    var ctx = document.getElementById('cvs').getContext('2d');
    ctx.beginPath();
    ctx.moveTo(100.5,20.5);
    ctx.lineTo(200.5,20.5);
    ctx.stroke();
    ctx.moveTo(100.5,40.5);
    ctx.lineTo(200.5,40.5)
    ctx.strokeStyle = '#f00';
    ctx.stroke();
    

    其中的0.5是為了避免”1px線條模糊問題“,你懂的。那么上面的代碼會得到什么樣的圖形呢?是不是一條黑線一條紅線呢?
    從代碼上看,我們的邏輯毫無問題,但結果是我們得到的是兩條紅線,并不是一黑一紅。
    canvas中的繪制方法(如stroke,fill),都會以“上一次beginPath”之后的所有路徑為基礎進行繪制。比如上面的代碼里面我stroke了兩次,其實這兩次都是以第一次beginPath后的所有路徑為基礎畫的。也就是說第一條路徑我們stroke了兩下,第一下是黑的,第二下是紅的,所以最終也是紅的。

    • 不管你用moveTo把畫筆移動到哪里,只要不beginPath,那你一直都是在畫一條路徑。
    • fillRect與strokeRect這種直接畫出獨立區域的函數,也不會打斷當前的path.
      說到beginPath,就不得不提到closePath,兩者是不是有很“緊”的聯系呢?答案是幾乎沒有關系。

    closePath的意思不是結束路徑,而是關閉路徑,它會試圖從當前路徑的終點連一條路徑到起點,讓整個路徑閉合起來。但是,這并不意味著它之后的路徑就是新路徑了!
    我們在上面的代碼的第一個lineTo后面加上closePath,可以發現還是得到了兩條紅線。但如果我們在第一個stroke后面加上beginPath,則會如愿得到一條黑線一條紅線。

    
    ctx.stroke();
    ctx.beginPath(); // 注意啦!
    ctx.moveTo(100.5,40.5);
    ctx.lineTo(200.5,40.5)
    ctx.strokeStyle = '#f00';
    ctx.stroke();
    
    
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內容

  • 線條樣式 繪制直線,第五章知識簡單回顧 lineWidth 設置或返回當前的線條寬度,單位為像素 lineCap ...
    Zd_silent閱讀 485評論 0 0
  • 在Canvas中,線段也是路徑中的一種,被稱之為線性路徑。在Canvas中繪制線性路徑主要用到moveTo(x,y...
    王叮叮當當響閱讀 2,963評論 0 2
  • 第一章 HTML5 (2014年10月29日發布)新特性: 10個 (1)新的語義標簽 (2)增強型表單 (3)視...
    fastwe閱讀 970評論 0 1
  • 本書由 Designed and licensed by 同道大叔創作,講述了party1—7。主要講述了談戀愛的...
    冷月花魂_舞桐閱讀 689評論 2 1
  • 畢業論文之未能完成,一拖到今。欲為之,竟不能動筆,何也!余乃有思焉,明日當學兩種:調查報告之作法,其一也;規範之作...
    寒窗寄傲生閱讀 156評論 0 0