图像
IE | Firefox | Safari | Chrome | Opera | iPhone | Android |
7.0+* | 3.0+ | 3.0+ | 3.0+ | 10.0+ | 1.0+ | 1.0+ |
* IE 7.0 和 8.0 需要使用第三方 JS 库explorercanvas;IE9 原生支持。 |
这里是一只猫的图片:
上面的图像是放在<img>
里面的。下面则是一只看上去一样的猫,不过它是使用<canvas>
绘制的:
画布的绘图上下文有一个drawImage()
方法,用于在画布上绘制图像。这个方法有3个重载,分别接受3、5、9个参数。
drawImage(image, dx, dy)
接受一幅图像,并且将其绘制到画布上。给定 (dx, dy) 是该图像左上角的坐标。坐标 (0, 0) 意味着图像出现在画布左上角。drawImage(image, dx, dy, dw, dh)
接受一幅图像,将其缩放至宽度为 dw,高度为 dh 后,在将其绘制到画布坐标 (dx, dy) 位置。drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
接受一幅图像,然后将其按照矩形 (sx, sy, sw, sh) 进行裁剪,再缩放至大小为 (dw, dh),最后将其绘制到画布坐标 (dx, dy) 位置。
HTML5 标准这样解释drawImage()
的参数:
源矩形是一个矩形[位于原始图像],其四个顶点的坐标分别为 (sx, sy),(sx+sw, sy),(sx+sw, sy+sh) 和 (sx, sy+sh)。
目标矩形是一个矩形[位于画布内],其四个顶点的坐标分别为 (dx, dy),(dx+dw, dy),(dx+dw, dy+dh) 和 (dx, dy+dh)。
为了在画布上绘制图像,我们首先需要一副图像。图像可以是已存在的 <img> 元素,也可以使使用 JavaScript 创建的Image()
对象。无论如何,你需要确保该图像在绘制到画布之前已经被加载完全。
如果你使用已有的<img>
元素,你可以放心地把绘制代码放到 window.onload 事件回调里面:
<img id="cat" src="images/cat.png" alt="sleeping cat" width="177" height="113"> <canvas id="e" width="177" height="113"></canvas> <script> window.onload = function() { var canvas = document.getElementById("e"); var context = canvas.getContext("2d"); var cat = document.getElementById("cat"); context.drawImage(cat, 0, 0); }; </script>
如果你完全使用 JavaScript 创建图像对象,你应该把绘制的代码放到 Image.onload 事件中去:
<canvas id="e" width="177" height="113"></canvas> <script> var canvas = document.getElementById("e"); var context = canvas.getContext("2d"); var cat = new Image(); cat.src = "images/cat.png"; cat.onload = function() { context.drawImage(cat, 0, 0); }; </script>
传递给drawImage()
方法可选的第三和第四个参数用于控制图像的缩放。下面给出的是同一副图像,将其大小缩至一半,然后在一个画布上的不同坐标进行重复绘制的效果:
cat.onload = function() { for (var x = 0, y = 0; x < 500 && y < 375; x += 50, y += 37) { context.drawImage(cat, x, y, 88, 56); } };
不过,到现在为止,我们可能还会有一个问题要问:为什么你要在 canvas 上绘制图像?为什么要编写那么复杂的代码,而不直接用<img>
加上一些 CSS 规则实现?就像上面说的“复杂”的效果,也不过是添加10个<img>
就可以了。
简单的回答是,同你希望在画布上画出文本的原因是一致的。画布的坐标图包括了文本、直线和特殊形状。所谓画布上的文本不过是一项复杂工程中的一小部分。一个更加复杂的图标可以很简单地使用drawImage()
来添加诸如图标、精灵或者其他图像元素。
IE 怎么办?
Internet Explorer 9.0 之前的版本都不支持 canvas API(IE9 是完全支持 canvas API 的)。但是,老版本的 Internet Explorer 是支持 Microsoft 的专有技术 VML 的。这种技术在很大程度上很像<canvas>
元素。因此,我们有了 excanvas.js。
Explorercanvas (excanvas.js) 是一个基于 Apache 协议开源的 JavaScript 库,在老版本的 Internet Explorer 上实现了 canvas API。为使用这个库,我们需要在页面的顶部加上<script>
元素。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Dive Into HTML5</title> <!--[if lt IE 9]> <script src="excanvas.js"></script> <![endif]--> </head> <body> ... </body> </html>
<!--[if lt IE 9]>
和<![endif]-->
就是我们前面提到的条件注释。Internet Explorer 将按照 if 语句解释它们:“如果当前浏览器版本低于9,则执行这个块。”而其他所有浏览器都会将其解释为普通的 HTML 注释。最终的结果是,Internet Explorer 7 和 8 将下载 excanvas.js 脚本并执行,而其他浏览器则会连同脚本一起忽略(不下载、不执行,什么都不做)。这将会使支持 canvas API 的浏览器能够更快地加载你的页面。
一旦你在你的页面的<head>
中引入了 excanvas.js,你就不需要为 Internet Explorer 做任何额外的操作了。只需要添加<canvas>
标记,或者使用 JavaScript 动态创建。接下来的指令和我们前面说的一样,获取<canvas>
的绘图上下文,然后绘制形状、文本或者填充图像。
好吧…其实也有一些区别,主要是有下面一些限制:
- 只有线性渐变,不支持辐射渐变;
- 填充图像必须向两侧重复;
- 不支持裁剪区域;
- 不是同一的缩放,可能造成边框笔触缩放不正确。
它很慢。我们不应该使用这种技术去实现一些惊人的动作,因为原本 Internet Explorer 的 JavaScript 解析器就比其他浏览器蛮很多。一旦你使用 JavaScript 库开始绘制复杂的形状,这个库会将这些指令转换成完全不同的另外的技术实现,效率由此降低很多。简单的例子,比如绘制几条直线或者图像变换,不会看出来,但是如果你开始使用基于 canvas 的动画或者其他疯狂的举措,性能下降一眼就看出来了。
使用 excanvas.js 还有一个警告,这个问题是我使用这个库创建本章的这些例子是遇到的,ExplorerCanvas 会在你包含了 excanvas.js 的页面中自动初始化它自己的假的 canvas。但是这并不意味着 Internet Explorer 能够立刻使用它。在特定的情形下,你可以在这个假的 canvas 差不多完成的时候给出一个竞争条件。主要问题是在你使用<canvas>
做任何操作,比如获取绘图上下文的时候,Internet Explorer 会抱怨说“该对象不支持这个属性或者方法”。
最简单的解决方案是将所有 canvas 相关的代码放到onload
事件触发之后。这可能会耽误一段时间,特别是你的页面包含了很多图像或者视频的时候,它们都会推迟onload
事件,但至少这样做能够让 ExplorerCanvas 正确的运行起来。