HTML5 Canvas (5) - 變形

HTML 5 canvas

HTML5 Canvas 變形。

9. 變形

9.1 轉換

對 translate 方法輸入位移值。下圖中灰色方塊位於座標(0,0),綠色方塊則是將座標位移到畫布正中。 程式碼如下:
var x = 0;
var y = 0;
var rW = 100;
var rH = 100;

//原點在畫布的左上角
context.beginPath();
context.fillStyle = "grey";
context.fillRect(x, y, rW, rH);

//將原點位移到畫布正中
context.beginPath();
context.translate(canvas.width / 2, canvas.height / 2);
context.fillStyle = "green";
context.fillRect(x, y , rW, rH);

9.2 比例縮放

對 scale 方法輸入縮放值達到縮放,值1等於原尺寸不縮放,小於1是縮小,大於1則放大。 程式碼如下:
var rW = 100;
var rH = 100;
var x = -rW / 2;
var y = -rH / 2;

context.beginPath();
context.translate(canvas.width / 2, canvas.height / 2);
context.scale(0.2, 2);
context.fillStyle = "gold";
context.fillRect(x, y , rW, rH);
利用scale還能做到鏡像效果,只要輸入的值是負的,圖像就會變成相反。下面做了一個簡單的文字倒影效果。 程式碼如下:
var rW = 100;
var rH = 100;
var x = -rW / 2;
var y = -rH / 2;
var text = "Mirror";

context.translate(canvas.width / 2, canvas.height / 2);

//文字
context.beginPath();
context.font = "50px Tahoma";
context.textAlign = "center";
context.textBaseline = "bottom";
context.fillText(text, 0, 0);

//鏡像
context.beginPath();
context.scale(1, -1);
context.font = "50px Tahoma";
context.fillStyle = "#c0c0c0";
context.textAlign = "center";
context.textBaseline = "bottom";
context.fillText(text, 0, 19);

9.3 旋轉

使用rotate方法並輸入弧度。下圖中,淺藍是不旋轉的原本樣子,深藍則是轉90度。 程式碼如下:
var rW = 100;
var rH = 200;
var x = -rW / 2;
var y = -rH / 2;
//轉90度
var radians = Math.PI / 2;

context.translate(canvas.width / 2, canvas.height / 2);

//不旋轉
context.beginPath();
context.fillStyle = "#ADD8E6";
context.fillRect(x, y , rW, rH);

//轉90度
context.beginPath();
context.rotate(radians);
context.fillStyle = "#357EC7";
context.fillRect(x, y , rW, rH);

9.4 扭曲

這裡必須利用數學矩陣,我們只要知道幾個矩陣中的值的涵意,就能夠使用了。 這張圖的原圖是從 wiki 的Transformation matrix找來的,我加了下面的紅字部份,只要知道這6個位置的涵意即可做到自訂變形。這6個數字會輸入 transfrom 方法中。
context.transform(a, b, c, d, e, f);
下圖中,灰色方塊為原圖,紅色方塊的起點位移到畫布正中,綠色方塊則以紅色方塊的座標為原點做水平位移,並且做Y軸的傾斜。 程式碼如下:
var rW = 50;
var rH = 50;
var x = 0;
var y = 0;

//(灰)原圖
context.beginPath();
context.fillStyle = "#808080";
context.fillRect(x, y , rW, rH);

//(紅)改變tx,ty的做法如同translate方法
var tx = canvas.width / 2;
var ty = canvas.height / 2;
context.beginPath();
context.transform(1, 0, 0 , 1, tx, ty);
context.fillStyle = "#A52A2A";
context.fillRect(x, y, rW, rH);

//(綠)對y軸做傾斜
tx = 60;
ty = 0;
var sx = 0;
var sy = 0.5;

context.beginPath();
context.transform(1, sy, sx , 1, tx, ty);
context.fillStyle = "#008000";
context.fillRect(x, y, rW, rH);
這個範例中,綠色方塊的座標受到紅色方塊使用transform的影響,所以出現在紅色方塊旁邊,我們可以使用setTransform方法把轉變效果歸零,讓下一個物件不會受到上一個物件變形的影響。只要在下一個物件之前使用
context.setTransform(1, 0, 0, 1, 0, 0);
就會把變形效果歸回原值。觀察之前的那個矩陣公式就可瞭解。

9.5 狀態的儲存及恢復

變形的效果可以儲存成狀態,之後可以恢復成該狀態。狀態的儲存方式採用堆疊的方式,也就是最先儲存的,最後才能取回。儲存狀態使用save方法,恢復狀態則使用restore方法。

下圖中,依序儲存了3個狀態,紅色方塊套用到全部的變形;藍色則因為恢復到前一狀態,而少了旋轉;綠色方塊則又少了放大效果;黃色方塊則是最原始的狀態無任何效果。 程式碼如下:
var rW = 50;
var rH = 50;
var x = 0;
var y = 0;
var radians = Math.PI / 4;

//儲存狀態:1 - 無任何效果
context.save();

//儲存狀態:2 - 位移
context.translate(x+71, y);
context.save();

//儲存狀態:3 - 放大
context.scale(2, 2);
context.save();

//旋轉
context.rotate(radians);

//(紅)套用效果:位移,放大,旋轉
context.fillStyle = "red";
context.fillRect(x, y, rW, rH);

//恢復到最後一次的狀態:3
//(藍)套用效果:位移,放大
context.restore();
context.fillStyle = "blue";
context.fillRect(x, y, rW, rH);

//恢復到最後一次的狀態:2
//(綠)套用效果:位移
context.restore();
context.fillStyle = "green";
context.fillRect(x, y, rW, rH);

//恢復到最後一次的狀態:1
//(綠)套用效果:無任何效果
context.restore();
context.fillStyle = "gold";
context.fillRect(x, y, rW, rH);
本文網址:http://blog.tonycube.com/2012/03/html5-canvas-5.html
Tony Blog 撰寫,轉載時請註明出處及文章連結,謝謝 😀

2 則留言

  1. 9.2 比例縮放
    裡面有提到scale是負值就可以做出鏡像效果
    但是我用負值之後他卻無法顯示
    求解

    回覆刪除
    回覆
    1. 你調一下"鏡像"部份的fillText()的座標值,它有可能跑到 canvas 外面了。
      我把程式碼貼在這(https://jsfiddle.net/f2r07ch4/1/#&togetherjs=r1HQDwFgmV)你可以玩玩看

      刪除

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。