2.7 使用图形操作
本节,我们将创建一个表格,该表格展示每种组合下图形的变化,通过它来探索组合操作。组合操作在这几种情况下特别有用:创建复杂图形、绘制图形位于其它图形的下面而非上面、创建其它有趣的效果。

准备工作
下面是对HTML5的画布API所提供的每一种可能的组合操作的说明,其中,红色的圆代表源图形(S),蓝色的矩形代表目标图形(D)。为了加深对组合操作的理解,在阅读每一项说明的同时,看一看相应操作的效果,会有帮助。
操作 | 含义 |
---|---|
source-atop (S atop D) | 在两个图像都是非透明的地方,显示源图像。在目标图像是非透明但源图像是透明的地方,显示目标图像。其他地方透明显示。 |
source-in (S in D) | 在源图像和目标图像均透明的地方,显示源图像。其他地方透明显示。 |
source-out (S out D) | 在源图像非透明且目标图像为透明的地方,显示源图像。其他地方透明显示。 |
source-over (S over D, default) | 在源图像为非透明的地方,显示源图像。其他地方显示目标图像。 |
destination-atop (S atop D) | 在源图像和目标图像均为非透明的地方,显示目标图像。在源图像非透明且目标图像为透明的地方,显示源图像。其他地方透明显示。 |
destination-in (S in D) | 在源图像和目标图像均为非透明的地方,显示目标图像。其他地方透明显示。 |
destination -out (S out D) | 在目标图像为非透明且源图像为透明的地方,显示目标图像。其他地方透明显示。 |
destination -over (S over D) | 在目标图像为非透明的地方,显示目标图像。其他地方显示目标图像。 |
lighter (S plus D) | 显示源图像和目标图像之和。 |
xor (S xor D) | 源图像和目标图像取异或操作。 |
copy (D is ignored) | 显示源图像,不显示目标图像。 |
在本书写作之时,对组合操作的处理还非常棘手,因为五大主流浏览器,如Chrome, Firefox, Safari, Opera, 和IE9,对组合的处理各不相同。如果你想使用图形组合,你应该上网搜索“浏览器对画布组合操作的支持情况”,来了解每个浏览器的当前支持情况,而不是通过一副图,向你展示在本书写作时每个浏览器的支持情况。
绘制步骤
按照以下步骤,创建一个表格,来展示组合操作的当前情况:
1. 定义画布和文本样式:
/* 选择body元素的div子元素 */
body > div {
width: 680px;
height: 430px;
border: 1px solid black;
float: left;
overflow: hidden;
}
canvas {
float: left;
margin-top: 30px;
}
div {
font-size: 11px;
font-family: verdana;
height: 15px;
float: left;
width: 160px;
}
/* 选择第1个,第5个,第9个div元素*/
body > div > div:nth-of-type(4n+1) {
margin-left: 40px;
}
2. 定义每个矩形和圆的尺寸及相对距离:
window.onload = function(){
var squareWidth = 55;
var circleRadius = 35;
var rectCircleDistX = 50;
var rectCircleDistY = 50;
3. 构建一个组合操作的数组:
//定义一个组合操作的数组:
var operationArray = [];
operationArray.push("source-atop"); // 0
operationArray.push("source-in"); // 1
operationArray.push("source-out"); // 2
operationArray.push("source-over"); // 3
operationArray.push("destination-atop"); // 4
operationArray.push("destination-in"); // 5
operationArray.push("destination-out"); // 6
operationArray.push("destination-over"); // 7
operationArray.push("lighter"); // 8
operationArray.push("xor"); // 9
operationArray.push("copy"); // 10
4. 执行每个操作,并将结果绘制在相应的画布上:
//绘制11个操作中的每一个
for (var n = 0; n < operationArray.length; n++) {
var thisOperation = operationArray[n];
var canvas = document.getElementById(thisOperation);
var context = canvas.getContext("2d");
//绘制矩形
context.beginPath();
context.rect(40, 0, squareWidth, squareWidth);
context.fillStyle = "blue";
context.fill();
//设置全局组合操作
context.globalCompositeOperation = thisOperation;
//绘制圆
context.beginPath();
context.arc(40 + rectCircleDistX, rectCircleDistY, circleRadius, 0, 2 * Math.PI, false);
context.fillStyle = "red";
context.fill();
}
};
5. 在HTML的body部分,为每个组合嵌入一个canvas标签:
<body>
<div>
<canvas id="source-atop" width="160" height="90"> </canvas>
<canvas id="source-in" width="160" height="90"> </canvas>
<canvas id="source-out" width="160" height="90"> </canvas>
<canvas id="source-over" width="160" height="90"> </canvas>
<div>
source-atop
</div>
<div>
source-in
</div>
<div>
source-out
</div>
<div>
source-over
</div>
<canvas id="destination-atop" width="160" height="90"> </canvas>
<canvas id="destination-in" width="160" height="90"> </canvas>
<canvas id="destination-out" width="160" height="90"> </canvas>
<canvas id="destination-over" width="160" height="90"> </canvas>
<div>
destination-atop
</div>
<div>
destination-in
</div>
<div>
destination-out
</div>
<div>
destination-over
</div>
<canvas id="lighter" width="160" height="90"> </canvas>
<canvas id="xor" width="160" height="90"> </canvas>
<canvas id="copy" width="160" height="90"> </canvas>
<canvas width="160" height="90"> </canvas>
<div>
lighter
</div>
<div>
xor
</div>
<div>
copy
</div>
</div>
</body>
工作原理
我们可以通过画布上下文对象的globalCompositeOperation属性来设置组合操作:
context.globalCompositeOperation=[value];
globalCompositeOperation属性接受11个属性值之一,这些属性值包括source-atop, source-in, source-out, source-over, destination-atop, destination-in, destination-out, destination-over, lighter, xor, copy。Source指的是在操作之后绘制在画布上的任何图形,destination指的是在操作之前绘制在画布上的任何图形。除非另有指定,组合操作的默认值为source-over,其基本含义是每次向画布绘制图形,都绘制在已有的图形之上。
我们可以为每一个组合操作创建一个数组,然后循环遍历每一个组合,将其结果绘制在相应的画布上。每次迭代,我们都绘制矩形、设置组合属性、然后绘制圆形。