#3 圖像變換

本章主要知識點:

  1. save() restore() 保存和恢復狀態(tài)
  2. translate(x, y), rotate(deg), scale(sx, sy)圖形變換
  3. transform(a, b, c, d, e, f), setTransform(a, b, c, d, e, f) 二維矩陣

圖形變換一般指translate, rotate, scale, transform等方法,對圖形進行控制。

通常繪制圖形一般會采用先繪制基本圖形,然后將基本圖形進行圖形變換得到自己想要的效果。

1.重構

上一章中講到繪制星星的圖形效果(星空效果),我們可以將其重構為,先繪制基本輪廓,然后再進行圖形變換操作。

重構為:

// 繪制一個標準的星星
// 小圓半徑是大圓的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): 移動圖形
  • rotate(deg): 旋轉多大弧度
  • scale(sx, sy): 縮放,要注意這個函數會產生副作用, 比如比例的平移,或增加描邊的寬度等,使用時需要注意

值得注意的是: 圖形變換是疊加的,比如:

// 假設圖形原坐標是(0, 0)
ctx.translate(100, 100); // 移動到(100, 100)
ctx.fillRect(0, 0, 400, 400); // 繪制一個矩形

// 再次移動
ctx.translate(200, 200);
# 此時的圖形坐標變?yōu)?100+200, 100+200) => (300, 300)
ctx.fillRect(0, 0, 400, 400)

一般我們移動繪制之后,再將其坐標移回去:

ctx.translate(100, 100); // 移動到(100, 100)
ctx.fillRect(0, 0, 400, 400); // 繪制一個矩形
# 繪制之后移動回去
ctx.translate(-100, -100);

// 再次移動
ctx.translate(200, 200);
# 因為上面進行了還原,此時的圖形坐標為(200, 200)
ctx.fillRect(0, 0, 400, 400)

但是這樣做顯得很繁瑣,因此canvas有保存狀態(tài),再恢復狀態(tài)的函數save(), restore()

3.save() | restore()

一般這2個函數成對出現

上面的例子可以寫為:

# 先保存之前的狀態(tài)
ctx.save();
ctx.translate(100, 100); // (100, 100)
ctx.fillRect(0, 0, 400, 400);
# 恢復到保存的狀態(tài)
ctx.restore();

ctx.save();
ctx.translate(200, 200);
ctx.fillRect(0, 0, 400, 400);
ctx.restore()

4.完成星空

可以在1.重構 的基礎上利用圖形變換完成星空圖:

// 獲取隨機顏色
function getRandomColor() {
  return '#' + ( '00000' + (Math.random() * 0x10000000<<2) ).toString(16).slice(-6);
}

function drawStar(ctx, x, y, R, rotation) {
  ctx.save();

  // 進行圖形變換
  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;
  # 這里有個技巧
  # 想要得到畫布的65%,則添加一個系數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: 想要得到星星分布在畫布高度的65%,則添加一個系數0.65

具體效果:圖形變換繪制星空

5.transform 變換矩陣

圖形學變換矩陣是都頂點坐標進行重計算的一種方式,對于二維系統,則是 3x3 的矩陣,對于三維系統則是 4x4 的矩陣。

對于3x3 的矩陣:

其中 a, c, b, d 負責對圖形進行scale, rotate, 對稱,skew 等變換, a, d負責圖形的縮放scale, e, f 負責對圖形進行平移(translate)變換。第3行也可以進行其他操作,二維矩陣 詳情。

對上圖中的默認值情況,即不進行變換時,該矩陣為單位矩陣。

對于transform函數:

transform(a, b, c, d, e, f)

所有:

translate(100, 100) =>
transform(1, 0, 0, 1, 100, 100)

# a為-1, 則產生對Y軸的鏡像效果
transform(-1, 0, 0, 1, 0, 0)
# 當然d的值為負數,則可以產生對x軸的鏡像翻轉效果


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來設置變換效果,使之前的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)

總結

本章的知識和css中的基礎知識類似,學起來也比較容易理解,對于二維矩陣則需要多花功夫去了解。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • >*很不幸,沒人能告訴你母體是什么,你只能自己體會* --駭客帝國 在第四章“可視效果”中,我們研究了一些增強圖層...
    夜空下最亮的亮點閱讀 1,731評論 0 2
  • Transform字面上就是變形,改變的意思。在CSS3中transform主要包括以下幾種:旋轉rotate、扭...
    hzrWeber閱讀 22,257評論 0 19
  • byzhangxinxufromhttp://www.zhangxinxu.com 本文地址:http://www...
    凌雲木閱讀 7,431評論 0 8
  • 看了很多視頻、文章,最后卻通通忘記了,別人的知識依舊是別人的,自己卻什么都沒獲得。此系列文章旨在加深自己的印象,因...
    DCbryant閱讀 1,980評論 0 4
  • 之前看到很多關于小朋友入園年齡的討論,這個不能一概而論,要因人而異。我家寶貝是兩歲八個月入園的,今年9月4號入園的...
    27ebdf2ac0e0閱讀 529評論 0 0

友情鏈接更多精彩內容