Canvas繪圖(一)
HTML5 Canvas是使用強(qiáng)大的繪圖缕允、著色、基本二維形狀變換為基礎(chǔ)的蹭越,然后可供選擇的內(nèi)建形狀不是很多障本,本章將學(xué)習(xí)以下技巧:
- 矩形
- Canvas狀態(tài)保留
- 使用路徑繪制線段
- 圓弧
一、矩形
最原始的Canvas內(nèi)建幾何形狀——矩形响鹃,繪制基本矩形有三種不同的方式
實(shí)現(xiàn)方式 | 接口 | 說明 |
---|---|---|
填充 | fillRect(x,y,width,height) | 在位置(x,y)除以寬高width驾霜、heigth繪制一個填充的矩形 |
描邊 | strokeRect(x,y,width,height) | ...繪制一個矩形邊框,它需要使用當(dāng)前strokeStyle买置、lineWidth粪糙、linJoin以及miterLimit設(shè)置 |
清除 | clearRect(x,y,width,height) | ...清除指定區(qū)域并使其完全透明(使用透明黑) |
使用以上方法時,需要先設(shè)置好Canvas繪圖所需要填充或描邊的樣式
- fillStyle : 填充的顏色
- strokeStyle : 描邊的顏色
例如忿项,繪制一個基本矩形 :
drawRectangle() {
this.context.fillStyle = "#000000";
this.context.strockStyle = "#66ccff";
this.context.lineWidth = 2;
this.context.fillRect(10, 10, 40, 40);
this.context.strokeRect(0, 0, 60, 60);
this.context.clearRect(20, 20, 20, 20);
}
二蓉冈、Canvas狀態(tài)
在Canvas環(huán)境中繪圖時,可以利用所謂的繪圖堆棧狀態(tài)轩触。該堆棧狀態(tài)隨時存儲上下文數(shù)據(jù)寞酿,下面是存儲在狀態(tài)堆棧中的數(shù)據(jù)列表
- 變化矩陣信息,例如旋轉(zhuǎn)與平移使用的
context.rotate
方法和context.setTransfrom
方法 - 當(dāng)前的剪貼區(qū)域
- 畫布屬性的當(dāng)前值
包括 :
- globalAlpha
- globalCommpositeOperation
- strokeStyle
- textAlign脱柱、textBaseline
- lineCap伐弹、LineJoin、lineWidth褐捻、miterLimit
- fillStyle
- font
- shadowBlur掸茅、shawdowColor椅邓、shadowOffsetX柠逞、shadowOffsetY
那有什么不屬于狀態(tài)的?
- 當(dāng)前路徑
- 當(dāng)前位圖
保存和恢復(fù)Canvas狀態(tài)
// 保存當(dāng)前狀態(tài)到堆棧景馁,調(diào)用下面函數(shù)
context.save()
// 調(diào)出最后存儲的堆棸遄常恢復(fù)畫布
context.restore()
三、使用路徑繪制線段
路徑可以用在畫布上繪制任何形狀合住,路徑就是一系列的點(diǎn)和這些點(diǎn)之間的連線绰精,Canvas環(huán)境只能有一個當(dāng)前路徑赃泡,當(dāng)調(diào)用context.save()
時传藏,不會將它存儲為當(dāng)前繪圖狀態(tài)的一部分拉队。我們需要熟悉以下方法
A. 設(shè)置路徑的開始與結(jié)束
- beginPath() : 開始一個路徑
- closePath() : 結(jié)束一個路徑
B. 動態(tài)繪圖
- moveTo(x,y) : 將路徑移動到位置(x,y)處
- lineTo(x,y) : 從起點(diǎn)到目標(biāo)位置(x,y)處連接一條線
- stroke() : 畫出構(gòu)建的路徑
另外我們需要熟悉以下屬性 :
- lineCap : 上下文中線的端點(diǎn)挣输,可以有三個值辰企。屬性如下
- lineJoin : 定義兩條線相交的拐角禽绪,可以稱為連接制跟,在連接處創(chuàng)建一個填充三角形骆莹,可以使用lineJoin設(shè)置的屬性。屬性如下
- lineWidth : 定義線寬
- strokeStyle : 定義線的形狀邊框以及顏色和樣式
屬性 | 取值 |
---|---|
lineCap | butt(默認(rèn)) : 端點(diǎn)垂直于線段邊緣的平直邊緣<br />round:端點(diǎn)以線寬為半徑的半圓 square : 端點(diǎn)是選段邊緣處以線寬為長靶草、以一半線寬為寬的矩形 |
lineJoin | miter : 默認(rèn)值蹄胰,在連接外邊緣處延長詳解,miterLimit是角長和線寬所允許的最大比例(默認(rèn)10) bevel : 連接處是一個對角線斜角 round : 連接處是一個圓 |
例如 :
drawLine() {
this.context.strokeStyle = "#000000";
this.context.lineWidth = 10;
this.context.lineCap = "square";
this.context.beginPath();
this.context.moveTo(20, 50);
this.context.lineTo(100, 50);
this.context.stroke();
this.context.closePath();
}
C. 繪制問題
在畫布上繪制線段時奕翔,會有一些奇怪的現(xiàn)象發(fā)生例如 :
drawQuestion() {
// 實(shí)例1 : 圓形端點(diǎn)裕寨,斜角連接,在畫布左上角
this.context.strokeStyle = '#000000'
this.context.lineWidth = 10
this.context.lineJoin = 'bevel' // 連接處是一個對角線斜角
this.context.lineCap = 'round' // 端點(diǎn)為圓角
this.context.beginPath()
this.context.moveTo(0,0)
this.context.lineTo(25,0)
this.context.lineTo(25,25)
this.context.stroke()
this.context.closePath()
// 實(shí)例2 : 圓形端點(diǎn)派继,斜角連接宾袜,不在畫布左上角
this.context.beginPath()
this.context.moveTo(10,50)
this.context.lineTo(35,50)
this.context.lineTo(35,75)
this.context.stroke()
this.context.closePath()
// 實(shí)例3 : 平直端點(diǎn),圓形連接互艾,不在畫布左上角
this.context.lineJoin = 'round' // 連接處是一個圓
this.context.lineCap = 'buff' // 端點(diǎn)垂直于線段邊緣的平直邊緣
this.context.beginPath()
this.context.moveTo(10,100)
this.context.lineTo(35,100)
this.context.lineTo(35,125)
this.context.stroke()
this.context.closePath()
}
你會發(fā)現(xiàn)有以下問題 :
- 第一個圖形由于繪制起點(diǎn)在左上角试和,所以上面的線段繪制到了畫布的外側(cè),由于這個原因纫普,第一個例子上面看上去要比10像素要細(xì)
- 例子2調(diào)整了坐標(biāo)阅悍,所以繪制的圖形沒有問題
- 例子3顯示了默認(rèn)端點(diǎn)的效果,并將連接處設(shè)置為圓角
四昨稼、高級路徑
這一節(jié)討論其他繪制路徑的方法节视,例如弧線曲線、以及組合復(fù)雜的圖像假栓。
A. 弧線
有以下幾種方式繪制弧線與曲線寻行,弧線可以是一個整圓,也可使圓的一部分
a. context.arc()
接口 | 說明 |
---|---|
context.arc (x,y,radius,startAngle,endAngle,anticlockwise) |
x匾荆、y : 定義圓心位置 radius定義弧線半徑 startAngle和endAngle使用弧度值而不是角度值拌蜘。 anticlockwise的值可以為true或者false,用于定義弧線的方向 |
drawArc() {
this.context.beginPath();
this.context.strokeStyle = "black";
this.context.lineWidth = 5;
this.context.arc(
100,
100,
20,
(Math.PI / 180) * 0,
(Math.PI / 180) * 360,
false
);
this.context.stroke()
this.context.closePath()
}
弧度 : 在數(shù)學(xué)和物理中牙丽,弧度是角的度量單位简卧。他的單位縮寫是rad。一周是360度烤芦,也就是2弧度
如果我們不以 0 和 360為起點(diǎn)與結(jié)束點(diǎn)举娩,那么可以繪制一段圓弧,例如下面這段代碼构罗,按照順時針畫 個圓铜涉。
this.context.arc(
100,
100,
20,
(Math.PI / 180) * 0,
(Math.PI / 180) * 90,
false
);
b. context.arcTo()
接口 | 說明 |
---|---|
context.arcTo(x1,y1,x2,y2,radius) | 以給定的半徑繪制一條弧線,圓弧的起點(diǎn)與當(dāng)前路徑的位置到(x1,y1)直線相切遂唧,圓弧的終點(diǎn)與(x1,y1)到(x2,y2)的直線相切 |
drawArcTo() {
this.context.beginPath();
this.context.moveTo(100, 200);
this.context.arcTo(350, 350, 100, 100, 20);
this.context.stroke();
this.context.closePath();
this.context.fillRect(350, 350, 10, 10);
this.context.fillRect(100, 100, 10, 10);
}
arcTo與acr雖然名字相似芙代,但是入?yún)s千差萬別,arcTo(x1,y1,x2,y2,radius)盖彭,它的使用前提是當(dāng)前路徑至少有一個子路徑纹烹,它的表現(xiàn)形式是從當(dāng)前上下文坐標(biāo)事甜,到(x1,y1)位置連接(比喻),然后再從(x1,y1)位置連接到(x2,y2)滔韵,這使得它們之間存在一個夾角逻谦,canvas根據(jù)半徑在該夾角選擇合適的位置繪制圓弧,并連接(x0,y0)與起點(diǎn)陪蜻。當(dāng)半徑越大邦马,圓弧的起點(diǎn)離(x0,y0)越近,當(dāng)半徑超過了一定大小宴卖,則會有以下表現(xiàn)滋将。
this.context.arcTo(350, 350, 100, 100, 50);
c. 貝塞爾曲線
貝塞爾曲線遠(yuǎn)比弧線靈活,他有立方和平方兩種形式
- context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)
- context.quadraticCurveTo(cpx,cpy,x,y)
在二維空間中症昏,貝塞爾曲線通過起點(diǎn)随闽、終點(diǎn)以及兩個決定曲線走向的控制點(diǎn)完成,而
- 立方貝塞爾曲線使用兩個點(diǎn)
- 平方貝塞爾曲線使用一個點(diǎn)
以下使用平方貝塞爾曲線畫一條弧線肝谭。
drawQuadraticCurveTo() {
this.context.beginPath();
this.context.moveTo(100, 100);
this.context.quadraticCurveTo(100, 25, 20, 50);
this.context.stroke();
this.context.closePath();
this.context.fillRect(100,25,10,10)
this.context.fillRect(20,50,10,10)
this.context.fillRect(100,100,10,10)
}
這條弧線從(100,100)開始掘宪,到(20,50)結(jié)束,而(100,25)這個點(diǎn)是圓弧的圓心(即控制點(diǎn))攘烛,它可以通過調(diào)整從而拉長或縮短圓弧魏滚。
以下使用立方貝塞爾曲線畫一個S弧線
drawBezierCurveTo() {
this.context.beginPath();
this.context.moveTo(100, 100);
this.context.bezierCurveTo(50, 150, 150, 250,100,300);
this.context.stroke();
this.context.closePath();
}