使用Canvas 绘图:不用说,HTML5 添加的最受欢迎的功能就是
与浏览器环境中的其他组件类似,
1.基本用法:要使用
A drawing of something.
与其他元素一样,
要在这块画布(canvas)上绘图,需要取得绘图上下文。而取得绘图上下文对象的引用,需要调用getContext()方法并传入上下文的名字。传入"2d",就可以取得2D 上下文对象。
var drawing = document.getElementById("drawing");
//确定浏览器支持元素
if (drawing.getContext){
var context = drawing.getContext("2d");
//更多代码
}
在使用
使用toDataURL()方法,可以导出在
var drawing = document.getElementById("drawing");
//确定浏览器支持元素
if (drawing.getContext){
//取得图像的数据URI
var imgURI = drawing.toDataURL("image/png");
//显示图像
var image = document.createElement("img");
image.src = imgURI;
document.body.appendChild(image);
}
默认情况下,浏览器会将图像编码为PNG 格式(除非另行指定)。Firefox 和Opera 也支持基于"image/jpeg"参数的JPEG 编码格式。由于这个方法是后来才追加的,所以支持
如果绘制到画布上的图像源自不同的域,toDataURL()方法会抛出错误。本章后面还将介绍更多相关内容。
2.2D 上下文:使用2D 绘图上下文提供的方法,可以绘制简单的2D 图形,比如矩形、弧线和路径。2D 上下文的坐标开始于
这两个属性的值可以是字符串、渐变对象或模式对象,而且它们的默认值都是"#000000"。如果为它们指定表示颜色的字符串值,可以使用CSS 中指定颜色值的任何格式,包括颜色名、十六进制码、rgb、rgba、hsl 或hsla。举个例子:
var drawing = document.getElementById("drawing");
//确定浏览器支持元素
if (drawing.getContext){
var context = drawing.getContext("2d");
context.strokeStyle = "red";
context.fillStyle = "#0000ff";
}
以上代码将strokeStyle 设置为red(CSS 中的颜色名),将fillStyle 设置为#0000ff(蓝色)。然后,所有涉及描边和填充的操作都将使用这两个样式,直至重新设置这两个值。如前所述,这两个属性的值也可以是渐变对象或模式对象。
首先,fillRect()方法在画布上绘制的矩形会填充指定的颜色。填充的颜色通过fillStyle 属性指定,比如:
var drawing = document.getElementById("drawing");
//确定浏览器支持元素
if (drawing.getContext){
var context = drawing.getContext("2d");
/*
* 根据Mozilla 的文档
* http://developer.mozilla.org/en/docs/Canvas_tutorial:Basic_usage
*/
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//绘制半透明的蓝色矩形
context.fillStyle = "rgba(0,0,255,0.5)";
context.fillRect(30, 30, 50, 50);
}
以上代码首先将fillStyle 设置为红色,然后从(10,10)处开始绘制矩形,矩形的宽和高均为50 像素。然后,通过rgba()格式再将fillStyle 设置为半透明的蓝色,在第一个矩形上面绘制第二个矩形。结果就是可以透过蓝色的矩形看到红色的矩形。
strokeRect()方法在画布上绘制的矩形会使用指定的颜色描边。描边颜色通过strokeStyle 属性指定。比如:
var drawing = document.getElementById("drawing");
//确定浏览器支持元素
if (drawing.getContext){
var context = drawing.getContext("2d");
/*
* 根据Mozilla 的文档
* http://developer.mozilla.org/en/docs/Canvas_tutorial:Basic_usage
*/
//绘制红色描边矩形
context.strokeStyle = "#ff0000";
context.strokeRect(10, 10, 50, 50);
//绘制半透明的蓝色描边矩形
context.strokeStyle = "rgba(0,0,255,0.5)";
context.strokeRect(30, 30, 50, 50);
}
以上代码绘制了两个重叠的矩形。不过,这两个矩形都只有框线,内部并没有填充颜色。
描边线条的宽度由lineWidth 属性控制,该属性的值可以是任意整数。另外,通过lineCap 属性可以控制线条末端的形状是平头、圆头还是方头("butt"、"round"或"square"),通过lineJoin 属性可以控制线条相交的方式是圆交、斜交还是斜接("round"、"bevel"或"miter")。
最后,clearRect()方法用于清除画布上的矩形区域。本质上,这个方法可以把绘制上下文中的某一矩形区域变透明。通过绘制形状然后再清除指定区域,就可以生成有意思的效果,例如把某个形状切掉一块。下面看一个例子。
var drawing = document.getElementById("drawing");
//确定浏览器支持元素
if (drawing.getContext){
var context = drawing.getContext("2d");
/*
* 根据Mozilla 的文档
* http://developer.mozilla.org/en/docs/Canvas_tutorial:Basic_usage
*/
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//绘制半透明的蓝色矩形
context.fillStyle = "rgba(0,0,255,0.5)";
context.fillRect(30, 30, 50, 50);
//在两个矩形重叠的地方清除一个小矩形
context.clearRect(40, 40, 10, 10);
}
两个填充矩形重叠在一起,而重叠的地方又被清除了一个小矩形区域。
创建了路径后,接下来有几种可能的选择。如果想绘制一条连接到路径起点的线条,可以调用closePath()。如果路径已经完成,你想用fillStyle 填充它,可以调用fill()方法。另外,还可以调用stroke()方法对路径描边,描边使用的是strokeStyle。最后还可以调用clip(),这个方法可以在路径上创建一个剪切区域。
下面看一个例子,即绘制一个不带数字的时钟表盘。
var drawing = document.getElementById("drawing");
//确定浏览器支持元素
if (drawing.getContext){
var context = drawing.getContext("2d");
//开始路径
context.beginPath();
//绘制外圆
context.arc(100, 100, 99, 0, 2 * Math.PI, false);
//绘制内圆
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2 * Math.PI, false);
//绘制分针
context.moveTo(100, 100);
context.lineTo(100, 15);
//绘制时针
context.moveTo(100, 100);
context.lineTo(35, 100);
//描边路径
context.stroke();
}
这个例子使用arc()方法绘制了两个圆形:一个外圆和一个内圆,构成了表盘的边框。外圆的半径是99 像素,圆心位于点(100,100),也是画布的中心点。为了绘制一个完整的圆形,我们从0 弧度开始,绘制2π 弧度(通过Math.PI 来计算)。在绘制内圆之前,必须把路径移动到内圆上的某一点,以避免绘制出多余的线条。第二次调用arc()使用了小一点的半径,以便创造边框的效果。然后,组合使用moveTo()和lineTo()方法来绘制时针和分针。最后一步是调用stroke()方法,这样才能把图形绘制到画布上。
在2D 绘图上下文中,路径是一种主要的绘图方式,因为路径能为要绘制的图形提供更多控制。由于路径的使用很频繁,所以就有了一个名为isPointInPath()的方法。这个方法接收x 和y 坐标作为参数,用于在路径被关闭之前确定画布上的某一点是否位于路径上,例如:
if (context.isPointInPath(100, 100)){
alert("Point (100, 100) is in the path.");
}
2D 上下文中的路径API 已经非常稳定,可以利用它们结合不同的填充和描边样式,绘制出非常复杂的图形来。
这几个属性都有默认值,因此没有必要每次使用它们都重新设置一遍值。fillText()方法使用fillStyle 属性绘制文本,而strokeText()方法使用strokeStyle 属性为文本描边。相对来说,还是使用fillText()的时候更多,因为该方法模仿了在网页中正常显示文本。例如,下面的代码在前一节创建的表盘上方绘制了数字12:
context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12", 100, 20);
因为这里把textAlign 设置为"center",把textBaseline 设置为"middle",所以坐标(100,20)表示的是文本水平和垂直中点的坐标。如果将textAlign 设置为"start",则x 坐标表示的是文本左端的位置(从左到右阅读的语言);设置为"end",则x 坐标表示的是文本右端的位置(从左到右阅读的语言)。例如:
//正常
context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12", 100, 20);
//起点对齐
context.textAlign = "start";
context.fillText("12", 100, 40);
//终点对齐
context.textAlign = "end";
context.fillText("12", 100, 60);
这一回绘制了三个字符串"12",每个字符串的x 坐标值相同,但textAlign 值不同。另外,后两个字符串的y 坐标依次增大,以避免相互重叠。
表盘中的分针恰好位于正中间,因此文本的水平对齐方式如何变化也能够一目了然。类似地,修改textBaseline 属性的值可以调整文本的垂直对齐方式:值为"top",y 坐标表示文本顶端;值为"bottom",y 坐标表示文本底端;值"hanging"、"alphabetic"和"ideographic",则y 坐标分别指向字体的特定基线坐标。
由于绘制文本比较复杂,特别是需要把文本控制在某一区域中的时候,2D 上下文提供了辅助确定文本大小的方法measureText()。这个方法接收一个参数,即要绘制的文本;返回一个TextMetrics对象。返回的对象目前只有一个width 属性,但将来还会增加更多度量属性。
measureText()方法利用font、textAlign 和textBaseline 的当前值计算指定文本的大小。比如,假设你想在一个140 像素宽的矩形区域中绘制文本Hello world!,下面的代码从100 像素的字体大小开始递减,最终会找到合适的字体大小。
var fontSize = 100;
context.font = fontSize + "px Arial";
while(context.measureText("Hello world!").width > 140){
fontSize--;
context.font = fontSize + "px Arial";
}
context.fillText("Hello world!", 10, 10);
context.fillText("Font size is " + fontSize + "px", 10, 50);
前面提到过,fillText 和strokeText()方法都可以接收第四个参数,也就是文本的最大像素宽度。不过,这个可选的参数尚未得到所有浏览器支持(最早支持它的是Firefox 4 )。提供这个参数后,调用fillText()或strokeText()时如果传入的字符串大于最大宽度,则绘制的文本字符的高度正确,但宽度会收缩以适应最大宽度。图15-7 展示了这个效果。
绘制文本还是相对比较复杂的操作,因此支持
可以通过如下方法来修改变换矩阵。
rotate(angle):围绕原点旋转图像angle 弧度。
scale(scaleX, scaleY):缩放图像,在x 方向乘以scaleX,在y 方向乘以scaleY。scaleX和scaleY 的默认值都是1.0。
translate(x, y):将坐标原点移动到(x,y)。执行这个变换之后,坐标(0,0)会变成之前由(x,y)表示的点。
transform(m1_1, m1_2, m2_1, m2_2, dx, dy):直接修改变换矩阵,方式是乘以如下矩阵。
m1_1 m1_2 dx
m2_1 m2_2 dy
0 0 1
setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):将变换矩阵重置为默认状态,然后再调用transform()。
变换有可能很简单,但也可能很复杂,这都要视情况而定。比如,就拿前面例子中绘制表针来说,如果把原点变换到表盘的中心,然后再绘制表针就容易多了。请看下面的例子。
var drawing = document.getElementById("drawing");
//确定浏览器支持元素
if (drawing.getContext){
var context = drawing.getContext("2d");
//开始路径
context.beginPath();
//绘制外圆
context.arc(100, 100, 99, 0, 2 * Math.PI, false);
//绘制内圆
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2 * Math.PI, false);
//变换原点
context.translate(100, 100);
//绘制分针
context.moveTo(0,0);
context.lineTo(0, -85);
//绘制时针
context.moveTo(0, 0);
context.lineTo(-65, 0);
//描边路径
context.stroke();
}
把原点变换到时钟表盘的中心点(100,100)后,在同一方向上绘制线条就变成了简单的数学问题了。所有数学计算都基于(0,0),而不是(100,100)。还可以更进一步,像下面这样使用rotate()方法旋转时钟的表针。
var drawing = document.getElementById("drawing");
//确定浏览器支持元素
if (drawing.getContext){
var context = drawing.getContext("2d");
//开始路径
context.beginPath();
//绘制外圆
context.arc(100, 100, 99, 0, 2 * Math.PI, false);
//绘制内圆
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2 * Math.PI, false);
//变换原点
context.translate(100, 100);
//旋转表针
context.rotate(1);
//绘制分针
context.moveTo(0,0);
context.lineTo(0, -85);
//绘制时针
context.moveTo(0, 0);
context.lineTo(-65, 0);
//描边路径
context.stroke();
}
因为原点已经变换到了时钟表盘的中心点,所以旋转也是以该点为圆心的。结果就像是表针真地被固定在表盘中心一样,然后向右旋转了一定角度。
无论是刚才执行的变换,还是fillStyle、strokeStyle 等属性,都会在当前上下文中一直有效,除非再对上下文进行什么修改。虽然没有什么办法把上下文中的一切都重置回默认值,但有两个方法可以跟踪上下文的状态变化。如果你知道将来还要返回某组属性与变换的组合,可以调用save()方法。调用这个方法后,当时的所有设置都会进入一个栈结构,得以妥善保管。然后可以对上下文进行其他修改。等想要回到之前保存的设置时,可以调用restore()方法,在保存设置的栈结构中向前返回一级,恢复之前的状态。连续调用save()可以把更多设置保存到栈结构中,之后再连续调用restore()则可以一级一级返回。
context.fillStyle = "#ff0000";
context.save();
context.fillStyle = "#00ff00";
context.translate(100, 100);
context.save();
context.fillStyle = "#0000ff";
context.fillRect(0, 0, 100, 200); //从点(100,100)开始绘制蓝色矩形
context.restore();
context.fillRect(10, 10, 100, 200); //从点(110,110)开始绘制绿色矩形
context.restore();
context.fillRect(0, 0, 100, 200); //从点(0,0)开始绘制红色矩形
首先,将fillStyle 设置为红色,并调用save()保存上下文状态。接下来,把fillStyle 修改为绿色,把坐标原点变换到(100,100),再调用save()保存上下文状态。然后,把fillStyle 修改为蓝色并绘制蓝色的矩形。因为此时的坐标原点已经变了,所以矩形的左上角坐标实际上是(100,100)。然后调用restore(),之后fillStyle 变回了绿色,因而第二个矩形就是绿色。之所以第二个矩形的起点坐标是(110,110),是因为坐标位置的变换仍然起作用。再调用一次restore(),变换就被取消了,而fillStyle 也返回了红色。所以最后一个矩形是红色的,而且绘制的起点是(0,0)。
需要注意的是,save()方法保存的只是对绘图上下文的设置和变换,不会保存绘图上下文的内容。
var image = document.images[0];
context.drawImage(image, 10, 10);
这两行代码取得了文档中的第一幅图像,然后将它绘制到上下文中,起点为(10,10)。绘制到画布上的图像大小与原始大小一样。如果你想改变绘制后图像的大小,可以再多传入两个参数,分别表示目标宽度和目标高度。通过这种方式来缩放图像并不影响上下文的变换矩阵。例如:
context.drawImage(image, 50, 10, 20, 30);
执行代码后,绘制出来的图像大小会变成20×30 像素。
除了上述两种方式,还可以选择把图像中的某个区域绘制到上下文中。drawImage()方法的这种调用方式总共需要传入9 个参数:要绘制的图像、源图像的x 坐标、源图像的y 坐标、源图像的宽度、源图像的高度、目标图像的x 坐标、目标图像的y 坐标、目标图像的宽度、目标图像的高度。这样调用drawImage()方法可以获得最多的控制。例如:
context.drawImage(image, 0, 10, 50, 50, 0, 100, 40, 60);
这行代码只会把原始图像的一部分绘制到画布上。原始图像的这一部分的起点为(0,10),宽和高都是50 像素。最终绘制到上下文中的图像的起点是(0,100),而大小变成了40×60 像素。
除了给drawImage()方法传入HTML 元素外,还可以传入另一个
结合使用drawImage()和其他方法,可以对图像进行各种基本操作。而操作的结果可以通过toDataURL()方法获得①。不过,有一个例外,即图像不能来自其他域。如果图像来自其他域,调用toDataURL()会抛出一个错误。打个比方,假如位于www.example.com 上的页面绘制的图像来自于www.wrox.com,那当前上下文就会被认为“不干净”,因而会抛出错误。
这些属性都可以通过context 对象来修改。只要在绘制前为它们设置适当的值,就能自动产生阴影。例如:
var context = drawing.getContext("2d");
//设置阴影
context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur = 4;
context.shadowColor = "rgba(0, 0, 0, 0.5)";
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//绘制蓝色矩形
context.fillStyle = "rgba(0,0,255,1)";
context.fillRect(30, 30, 50, 50);
不同浏览器对阴影的支持有一些差异。IE9、Firefox 4 和Opera 11 的行为最为规范,其他浏览器多多少少会有一些奇怪的现象,甚至根本不支持阴影。Chrome(直至第10 版)不能正确地为描边的形状应用实心阴影。Chrome 和Safari(直至第5 版)在为带透明像素的图像应用阴影时也会有问题:不透明部分的下方本来是该有阴影的,但此时则一概不见了。Safari 也不能给渐变图形应用阴影,其他浏览器都可以。
创建了渐变对象后,下一步就是使用addColorStop()方法来指定色标。这个方法接收两个参数:色标位置和CSS 颜色值。色标位置是一个0(开始的颜色)到1(结束的颜色)之间的数字。例如:
var gradient = context.createLinearGradient(30, 30, 70, 70);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
此时,gradient 对象表示的是一个从画布上点(30,30)到点(70,70)的渐变。起点的色标是白色,终点的色标是黑色。然后就可以把fillStyle 或strokeStyle 设置为这个对象,从而使用渐变来绘制形状或描边:
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//绘制渐变矩形
context.fillStyle = gradient;
context.fillRect(30, 30, 50, 50);
为了让渐变覆盖整个矩形,而不是仅应用到矩形的一部分,矩形和渐变对象的坐标必须匹配才行。
如果没有把矩形绘制到恰当的位置,那可能就只会显示部分渐变效果。
context.fillStyle = gradient;
context.fillRect(50, 50, 50, 50);
这两行代码执行后得到的矩形只有左上角稍微有一点白色。这主要是因为矩形的起点位于渐变的中间位置,而此时渐变差不多已经结束了。由于渐变不重复,所以矩形的大部分区域都是黑色。确保渐变与形状对齐非常重要,有时候可以考虑使用函数来确保坐标合适。例如:
function createRectLinearGradient(context, x, y, width, height){
return context.createLinearGradient(x, y, x+width, y+height);
}
这个函数基于起点的x 和y 坐标以及宽度和高度值来创建渐变对象,从而让我们可以在fillRect()中使用相同的值。
var gradient = createRectLinearGradient(context, 30, 30, 50, 50);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
//绘制渐变矩形
context.fi llStyle = gradient;
context.fillRect(30, 30, 50, 50);
使用画布的时候,确保坐标匹配很重要,也需要一些技巧。类似createRectLinearGradient()这样的辅助方法可以让控制坐标更容易一些。
要创建径向渐变(或放射渐变),可以使用createRadialGradient()方法。这个方法接收6 个参数,对应着两个圆的圆心和半径。前三个参数指定的是起点圆的原心(x 和y)及半径,后三个参数指定的是终点圆的原心(x 和y)及半径。可以把径向渐变想象成一个长圆桶,而这6 个参数定义的正是这个桶的两个圆形开口的位置。如果把一个圆形开口定义得比另一个小一些,那这个圆桶就变成了圆锥体,而通过移动每个圆形开口的位置,就可达到像旋转这个圆锥体一样的效果。
如果想从某个形状的中心点开始创建一个向外扩散的径向渐变效果,就要将两个圆定义为同心圆。比如,就拿前面创建的矩形来说,径向渐变的两个圆的圆心都应该在(55,55),因为矩形的区域是从(30,30)到(80,80)。请看代码:
var gradient = context.createRadialGradient(55, 55, 10, 55, 55, 30);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//绘制渐变矩形
context.fillStyle = gradient;
context.fillRect(30, 30, 50, 50);
因为创建比较麻烦,所以径向渐变并不那么容易控制。不过,一般来说,让起点圆和终点圆保持为同心圆的情况比较多,这时候只要考虑给两个圆设置不同的半径就好了。
var image = document.images[0],
pattern = context.createPattern(image, "repeat");
//绘制矩形
context.fillStyle = pattern;
context.fillRect(10, 10, 150, 150);
需要注意的是,模式与渐变一样,都是从画布的原点(0,0)开始的。将填充样式(fillStyle)设置为模式对象,只表示在某个特定的区域内显示重复的图像,而不是要从某个位置开始绘制重复的图像。
createPattern()方法的第一个参数也可以是一个
var imageData = context.getImageData(10, 5, 50, 50);
这里返回的对象是ImageData 的实例。每个ImageData 对象都有三个属性:width、height 和data。其中data 属性是一个数组,保存着图像中每一个像素的数据。在data 数组中,每一个像素用4 个元素来保存,分别表示红、绿、蓝和透明度值。因此,第一个像素的数据就保存在数组的第0 到第3 个元素中,例如:
var data = imageData.data,
red = data[0],
green = data[1],
blue = data[2],
alpha = data[3];
数组中每个元素的值都介于0 到255 之间(包括0 和255)。能够直接访问到原始图像数据,就能够以各种方式来操作这些数据。例如,通过修改图像数据,可以像下面这样创建一个简单的灰阶过滤器。
var drawing = document.getElementById("drawing");
//确定浏览器支持元素
if (drawing.getContext){
var context = drawing.getContext("2d"),
image = document.images[0],
imageData, data,
i, len, average,
red, green, blue, alpha;
//绘制原始图像
context.drawImage(image, 0, 0);
//取得图像数据
imageData = context.getImageData(0, 0, image.width, image.height);
data = imageData.data;
for (i=0, len=data.length; i < len; i+=4){
red = data[i];
green = data[i+1];
blue = data[i+2];
alpha = data[i+3];
//求得rgb 平均值
average = Math.floor((red + green + blue) / 3);
//设置颜色值,透明度不变
data[i] = average;
data[i+1] = average;
data[i+2] = average;
}
//回写图像数据并显示结果
imageData.data = data;
context.putImageData(imageData, 0, 0);
}
这个例子首先在画面上绘制了一幅图像,然后取得了原始图像数据。其中的for 循环遍历了图像数据中的每一个像素。这里要注意的是,每次循环控制变量i 都递增4。在取得每个像素的红、绿、蓝颜色值后,计算出它们的平均值。再把这个平均值设置为每个颜色的值,结果就是去掉了每个像素的颜色,只保留了亮度接近的灰度值(即彩色变黑白)。在把data 数组回写到imageData 对象后,调用putImageData()方法把图像数据绘制到画布上。最终得到了图像的黑白版。
只有在画布“干净”的情况下(即图像并非来自其他域),才可以取得图像数据。如果画布“不干净”,那么访问图像数据时会导致JavaScript 错误。
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//修改全局透明度
context.globalAlpha = 0.5;
//绘制蓝色矩形
context.fillStyle = "rgba(0,0,255,1)";
context.fillRect(30, 30, 50, 50);
//重置全局透明度
context.globalAlpha = 0;
在这个例子中,我们把蓝色矩形绘制到了红色矩形上面。因为在绘制蓝色矩形前,globalAlpha已经被设置为0.5,所以蓝色矩形会呈现半透明效果,透过它可以看到下面的红色矩形。
第二个属性globalCompositionOperation 表示后绘制的图形怎样与先绘制的图形结合。这个属性的值是字符串,可能的值如下。
这个合成操作实际上用语言或者黑白图像是很难说清楚的。要了解每个操作的具体效果,请参见https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html。推荐使用IE9+或Firefox4+访问前面的网页,因为这两款浏览器对Canvas 的实现最完善。下面来看一个例子。
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//设置合成操作
context.globalCompositeOperation = "destination-over";
//绘制蓝色矩形
context.fillStyle = "rgba(0,0,255,1)";
context.fillRect(30, 30, 50, 50);
如果不修改globalCompositionOperation,那么蓝色矩形应该位于红色矩形之上。但把globalCompositionOperation 设置为"destination-over"之后,红色矩形跑到了蓝色矩形上面。
在使用globalCompositionOperation 的情况下,一定要多测试一些浏览器。因为不同浏览器对这个属性的实现仍然存在较大的差别。Safari 和Chrome 在这方面还有问题,至于有什么问题,大家可以比较在打开上述页面的情况下,IE9+和Firefox 4+与它们有什么差异。