JS學(xué)習(xí)14(Canvas)

canvas由Apple公司推出,現(xiàn)在大部分瀏覽器支持繪制2D圖形,3D圖形的繪制使用WebGL的3D上下文。

基本用法

首先最重要的就是要給canvas畫布一個寬高。
要在畫布上繪圖需要取得繪圖上下文,使用getContext()方法并傳入上下文的名字。
在使用canvas元素之前首先要檢測getContext()方法是否存在以確定瀏覽器是否支持canvas。這個是最準(zhǔn)確的方法

var drawing = document.getElementById("drawing");
if (drawing.getContext){
    var context = drawing.getContext("2d"); 
}

使用toDataURL()可以導(dǎo)出canvas元素上繪制的圖像,接受一個MIME類型格式。

if (drawing.getContext){
    var imgURI = drawing.toDataURL("image/png");
    var image = document.createElement("img");
    image.src = imgURI;
    document.body.appendChild(image);
}

如果繪制到畫布上的圖像源自不同的域,這個方法會拋出錯誤。

2D上下文

2D上下文的坐標(biāo)開始于左上角(0,0),所有坐標(biāo)值都基于這個原點計算。

填充和描邊

2D上下文的兩種基本繪圖操作是填充和描邊,而操作結(jié)果取決于兩個屬性:fillStyle和strokeStyle。這兩個屬性的值可以是字符串,漸變對象或模式對象。

context.strokeStyle = "red";
context.fillStyle = "#0000ff";

接下來所有的描邊和填充都會使用這兩個值直到重新設(shè)置這兩個值。

繪制矩形

矩形是唯一一種可以直接設(shè)置的形狀,有3個方法

  • fillRect()繪制并填充
  • strokeRect()只畫個邊
  • clearRect()清除矩形區(qū)域,本質(zhì)上是吧一塊變透明

參數(shù)為x,y,width,height

var context = drawing.getContext("2d");
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
context.fillStyle = "rgba(0,0,255,0.5)";
context.fillRect(30, 30, 50, 50);
context.strokeStyle = "#ff0000";
context.strokeRect(100, 10, 50, 50);
context.strokeStyle = "rgba(0,0,255,0.5)";
context.strokeRect(120, 30, 50, 50);
context.clearRect(40, 40, 10, 10);

線條寬度由lineWidth控制
lineCap可以控制線條末端是平頭,圓頭,還是方頭(butt、round、square)
通過lineJoin屬性可以控制線條相交的方式是圓交,斜交還是斜接(round、bevel、miter)

繪制路徑

首先調(diào)用beginPath()方法,表示要開始繪制新的路徑。然后調(diào)用下面的方法來繪制實際的路徑:

  • arc(x, y, radius, startAngle, endAngle, counterclockwise):以(x,y)為圓心繪制一條弧線,弧線半徑為radius,起始角度和結(jié)束角度為startAngle,endAngle(以弧度表示)。counterclockwise為false表示按順時針
  • arcTo(x1, y1, x2, y2, radius):arcTo()方法將利用當(dāng)前端點、端點1(x1,y1)和端點2(x2,y2)這三個點所形成的夾角,繪制一段與夾角的兩邊相切并且半徑為radius的圓上弧線。弧線的起點就是當(dāng)前端點所在邊與圓的切點,弧線的終點就是端點2(x2,y2)所在邊與圓的切點,并且繪制的弧線是兩個切點之間長度最短的那個圓弧。此外,如果當(dāng)前端點不是弧線起點,arcTo()方法還將添加一條當(dāng)前端點到弧線起點的直線線段。
  • bezierCurveTo(c1x, c1y, c2x, c2y, x, y):從上一點開始繪制一條曲線,到(x,y)為止,并以(c1x,c1y),(c2x,c2y)為控制點。
  • lineTo(x, y):從上一點開始繪制一條直線,到(x,y)
  • moveTo(x, y):將繪制畫筆移動到(x,y),不畫線
  • quadraticCurveTo(cx, cy, x, y):從上一點開始繪制一條二次曲線,到(x,y)為止,并以(cx,cy)為控制點
  • rect(x, y, width, height):從(x,y)開始繪制一個矩形,寬和高分別為width和height。這個方法繪制的矩形是路徑,不是圖形哦,和前面的方法并不一樣。

路徑創(chuàng)建完畢,如果你想繪制一條連接到起點的線條,可以調(diào)用closePath()。如果路徑已經(jīng)完成,你想使用fillStyle填充,使用fill()方法。如果想描邊,使用stroke()。還可以調(diào)用clip(),這個方法在路徑上創(chuàng)建一個剪切區(qū)域。

