canvas 基礎

本文基本上能夠用來當作 canvas 的一個基本參考。基本涵蓋了全部的 canvas 內容,固然,不包括使用 canvas 來處理的高級應用。css

基本的有:css3

畫線

基本的架構爲:web

ctx.beginPath(); // 開始畫線,裏面沒有任何參數
ctx.moveTo(x,y); // 定義起始點
ctx.lineTo(x,y); // 定義過程點
// 還能夠定義線寬,線的顏色
ctx.stroke();  // 開始劃線,裏面沒任何參數

line

// 簡單就是 
ctx.moveTo(x,y)
ctx.lineTo(x,y)

lineWidth

控制線寬算法

ctx.lineWidth = 20; // 單位默認爲 px

lineColor

線顏色定義可使用:chrome

ctx.strokeStyle = "#fff";

lineCap

定義線兩端的格式爲:canvas

context.lineCap = 'butt';

該屬性有 3 個取值:butt,round,square。分別爲:數組

lineCap

lineJoin

用來描述,多個路徑之間的鏈接方式。基本取值有:round,bevel,miter。瀏覽器

context.beginPath();
      context.moveTo(379, 150);
      context.lineTo(429, 50);
      context.lineTo(479, 150);
      context.lineJoin = 'bevel';
      context.stroke();

詳情爲:架構

lineJoin

曲線

曲線和線段
基本區現有: 弧線,二次曲線,貝塞爾曲線。ide

arcTo

基本格式爲:

ctx.arcTo(cx1, cy1, x2, y2, radius);

一樣,使用 moveTo 或者 lineTo 肯定第一個起始點。

context.beginPath();
    context.moveTo(100, 225);             // P0
    context.arcTo(228, 40, 530, 70, 89); // P1, P2 and the radius
    context.lineTo(530, 70);             // P2 
    context.stroke();

上面,P2 點用到了 lineTo。 這有什麼影響嗎?有的。
若是沒定義 lineTo,圓弧可能並不會過到 P2 點,由於圓弧實際的算法爲:

arcTo

它只會肯定最終圓弧的範圍的大小,並不會關注 P2 點是否鏈接。若是沒定義 lineTo 的話,結果爲:

no_lineTo

Quadratic Curve

該是用來畫二次曲線的:

ctx.quadraticCurveTo(cpx, cpy, x, y);

他一般結合 moveTo 來找到 3 個點,肯定二次函數。

ctx.beginPath();
ctx.moveTo(50,20);  // x 軸上的點 (50,20)
ctx.quadraticCurveTo(230, 30, 50, 100); // 控制點爲 (230,30)。
// 另外 x 軸上的點爲 (50,100)
ctx.stroke();

屏幕快照 2016-10-12 20.16.31.png-10.2kB

bezier Curve

該 tag 是用來畫貝塞爾曲線的,即經過定義 4 個點,便可肯定,線的形狀,具體格式爲:

// 這裏定義了兩個控制點,一個基準點
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);

上面說到 4 個點,還有一個點是經過 moveTo 來定義的。基本格式爲:

ctx.beginPath();
ctx.moveTo(50,20);
ctx.bezierCurveTo(230, 30, 150, 60, 50, 100);
ctx.stroke();

如圖:

bezier

實際計算方法是取中點,而後取過中點的切線。

bezier

圖形

基本的簡單圖形有:,圓,橢圓,自定義圖形.
圖形方面一般是結合,ctx.fill() 來進行觸發渲染的操做。

rect()

該API 用來在 canvas 上畫一個。

// 基本格式爲
ctx.rect(x, y, width, height);
ctx.fill();

// 或者使用二者的結合屬性
ctx.fillRect(x, y, width, height);

看 API 應該很容易就知道,這個是用來幹啥的了。
rect 默認顏色是 black。固然,你也能夠經過使用 fillStyle 來顯示的改變顏色。

ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 100);

矩形框

上面那種形式,是用來畫圖形內容,接着,咱們可使用 strokeRect() 來畫一個矩形邊框使用。
基本格式爲:

ctx.strokeRect(x, y, width, height);

實際畫法。

ctx.strokeStyle = "green";
ctx.strokeRect(10, 10, 100, 100);

這裏,直接使用 stroke 便可,不須要在顯示觸發渲染啥的了。畫邊框,固然可使用 line 相關的屬性,好比,定義線寬。

