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對象的狀態(tài)以及對象的所有屬性抵代,并不包括這個對象上繪制的圖形腾节。官方文檔描述如下:

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

  2. 繪制矩形api

    • fillRect(x, y, width, height):繪制一個填充的矩形
    • strokeRect(x, y, width, height):繪制一個矩形的邊框
    • clearRect(x, y, width, height):清除指定矩形區(qū)域康吵,讓清除部分完全透明.經常用來清除干凈畫布劈榨,`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()方法將剪切區(qū)域設置為當前剪切區(qū)域與當前路徑的交集扮念。在第一次調用clip()方法之前垒在,剪切區(qū)域與整個Canvas畫布大小一致。因為clip()方法會將剪切區(qū)域設置為當前剪切區(qū)域與當前路徑的交集扔亥,所以對該方法的調用一般都是嵌入save()和restore()方法之間的场躯。否則,剪切區(qū)域將會越變越小旅挤,這通常不是我們想要的效果踢关。

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

    • createImageData() 方法創(chuàng)建新的空白 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. 以指定的尺寸(以像素計)創(chuàng)建新的 ImageData 對象:
      var imgData=ctx.createImageData(width,height);
      // 2. 創(chuàng)建與指定的另一個 ImageData 對象尺寸相同的新 ImageData 對象(不會復制圖像數據):
      var imgData=ctx.createImageData(imageData);
      
    • getImageData() 方法返回 ImageData 對象捶牢,該對象拷貝了畫布指定矩形的像素數據鸠珠。

      // x    開始復制的左上角位置的 x 坐標。相對與canvas
      // y    開始復制的左上角位置的 y 坐標秋麸。
      // width    將要復制的矩形區(qū)域的寬度渐排。
      // height 將要復制的矩形區(qū)域的高度。
      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  規(guī)定要放回畫布的 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  規(guī)定要使用的圖像搂捧、畫布或視頻驮俗。
    // 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這種直接畫出獨立區(qū)域的函數,也不會打斷當前的path.
      說到beginPath卧秘,就不得不提到closePath呢袱,兩者是不是有很“緊”的聯(lián)系呢?答案是幾乎沒有關系翅敌。

    closePath的意思不是結束路徑羞福,而是關閉路徑,它會試圖從當前路徑的終點連一條路徑到起點蚯涮,讓整個路徑閉合起來治专。但是卖陵,這并不意味著它之后的路徑就是新路徑了!
    我們在上面的代碼的第一個lineTo后面加上closePath张峰,可以發(fā)現還是得到了兩條紅線泪蔫。但如果我們在第一個stroke后面加上beginPath,則會如愿得到一條黑線一條紅線喘批。

    
    ctx.stroke();
    ctx.beginPath(); // 注意啦撩荣!
    ctx.moveTo(100.5,40.5);
    ctx.lineTo(200.5,40.5)
    ctx.strokeStyle = '#f00';
    ctx.stroke();
    
    
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市饶深,隨后出現的幾起案子餐曹,更是在濱河造成了極大的恐慌,老刑警劉巖敌厘,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件台猴,死亡現場離奇詭異,居然都是意外死亡额湘,警方通過查閱死者的電腦和手機卿吐,發(fā)現死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門旁舰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锋华,“玉大人,你說我怎么就攤上這事箭窜√夯溃” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵磺樱,是天一觀的道長纳猫。 經常有香客問我,道長竹捉,這世上最難降的妖魔是什么芜辕? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮块差,結果婚禮上侵续,老公的妹妹穿的比我還像新娘。我一直安慰自己憨闰,他們只是感情好状蜗,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鹉动,像睡著了一般轧坎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上泽示,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天缸血,我揣著相機與錄音蜜氨,去河邊找鬼。 笑死捎泻,一個胖子當著我的面吹牛记劝,可吹牛的內容都是我干的。 我是一名探鬼主播族扰,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼厌丑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了渔呵?” 一聲冷哼從身側響起怒竿,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎扩氢,沒想到半個月后耕驰,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡录豺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年朦肘,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片双饥。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡媒抠,死狀恐怖,靈堂內的尸體忽然破棺而出咏花,到底是詐尸還是另有隱情趴生,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布昏翰,位于F島的核電站苍匆,受9級特大地震影響,放射性物質發(fā)生泄漏棚菊。R本人自食惡果不足惜浸踩,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望统求。 院中可真熱鬧检碗,春花似錦、人聲如沸球订。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冒滩。三九已至微驶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背因苹。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工苟耻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人扶檐。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓凶杖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親款筑。 傳聞我的和親對象是個殘疾皇子智蝠,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內容

  • 線條樣式 繪制直線,第五章知識簡單回顧 lineWidth 設置或返回當前的線條寬度奈梳,單位為像素 lineCap ...
    Zd_silent閱讀 476評論 0 0
  • 神奇且強大的canvas 一.Canvas的基本介紹 1.什么是Canvas 定義:是HTML5提供的一種新標簽,...
    Ainy塵世繁花終凋落閱讀 10,746評論 1 18
  • 在Canvas中杈湾,線段也是路徑中的一種,被稱之為線性路徑攘须。在Canvas中繪制線性路徑主要用到moveTo(x,y...
    王叮叮當當響閱讀 2,910評論 0 2
  • 第一章 HTML5 (2014年10月29日發(fā)布)新特性: 10個 (1)新的語義標簽 (2)增強型表單 (3)視...
    fastwe閱讀 953評論 0 1
  • 本書由 Designed and licensed by 同道大叔創(chuàng)作于宙,講述了party1—7浮驳。主要講述了談戀愛的...
    冷月花魂_舞桐閱讀 679評論 2 1