if (drawing.getContext){
    var context = drawing.getContext("2d");
    context.beginPath();
    context.arc(100, 100, 99, 0, 2 * Math.PI, false);
    context.moveTo(194, 100);
    context.arc(100, 100, 94, 0, 2 * Math.PI, false);
    context.moveTo(100, 100);
    context.lineTo(100, 15);
    context.moveTo(100, 100);
    context.lineTo(35, 100);
    context.stroke();
}

還有一個方法用來在路徑被關(guān)閉前判斷某點是否在路徑上。isPointInPath()

繪制文本

繪制文本主要有兩個方法,fillText()和strokeText()。接收4個參數(shù),要繪制的文本字符串,x坐標(biāo),y坐標(biāo),最大像素寬度。這兩個方法以3個屬性為基礎(chǔ):

  • font:文本字體,"10px Arial"
  • textAlign:文本對齊,有"start""end""left""right""center"。
  • textBaseline:文本基線,"top""hanging""middle""alphabetic" "ideographic""bottom"
context.font = "bold 14px Arial"; 
context.textAlign = "center"; 
context.textBaseline = "middle"; 
context.fillText("12", 100, 20);  

有一個輔助確定文本大小的方法,measureText(),這個方法接收一個參數(shù),即要繪制的文本,返回一個TextMetrics對象,目前只有一個width屬性。

變換

這個也是基于上下文的設(shè)置,在下次設(shè)置前不會改變。

  • rotate(angle):圍繞原點旋轉(zhuǎn)圖像angle弧度
  • scale(scaleX, scaleY):縮放,于x乘scaleX,y乘scaleY
  • translate(x, y):將坐標(biāo)原點移動到(x,y),以后(x,y)就是00點 ?
  • transform(m1_1, m1_2, m2_1, m2_2, dx, dy):直接修改矩陣
  • setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):先將矩陣恢復(fù)至默認(rèn)狀態(tài),再調(diào)用transform()

上下文里有好多設(shè)置,提供了保存和恢復(fù)方法來方便使用:
這里使用的是棧結(jié)構(gòu),可以存多次,再一次一次取。

context.fillStyle = "#ff0000";
    context.save();
    context.fillStyle = "#00ff00";
    context.translate(100, 100);
    context.rotate(1);
    context.save();
    context.fillStyle = "#0000ff";
    context.fillRect(120, 0, 100, 200); //(100,100)
    context.restore();
    context.fillRect(10, 10, 100, 200); //(110,110)
    context.restore();
    context.fillRect(0, 0, 100, 200);

繪制圖像

可以把一幅圖像繪制在畫布上,有3種調(diào)用方式:
只傳進(jìn)一個img元素或另一個canvas元素和起點坐標(biāo)

context.drawImage(image, 10, 10); 

再傳進(jìn)規(guī)定的大小,可以把圖像壓縮到你想要的寬高。這時寬高比例和原始圖像不一樣的話圖像會變形。

context.drawImage(image, 50, 10, 20, 30); 

如果你只想把原始圖像的一部分畫到畫布上,需要9個參數(shù):
圖像、源圖像x、源圖像y、源圖像寬、源圖像高、目標(biāo)圖像x、目標(biāo)圖像y、目標(biāo)圖像寬、目標(biāo)圖像高

 context.drawImage(image, 0, 10, 50, 50, 0, 100, 40, 60); 

源圖像x、源圖像y說明從源圖像的哪里開始截取,源圖像寬、源圖像高說明截取多大一部分。這些值都是相對源圖像來說的。
目標(biāo)圖像x、目標(biāo)圖像y說明這幅截取完成的圖最終畫在畫布的哪里,目標(biāo)圖像寬、目標(biāo)圖像高會將截取好的圖拉伸至你給的像素。

陰影

2D上下文會依據(jù)以下幾個屬性的值,自動為形狀或路徑繪制出陰影。

  • shadowColor
  • shadowOffsetX
  • shadowOffsetY
  • shadowBlur

context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur    = 4;
context.shadowColor   = "rgba(0, 0, 0, 0.5)";

漸變

漸變由CanvasGradient實例表示
線性漸變
創(chuàng)建線性漸變時只需傳入起點和終點
起點和終點要與你要填充的元素匹配。

var gradient = context.createLinearGradient(0, 0, 100, 200);
gradient.addColorStop(0, "red");
gradient.addColorStop(0.165, "orange");
gradient.addColorStop(0.33, "yellow");
gradient.addColorStop(0.495, "green");
gradient.addColorStop(0.66, "#2aabd2");
gradient.addColorStop(0.825, "blue");
gradient.addColorStop(1, "#e4b9b9");
context.fillStyle = gradient;
context.fillRect(0, 0, 100, 200);

