<canvas>標(biāo)簽用于繪制圖像(通過腳本,通常是 JavaScript)。不過,<canvas>元素本身并沒有繪制能力(它僅僅是圖形的容器) - 您必須使用腳本來完成實(shí)際的繪圖任務(wù)。
Internet Explorer 9、Firefox2.0、Opera9.0、Chrome4.0 以及 Safari3.1 支持 <canvas> 及其屬性和方法。
開始使用
- 首先新建一個(gè)<canvas>網(wǎng)頁元素。
<canvas id="myCanvas" width="400" height="200">
你的瀏覽器不支持canvas!
</canvas>
上面代碼中,如果瀏覽器不支持,則就會(huì)顯示<canvas>標(biāo)簽中間的文字——“您de瀏覽器不支持canvas!”。
- 取這個(gè)canvas對(duì)象,方法是使用
getContext。
var canvas = document.getElementById('myCanvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
}
getContext方法指定參數(shù)2d,表示該canvas節(jié)點(diǎn)用于生成2D圖案(即平面圖案)。如果參數(shù)是webgl,就表示用于生成3D圖像(即立體圖案),這部分實(shí)際上單獨(dú)叫做WebGL API。
繪圖方法
canvas畫布提供了一個(gè)用來作圖的平面空間,該空間的每個(gè)點(diǎn)都有自己的坐標(biāo),x表示橫坐標(biāo),y表示豎坐標(biāo)。原點(diǎn)(0, 0)位于圖像左上角,x軸的正向是原點(diǎn)向右,y軸的正向是原點(diǎn)向下
繪制路徑
beginPath方法表示開始繪制路徑,
moveTo(x, y)方法設(shè)置線段的起點(diǎn),
lineTo(x, y)方法設(shè)置線段的終點(diǎn),
stroke方法用來給透明的線段著色。
ctx.beginPath(); // 開始路徑繪制
ctx.moveTo(20, 20); // 設(shè)置路徑起點(diǎn),坐標(biāo)為(20,20)
ctx.lineTo(200, 20); // 繪制一條到(200,20)的直線
ctx.lineWidth = 1.0; // 設(shè)置線寬
ctx.strokeStyle = '#CC0000'; // 設(shè)置線的顏色
ctx.stroke(); // 進(jìn)行線的著色,這時(shí)整條線才變得可見

moveto和lineto方法可以多次使用。最后,還可以使用closePath方法,自動(dòng)繪制一條當(dāng)前點(diǎn)到起點(diǎn)的直線,形成一個(gè)封閉圖形,省卻使用一次lineto方法。
ctx.beginPath();
ctx.moveTo(40,20);
ctx.lineTo(60,20);
ctx.lineTo(60,40);
ctx.lineTo(40,40);
ctx.lineTo(40,20);//繪制閉合圖形時(shí),可以替換成ctx.closePath();
ctx.lineWidth = 1.0;
ctx.strokeStyle = '#CC0000';
ctx.stroke();

繪制矩形
fillRect(x, y, width, height)方法用來繪制矩形,它的四個(gè)參數(shù)分別為矩形左上角頂點(diǎn)的x坐標(biāo)、y坐標(biāo),以及矩形的寬和高。fillStyle屬性用來設(shè)置矩形的填充色。
ctx.fillStyle = 'yellow';
ctx.fillRect(50, 50, 200, 100);

strokeRect(x, y, width, height)方法與fillRect類似,用來繪制空心矩形。
ctx.strokeRect(60,200,200,100);

clearRect(x, y, width, height)方法用來清除某個(gè)矩形區(qū)域的內(nèi)容。
ctx.clearRect(100,50,50,50);

繪制文本
fillText(string, x, y)用來繪制文本,它的三個(gè)參數(shù)分別為文本內(nèi)容、起點(diǎn)的x坐標(biāo)、y坐標(biāo)。使用之前,需用font設(shè)置字體、大小、樣式(寫法類似與CSS的font屬性)。與此類似的還有strokeText(string, x, y)方法,用來添加空心字。
ctx.font = "Bold 20px Arial";// 設(shè)置字體
ctx.textAlign = "left";// 設(shè)置對(duì)齊方式
ctx.fillStyle = "#333";// 設(shè)置填充顏色
ctx.fillText("Hello!", 320, 50);// 設(shè)置字體內(nèi)容,以及在畫布上的位置
ctx.textAlign = "center";// 設(shè)置對(duì)齊方式
ctx.strokeStyle = "#000";// 設(shè)置顏色
ctx.strokeText("Hello!",320, 80);// 繪制空心字
ctx.textAlign = "right";// 設(shè)置對(duì)齊方式
ctx.strokeStyle = "green";// 設(shè)置顏色
ctx.strokeText("Hello!",320, 110);// 繪制空心字

