Menu
第15章 使用 Canvas 繪圖
15.1 基本用法
15.2 2D 上下文
- 15.2.1 填充和描邊
- 15.2.2 繪制矩形
- 15.2.3 繪制路徑
- 15.2.4 繪制文本
- 15.2.5 變換
- 15.2.6 繪制圖像
- 15.2.7 陰影
- 15.2.8 漸變
- 15.2.9 模式
- 15.2.10 使用圖像數(shù)據(jù)
- 15.2.11 合成
15.1 基本用法
- HTML里添加<canvas>元素:接著必須先設置其 width 和 height 屬性箩朴,指定可以繪圖的區(qū)域大小笛臣。出現(xiàn)在開始和結束標簽中的內容是后備信息,如果瀏覽器不支持<canvas>元素隧饼,就會顯示這些信息。下面就是<canvas>元素的例子静陈。
<canvas id="drawing" width=" 200" height="200">A drawing of something.</canvas>
- 取得繪圖上下文:要在這塊畫布(canvas)上繪圖燕雁,需要取得繪圖上下文诞丽。而取得繪圖上下文對象的引用,需要調用getContext()方法并傳入上下文的名字拐格。傳入"2d"僧免,就可以取得 2D 上下文對象。
var drawing = document.getElementById("drawing");
// 取得 2D 上下文對象
var context = drawing.getContext("2d");
- 導出在<canvas>元素上繪制的圖像:使用 toDataURL()方法捏浊,這個方法接受一個參數(shù)懂衩,即圖像的 MIME
類型格式,而且適合用于創(chuàng)建圖像的任何上下文金踪。默認情況下浊洞,瀏覽器會將圖像編碼為 PNG 格式(除非另行指定
)。比如胡岔,要取得畫布中的一幅 PNG 格式的圖像法希。:
var drawing = document.getElementById("drawing");
//取得圖像的數(shù)據(jù) URI
var imgURI = drawing.toDataURL("image/png");
//顯示圖像
var image = document.createElement("img");
image.src = imgURI;
document.body.appendChild(image);
15.2 2D 上下文
- 2D 上下文的坐標開始于<canvas>元素的左上角,原點坐標是(0,0)靶瘸。
- 15.2.1 填充和描邊
- 2D 上下文的兩種基本繪圖操作是填充和描邊苫亦。填充,就是用指定的樣式(顏色怨咪、漸變或圖像)填
充圖形屋剑;描邊,就是只在圖形的邊緣畫線诗眨。操作的結果取決于兩個屬性: fillStyle 和 strokeStyle唉匾。 - 這兩個屬性的值可以是字符串、漸變對象或模式對象辽话,而且它們的默認值都是"#000000"肄鸽。如果為它們指定表示顏色的字符串值,可以使用 CSS 中指定顏色值的任何格式油啤,包括顏色名典徘、十六進制碼、rgb益咬、 rgba逮诲、 hsl 或 hsla。舉個例子:
var drawing = document.getElementById("drawing");
var context = drawing.getContext("2d");
// 所有涉及描邊和填充的操作都將使用這兩個樣式幽告,填充和描邊的顏色需要寫在位置前面梅鹦;
context.strokeStyle = "red";
context.fillStyle = "#0000ff"
15.2.2 繪制矩形
-
矩形是唯一一種可以直接在 2D 上下文中繪制的形狀。與矩形有關的方法包括 fillRect()冗锁、strokeRect()和 clearRect()齐唆。這三個方法都能接收 4 個參數(shù):矩形的 x 坐標、矩形的 y 坐標冻河、矩形寬度和矩形高度箍邮。這些參數(shù)的單位都是像素茉帅。
- fillRect():方法在畫布上繪制的矩形,默認填充黑色锭弊;
- fillStyle:屬性指定填充的顏色堪澎。可以使用 CSS 中指定顏色值的任何格式味滞,包括顏色名樱蛤、十六進制碼、rgb剑鞍、 rgba昨凡、 hsl 或 hsla。
//繪制紅色矩形
context.fillStyle = "#ff0000";
// (x, y, width, height)
context.fillRect(10, 10, 50, 50);
//繪制半透明的藍色矩形
context.fillStyle = "rgba(0,0,255,0.5)";
context.fillRect(30, 30, 50, 50);
- strokeStyle屬性:描邊顏色通過 strokeStyle 屬性指定攒暇。
- strokeRect()方法:方法在畫布上繪制的矩形描邊土匀,默認填充黑色;
- lineWidth屬性:描邊線條的寬度由 lineWidth 屬性控制形用,該屬性的值可以是任意整數(shù)就轧;
- lineCap 屬性:可以控制線條末端的形狀是平頭、圓頭還是方頭("butt"田度、"round"或"square")妒御,
- lineJoin 屬性:可以控制線條相交的方式是圓交、斜交還是斜接("round"镇饺、 "bevel"或"miter")乎莉。
//繪制紅色描邊矩形
context.strokeStyle = "#ff0000";
context.strokeRect(10, 10, 50, 50);
//繪制半透明的藍色描邊矩形
context.strokeStyle = "rgba(0,0,255,0.5)";
context.strokeRect(30, 30, 50, 50);
// 以上代碼繪制了兩個重疊的矩形。不過奸笤,這兩個矩形都只有框線惋啃,內部并沒有填充顏色
- clearRect()方法:用于清除畫布上的矩形區(qū)域。這個方法可以把繪制上下文中的某一矩形區(qū)域變透明监右。
ctx.fillRect(0, 0, 100, 100);
ctx.clearRect(30, 30, 40, 40)
- 15.2.3 繪制路徑
- beginPath()方法:開始繪制新路徑立倍。
- arc(x, y, radius, startAngle, endAngle, counterclockwise):繪制圓形漩符;參數(shù)如下:
- x:圓弧中心(圓心)的 x 軸坐標狠角。
- y:圓弧中心(圓心)的 y 軸坐標巴碗。
- radius:圓弧的半徑。
- startAngle:圓弧的起始點扣癣, x軸方向開始計算惰帽,單位以弧度表示。
- endAngle:圓弧的終點父虑, 單位以弧度表示该酗。(0, 2*Math.PI 表示畫整個圓)
- anticlockwise :可選的Boolean值 士嚎,如果為 true垂涯,逆時針繪制圓弧烁焙,反之,順時針繪制耕赘。
canvas = document.getElementById("drawing");
context = canvas.getContext("2d"); // 得到畫圖板對象; ?
context.beginPath(); // 創(chuàng)建新路徑膳殷;
context.strokeStyle = "rgba(255,0,255,0.66)";
context.lineWidth = 3;
context.arc(250, 250, 100, 2*Math.PI, false); // 弧度方法操骡;
context.stroke();
- lineTo(x, y):從上一點開始繪制一條直線,到(x,y)為止赚窃。
context.moveTo(250,250);
context.lineTo(250,160);
context.stroke();
- moveTo(x, y):將繪圖游標移動到(x,y)册招,不畫線。
- arcTo(x1, y1, x2, y2, radius):從上一點開始繪制一條弧線勒极,到(x2,y2)為止是掰,并且以給定的半徑 radius 穿過(x1,y1)。(是 Canvas 2D API 根據(jù)控制點和半徑繪制圓弧路徑辱匿,使用當前的描點(前一個moveTo或lineTo等函數(shù)的止點)键痛。根據(jù)當前描點與給定的控制點1連接的直線,和控制點1與控制點2連接的直線匾七,作為使用指定半徑的圓的切線絮短,畫出兩條切線之間的弧線路徑。)
- bezierCurveTo(c1x, c1y, c2x, c2y, x, y):貝塞爾曲線昨忆, 從上一點開始繪制一條曲線丁频,到(x,y)為止,并且以(c1x,c1y)和(c2x,c2y)為控制點邑贴。
var c=document.getElementById("drawing");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.moveTo(50,250);
ctx.bezierCurveTo(200,150,300,350,450,250);
// cp1x 第一個貝塞爾控制點的 +
x 坐標
// cp1y 第一個貝塞爾控制點的 y 坐標
// cp2x 第二個貝塞爾控制點的 x 坐標
// cp2y 第二個貝塞爾控制點的 y 坐標
// x 結束點的 x 坐標
// y 結束點的 y 坐標
- quadraticCurveTo(cx, cy, x, y):從上一點開始繪制一條二次曲線席里,到(x,y)為止,并且以(cx,cy)作為控制點拢驾。
canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d"); // 創(chuàng)建canvas的執(zhí)行環(huán)境奖磁;
context.beginPath(); // 創(chuàng)建畫圖路徑;
context.moveTo(50,250);
context.quadraticCurveTo(250, 450,450, 250); // 一個控制點的線独旷;
context.stroke() // 筆畫描邊署穗;
- rect(x, y, width, height):從點(x,y)開始繪制一個矩形,寬度和高度分別由 width 和height 指定嵌洼。這個方法繪制的是矩形路徑案疲,而不是 strokeRect()和 fillRect()所繪制的獨立的形狀。
context.beginPath(); // 創(chuàng)建畫圖路徑麻养;
context.rect(50,50,100,65);
context.stroke() // 筆畫描邊褐啡;
- closePath():繪制一條連接到路徑起點的線條;
context.beginPath(); // 創(chuàng)建畫圖路徑鳖昌;
context.moveTo(50,250);
context.quadraticCurveTo(250, 450,450, 250); // 一個控制點的線备畦;
context.closePath()低飒;
context.stroke(); // 筆畫描邊懂盐;
- fill():用 fillStyle 填充路徑褥赊。
- stroke():用strokeStyle描邊路徑。
- clip() 方法從原始畫布中剪切任意形狀和尺寸莉恼。一旦剪切了某個區(qū)域拌喉,則所有之后的繪圖都會被限制在被剪切的區(qū)域內(不能訪問畫布上的其他區(qū)域)。您也可以在使用 clip() 方法前通過使用 save() 方法對當前畫布區(qū)域進行保存俐银,并在以后的任意時間對其進行恢復(通過 restore() 方法)尿背。
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
// 剪切矩形區(qū)域
ctx.rect(50,20,200,120);
ctx.stroke();
ctx.clip();
// 在 clip() 之后繪制綠色矩形
ctx.fillStyle="green";
ctx.fillRect(0,0,150,100);
- 15.2.4 繪制文本
- 繪制文本主要有兩個方法: fillText()和 strokeText()。這兩個方法都可以接收 4 個參數(shù):要繪制的文本字符串捶惜、 x 坐標田藐、 y 坐標和可選的最大像素寬度。
- 第四個參數(shù)表示字符的最大寬度限制:傳入的字符串大于最大寬度吱七,則繪制的文本字符的高度正確汽久,但寬度會收縮以適應最大寬度。
- font屬性:表示文本樣式陪捷、大小及字體回窘,用 CSS 中指定字體的格式來指定,例如"10px Arial"市袖。
- textAlign屬性:表示文本對齊方式啡直。可能的有"start"苍碟、"end"酒觅、"left"、"right"和"center"微峰。建議使用"start"和"end"舷丹,不要使用"left"和"right",因為前兩者的意思更穩(wěn)妥蜓肆,能同時適合從左到右和從右到左顯示(閱讀)的語言颜凯。
- textBaseline屬性:表示文本的基線≌萄铮可能的值有"top"症概、"hanging"、"middle"早芭、"alphabetic"彼城、"ideographic"和"bottom"。
- alphabetic:默認。文本基線是普通的字母基線募壕。
- top:文本基線是 em 方框的頂端调炬。。
- hanging:文本基線是懸掛基線舱馅。
- middle:文本基線是 em 方框的正中缰泡。
- ideographic:文本基線是表意基線。
- bottom:文本基線是 em 方框的底端代嗤。
- **Context.measureText() **
- 方法返回一個 TextMetrics 對象匀谣,包含關于文本尺寸的信息(例如文本的寬度)。
var text = ctx.measureText("foo"); // TextMetrics object
text.width; // 16;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
fontsize = 150;
ctx.font = fontsize + "px Arial";
while(ctx.measureText("Hello world!").width > 500){
fontsize-- ;
ctx.font = fontsize + "px Arial";
}
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.translate(250, 250);
ctx.rotate(90 * Math.PI / 180);
ctx.scale(0.5, 0.5);
ctx.fillText("Hello World", 10 , 10);
- 15.2.5 變換
- rotate(angle):圍繞原點旋轉圖像 angle 弧度资溃;要移動圓點, 使用下面的translate(x, y)方法烈炭;
- 怎樣實現(xiàn)原地旋轉:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "pink";
ctx.fillRect(100,100,100,100)
var deg = Math.PI/180; //deg = 1°
ctx.translate(150, 150); //把原點點從零移到正方形的中心點
ctx.rotate(45*deg); //繞著原點旋轉45度(即繞著圖像中心點旋轉45度)溶锭, 下面的transform也是同樣作用
// transfrom要實現(xiàn)旋轉,需要設置前4個參數(shù)
// ctx.transform(Math.cos(45*deg),Math.sin(45*deg),-Math.sin(45*deg),Math.cos(45*deg),0,0);
ctx.fillStyle = "blue";
ctx.fillRect(-50,-50,100,100) //旋轉后的圖像坐標需要從新的圓點回到原來的坐標符隙, 即-width趴捅, -height
- translate(x, y):將坐標原點移動到(x,y)。執(zhí)行這個變換之后霹疫, 坐標(0,0)會變成之前由(x,y)表示的點拱绑。
ctx.font = "150px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.translate(250, 250);
ctx.rotate(90 * Math.PI / 180);
ctx.fillText("Hello World", 10 , 10);
- scale(scaleX, scaleY):縮放圖像,在 x 方向乘以 scaleX丽蝎,在 y 方向乘以 scaleY猎拨。 scaleX和 scaleY 的默認值都是 1.0。
ctx.scale(0.5, 0.5);
ctx.fillText("Hello World", 10 , 10);
- transform(a, b, c, d, e, f):直接修改變換矩陣屠阻。
- 默認參數(shù):transfrom(1, 0, 0, 1, 0, 0)
a 水平縮放繪圖
b 水平傾斜繪圖
c 垂直傾斜繪圖
d 垂直縮放繪圖
e 水平移動繪圖
f 垂直移動繪圖
- 默認參數(shù):transfrom(1, 0, 0, 1, 0, 0)
15.2.6 繪制圖像
context.drawImage()
-
要加入事件才能在畫布里顯示出圖片
- <img onload="somefunc(event)" src="image.jpg" id="myImg">
-
如果你想把一幅圖像繪制到畫布上红省,可以使用 drawImage()方法。根據(jù)期望的最終結果不同国觉,調用這個方法時吧恃,可以使用三種不同的參數(shù)組合。
- 傳入一個 HTML <img>Element麻诀,以及繪制該圖像的起點的 x 和 y 坐標.
- context.drawImage(image, 10, 10);
- 如果你想改變繪制后圖像的大小痕寓,可以再多傳入兩個參數(shù),分別表示目標寬度和目標高度蝇闭。
- context.drawImage(image, 50, 10, 20, 30);
- 還可以選擇把圖像中的某個區(qū)域繪制到上下文中呻率。 drawImage()方法的這種調
用方式總共需要傳入 9 個參數(shù):
要繪制的圖像、
源圖像的 x 坐標丁眼、源圖像的 y 坐標筷凤、
源圖像的寬度、源圖像的高度、
目標圖像的 x 坐標藐守、目標圖像的 y 坐標挪丢、
目標圖像的寬度、目標圖像的高度卢厂。
- context.drawImage(圖片obj, 源圖片x,源圖片y, x開始切的寬度,x開始切的高度,畫布x點,畫布y點,畫布圖片的寬度,畫布圖片的高度)
除了給 drawImage()方法傳入 HTML <img>元素外乾蓬,還可以傳入另一個<canvas>元素作為其第一個參數(shù)。這樣慎恒,就可以把另一個畫布內容繪制到當前畫布上任内。
獲得圖片修改后的結果:re = canvas.toDataURL(),可以把結果再放回到img元素里融柬;img.src = re;
即圖像不能來自其他域死嗦。如果圖像來自其他域,調用toDataURL()會拋出一個錯誤粒氧。
15.2.7 陰影
2D 上下文會根據(jù)以下幾個屬性的值越除,自動為形狀或路徑繪制出陰影。
context.shadowColor = "rgba(0,0,255,0.1)"; // 陰影顏色外盯,不設置默認黑色和透明度 不透明是1
context.shadowOffsetX = -100; // x 軸方向的陰影偏移量 默認0
context.shadowOffsetY = 1; // y 軸方向的陰影偏移量 默認0
context.shadowBlur = 20; // 模糊的像素數(shù)摘盆,默認 0,即不模糊
context.drawImage(img,50,50,200,150)
-
15.2.8 漸變
- 可以調用 createLinearGradient()方法饱苟。這個方法接收 4 個參數(shù):起點的 x 坐標孩擂、起點的 y 坐標、終點的 x 坐標箱熬、終點的 y 坐標类垦。
- 下一步就是使用 addColorStop()方法來指定色標。這個方法接收兩個參數(shù):色標位置和 CSS 顏色值坦弟。色標位置是一個 0(開始的顏色)到 1(結束的顏色)之間的數(shù)字护锤。
- 然后就可以把 fillStyle 或 strokeStyle 設置為這個對象,從而使用漸變來繪制形狀或描邊.
var gradient = context.createLinearGradient(30, 30, 80, 80);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
//繪制漸變矩形
context.fillStyle = gradient;
context.fillRect(30, 30, 50, 50);
- 放射漸變
- var gradient = context.createRadialGradient(55, 55, 10, 55, 55, 30);
- 前三個參數(shù)指定的是起點圓的原心(x 和 y)及半徑酿傍,后三個參數(shù)指定的是終點圓的原心(x 和 y)及半徑烙懦。可以把徑向漸變想象成一個長圓桶赤炒,而這 6 個參數(shù)定義的正是這個桶的兩個圓形開口的位置氯析。如果把一個圓形開口定義得比另一個小一些,那這個圓桶就變成了圓錐體莺褒,而通過移動每個圓形開口的位置掩缓,就可達到像旋轉這個圓錐體一樣的效果。
var gradient = context.createRadialGradient(55, 55, 10, 55, 55, 30);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
//繪制漸變矩形
context.fillStyle = gradient;
context.fillRect(30, 30, 50, 50);
- 15.2.9 模式
- 模 式 其 實 就 是 重 復 的 圖 像 遵岩, 可 以 用 來 填 充 或 描 邊 圖 形 你辣。
- 要 創(chuàng) 建 一 個 新 模 式 巡通, 可 以 調 用createPattern()方法。
- 有2個參數(shù):1.imgElement 2.repeat方式: 包括"repeat"舍哄、 "repeat-x"宴凉、"repeat-y"和"no-repeat"。
img = document.getElementById("myImg");
canvasB = document.getElementById("myCanvasB");
contextB = canvasB.getContext("2d");
// 獲取圖像表悬,把圖像縮小到100x100像素弥锄;
contextB.drawImage(img, 0,0,100,100);
canvasA = document.getElementById("myCanvasA");
contextA = canvasA.getContext("2d");
// convasA的Context里創(chuàng)建Pattern,放縮小了的canvasB畫布和repeat模式
pattern = contextA.createPattern(canvasB,"repeat");
// 填充規(guī)則
contextA.fillStyle = pattern;
contextA.fillRect(0,0,500,500)
}
- createPattern()方法的第一個參數(shù)也可以是一個<video>元素蟆沫,或者另一個<canvas>元素籽暇。
- 15.2.10 使用圖像數(shù)據(jù)
img = document.getElementById("myImg");
var c=document.getElementById("drawing");
var ctx=c.getContext("2d");
// img放到畫布里;
ctx.drawImage(img,0,0,500,500);
// 取得圖像數(shù)據(jù)
imgData = ctx.getImageData(0,0,c.width,c.height);
// 每個 ImageData 對象都有三個屬性: width饭庞、 height 和data戒悠。
// 在imgData.data數(shù)組中,存著每一個像素點的rgba的值舟山;
data = imgData.data;
for (let i=0, len=data.length; i<len; i+=4){
//得到每個像素點的數(shù)據(jù)
red = data[i];
green = data[i+1];
blue = data[i+2];
//求得每個像素點rgb的平均值
var average = Math.floor((red+green+blue)/3);
//設置顏色值救崔,透明度不變
data[i] = average;
data[i+1] = average;
data[i+2] = average;
}
// 覆蓋原來的imgData.data的值
imgData.data = data;
ctx.putImageData(imgData,0,0);
- 15.2.11 合成
- 上下文的屬性:context.globalAlpha 設置透明度 1不透明 0透明 ;
canvas = document.getElementById("drawing");
context = canvas.getContext("2d");
context.globalAlpha = 0.5; // 設置全局上下文的透明度
context.fillStyle = "red";
context.fillRect(0,0, 300, 150); // 半透明紅色
context.fillStyle = "blue";
context.fillRect(100,100, 300, 150); // 半透明藍色
-
globalCompositionOperation屬性 表示后繪制的圖形怎樣與先繪制的圖形結合捏顺。這個屬性的值是字符串,可能的值如下纬黎。
- source-over(默認值):后繪制的圖形位于先繪制的圖形上方幅骄。
- source-in:后繪制的圖形與先繪制的圖形重疊的部分可見,兩者其他部分完全透明本今。
- source-out:后繪制的圖形與先繪制的圖形不重疊的部分可見拆座,先繪制的圖形完全透明。
- source-atop:后繪制的圖形與先繪制的圖形重疊的部分可見冠息,先繪制圖形不受影響挪凑。
- destination-over: 后繪制的圖形位于先繪制的圖形下方,只有之前透明像素下的部分才可見逛艰。
- destination-in:后繪制的圖形位于先繪制的圖形下方躏碳,兩者不重疊的部分完全透明。
- destination-out:后繪制的圖形擦除與先繪制的圖形重疊的部分散怖。
- destination-atop:后繪制的圖形位于先繪制的圖形下方菇绵,在兩者不重疊的地方,先繪制的圖形會變透明镇眷。
- lighter:后繪制的圖形與先繪制的圖形重疊部分的值相加咬最,使該部分變亮。
- copy:后繪制的圖形完全替代與之重疊的先繪制圖形欠动。
- xor:后繪制的圖形與先繪制的圖形重疊的部分執(zhí)行“異或”操作永乌。