ctx.lineWidth = 5;

實際上,結合 rect 也能夠來畫一個矩形框:

context.beginPath();
      context.rect(188, 50, 200, 100);
      context.fillStyle = 'yellow';
      context.fill();
      context.lineWidth = 7;
      context.strokeStyle = 'black';
      context.stroke();  // 觸發畫邊框的效果

arc

基本格式爲:

// 默認爲逆時針
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

startAngle 是從 x 軸正方向,順時針計算角度。
詳細demo:

ctx.arc(75, 75, 50, 0, 2 * Math.PI);

// 順時針畫圓
ctx.arc(75, 75, 50, 0, 2 * Math.PI,false);

好比,另外畫一個半圓。

context.beginPath();
      context.arc(288, 75, 70, 0, Math.PI, false);
      context.closePath();  // 封閉圖形
      context.lineWidth = 5;
      context.fillStyle = 'red';
      context.fill();
      context.strokeStyle = '#550000';
      context.stroke();

ellipse*

這個 API 是最近提出來的,比較新。因此,兼容性須要考慮。基本格式爲:

// x,y 肯定長軸,短軸的位置
// rotation 按照 x 軸正方向,按照 anticlockwise 的設置進行旋轉,也是弧度制
// startAngle,endAngle 也是按照 x 軸正方向來的
ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise);

他的角度表示都是 弧度制(radians)。
看個實例:

ctx.beginPath();
ctx.ellipse(100, 100, 50, 75, 45 * Math.PI/180, 0, 2 * Math.PI);
ctx.stroke();

圖爲:

image_1auueo1qd1ott1hsmiau1npa1kh89.png-4.1kB

固然,你也可使用 fill 等,來填充相關顏色。

自定義圖形

若是你想畫一個自定義圖形的話,須要結合 line 相關的標籤。最後使用 closePath() 來顯示封閉圖形。
closePath API 的實際做用是: 當你當前的點已經和起始點重合,那麼 do nothing。不然,將當前點和起始點用直線鏈接起來,構成封閉圖形,這樣纔可能使用 fill 相關來進行填充。

var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');

      // begin custom shape
      context.beginPath();
      context.moveTo(170, 80);
      context.bezierCurveTo(130, 100, 130, 150, 230, 150);
      context.bezierCurveTo(250, 180, 320, 180, 340, 150);
      context.bezierCurveTo(420, 150, 420, 120, 390, 100);
      context.bezierCurveTo(430, 40, 370, 30, 340, 50);
      context.bezierCurveTo(320, 5, 250, 20, 250, 50);
      context.bezierCurveTo(200, 5, 150, 20, 170, 80);

      // complete custom shape
      context.closePath();
      context.lineWidth = 5;
      context.strokeStyle = 'blue';
      context.stroke();

最後必定要記得使用 closePath() 這樣,才能達到完整圖形的效果。

填充

關於填充有:基本顏色填充,漸變填充,圖片填充。基本的顏色填充會涉及到兩個,一個是 fillStyle,還有一個是 strokeStyle。兩個的基本形似是如出一轍的:

// 填充基本顏色值,好比 #fff
ctx.fillStyle = color;
// 填充漸變值,好比 createLinear 建立的漸變等
ctx.fillStyle = gradient;
// 一般用來貼圖用的值
ctx.fillStyle = pattern;

顏色填充

這個就不過說了,就是填 RGB 值。

ctx.fillStyle = "blue";

漸變色填充

漸變色有兩種,一個是線性漸變:createLinearGradient(),一個是中心漸變:createRadialGradient()。 他們可使用一個共同的 API : addColorStop()。來設置間隔色。基本格式爲:

addColorStop(offset, color);
  • offset: 爲 [0,1] 之間的數

  • color: rgb 的值

var gradient = ctx.createLinearGradient(0,0,200,0);
gradient.addColorStop(0,"green");
gradient.addColorStop(1,"white");
ctx.fillStyle = gradient;
ctx.fillRect(10,10,200,100);

createLinearGradient()

線性漸變的內容是:

ctx.createLinearGradient(x0, y0, x1, y1);

兩個點肯定一條直線,而後將顏色按照這個線段進行漸變。

實例:

image_1auuik89a9ba1kj8tq21eurvcm.png-12.3kB

代碼爲:

