首页 HTML5 Dive Into HTML5:绘图(续四)

Dive Into HTML5:绘图(续四)

0 1.6K

图像

IEFirefoxSafariChromeOperaiPhoneAndroid
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 正确的运行起来。

发表评论

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2