初識canvas(二)
上節文章中,給大家分享了canvas
最基礎的用法,包括繪製線條、控制渲染方式、繪製圖形、作用域、新增陰影、清理、剪下等功能,本節將繼續為大家分享canvas
的基礎用法,同時也是最後一節基礎知識分享,之後的內容,我們將會進入到對webgl
的分享中。
1. 文字繪製
首先我們要提到的是繪製文字,在canvas
的開發過程中,文字的內容是肯定會存在的。本小節就來給大家分享下如何渲染文字。
1.1 繪製空心和實心文字
canvas
中提供了兩種繪製文字的方法,分別是繪製實心文字和空心文字,它們的方法分別是:
- strokeText(text, x, y, maxWidth): 繪製空心文字
- fillText(text, x, y, maxWidth): 繪製實心文字
引數介紹:
- text: 要繪製的文字內容
x, y
: 座標點,文字左上角的座標點- maxWidth: 允許渲染的最大畫素寬度
栗子:
// 繪製實心文字
c.fillText('hello world', 100, 100); // 將 hello world 這個內容從 100 100 這個點開始渲染。
// 繪製空心文字
c.strokeText('hello world', 200, 200);
如果這裡你的字型是預設大小,可能會看不到空心效果。改變字型大小在下文中有分享到。
1.2 改變文字樣式
如果我們想修改字型的顏色,可以根據 繪製圖形 一節中的方法,使用 strokeStyle、fillStyle
1. 要設定實心文字字型為藍色
c.fillStyle = 'blue';
c.fillText('hello world', 100, 100);
2. 要設定空心字型為紅色
c.strokeStyle = 'yellow';
c.strokeText('hello world', 200, 200);
1.3 改變文字大小和字型樣式
修改字型大小和字型樣式需要用到 font = '字型大小 字型樣式’
屬性。
如:把字型改為 宋體 40px。
c.font = '40px 宋體';
如果是特殊的字型,會出現不支援的現象。
1.4 修改文字對齊方式
文字對齊方式分為 垂直 和 水平 對齊方式。
1. 垂直方向對齊。
這裡需要用到 textBaseLine
這個屬性。意為按照基線對齊。它有6個值,分別是:
- alphabetic: 預設值,意為普通的字母基線。可理解為四線三格的第三條線。
- top:文字頭部對齊基線
- hanging:懸掛基線,與top稍有不同
- middle:文字中部對齊
- ideographic:表意基線。稍難理解,可看示意圖
- bottom:文字底部對齊基線
示例:
// 首先我們畫一條基準線,讓文字按照這條線對齊
c.strokeStyle = 'blue';
c.moveTo(5, 100);
c.lineTo(700, 100);
c.stroke();
c.font = '20px 宋體';
// 列舉可用的對齊方式。
c.textBaseline = 'top';
c.fillText('Top', 5, 100);
c.textBaseline = 'bottom';
c.fillText('Bottom', 100, 100);
c.textBaseline = 'middle';
c.fillText('Middle', 200, 100);
c.textBaseline = 'alphabetic';
c.fillText('Alphabetic', 300, 100);
c.textBaseline = 'hanging';
c.fillText('Hanging', 400, 100);
c.textBaseline = 'ideographic';
c.fillText('ideographic', 500, 100);
示例圖:
2. 水平居中
水平居中需要使用 textAlign
屬性。同樣也是基於基準線對齊,有5個屬性值。
- start: 預設。文字在指定的位置開始。
- end: 在指定的位置結束
- center: 文字中心被放在指定位置
- left: 文字左對齊
- right: 文字右對齊
栗子:
// 建立基準線
c.strokeStyle = 'blue';
c.moveTo(150, 20);
c.lineTo(150, 400);
c.stroke();
c.font = '30px 宋體';
// 列舉可用的對齊方式。
c.textAlign = 'start';
c.fillText('start', 150, 50);
c.textAlign = 'end';
c.fillText('end', 150, 100);
c.textAlign = 'left';
c.fillText('left', 150, 150);
c.textAlign = 'center';
c.fillText('center', 150, 200);
c.textAlign = 'right';
c.fillText('right', 150, 250);
示例圖:
3. 不固定寬高的畫布水平居中
對於寬度不固定的畫布,我們使用 textAlign
的作用就不太大了。因為此時我們需要根據畫布的寬度進行實時計算。此時我們需要獲得兩個數值。畫布寬度和字型寬度。畫布寬度比較簡單,使用 ctx.width
就可以獲取。
字型的寬度。需要用到 measureText(text)
方法。此方法可根據你設定的字型大小來返回傳入文字的畫素寬度。
栗子:
c.font = '20px 宋體'
const textData = c.measureText('hello world');
console.log(textData.width) // 84
設定字型寬度為 20px
,則渲染後的 hello world
佔據的畫素寬度為 84px
(不同瀏覽器之間會有差異)
這樣我們就可以得到水平居中的計算方式
文字x座標 = (畫布寬 - 文字寬)/ 2
const x = (ctx.width - c.measureText('hello world')) / 2;
2. 動畫
2.1 狀態儲存與恢復
分享動畫之前 ,我們先來介紹 save 和 restore
這兩個方法。因為我們在處理動畫的過程中,避免不了對畫布進行旋轉、平移和縮放的操作。從而導致之前或之後的繪製出現錯亂。而``save 和 restore` 這兩個方法就可以避免這個問題。
-
save
: 儲存當前canvas
的狀態。 -
restore
: 恢復之前儲存的狀態。
2.2 變換
說到動畫,無非就是對圖形的旋轉、縮放、平移這幾項內容。canvas
中提供了一系列的方法。
- translate(x, y): 平移。可改變當前畫布的原點位置。
- rotate(deg) :旋轉。其中 deg 代表的是弧度制。(角度轉弧度請看初始canvas(一)的內容)
- scale(x,y): 縮放,
x
代表x軸縮放。y
代表y軸縮放。
栗子:
// 原始矩形
c.save()
c.fillRect(10, 10, 100, 100);
c.restore()
// 平移50px
c.save()
c.translate(50, 50);
c.fillRect(10,10,100,100);
c.restore()
// 旋轉45度
c.save()
c.rotate(45 * Math.PI / 180);
c.fillRect(210, 110, 100, 100)
c.restore()
// x軸縮放0.5 y軸縮放1.1
c.save()
c.scale(0.5, 1.1)
c.fillRect(410, 210, 100, 100)
c.restore()
注意:translate
平移之後是可以改變畫布原點的位置的,此時如果我們需要讓某個圖形圍繞自身旋轉,則需要將影象的中心點位於畫布圓點上。如下方程式碼所示:
// 將畫布中心移入到 50,50 這個點
c.translate(50, 50);
setInterval(() => {
// 每次繪製之前先清空畫布,這裡的原點已經在50,50這個位置了。所以需要從 -50這裡開始清理。
c.clearRect(-50, -50, ctx.width, ctx.height);
// 每次旋轉 1 度
c.rotate(Math.PI / 180);
// 繪製實心矩形。
c.fillRect(-25,-25, 50,50);
}, 16)
這裡就可以得到一個圍繞自身旋轉的實心矩形。
2.3 transform 矩陣操作
方法接收 6
個引數。transform(a,b,c,d,e,f)
其中,
-
平移:涉及到
e, f
兩個引數 -
縮放:涉及到
a, d
兩個引數 -
拉伸:涉及到
b, c
兩個引數 -
旋轉:涉及到
a, b, c, d
四個引數
此方法在後續的講解中還會出現,並且方法不太好理解,這裡只簡單說明。不做過多介紹。
3. 漸變
本小節來說下如何給圖形新增漸變色。漸變色也是我們經常可以用到的功能。新增漸變色我們需要用到下面這兩個方法
- createLinearGradient(sx,sy,ex,ey) 經向漸變
- createRadialGradient (sx,sy,sr,ex,ey,er) 環形漸變
sx, sy, sr
代表的是起始點漸變圓的原點座標和半徑,ex, ey, er
代表的是終止點漸變圓的原點座標和半徑。漸變方法返回一個物件。我們可以使用這個返回物件的 addColorStop(position, color)
方法 執行新增顏色的操作。
position
表示漸變的百分比,也就是漸變的位置。值是0-1
之間的浮點數。
color
是要新增的顏色
下面,我們通過一個栗子來看下如何建立漸變圖形。
栗子1 -- 徑向漸變:
// 建立徑向漸變,得到漸變物件。
const lg = c.createLinearGradient(10, 10, 200, 200);
// 通過漸變物件來新增顏色
lg.addColorStop(0,"black");
lg.addColorStop(1, 'orange');
// 將得到的漸變色新增到填充樣式中。
c.fillStyle = lg;
c.fillRect(100, 100, 200, 200);
栗子2 -- 環形漸變:
// 起始點和終止點圓心座標相同,代表從同一點開始散發
const lg = c.createRadialGradient(150, 100, 5, 150, 100, 100);
lg.addColorStop(0,"black");
lg.addColorStop(1, 'orange');
c.fillStyle = lg;
c.arc(150, 100, 100, 0, 2 * Math.PI);
c.fill();
漸變示意圖:
4. 源目標和透明度
4.1 透明度設定
對於透明度設定我們只需要知道一個屬性就可以。
- globalAlpha = value:
value
的取值範圍在0-1
之間。代表當前畫布的透明度是多少。
4.2 源目標設定
源與目標設定我們需要用到 globalCompositeOperation
這個屬性,它有N
個屬性值。這裡我們就不一一介紹了,這裡我們先繪製一個紅色的矩形,再繪製一個藍色的矩形,然後我們來看下設定不同的globalCompositeOperation
會出現什麼情況。
圖解:
有需要的話可根據上圖進行篩查,看下自己需要哪種效果。對應設定。
5. 圖片繪製和背景設定
5.1 圖片繪製
對於圖片的操作在日常的工作中肯定會經常用到。canvas
中也提供了對於圖片操作的方法供開發人員使用。
注意:
在載入圖片的時候,一定要確保的是要在圖片載入完成之後再新增到畫布中。因此可以給圖片使用onload事件。
如:
const image = new Image();
image.onload = function () {
// 繪製圖片操作
}
image.src = '圖片連結';
接下來繪製圖片的方法預設都是存在於 onload
事件中的。
drawImage
可接收3,5,9
個引數;- 三個引數
(img,x,y)
img
是圖片物件,x,y
是圖片在畫布中的原點位置
- 五個引數
(img,x,y,imageWidth,imageHeight)
;- 前三個引數不變,
imageWidth,imageHeight
設定的是圖片的寬和高
- 前三個引數不變,
- 九個引數
(img,x,y,imageWidth,imageHeight,imgx,imgy,imgw,imgh)
;- 前五個引數不改變,
imgx,imgy
表示從圖片的這個點開始取畫素。imgw,imgh
表示的是取多寬多高的畫素。
- 前五個引數不改變,
- 三個引數
5.2 背景設定
通過createPattern(image, repetition)
可以為畫布設定背景影象。
其中, image
代表的是圖片物件。repetition
代表的是是否平鋪,repeat:平鋪, no-repeat:不平鋪
6. 畫素操作
canvas
最引入注目的功能就是對於畫素點的操作。這個功能可以讓我們實現眾多絢麗的特效。希望小夥伴們在領悟了畫素操作的真諦之後,也能做出絢麗的特效。這個我們也成為粒子效果;
對於畫素操作,canvas
中提供了三個方法。
getImageData(x,y,w,h)
: 獲取畫布中指定位置的畫素集合 前兩個引數是你想要獲取的原點位置,後兩個引數是你想要獲取的範圍putImageData(data, x,y)
: 設定畫布中指定位置的畫素集合,前兩個引數是你想要設定的原點位置createImageData(data)
: 直接生成新的畫素矩陣,不用獲取
栗子:
const data = c.getImageData(0, 0, 10, 10);
console.log(data);
/*
[
[1,2,3,4,5,6,7,8,9,10……],
…………
]
*/
這裡我們通過 getImageData
可以獲取到一個二維陣列,代表獲取到的點點陣圖。
陣列中,每四個元素是一組。分別代表 r,g,b,a
中的每一項。每個r,g,b
元素的取值範圍為 0-255
,a
的取值範圍為0-1
;
如果我們想對畫素做操作,那就修改這些值,如圖片取反、復古風、底片…………等等,都可以實現。
有興趣的小夥伴可以探討一下喲~
7. 曲線
arcTo(startx, starty, endx, endy, r)
- 此方法可以讓我們建立弧形線條。
startx, starty
表示弧的起始點。endx, endy
表示弧的終點。r
表示你弧的半徑。
- 此方法可以讓我們建立弧形線條。
示例:
c.beginPath()
c.moveTo(20,20);
c.lineTo(100,20);
c.arcTo(150,20,150,70,10); // 建立弧
c.lineTo(150,120);
c.stroke()
quadraticCurveTo(cox, coy, endx, endy)
二次貝塞爾曲線- 貝塞爾曲線可以幫我們獲得更加多變的曲線內容。
cox, coy
表示控制點座標。endx, endy
表示結束點座標。
- 貝塞爾曲線可以幫我們獲得更加多變的曲線內容。
示例:
c.beginPath()
c.moveTo(20,20);
// 將控制點設定線上段中間,
c.quadraticCurveTo(60, 80, 100, 20)
c.stroke()
示例圖:
除了這兩種曲線,還有三次貝塞爾曲線。小夥伴們可以自己試驗下,與二次貝塞爾曲線不同的是添加了一組控制點。
8. 事件
作為canvas
中唯二的兩個可以獲取到當前圖形資訊的事件。isPointInPath和isPointInStroke
的作用不可小覷。在很多針對圖形的操作我們都需要用到這個方法。
方法也是比較簡單。
isPointInPath(x, y)
接收兩個引數,一個x座標
一個y座標
,判斷當前座標是否在圖形之內。isPointInStroke(x, y)
接收兩個引數,一個x座標
一個y座標
,判斷當前座標是否在空心圖形邊框上。
9. 將canvas轉換為圖片 -- toDataURL
最後一個來分享下如何將我們繪製好的圖形儲存下來。對之後的分享自己繪製的圖形,在其他內容上顯示等等等等,都可以用到。
將canvas
轉換為圖片,我們需要用到 toDataURL(type, encoderOptions)
,
type
可以設定我們想得到的型別。如: image/png、image/jpg…………
encoderOptions
可以設定圖片的質量。
栗子:
const url = ctx.toDataURL('image/png')
console.log(url); // data:image/png;base64,……………………
注意:
這裡我們是使用的 ctx
來轉換圖片,也就是使用 canvas
這個標籤物件來轉換。
到這裡我們對於 canvas
的基礎內容就分享完了,從下節開始,我們就要進入到對 webgl
的學習中了。
好了,今天的分享就到這裡了,Bye~