gradient.addColorStop(0,'red');
gradient.addColorStop(1,'black');
ctx.fillStyle=gradient;
ctx.fillRect(0,0,320,320);

createRadialGradient()

中心漸變內容爲:

ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);

以及上就是兩個圓,而後按照順序,將顏色漸變,固然中間也能夠添加多段。

實例:

canvas-radial

代碼爲:

let gradient = ctx.createRadialGradient(200,200,0,200,200,160);
        gradient.addColorStop(0,'red');
        gradient.addColorStop(1,'white');
        ctx.fillStyle=gradient;
        ctx.arc(200,200,160,0,2*Math.PI);
        ctx.fill();

pattern - 貼圖

這一塊應該算是 canvas 牛逼的地方,可以和圖形相關的元素結合起來的關鍵點。格式爲:

ctx.createPattern(image, repetition);
  • image: 該類型的取值有不少,好比 image,video,cavnas,imageData,blob 等。

    • HTMLImageElement (< img>)

    • HTMLVideoElement (< video>)

    • HTMLCanvasElement (< canvas>)

    • CanvasRenderingContext2D

    • ImageBitmap

    • ImageData

    • Blob

  • repetition:該取值內容就很簡單,至關於 background 同樣,用來設置圖片的重複形式。

    • repeat (默認值)

    • repeat-x

    • repeat-y

    • no-repeat

這裏就舉一個貼圖的列子:

// FROM MDN
var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
img.onload = function() {
  var pattern = ctx.createPattern(img, 'repeat');
  ctx.fillStyle = pattern;
  ctx.fillRect(0,0,400,400);
};

圖片處理

圖片處理相關的 API 有不少,這裏先說最基本的,drawImage()。它有 3 種基本形式:

void ctx.drawImage(image, dx, dy);
void ctx.drawImage(image, dx, dy, dWidth, dHeight);
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

分別說一下:

簡單繪製

void ctx.drawImage(image, dx, dy);

簡單的 3 個參數,就用來肯定圖片在 canvas 上的位置,不進行任何縮放。

simple_draw

縮放繪製

基本格式爲:

void ctx.drawImage(image, dx, dy, dWidth, dHeight);

經過, dWidth 和 dHeight 來肯定在 canvas 中繪製的大小,能夠放大和縮小。

scale_image

代碼爲:

let img = new Image();
img.onload = function(){
        ctx.drawImage(img,20,20,150,100);
}
img.src = "...";

裁剪繪製

基本格式爲:

void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

其中,sx,sy,sWidth,sHeight 用來肯定在原來圖片上,截取圖像的區域。

sheight

具體代碼爲:

let img = new Image();
img.onload = function(){
        ctx.drawImage(img,20,20,60,95,60,60,100,200);
}
img.src = "...";

字體處理

在 canvas 裏,還有顯示文字的一個 trick 。文字方面的話,沒什麼特別的就是基本的 style, szie ,color 等。 通常結合 fillText/stokeText API 一塊兒使用,進行繪製。這裏兩個 API 的區別也很普通,就是簡單的 填充實心字體 和 邊界字體。

context.font = 'italic 40pt Calibri';
context.fillText('Hello World!', 150, 100);

先簡單說一下,這兩個 API。他們的格式,基本上是同樣的:

ctx.strokeText(text, x, y [, maxWidth]);
  • x,y 用來肯定 text 的左下角起始點。很重要,是左下角!

  • maxWidth: 用來肯定 text 渲染的寬度,若是字體大了,則會自動縮小,不會換行。

strokeText

代碼爲:

ctx.font="20px serif";
ctx.strokeText("I dont Know how to Do",20,20,200);

字體-font

定義一個最簡單的字體,使用的是:

ctx.font=value;

value 的值,就是通常的 css font 屬性的值。默認爲: 10px sans-serif

ctx.font = "48px serif";

這裏,還可使用比較新的 API FontFace() 來使用在線字體:

var f = new FontFace("font-name", "url(x)");
  f.load().then(function() {
    ctx.font="20px font-name";
    ctx.fillText("ABC",100,100);
});

字體顏色

字體的顏色相關和上面圖形同樣,一樣使用的是 fillStylestrokeStyle 這裏就不贅述了。

字體邊框粗細

定義粗細的話,一樣使用 lineWidth 便可。

字體的排列

基本格式爲:

// 默認爲 start
ctx.textAlign = "left" || "right" || "center" || "start" || "end";

