十、合成 Composites
10.1陰影 Shadows
要用HTML5畫布添加陰影,可以使用畫布上下文對象的shadowColor、shadowBlur、shadowOffsetX和shadowOffsetY屬性。
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.rect(188, 40, 200, 100);
context.fillStyle = 'red';
context.shadowColor = '#999';
context.shadowBlur = 20;
context.shadowOffsetX = 15;
context.shadowOffsetY = 15;
context.fill();
</script>
</body>
</html>
以上代碼演示了在畫布上繪製一個矩形,並設置陰影參數。
10.2透明度 Alpha
爲了用HTML5畫布設置元素的不透明度,我們可以將畫布上下文的globalAlpha屬性設置爲0到1之間的實數,其中0是完全透明的,1是完全不透明的。
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// draw blue rectangle
context.beginPath();
context.rect(200, 20, 100, 100);
context.fillStyle = 'blue';
context.fill();
// draw transparent red circle
context.globalAlpha = 0.5;
context.beginPath();
context.arc(320, 120, 60, 0, 2 * Math.PI, false);
context.fillStyle = 'red';
context.fill();
</script>
</body>
</html>
以上代碼演示了在畫布上重疊兩個半透明的圖形。
10.3剪輯區域 Clipping Region
若要使用HTML5畫布定義剪輯區域,可以繪製路徑,然後使用上下文對象的clip()方法。隨後繪製的所有圖形將被綁定在剪輯區域內。一旦我們在裁剪區域內完成了繪圖,可以使用restore()方法將畫布上下文返回到其原始狀態,以便進一步的繪圖不綁定到裁剪區域。
在本教程中,我們將通過繪製一個圓,然後使用clip()來定義一個圓形裁剪區域,然後繪製幾個在圓形路徑內裁剪的圓。接下來,我們將使用restore()方法將畫布上下文恢復到其原始狀態,然後在原始剪輯區域周圍繪製一個環。
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var offset = 50;
/*
* save() allows us to save the canvas context before
* defining the clipping region so that we can return
* to the default state later on
*/
context.save();
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.clip();
// draw blue circle inside clipping region
context.beginPath();
context.arc(x - offset, y - offset, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'blue';
context.fill();
// draw yellow circle inside clipping region
context.beginPath();
context.arc(x + offset, y, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'yellow';
context.fill();
// draw red circle inside clipping region
context.beginPath();
context.arc(x, y + offset, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'red';
context.fill();
/*
* restore() restores the canvas context to its original state
* before we defined the clipping region
*/
context.restore();
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.lineWidth = 10;
context.strokeStyle = 'blue';
context.stroke();
</script>
</body>
</html>
以上代碼演示了在畫布上設置狀態保存點,然後設置剪輯區域,然後在剪輯區域內繪圖,然後恢復到保存點,並用藍色爲剪輯區域描邊。
10.4全局合成操作 Global Composite Operations
要使用HTML5畫布執行合成操作,可以使用畫布上下文的globalCompositeOperation屬性。此屬性定義畫布的源和目的地狀態之間的合成操作。目的地定義爲合成操作之前的畫布狀態,源定義爲複合操作後的畫布狀態。
可以執行十二個種合成操作之一,包括:source-atop、source-in、source-out、source-over、destination-atop、destination-in、destination-out、destination-over、lighter、xor和copy。除非另有聲明,否則默認的複合操作爲source-over。
需要注意的是,畫布上下文只能在整個生命週期中支持一次合成操作。如果想要使用多次合成操作,要如本教程所示,首先在一個不可見的畫布上進行繪圖操作,然後將繪製結果複製到可見畫布上。
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="430"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var tempCanvas = document.createElement('canvas');
var tempContext = tempCanvas.getContext('2d');
var squareWidth = 55;
var circleRadius = 35;
var shapeOffset = 50;
var operationOffset = 150;
var arr = [];
arr.push('source-atop');
arr.push('source-in');
arr.push('source-out');
arr.push('source-over');
arr.push('destination-atop');
arr.push('destination-in');
arr.push('destination-out');
arr.push('destination-over');
arr.push('lighter');
arr.push('darker');
arr.push('xor');
arr.push('copy');
// translate context to add 10px padding
context.translate(10, 10);
// draw each of the operations
for(var n = 0; n < arr.length; n++) {
var thisOperation = arr[n];
tempContext.save();
// clear temp context
tempContext.clearRect(0, 0, canvas.width, canvas.height);
// draw rectangle (destination)
tempContext.beginPath();
tempContext.rect(0, 0, squareWidth, squareWidth);
tempContext.fillStyle = 'blue';
tempContext.fill();
// set global composite
tempContext.globalCompositeOperation = thisOperation;
// draw circle (source)
tempContext.beginPath();
tempContext.arc(shapeOffset, shapeOffset,
circleRadius, 0, 2 * Math.PI, false);
tempContext.fillStyle = 'red';
tempContext.fill();
tempContext.restore();
// draw text
tempContext.font = '10pt Verdana';
tempContext.fillStyle = 'black';
tempContext.fillText(thisOperation, 0, squareWidth + 45);
// translate visible context so operation is drawn in the right place
if(n > 0) {
if(n % 4 === 0) {
context.translate(operationOffset * -3, operationOffset);
}
else {
context.translate(operationOffset, 0);
}
}
// copy drawing from tempCanvas onto visible canvas
context.drawImage(tempCanvas, 0, 0);
}
</script>
</body>
</html>
以上代碼演示了創建不可見的臨時畫布,並在臨時畫布上分別執行不同類型的多次合成操作,並將繪製內容複製到可見畫布的過程。本例也演示了不同的合成操作之間的差異。
對於這種首先在不可見畫布繪圖然後再複製到可見畫布的操作,又稱之爲雙緩衝區機制double buffer,其特點是在繪製過程中不會影響可見畫布的顯示,在很多其他開發語言入Java中,這種影響主要是指畫面閃爍。