一. canvas API 的scale() 函數用於縮放.
scale() 帶有兩個參數,分別代表在x, y 兩個維度的值, 每個參數在canvas 顯示圖像的時候, 向其傳遞在本方向軸上影像要放大(或縮小) 的量, 如果x為2, 就代表所繪製影像中全部元素都會變成兩倍寬, 如果y 值為0.5 ,繪製出來的影像全部元素都會變成之前的一半高。
例如以下程序很方便地在canvas 上創建出新的樹.
<!DOCTYPE html> <html> <meta charset="UTF-8"> <title>缩放示例</title> <canvas id="trails" style="border: 1px solid;" width="400" height="600"> </canvas> <script> var gravel = new Image(); gravel.src = "gravel.jpg"; gravel.onload = function () { drawTrails(); } function createCanopyPath(context) { context.beginPath(); context.moveTo(-25, -50); context.lineTo(-10, -80); context.lineTo(-20, -80); context.lineTo(-5, -110); context.lineTo(-15, -110); context.lineTo(0, -140); context.lineTo(15, -110); context.lineTo(5, -110); context.lineTo(20, -80); context.lineTo(10, -80); context.lineTo(25, -50); context.closePath(); } // 将绘制树的方法 放到 drawTree(),方便重用 function drawTree(context) { var trunkGradient = context.createLinearGradient(-5, -50, 5, -50); trunkGradient.addColorStop(0, '#663300'); trunkGradient.addColorStop(0.4, '#996600'); trunkGradient.addColorStop(1, '#552200'); context.fillStyle = trunkGradient; context.fillRect(-5, -50, 10, 50); var canopyShadow = context.createLinearGradient(0, -50, 0, 0); canopyShadow.addColorStop(0, 'rgba(0, 0, 0, 0.5)'); canopyShadow.addColorStop(0.2, 'rgba(0, 0, 0, 0.0)'); context.fillStyle = canopyShadow; context.fillRect(-5, -50, 10, 50); createCanopyPath(context); context.lineWidth = 4; context.lineJoin = 'round'; context.strokeStyle = '#663300'; context.stroke(); context.fillStyle = '#339900'; context.fill(); } function drawTrails() { var canvas = document.getElementById('trails'); var context = canvas.getContext('2d'); // 在 X=130, Y=250的位置绘制第一棵树 context.save(); context.translate(130, 250); drawTree(context); context.restore(); // 在 X=260, Y=500 位置绘制第二棵树 context.save(); context.translate(260, 500); // 将第二棵树的宽高分别放大至原来的2倍 context.scale(2, 2); drawTree(context); context.restore(); context.save(); context.translate(-10, 350); context.beginPath(); context.moveTo(0, 0); context.quadraticCurveTo(170, -50, 260, -190); context.quadraticCurveTo(310, -250, 410,-250); context.strokeStyle = context.createPattern(gravel, 'repeat'); context.lineWidth = 20; context.stroke(); context.restore(); } </script> </html>
二. 旋轉context.rotate(angle), 參數angle 以弧度為單位
看程式碼
<!DOCTYPE html> <html> <meta charset="UTF-8"> <title>旋转示例</title> <canvas id="trails" style="border: 1px solid;" width="400" height="600"> </canvas> <script> var gravel = new Image(); gravel.src = "gravel.jpg"; gravel.onload = function () { drawTrails(); } function createCanopyPath(context) { context.beginPath(); context.moveTo(-25, -50); context.lineTo(-10, -80); context.lineTo(-20, -80); context.lineTo(-5, -110); context.lineTo(-15, -110); context.lineTo(0, -140); context.lineTo(15, -110); context.lineTo(5, -110); context.lineTo(20, -80); context.lineTo(10, -80); context.lineTo(25, -50); context.closePath(); } // 将绘制树的方法 放到 drawTree() function drawTree(context) { var trunkGradient = context.createLinearGradient(-5, -50, 5, -50); trunkGradient.addColorStop(0, '#663300'); trunkGradient.addColorStop(0.4, '#996600'); trunkGradient.addColorStop(1, '#552200'); context.fillStyle = trunkGradient; context.fillRect(-5, -50, 10, 50); var canopyShadow = context.createLinearGradient(0, -50, 0, 0); canopyShadow.addColorStop(0, 'rgba(0, 0, 0, 0.5)'); canopyShadow.addColorStop(0.2, 'rgba(0, 0, 0, 0.0)'); context.fillStyle = canopyShadow; context.fillRect(-5, -50, 10, 50); createCanopyPath(context); context.lineWidth = 4; context.lineJoin = 'round'; context.strokeStyle = '#663300'; context.stroke(); context.fillStyle = '#339900'; context.fill(); } function drawTrails() { var canvas = document.getElementById('trails'); var context = canvas.getContext('2d'); // 在 X=130, Y=250的位置绘制第一棵树 context.save(); context.translate(100, 150); context.rotate(1.57); //旋转角度以弧度为单位 drawTree(context); context.restore(); context.save(); context.translate(-10, 450); context.beginPath(); context.moveTo(0, 0); context.quadraticCurveTo(170, -50, 260, -190); context.quadraticCurveTo(310, -250, 410,-250); context.strokeStyle = context.createPattern(gravel, 'repeat'); context.lineWidth = 20; context.stroke(); context.restore(); } </script> </html>
以上兩個範例,需注意之處:
總是在原點執行圖形和路徑的變換操作 範例中示範了為什麼要在原點執行圖形和路徑的變換操作, 執行完後再統一平移. 因為縮放scale 和旋轉rotate 等變換操作都是針對原點進行的.
如果對一個不在原點的圖形進行旋轉, 那麼圖形繞著原點旋轉而不是在原地旋轉。 類似地,如果進行縮放操作時沒有將圖形放置到適當的座標上,那麼所有座標都會被同時縮放, 新的座標可能會超出canvas 範圍。
三。 相關代碼: 剪裁過的 「陰影」 樹會先被顯示出來, 這樣一來, 真正的樹就會按照Z軸(canvas 中物件的重疊順序) 顯示在陰影的上面。 此外樹影的填充用到了CSS 的RGBA特性, 透過特性我們將透明度值設為正常情況下的20%, 至此,帶有半透明效果的樹影就做好了。
範例中用到圖片 gravel.jpg 在之前部落格文章可找到. 陰影、創造詞請關注PHP中文網(m.sbmmt.com)! <!DOCTYPE html>
<html>
<meta charset="UTF-8">
<title>变换阴影</title>
<canvas id="trails" style="border: 1px solid;" width="400" height="600"> </canvas>
<script>
var gravel = new Image();
gravel.src = "gravel.jpg";
gravel.onload = function () {
drawTrails();
}
function createCanopyPath(context) {
context.beginPath();
context.moveTo(-25, -50);
context.lineTo(-10, -80);
context.lineTo(-20, -80);
context.lineTo(-5, -110);
context.lineTo(-15, -110);
context.lineTo(0, -140);
context.lineTo(15, -110);
context.lineTo(5, -110);
context.lineTo(20, -80);
context.lineTo(10, -80);
context.lineTo(25, -50);
context.closePath();
}
function drawTree(context) {
context.save();
// X值随着Y值的增加而增加,借助拉伸变换,可以创建一棵用作阴影的倾斜的树,应用了
// 变换以后,所有坐标都与矩阵相乘
context.transform(1, 0, -0.5, 1, 0, 0);
// 在Y轴方向,将阴影的高度压缩为原来的60%
context.scale(1, 0.6);
// 使用透明度为20%的黑色填充树干
context.fillStyle = 'rgba(0, 0, 0, 0.2)';
context.fillRect(-5, -50, 10, 50);
// 使用已有的阴影效果重新绘制
createCanopyPath(context);
context.fill();
context.restore();
var trunkGradient = context.createLinearGradient(-5, -50, 5, -50);
trunkGradient.addColorStop(0, '#663300');
trunkGradient.addColorStop(0.4, '#996600');
trunkGradient.addColorStop(1, '#552200');
context.fillStyle = trunkGradient;
context.fillRect(-5, -50, 10, 50);
var canopyShadow = context.createLinearGradient(0, -50, 0, 0);
canopyShadow.addColorStop(0, 'rgba(0, 0, 0, 0.5)');
canopyShadow.addColorStop(0.2, 'rgba(0, 0, 0, 0.0)');
context.fillStyle = canopyShadow;
context.fillRect(-5, -50, 10, 50);
createCanopyPath(context);
context.lineWidth = 4;
context.lineJoin = 'round';
context.strokeStyle = '#663300';
context.stroke();
context.fillStyle = '#339900';
context.fill();
}
function drawTrails() {
var canvas = document.getElementById('trails');
var context = canvas.getContext('2d');
context.save();
context.translate(130, 250);
drawTree(context);
context.restore();
context.save();
context.translate(260, 500);
context.scale(2, 2);
drawTree(context);
context.restore();
context.save();
context.translate(-10, 350);
context.beginPath();
context.moveTo(0, 0);
context.quadraticCurveTo(170, -50, 260, -190);
context.quadraticCurveTo(310, -250, 410,-250);
context.strokeStyle = context.createPattern(gravel, 'repeat');
context.lineWidth = 20;
context.stroke();
context.restore();
}
</script>
</html>
分析這種變換背後的數學意義, 可以看出透過調整與Y軸值相對應的參數改變了X軸的值, 這樣做是為了拉伸出一查灰色的樹做陰影。 接下來, 我們按照60% 的比例將剪裁出的樹縮小到了合適的尺寸。