注意
- 當(dāng)繪制空心字時(shí),著色應(yīng)使用
strokeStyle;而繪制實(shí)心字時(shí),使用fillStyle來著色 -
textAlign方法與我們css中所理解的有所區(qū)別,舉個(gè)栗子你就明白啦
// 在位置 600 創(chuàng)建藍(lán)線
ctx.strokeStyle="blue";
ctx.moveTo(600,20);
ctx.lineTo(600,170);
ctx.stroke();
ctx.font="15px Arial";
// 顯示不同的 textAlign 值
ctx.textAlign="start";
ctx.fillText("textAlign=start",600,60);
ctx.textAlign="end";
ctx.fillText("textAlign=end",600,80);
ctx.textAlign="left";
ctx.fillText("textAlign=left",600,100);
ctx.textAlign="center";
ctx.fillText("textAlign=center",600,120);
ctx.textAlign="right";
ctx.fillText("textAlign=right",600,140);

fillText方法不支持文本斷行,即所有文本出現(xiàn)在一行內(nèi)。所以,如果要生成多行文本,只有調(diào)用多次fillText方法。
家庭作業(yè):使用canvas繪制多行文本
繪制圓形和扇形
arc(x, y, radius, startAngle, endAngle, anticlockwise)方法用來繪制扇形,x和y參數(shù)是圓心坐標(biāo),radius是半徑,startAngle和endAngle則是扇形的起始角度和終止角度(以弧度表示),anticlockwise表示做圖時(shí)應(yīng)該逆時(shí)針畫true,還是順時(shí)針畫false。
//繪制實(shí)心圓
ctx.beginPath();
ctx.arc(60, 60, 50, 0, Math.PI*2, true);
ctx.fillStyle = "#000000";
ctx.fill();
//繪制空心圓形
ctx.beginPath();
ctx.arc(60, 60, 50, 0, Math.PI*2, true);
ctx.lineWidth = 1.0;
ctx.strokeStyle = "#000";
ctx.stroke();

for(var i = 0; i < 10;i++){
context.beginPath();
context.arc(50 + i*100,60,40,0,2*Math.PI*(i+1)/10);
context.closePath();//沒有閉合的圓弧,會(huì)自動(dòng)閉合圖形
context.stroke();
}
for (var i = 0; i < 10; i++) {
context.beginPath();
context.arc(50 + i * 100, 180, 40, 0, 2 * Math.PI * (i + 1) / 10);
context.stroke();
}
for (var i = 0; i < 10; i++) {
context.beginPath();
context.arc(50 + i * 100, 300, 40, 0, 2*Math.PI * (i + 1)/10 , true);
context.closePath();
context.stroke();
}
for (var i = 0; i < 10; i++) {
context.beginPath();
context.arc(50 + i * 100, 420, 40, 0, 2 * Math.PI * (i + 1) / 10, true);
context.stroke();
}
context.fillStyle = '#058';
for (var i = 0; i < 10; i++) {
context.beginPath();
context.arc(50 + i * 100, 540, 40, 0, 2 * Math.PI * (i + 1) / 10);
context.closePath();//有無closePath對(duì)于fill填充無效
context.fill();
}
for (var i = 0; i < 10; i++) {
context.beginPath();
context.arc(50 + i * 100, 660, 40, 0, 2 * Math.PI * (i + 1) / 10);
context.fill();
}