這裏,並非用來定義字體在 canvas 中的排列位置,而是用來定義,基準點相對於字體的位置。
經常使用的就是居中佈局:

text_align

代碼爲:

ctx.font="20px serif";
ctx.textAlign='center';
ctx.strokeText("I dont Know how to Do",200,200);

其他的取值,好比 left,right 都是相對於該點進行繪製的。
好比,取 right/end:

right

基線位置

基本格式爲:

// 默認值爲: ideographic
ctx.textBaseline = "top" || "hanging" || "middle" || "alphabetic" || "ideographic" || "bottom";

該屬性和 baseline 差很少,是用來肯定基線在字體的哪個位置。 在定位的時候,線是不動的,動的是字。
詳情參考:

baseline

測量字體

若是想知道當前字體的寬度,可使用 measureText API 來完成。基本使用也很簡單:

var text = ctx.measureText("foo"); // TextMetrics object
text.width; // 16;

固然,這個屬性返回的對象上面,還掛載了不少其餘測量值,不過兼容性比較差。關鍵點在於,能夠結合該 API 來畫出分行的字體內容。簡單的說來就是經過將字符串拆分,判斷渲染字符串是否超過本行的寬度,進而決定是否將標識點 y 軸值加 lineheight。
簡單看個算法:

function wrapText(context, text, x, y, maxWidth, lineHeight) {
        // 經過使用 ' ' 進行字符的拆分 (這裏就不針對中文了)
        var words = text.split(' ');
        var line = '';

        for(var n = 0; n < words.length; n++) {
         // 判斷行
          var testLine = line + words[n] + ' ';
          // 測量渲染的寬度
          var metrics = context.measureText(testLine);
          var testWidth = metrics.width;
          if (testWidth > maxWidth && n > 0) {
           // 超過,則下一該行
            context.fillText(line, x, y);
            line = words[n] + ' ';
            y += lineHeight;
          }
          else {
            line = testLine;
          }
        }
        context.fillText(line, x, y);
      }
      
      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
      var maxWidth = 400;
      var lineHeight = 25;
      var x = (canvas.width - maxWidth) / 2;
      var y = 60;
      var text = 'All the world \'s a stage, and all the men and women merely players. They have their exits and their entrances; And one man in his time plays many parts.';

      context.font = '16pt Calibri';
      context.fillStyle = '#333';

      wrapText(context, text, x, y, maxWidth, lineHeight);

canvas 中的變換

關於變化,最基本的就是 translate, scale,skew 等。在 canvas 中,這些就是針對於 canvas 座標系來的。

translate

這是用來進行原點平移的變化。基本格式爲:

ctx.translate(x, y);
  • x: 當前座標系在 x 軸向的移動方向

  • y:當前座標在 y 軸向的移動方向

固然,還有對應的 2D 變換矩陣,這和 transform 屬性同樣。可使用下列的變換:

ctx.setTransform(1, 0, 0, 1, x, y);

rotate

這是用來旋轉座標系的。基本格式爲:

// 裏面的參數是弧度,可使用 Math.PI 來進行轉換
ctx.rotate(angle);

例如:

ctx.rotate(45 * Math.PI / 180);
ctx.fillRect(70,0,100,30);

當在旋轉時,在矩陣中是根據 sin 函數來表示的旋轉角度的值。

ctx.setTransform(cosθ,sinθ,-sinθ,cosθ,0,0) // 就是 cs-sc

scale

縮放座標系,基本格式爲:

ctx.scale(x, y);

它表達的意思是:

  • x: 將 x 軸放大/縮小 x 倍。即,設置的像素值會乘以該 x 值.

  • y: 將 y 軸放大/縮小 y 倍。即,設置的像素值會乘以該 y 值.

看個 demo:

ctx.scale(10, 3);
ctx.fillRect(10,10,10,10);
// 最後的結果就是,在 (100,30) 點,畫出 width: 100,height: 30 的矩形。

另外,你還能夠利用這個屬性做顛倒:

ctx.scale(-1, 1); // x 軸對稱
ctx.font = "48px serif";
ctx.fillText("Hello world!", -320, 120); // x 軸的值須要設爲負數
ctx.setTransform(1, 0, 0, 1, 0, 0); // 還原座標

它對應於矩陣的表達就是:

setTransform(A, 0, 0, B, 0,0);
// X 軸放大 A 倍
// Y 軸放大 B 倍

