loveky

Canvas与SVG: 选择合适的工具

loveky · 2016-07-25翻译 · 1270阅读 原文链接

jCanvas入门: 当jQuery遇上HTML5 Canvas发表在SitePoint之后,由Craig Buckler发起的一项讨论如雨后春笋般涌现出来:是否存在一些使用场景更适合使用HTML5 Canvas而不是SVG呢?

两者都是可以用来创建经验的图像与视觉体验的标准HTML5技术。但是在你项目里使用哪一个是否会有不同呢?

Craig的评论曾经直至关于Canvas和SVG讨论的核心,正如他写的那样:

Canvas的一个好处是你不需要一个DOM结构。它允许你操纵成千上万元素的动画而不用担心DOM操作的开销 —— 这对游戏来说简直完美。

跟随Craig的脚步,我会尽我所能去探索上述问题并讨论技术选型时要考虑的关键因素。

首先,让我们通过一段文字了解一下HTML5 Canvas与SVG。

什么是HTML5 Canvas?

以下是WHATWG规范中对canvas元素的描述

Canvas元素提供了一个可以通过脚本访问的,与分辨率相关的位图画布。利用它你可以实时的绘制图像,游戏画面,艺术或是其它视觉影像。

换句话说,<canvas>标签提供了一个可以通过JavaScript创建图像或对图像进行像素级操作的接口。

这里有一个简单的示例

HTML部分:

<canvas id="myCanvas" width="800" height="800"></canvas>

JavaScript部分:

var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.fillStyle = '#c00';
context.fillRect(10, 10, 100, 100);

你可以利用HTML5 Canvas API获取一个2D上下文对象。在上边的例子中,我画了一个红色的正方形,100x100像素大,距离绘画区域的左上角在水平和垂直方向上各10像素。

Red square drawn using HTML5 Canvas

由于与分辨率相关,当<canvas>中的图像被放大或是展示在视网膜屏上时会出现失真。

绘制一些简单的形状只是Canvas功能的冰山一角。HTML5的Canvas API允许你绘制圆弧,路径,文本,渐变等效果。你还可以逐像素的操作图片。这意味着你可以把图像某个区域的颜色进行替换,为图像增加动画效果,甚至在Canvas上绘制视频并修改它的展现方式。

什么是SVG?

SVG代表可缩放矢量图形根据规范中的描述

SVG是一种描述二维图像的语言。它可以作为独立的语言使用,或是当与其它XML混合使用时,使用XML语法[XML10]。当和HTML5配合使用时,它使用HTML5的语法[HTML]。

SVG图像可以是动态且有交互效果的。动画的定义和触发可以通过声明(在SVG内容中内嵌SVG动画元素)或脚本实现。

SVG是一种被设计用来创建向量图像的XML文件格式。与通过HTML5 Canvas生成的图像不同,可缩放的优势在于当你增加或缩小图像大小的时候,图片的锐度和质量并不会受到影响。

以下是一个和通过HTML5 Canvas创建的完全相同的红色方块,但这次使用了SVG绘制:

<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 600 600">
  <desc>Red rectangle shape</desc>
  <rect x="10" y="10" width="100" height="100" fill="#c00"  />
</svg>

你可以使用SVG完成使用<canvas>时的绝大多数操作,例如绘制形状,路径,渐变,图案,动画等等。然而,这两种技术有着根本上的不同。如在以下各章节越来越清晰的那样,这些差异将在很大程度上决定你的下一个项目该使用<canvas>还是SVG。

立即模式与保留模式

区分开立即模式保留模式是很重要的。它们是把内容展示在浏览器上的两种方式。

HTML5 Canvas API是立即模式的一个例子:你,作为程序员,需要计算出绘制对象的命令,创建和维护的最终输出应是什么样子的模型或场景,并指定需要更新的内容。浏览器的图形API只是简单地传达你的绘图命令到浏览器,然后执行它们。

SVG则使用了保留模式,你只需描述你想在屏幕上展示的效果,浏览器的图形API会在内存中创建关于最终展示效果的模型活场景并把它翻译为浏览器可以理解的绘制命令。

回到Craig的评论,作为一个立即模式的图形系统,<canvas>不需要DOM,也就是文档对象模型。通过<canvas>,你可以绘制像素,系统并不会记录它们,这就避免了需要额外的内存空间来维护绘制的状态。使用SVG时,你绘制的每个对象都会被记录到内置模型中,这对你来说会方便很多,但会消耗额外的性能。