注意
-
anticlockwise參數(shù)省略時(shí),默認(rèn)為順時(shí)針; -
closePath()在繪制空心圓弧時(shí),依然會(huì)自動(dòng)閉合圖??;對(duì)實(shí)心圓弧則無效
設(shè)置漸變色
createLinearGradient(x1, y1, x2, y2)用來設(shè)置漸變色,其中x1和y1是起點(diǎn)坐標(biāo),x2和y2是終點(diǎn)坐標(biāo)。通過不同的坐標(biāo)值,可以生成從上至下、從左到右的漸變等等。使用該對(duì)象作為strokeStyle或fillStyle屬性的值,可用于填充矩形、圓形、線條、文本等等。使用addColorStop()方法規(guī)定不同的顏色,以及在 gradient 對(duì)象中的何處定位顏色
var my_gradient=ctx.createLinearGradient(500,0,700,0);
my_gradient.addColorStop(0,"black");
my_gradient.addColorStop(0.5,"red");
my_gradient.addColorStop(1,"white");
ctx.fillStyle=my_gradient;
ctx.strokeStyle = my_gradient;
ctx.fillRect(500,300,200,100);//繪制漸變圖形
ctx.moveTo(500,430);
ctx.lineTo(700,430);
ctx.stroke();//繪制漸變線
ctx.textAlign="left";
ctx.fillText("Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!", 500, 470);//繪制漸變字

createLinearGradient(x0,y0,r0,x1,y1,r1)方法創(chuàng)建放射狀/圓形漸變對(duì)象,x0漸變的開始圓的 x 坐標(biāo);y0漸變的開始圓的 y 坐標(biāo);r0開始圓的半徑;x1漸變的結(jié)束圓的 x 坐標(biāo);y1漸變的結(jié)束圓的 y 坐標(biāo);r1結(jié)束圓的半徑
var radialGrad = context.createRadialGradient(400,400,0,400,400,500);
radialGrad.addColorStop(0.0,'white');
radialGrad.addColorStop(0.25,'yellow');
radialGrad.add.ColorStop(0.5,'green');
radialGrad.add.ColorStop(0.75,'blue');
radialGrad.add.ColorStop(1.0,'black');
context.fillStyle = radialGrad;
context.fillRect(0,0,800,800);

設(shè)置陰影
shadowBlur方法設(shè)置陰影的模糊范圍;
shadowOffsetX方法設(shè)置水平位移;
shadowOffsetY方法設(shè)置垂直位移;
shadowColor設(shè)置陰影顏色
ctx.shadowOffsetX = 10; // 設(shè)置水平位移
ctx.shadowOffsetY = 10; // 設(shè)置垂直位移
ctx.shadowBlur = 5; // 設(shè)置模糊度
ctx.shadowColor = "rgba(0,0,0,0.5)"; // 設(shè)置陰影顏色
ctx.fillStyle = "#CC0000";
ctx.fillRect(10,10,200,100);