矩陣變換

矩陣變換的 API 和 css3 動畫中的沒啥區別:

ctx.setTransform(a, b, c, d, e, f);

最常使用的是用來進行座標還原。由於,它每一次變換都是覆蓋掉上一次變化,因此,還原座標常使用:

ctx.setTransform(1,0,0,1,0,0);

不過,除了這個方法外,其餘變換都是基於已經變化後的座標來變換的。

transform

該 API 和 setTransform 有些不一樣。setTransform 至關於重置,而 transform 會基於前一個變換結果,接着進行變換。它的使用方式和 setTransform 差很少。

ctx.transform(a, b, c, d, e, f);

resetTransform

至關於就是 setTransform(1,0,0,1,0,0)的封裝。

ctx.resetTransform();

state stack

在 canvas 裏面,由於有時候操做比較多,可能會形成來回變換座標。這時候,就可使用 canvas 裏面的狀態管理。save & restore,這兩個方法至關於 stack 的 push & pop 方法。一個入棧,一個出棧。那麼,這些狀態會保存什麼呢?

  • 變形操做,基本的移動,縮放,旋轉,矩陣變換等。

  • 裁剪區域

  • dash list

  • 以及相關的筆觸,填充狀態。好比: strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin。

不過,它僅僅只是做爲一個狀態進行保存的。當結合 restore 一塊兒,纔會發揮它應該有的效果。

ctx.save();
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 100);
ctx.restore();
// 恢復原始的 fillStyle 內容
ctx.fillRect(150, 75, 100, 100);

composite

在 canvas 中的層合併,涉及到陰影,裁剪等效果。

陰影特效

關於 canvas 中的陰影涉及到 4 個API。

  • shadowBlur

  • shadowColor

  • shadowOffsetX

  • shadowOffsetY

分別介紹一下:

shadowBlur

這是用來添加陰影的,基本格式爲:

ctx.shadowBlur = level;

level 的值默認爲 0,表示不存在陰影。而且,不能取 Negative, Infinity or NaN。level 表示的意義只在於,規定陰影模糊的範圍而已。須要注意,一旦你設置了 shadoeBlur,那麼接下來,在 canvas 上畫的全部元素,都會帶上陰影的效果,即便是透明元素。因此,通常狀況下能夠手動回撤:

ctx.shadowBlur = 0;

或者,結合 save 和 restore 來進行狀態回撤。

ctx.save();
ctx.shadowBlur = 5;
ctx.fillRect(0,0,400,400);
ctx.restore();

shadowColor

用來設置陰影的顏色值,默認是不透明的黑色。

blurColor

基本格式爲:

// color 默認爲 「black」
ctx.shadowColor = color;

shadowOffsetX/Y

這個實際上和 box-shadow 設置的陰影效果是同樣的,用來定義陰影相對於原始圖形的偏移量。基本格式爲:

// offset 默認值爲 0,至關於取 canvas 上的像素值
// 能夠爲負值,但不能取 Infinity or NaN
ctx.shadowOffsetX = offset;

實例爲:

// 在 x 軸上移動陰影
ctx.shadowOffsetX = 10;
// 在 Y 軸上移動陰影
ctx.shadowOffsetY = 10;

透明度

在 canvas 裏面,定義顏色通常只支持 RGB 的格式,若是想要設置透明顏色的話,則須要使用 globalAlpha 屬性值。基本格式爲:

// value 爲 [0.0,1.0] 
// 默認值爲 0.0,表示不透明
ctx.globalAlpha = value;

看個 demo:

ctx.globalAlpha = 0.5;

ctx.fillStyle = "blue";
ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = "red";
ctx.fillRect(50, 50, 100, 100);

globalAlpha

裁剪效果

在 canvas 裏面,通常使用的是 clip API 來進行對屏幕的裁剪。基本格式爲:

// 最經常使用
void ctx.clip();
// fillRule 主要有兩種,下面再解釋
void ctx.clip(fillRule);
// 這裏就是將須要畫的路徑,當參數傳到 clip 裏
void ctx.clip(path, fillRule);

fillRule

先解釋一下 fillRule:
經常使用的 fillRule 有兩種,一種是 nonzero,一種是 even-odd 。主要做用就是用來判斷重疊區域是否屬於裁剪區域。ok,什麼叫重疊區域呢?就是:

fillRule

