本章主要知識(shí)點(diǎn):
- save() restore() 保存和恢復(fù)狀態(tài)
- translate(x, y), rotate(deg), scale(sx, sy)圖形變換
- transform(a, b, c, d, e, f), setTransform(a, b, c, d, e, f) 二維矩陣
圖形變換一般指translate, rotate, scale, transform等方法邀泉,對(duì)圖形進(jìn)行控制匾南。
通常繪制圖形一般會(huì)采用先繪制基本圖形,然后將基本圖形進(jìn)行圖形變換得到自己想要的效果。
1.重構(gòu)
上一章中講到繪制星星的圖形效果(星空效果)葛假,我們可以將其重構(gòu)為,先繪制基本輪廓窟社,然后再進(jìn)行圖形變換操作痊末。
重構(gòu)為:
// 繪制一個(gè)標(biāo)準(zhǔn)的星星
// 小圓半徑是大圓的1/2
function starPath(ctx) {
ctx.beginPath();
for (var i = 0; i < 5; i++) {
ctx.lineTo(
Math.cos((18 + i * 72 - rotation) / 180 * Math.PI),
-Math.sin((18 + i * 72 - rotation) / 180 * Math.PI)
);
ctx.lineTo(
Math.cos((54 + i * 72 - rotation) / 180 * Math.PI) * 0.5,
-Math.sin((54 + i * 72 - rotation) / 180 * Math.PI) * 0.5
);
}
ctx.closePath();
}
function drawStar(ctx, x, y, R, rotation) {
// 圖形變換操作
// 繪制基本輪廓
starPath(ctx);
}
2.translate, rotate, scale
- translate(x, y): 移動(dòng)圖形
- rotate(deg): 旋轉(zhuǎn)多大弧度
- scale(sx, sy): 縮放,要注意這個(gè)函數(shù)會(huì)產(chǎn)生副作用, 比如比例的平移检眯,或增加描邊的寬度等厘擂,使用時(shí)需要注意
值得注意的是: 圖形變換是疊加的,比如:
// 假設(shè)圖形原坐標(biāo)是(0锰瘸, 0)
ctx.translate(100, 100); // 移動(dòng)到(100刽严, 100)
ctx.fillRect(0, 0, 400, 400); // 繪制一個(gè)矩形
// 再次移動(dòng)
ctx.translate(200, 200);
# 此時(shí)的圖形坐標(biāo)變?yōu)?100+200, 100+200) => (300, 300)
ctx.fillRect(0, 0, 400, 400)
一般我們移動(dòng)繪制之后,再將其坐標(biāo)移回去:
ctx.translate(100, 100); // 移動(dòng)到(100避凝, 100)
ctx.fillRect(0, 0, 400, 400); // 繪制一個(gè)矩形
# 繪制之后移動(dòng)回去
ctx.translate(-100, -100);
// 再次移動(dòng)
ctx.translate(200, 200);
# 因?yàn)樯厦孢M(jìn)行了還原舞萄,此時(shí)的圖形坐標(biāo)為(200, 200)
ctx.fillRect(0, 0, 400, 400)
但是這樣做顯得很繁瑣,因此canvas有保存狀態(tài)管削,再恢復(fù)狀態(tài)的函數(shù)save(), restore()
3.save() | restore()
一般這2個(gè)函數(shù)成對(duì)出現(xiàn)
上面的例子可以寫(xiě)為:
# 先保存之前的狀態(tài)
ctx.save();
ctx.translate(100, 100); // (100, 100)
ctx.fillRect(0, 0, 400, 400);
# 恢復(fù)到保存的狀態(tài)
ctx.restore();
ctx.save();
ctx.translate(200, 200);
ctx.fillRect(0, 0, 400, 400);
ctx.restore()
4.完成星空
可以在1.重構(gòu) 的基礎(chǔ)上利用圖形變換完成星空?qǐng)D:
// 獲取隨機(jī)顏色
function getRandomColor() {
return '#' + ( '00000' + (Math.random() * 0x10000000<<2) ).toString(16).slice(-6);
}
function drawStar(ctx, x, y, R, rotation) {
ctx.save();
// 進(jìn)行圖形變換
ctx.translate(x, y);
ctx.rotate(rotation / 180 * Math.PI);
ctx.scale(R, R);
// 然后繪制基本的輪廓
starPath(ctx);
ctx.fillStyle = getRandomColor();
ctx.fill();
ctx.restore();
}
for (var i = 0; i < 100; i++) {
var ran = Math.random();
var x = ran * canvas.width;
# 這里有個(gè)技巧
# 想要得到畫(huà)布的65%倒脓,則添加一個(gè)系數(shù)0.65
var y = ran * canvas.height * 0.65;
var R = ran * 2 * 10;
var rotation = ran * 360;
drawStar(ctx, x, y, R, rotation);
}
tips: 想要得到星星分布在畫(huà)布高度的65%佩谣,則添加一個(gè)系數(shù)0.65
具體效果:圖形變換繪制星空
5.transform 變換矩陣
圖形學(xué)變換矩陣是都頂點(diǎn)坐標(biāo)進(jìn)行重計(jì)算的一種方式把还,對(duì)于二維系統(tǒng),則是 3x3 的矩陣茸俭,對(duì)于三維系統(tǒng)則是 4x4 的矩陣吊履。
對(duì)于3x3 的矩陣:
其中 a, c, b, d 負(fù)責(zé)對(duì)圖形進(jìn)行scale, rotate, 對(duì)稱(chēng),skew 等變換调鬓, a, d負(fù)責(zé)圖形的縮放scale, e, f 負(fù)責(zé)對(duì)圖形進(jìn)行平移(translate)變換艇炎。第3行也可以進(jìn)行其他操作,二維矩陣 詳情腾窝。
對(duì)上圖中的默認(rèn)值情況缀踪,即不進(jìn)行變換時(shí),該矩陣為單位矩陣虹脯。
對(duì)于transform函數(shù):
transform(a, b, c, d, e, f)
所有:
translate(100, 100) =>
transform(1, 0, 0, 1, 100, 100)
# a為-1驴娃, 則產(chǎn)生對(duì)Y軸的鏡像效果
transform(-1, 0, 0, 1, 0, 0)
# 當(dāng)然d的值為負(fù)數(shù),則可以產(chǎn)生對(duì)x軸的鏡像翻轉(zhuǎn)效果
scale(1.5, 1.5) =>
transform(1.5, 0, 0, 1.5, 0, 0)
skew則改變b, c的值 =>
transform(1, 0.2, 0, 1, 0, 0)
setTransform()
同樣循集,transform操作是疊加的唇敞,我們可以使用setTransform來(lái)設(shè)置變換效果,使之前的transform失效:
ctx.save()
ctx.transform(1, 0, 0, 1, 50, 100)
ctx.transform(2, 0, 0, 1.5, 0, 0)
# 使上面的transform失效咒彤,得到新的transform效果
ctx.setTransform(1, 0, 0, 1, 100, 100)
總結(jié)
本章的知識(shí)和css中的基礎(chǔ)知識(shí)類(lèi)似疆柔,學(xué)起來(lái)也比較容易理解,對(duì)于二維矩陣則需要多花功夫去了解镶柱。