圖像處理方法
drawImage方法
Canvas允許將圖像文件插入畫布,做法是讀取圖片后,使用
drawImage方法在畫布內(nèi)進(jìn)行重繪。
drawImage(img,sx,sy,swidth,sheight,x,y,width,height)
img規(guī)定要使用的圖像、畫布或視頻。
sx可選。開始剪切的 x 坐標(biāo)位置。
sy可選。開始剪切的 y 坐標(biāo)位置。
swidth可選。被剪切圖像的寬度。
sheight可選。被剪切圖像的高度。
x在畫布上放置圖像的 x 坐標(biāo)位置。
y在畫布上放置圖像的 y 坐標(biāo)位置。
width可選。要使用的圖像的寬度。(伸展或縮小圖像)
height可選。要使用的圖像的高度。(伸展或縮小圖像)
var img = new Image();
img.src = 'image.png';
ctx.drawImage(img, 0, 0); // 設(shè)置對(duì)應(yīng)的圖像對(duì)象,以及它在畫布上的位置
上面代碼將一個(gè)PNG圖像載入畫布。drawImage()方法接受三個(gè)參數(shù),第一個(gè)參數(shù)是圖像文件的DOM元素(即<img>節(jié)點(diǎn)),第二個(gè)和第三個(gè)參數(shù)是圖像左上角在畫布中的坐標(biāo),上例中的(0, 0)就表示將圖像左上角放置在畫布的左上角。
由于圖像的載入需要時(shí)間,drawImage方法只能在圖像完全載入后才能調(diào)用,因此上面的代碼并沒有成功畫入圖片,需要改寫:
var image = new Image();
image.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext('2d').drawImage(image, 0, 0);
// 插入頁面底部
document.body.appendChild(image);
return canvas;
}
image.src = 'image.jpg';
getImageData方法,putImageData方法
通過 getImageData(x,y,width,height)復(fù)制畫布上指定矩形的像素?cái)?shù)據(jù),
然后通過 putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight) 將圖像數(shù)據(jù)放回畫布。
getImageData(x,y,width,height)
x開始復(fù)制的左上角位置的 x 坐標(biāo)(以像素計(jì))。
y開始復(fù)制的左上角位置的 y 坐標(biāo)(以像素計(jì))
width要復(fù)制的矩形區(qū)域的寬度。
height要復(fù)制的矩形區(qū)域的高度。
getImageData() 方法返回 ImageData 對(duì)象,該對(duì)象拷貝了畫布指定矩形的像素?cái)?shù)據(jù)。
注意:ImageData 對(duì)象不是圖像,它規(guī)定了畫布上一個(gè)部分(矩形),并保存了該矩形內(nèi)每個(gè)像素的信息。
對(duì)于 ImageData 對(duì)象中的每個(gè)像素,都存在著四方面的信息,即 RGBA 值:
- R - 紅色(0-255)
- G - 綠色(0-255)
- B - 藍(lán)色(0-255)
- A - alpha 通道(0-255; 0 是透明的,255 是完全可見的)
color/alpha 信息以數(shù)組形式存在,并存儲(chǔ)于 ImageData 對(duì)象的 data 屬性中。
putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight)
imgData規(guī)定要放回畫布的 ImageData 對(duì)象。
xImageData 對(duì)象左上角的 x 坐標(biāo),以像素計(jì)。
yImageData 對(duì)象左上角的 y 坐標(biāo),以像素計(jì)。
dirtyX可選。水平值(x),以像素計(jì),在畫布上放置圖像的位置。
dirtyY可選。垂直值(y),以像素計(jì),在畫布上放置圖像的位置。
dirtyWidth可選。在畫布上繪制圖像所使用的寬度。
dirtyHeight可選。在畫布上繪制圖像所使用的高度。
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="red";
ctx.fillRect(10,10,50,50);
function copy()
{
var imgData=ctx.getImageData(10,10,50,50);
ctx.putImageData(imgData,10,70);
}
</script>
<button onclick="copy()">復(fù)制</button>
toDataURL方法
對(duì)圖像數(shù)據(jù)做出修改以后,可以使用toDataURL方法,將Canvas數(shù)據(jù)重新轉(zhuǎn)化成一般的圖像文件形式。該方法返回一個(gè)包含圖片展示的 data URI ??梢允褂?type參數(shù)其類型,默認(rèn)為 PNG 格式。圖片的分辨率為96dpi。
toDataURL(type, encoderOptions)
type可選,圖片格式,默認(rèn)為 image/png
encoderOptions可選,在指定圖片格式為 image/jpeg 或 image/webp的情況下,可以從 0 到 1 的區(qū)間內(nèi)選擇圖片的質(zhì)量。如果超出取值范圍,將會(huì)使用默認(rèn)值 0.92。其他參數(shù)會(huì)被忽略。
var canvas = document.getElementById("canvas");
var dataURL = canvas.toDataURL();
console.log(dataURL);
// "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAADElEQVQImWNgoBMAAABpAAFEI8ARAAAAAElFTkSuQmCC"
var fullQuality = canvas.toDataURL("image/jpeg", 1.0);
//data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ...9oADAMBAAIRAxEAPwD/AD/6AP/Z"
var mediumQuality = canvas.toDataURL("image/jpeg", 0.5);
var lowQuality = canvas.toDataURL("image/jpeg", 0.1);
save方法,restore方法
save:用來保存Canvas的狀態(tài)。save之后,可以調(diào)用Canvas的平移、放縮、旋轉(zhuǎn)、錯(cuò)切、裁剪等操作。 restore:用來恢復(fù)Canvas之前保存的狀態(tài)。防止save后對(duì)Canvas執(zhí)行的操作對(duì)后續(xù)的繪制有影響。
ctx.save();
ctx.shadowOffsetX = 10;
ctx.shadowOffsetY = 10;
ctx.shadowBlur = 5;
ctx.shadowColor = 'rgba(0,0,0,0.5)';
ctx.fillStyle = '#CC0000';
ctx.fillRect(10,10,150,100);
ctx.restore();
ctx.fillStyle = '#000000';
ctx.fillRect(180,10,150,100);
上面代碼先用save方法,保存了當(dāng)前設(shè)置,然后繪制了一個(gè)有陰影的矩形。接著,使用restore方法,恢復(fù)了保存前的設(shè)置,繪制了一個(gè)沒有陰影的矩形。
注意
- restore只能撤回到上一個(gè)save()的狀態(tài);
- restore可以多次執(zhí)行,一直向上這回。