這種狀況下,canvas 怎麼判斷這樣的區域是否重疊呢?
默認的算法是 nonzero。

nonzero

P

它具體的過程是,在重疊區域中,選擇一個 P 點,而後隨機的按照一個方向,作無限長的射線,檢測該線和邊界的交叉點,判斷接觸位置是 順時針仍是逆時針。若是爲順時針則 -1,若是爲逆時針則 +1。統計最終的結果,若是爲 0 則說明,該區域在外部,不然在內部。
因此,上面的結果是 -2,不是 0,則表示在內部。

even-odd rule

even-odd

該算法主要約定的是,統計射線和邊界相交的次數,若是爲偶數,則表示不在內部,若是爲奇數,則表示在內部。

因此,根據該算法,上面的結果爲 2 (偶數),則不在內部。

不過,在大多數狀況下,這你都不須要過多關心。接下來,咱們來實踐一下,如何繪製裁剪區域。這裏,咱們就能夠將 clip 方法想象爲 stroke 方法。在 clip 前,先手動繪製路徑,繪製完成後,即可以觸發 clip 進行裁剪就 ok 了。

ctx.beginPath();
ctx.ellipse(100,100,30,50,0,0,2*Math.PI);
ctx.clip();
ctx.fillRect(100,100,30,50);

實際樣式爲:

clip_area

圖層重疊的效果

圖層重疊用到的 API 爲: globalCompositeOperation。它的做用主要是用來規定,兩個重疊圖層繪製的效果。基本格式爲:

globalCompositeOperation = type

基本的取值,能夠參考: globalCompositeOperation - 取值內容

canvas 的圖像處理

canvas 中的圖像處理內容很少,基本上有 3 個API:createImageData(),putImageData(),getImageData()。第一個就是用來截屏用的,第二/三個就是用來獲取圖片的基本信息,在關於 image 有個比較重要的概念就是 imagedata。

  • imageData:實際上就是完整的圖片內容。它是底層像素的上層表示,其掛載了 3 個屬性。

    • width: 圖片的寬

    • height:圖片的高

    • data: 是 Uint8ClampedArray 格式,實際上一個一維數組,按順序,每一個像素點佔 4 位,裏面包含了 RGBA 的內容,每一位都是 0-255 大小的數。最後透明度有點特殊,取值爲 [0-255] 表示不透明。若是須要用到 css 的 rgba 中,須要 /255。例如: [0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255] ,4個點。

  • 最常獲取到 imagedata 就是經過 createImageData。注意,經過 image 是不能獲取 imagedata 的,imagedata 只能經過 createImageData 來獲取和建立。

ctx.rect(10, 10, 100, 100);
ctx.fill();

let imagedata = ctx.createImageData(100, 100);

createImageData

用來手動建立一個空圖片內容,默認的像素都是透明的黑色,基本格式爲:

ImageData ctx.createImageData(width, height);
ImageData ctx.createImageData(imagedata);
  • width/height:用來設置當前 imgObj 的大小。

  • imagedata:得到一個已知 imgObj 的大小,注意這裏不是複製,只是 copy imagedata 的 width/height。

目前來講,它的用途,還不知道在哪裏~

getImageData

該 API 經常用來做爲圖片分析,由於它能夠直接獲取 canvas 上像素的內容,而後進行相關操做。基本格式爲:

ctx.getImageData(x, y, width, height);
  • x,y 用來指定截取像素的起始點

  • widht/height 用來指定截取像素點的寬/高

例如:

ctx.fillRect(0,0,200,200);
let new_one = ctx.getImageData(0,0,2,2);

該屬性最大的用處在於,用來做爲取色器。經過,傳入 canvas 裏的座標,來獲取指定位置的顏色值。

ctx.fillRect(0,0,200,200);
let new_one = ctx.getImageData(0,0,1,1);
let backColor = function(data){
       return `(${data[0]},${data[1]},${data[2]},${data[3]/255})`;
}

putImageData

該屬性經常用來做爲,像素的填寫。基本格式爲:

void ctx.putImageData(imagedata, dx, dy);
void ctx.putImageData(imagedata, dx, dy, startX, startY, width, height);

主要所一下第二種形式吧:

  • dx/y 表明在 canvas 上繪製的繪製

  • startX/Y 表示相對於圖片其實的位置

  • width/height 表示獲取的寬/高