基于立即模式和保留模式的差别以及<canvas>和SVG各自的特性,可以归纳出一些使用某一个技术优于使用另一个技术的场景。

HTML5 Canvas与SVG对比

HTML5 Canvas规范中清楚的建议,当有其它更合适的方法时,不要使用<canvas>

例如,对于一个丰富多彩的<header>元素来说,最好的开发工具是HTML和CSS,而不是<canvas>。这是一个明确的不该使用<canvas>的例子。

现在,让我们归纳出一些适用于(甚至优于SVG)<canvas>的场景。

为了这个目的,让我们分别总结一下<canvas>和SVG各自的特性。这将有助于帮助我们了解他们的能力和局限性。

什么是HTML5 Canvas擅长的呢?

总结起来,HTML5 Canvas是一种依赖分辨率的,不维护自身模型的立即绘制系统。最后一个特点是其绘制速度如此之快的关键所在,这使得HTML5 Canvas非常适合执行以下任务:

光线追踪

光线追踪是一种创建3D图形的方法。如果你感兴趣,这里是一个光线追踪应用的实例。

Canvas Raytracer by Mark Webster

然而,虽然HTML5 Canvas比SVG更适合这项工作,但这并不意味着光线追踪在<canvas>上执行是最好的。事实上,针对CPU的消耗可能会非常大,大到可能导致你的浏览器停止响应。

在一个较小的空间绘制大量的对象

另一个例子是当你需要在一个较小的空间绘制大量对象的时候。比如非交互式的实时数据可视化,比如气象图。

Graphical representation of weather patterns with HTML5 Canvas

上边的图片来自MSDN的文章

针对视频的像素级操作

像在HTML5 Doctor的文章里演示的那样,另一种适合使用Canvas的场景是当需要替换一段视频的背景色为另一种颜色,场景,图片的时候。

Replacing pixels in a video to convert it to grayscale on the fly using HTML5 Canvas

什么是Canvas不擅长的?

另一方面,和SVG相比,还有一些场景中<canvas>并不是最佳选择。

可伸缩性

在需要支持伸缩性的大多数场景里,SVG都比<canvas>更合适。高保真度的复杂图像比如建筑和工程图,组织结构图,生物图等,都是这方面的例子。

如果使用SVG绘制,当放大图像或是打印图像时所有高质量的细节都会被保留。你还可以从数据库中生成这些文档,这使得SVG的XML格式非常适合这种工作。此外,这些图像通常都是可交互的。设想一下当你预定机票时的座位图,这就是一个非常适合使用保留模式图像系统,比如SVG,的场景。

无障碍性

如果无障碍性对你的应用来说很重要,那通常不建议你使用<canvas>。你在Canvas上绘制的只是一堆像素点,这并不能被辅助技术或是搜索引擎爬虫读取或解析。这又是一个更适合SVG的领域:SVG只是XML文档,这使得它既可以被人类也可以被机器阅读。

不依赖JavaScript

如果你不在应用中使用JavaScript,那么<canvas>就不是你的首选了。事实上,使用<canvas>的唯一途径就是JavaScript。相反,你可以使用如Adobe Illustrator或Inkscape这样的标准矢量编辑程序绘制SVG图形,你可以用纯CSS来可以控制它的外观和执行有吸引力的动画。

在高级场景下组合使用HTML5 Canvas和SVG

有些情况下你可应用可以组合使用HTML5Canvas和SVG来达到最佳效果。例如,一个基于<canvas>的游戏可以利用矢量编辑程序生成的SVG图来实现雪碧图以达到伸缩性和减少下载量的目的。又或者一个绘图程序可以利用SVG来构建用户界面并使用嵌入的<canvas>元素用来绘图。

资料

如果你想深入了解今天的话题,以下是一些不错的资料:

总结

在本文中,我们讨论了HTML5 Canvas和SVG的一些核心功能以便在某些特定的场景下对两者做出选择。

在我看来,最终结果是没有硬性规定表明<canvas>一定比SVG好。然而,立即模式和保留模式的区别还是为我们的选择提供了一些依据。

我想以一个在HTML5 Canvas和SVG之间选择时非常具体的提示结束本文:

如果你想向屏幕绘制像素而不用关心获取并修改这些图形,那么Canvas很可能是最佳选择。如果你需要读取并改变图像中的特定部分,那么SVG可能会更合适。

HTML5 Canvas和SVG,你会选择哪一个呢?

所有HTML5 Canvas和SVG的大神,都来分享一下你们的经验吧!

相关文章