鏡像漸變
createRadialGradient()方法,這個方法接收6個參數(shù),起點圓的圓心和半徑,終點圓的圓心和半徑。

var gradient2 = context.createRadialGradient(170, 250, 0, 170, 250, 50);
gradient2.addColorStop(0, "red");
gradient2.addColorStop(0.165, "orange");
gradient2.addColorStop(0.33, "yellow");
gradient2.addColorStop(0.495, "green");
gradient2.addColorStop(0.66, "#2aabd2");
gradient2.addColorStop(0.825, "blue");
gradient2.addColorStop(1, "#e4b9b9");
context.fillStyle = gradient2;

模式

模式其實就是重復(fù)的圖像,可以用來填充或描邊圖形
createPattern()接收一個img,video,canvas元素和一個表示如何重復(fù)的字符串"repeat""repeat-x" "repeat-y""no-repeat"

pattern = context.createPattern(img, "repeat");
context.fillStyle = pattern;

使用圖像數(shù)據(jù)

2D上下文的一個明顯長處就是,可以通過getImageData()取得原始圖像數(shù)據(jù),傳入4個參數(shù),起點和寬高,返回的對象是一個ImageData的實例,每個實例有3個屬性,width,height,data。data是個數(shù)組,保存著每個像素的數(shù)據(jù),每個像素用4個元素:紅、綠、藍(lán)、透明度。值的范圍都在0-255。這樣就可以對圖像的元數(shù)據(jù)進(jìn)行操作了。下面的代碼實現(xiàn)了近似的灰階過濾,并使用putImageData()重繪了整個畫布:

if (drawing.getContext){
    var context = drawing.getContext("2d"),
        imageData, data,
        i, len, average,
        red, green, blue, alpha;
    imageData = context.getImageData(0, 0, drawing.width, drawing.height);
    data = imageData.data;
    for (i=0, len=data.length; i < len; i+=4){
        red = data[i];
        green = data[i+1];
        blue = data[i+2];
        alpha = data[i+3];
        // rgb
        average = Math.floor((red + green + blue) / 3);
        data[i] = average;
        data[i+1] = average;
        data[i+2] = average;
    }        //
    imageData.data = data;
    context.putImageData(imageData, 0, 0);
}

要注意畫布上如果有來自其他域的圖片,是不能獲取圖像元數(shù)據(jù)的,會報錯。

合成

還有兩個會應(yīng)用到2D上下文中所有繪制操作的屬性:globalAlpha和globalCompositionOperation
globalAlpha是全局透明度,介于0,1之間。默認(rèn)值為0,如果某些繪制是需要透明度的,將他設(shè)置為相應(yīng)值,用完再設(shè)置回0。
globalCompositionOperation表示后繪制的矩形怎么和先繪制的圖形結(jié)合。有下面幾種值:

  • source-over
  • source-in
  • source-out
  • source-atop
  • destination-over
  • destination-in
  • destination-out
  • destination-atop
  • lighter
  • copy

這些屬性的效果大家自己測試吧,不同瀏覽器實現(xiàn)有差別,真正要用的時候要注意哦。

WebGL

這部分請參考:
http://www.hiwebgl.com/?p=42

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一:canvas簡介 1.1什么是canvas? ①:canvas是HTML5提供的一種新標(biāo)簽 ②:HTML5 ...
    GreenHand1閱讀 4,878評論 2 32
  • 一、canvas簡介 1.1 什么是canvas?(了解) 是HTML5提供的一種新標(biāo)簽 Canvas是一個矩形區(qū)...
    Looog閱讀 4,035評論 3 40
  • 本章內(nèi)容 理解 元素 繪制簡單的 2D 圖形 使用 WebGL 繪制 3D 圖形 這個元素負(fù)責(zé)在頁面中設(shè)定一個區(qū)域...
    悶油瓶小張閱讀 978評論 0 0
  • 一、簡介 HTML5 中的定義:“它是依賴分辨率的位圖畫布,你可以在 canvas 上面繪制任何圖形,甚至加載照片...
    destiny0904閱讀 10,826評論 1 4
  • 我和你之間隔著手機(jī) 未曾注意你注意我迫切的眼神 許久 你輕輕的拿掉我的手機(jī) 溫柔的說 媽媽,看手機(jī)眼睛里會有芝麻糊...
    愛吃魚的豆媽閱讀 142評論 0 0

友情鏈接更多精彩內(nèi)容