具體的含義爲:

ctx.fillRect(0,0,100,100);
var imagedata = ctx.getImageData(0,0,100,100); // 獲取部分圖像信息
ctx.putImageData(imagedata, 150, 0, 20, 20, 25, 25);
ctx.strokeRect(150,0,100,100);

putImageData API 詳解

該經常用來做爲放大預覽,灰度處理,導出圖片等。詳情能夠參考: 圖片像素處理。總而言之,putImageData 常做爲處理圖片自己,而 drawImage 經常使用於建立另一新的 canvas。

生成 URI

這應該算一種快速生成圖片格式的方法吧。該是經過算法,將圖像中的像素點轉化爲序列值(也就是文本),咱們能夠直接將文本放入 img.src 中,便可顯示圖片。
在 canvas 中生成 URI 須要使用:

canvas.toDataURL(type, encoderOptions);

該 API 是直接掛在到 canvas 下的。

  • type: 用來設置導出圖片類型,默認爲:image/png。可選值有:image/jpeg,image/webp(chrome支持)。

  • encoderOptions[Number]:用來設置壓縮比。只針對於 image/jpeg or webp 有用。一般取值爲 0-1。默認值爲 0.92。

DataURI 的基本格式爲:

data:[<mediatype>][;base64],<data>
// 例如:
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ9oADAMBAAIRAxEAPwD/AD/6AP/Z

生成的 DataURI 是根據 canvas 的大小來肯定的。

var canvas = document.getElementById("canvas"); // canvas size: 5x5
var dataURL = canvas.toDataURL(); // 生成的大小爲 5x5

不過並非,任何圖片都能生成 DataURI 的,有些瀏覽器因爲內存的限制,對 DataURI 的長度也會有所限制。例如:Opera 限制爲 65000 characters。

Canvas Animation

使用 Canvas 來作動畫,咱們須要瞭解幕布的蓋簾--擦除,繪製。基本的 API 有: clearRect, requestAnimation

clearRect

該 API 用來清空一塊幕布,基本格式爲:

ctx.clearRect(x, y, width, height);

用來清除指定區域的內容。

  • x,y:用來指定區域的起始位置

  • width,height:指定區域的寬高

通常來講,一般是用來清除整個 canvas 內容。

ctx.clearRect(0, 0, canvas.width, canvas.height);

使用 requestAnimationFrame

主要仍是依靠循環調用 RAF,來實現流暢動畫。看一個 demo

地球_canvas

var sun = new Image();
var moon = new Image();
var earth = new Image();
function init(){
  // online
 earth.src = 'https://mdn.mozillademos.org/files/1429/Canvas_earth.png';
  sun.src = 'https://mdn.mozillademos.org/files/1456/Canvas_sun.png';
  moon.src = 'https://mdn.mozillademos.org/files/1443/Canvas_moon.png';

  // local
  earth.src = 'Canvas_earth.png';
  sun.src='Canvas_sun.png';
  window.requestAnimationFrame(draw);
}


function draw(){
  let canvas = document.getElementsByTagName('canvas')[0],
      ctx = canvas.getContext('2d'),
      width = canvas.width,
      height = canvas.height;
    // ctx.globalCompositeOperation = 'destination-over';
    ctx.clearRect(0,0,width,height);
    ctx.drawImage(sun,0,0,width,height);
    ctx.fillStyle= 'rgba(0,0,0,0.4)';
    ctx.strokeStyle = 'rgba(0,50,50,0.5)';
    ctx.arc(width/2,height/2,width/3,0,2*Math.PI);
  
  
    ctx.stroke();
    // ctx.fill();
  
    ctx.save();
    //earth
    let date = new Date();

    ctx.translate(width/2,height/2);
    // 公轉
    ctx.rotate ((2*Math.PI)*1*(date.getSeconds()/60 + date.getMilliseconds()/60000) );
    ctx.translate(width/3,0);
    // 自轉
    ctx.rotate ((2*Math.PI)*25*(date.getSeconds()/60 + date.getMilliseconds()/60000) );
    ctx.drawImage(earth,-earth.width/2,-earth.height/2);
    ctx.save();
    ctx.translate(20,0);
    ctx.drawImage(moon,-moon.width/2,-moon.height/2);

    ctx.restore();
    ctx.restore();
    window.requestAnimationFrame(draw);
}
init();
相關文章
相關標籤/搜索