SVG 与 Canvas:如何选择

文章来源:https://msdn.microsoft.com/zh-cn/library/gg193983

本主题一开始将对 SVG 与 Canvas 进行简要比较,接下来会讨论大量的比较代码示例,如光线跟踪和绿屏。

注意  为了查看本主题中包含的很多示例,你必须使用支持 SVG 和 Canvas 元素的浏览器(如 Windows Internet Explorer 9)。

 

简介

HTML 不断演变以提供更好、更丰富的标准图形来帮助改进客户体验。 为 Web 开发人员创造了使用基于标准的 Web 技术创建图形丰富的交互网站和应用程序的机会,而无需使用专用的技术或编写浏览器特定的代码。以下各节介绍了矢量图形的概念并执行相应操作:

  • 区分即时模式和保留模式之间的差异
  • 介绍用于即时模式图形的 HTML5 Canvas 元素并提供对 Canvas 的概述
  • 介绍可缩放矢量图形 (SVG)、一组用于保留模式图形的 HTML5 元素并提供对 SVG 的概述
  • 指导新开发人员和有经验的开发人员对矢量图形和 HTML5 使用其中一个矢量图形模型(或同时使用两者,具体取决于方案)

矢量图形

矢量图形不是新概念。它们是全部基于矢量来表示图像的几何基元(形状、点、线条和多边形)。在 1960 年代后期,向 Logo 编程语言添加了矢量图形语言(海龟绘图)来支持用于执行绘图功能的海龟机器人。虽然图形世界在复杂性方面已经发生了重大的演变,但是存在的基本概念是相同的。

矢量图形的复杂性范围从简单到适中再到相当复杂。下面是一些基本示例。

  • 简单 – 一个文档或插图中的标注。
  • 适中 – 图表、关系图和地图等插图。
  • 复杂 – 类似那些用于工程的文档。

尽管前面的示例在性质上是静态的,但是矢量图形也支持交互性,这是一项可显著扩展方案的关键功能。矢量图形为 Web、桌面和设备上的应用程序提供交互和静态的格式。

矢量图形方案的简要概述

在当今 Web 上

  • 网页中使用矢量图形作为背景图像以支持高 DPI 和“收缩”缩放功能。
  • 地图属性(如 Bing 地图)用来执行线路查找操作。
  • 显示实时的图表和图形的交互式股票网站。
  • 选择和其他地图
  • 航班或音乐厅的座位图。
  • 游戏。

在办公室中

  • Microsoft Office Word(用于剪贴画)、PowerPoint 和 Excel 以及 Visio 形状等高效工具。
  • 输出矢量图形格式的 CAD 工具。
  • 呈现交互图表和图形的 Oracle 和 Microsoft Dynamics 应用程序等企业工具。

在设备上

  • 使得图形用户界面更加丰富。
  • 用户交互小工具和图标。
  • 完整 PDA 用户体验。

专业设计器和使用工具

专业的 Web 设计人员在如下工具集中查看矢量图形:

  • 用于创建高质量静态图像(可以导出为 SVG)的 Adobe Illustrator
  • 可以导出为基于 XML 的矢量语言的 Adobe Flash Professional
  • 用于 Windows Presentation Foundation (WPF) 和 Silverlight 的 Microsoft Expression Blend

请务必注意,矢量图形已经在桌面、设备和 Web 上存在很长时间了。

HTML5 图形技术

借助 HTML5,开发人员或设计人员现在可以使用基于标准的技术来创建以前的体验。这样可消除对插件的安装(50% 的网站放弃访问均与插件的安装相关),从而可以极大地改善用户体验。目前,图形由浏览器原生提供,而对于 Internet Explorer 9,则利用 Microsoft Windows 和硬件加速图形的功能。

下一节概述了两种全新但不同的技术、这两种技术的使用方法以及各自的优势和限制。使用一个矢量图形方案谱表来讨论用于为每个方案选择最佳技术的方法。

下图显示了存在于矢量图形中的一个常规方案谱表。每一个方案都可能会更接近于 canvas 或 svg,这意味着一种技术相对于其他技术更适合该方案。如果方案位于谱表中间,那么选择任一技术都是可行的

矢量图形方案谱表几乎所有矢量图形都可以使用上述任一种技术来绘制,但有时根据任务的不同,会有非常多的工作要由开发人员或计算机完成。 当我们检查每种技术的用例,然后将其应用于常见方案时,我们会进一步了解此谱表。

技术简介

下一节介绍了用于在 HTML5 中创建矢量图形的技术,从而建立对早期存在的方案的讨论。

使用示例

若要使用以下示例,请将以下代码示例用作模板。可以使用此模板来开发 SVG 而非 HTML。此模板在本主题的每个示例中使用。由于格式原因,你可以使用脚本以及样式。此模板还包含一个 Meta 标记,这使得可以在本地文件共享上更轻松地进行 SVG 开发。这些示例使用下面的格式。首先提供有意义的代码,然后链接到完整代码。

<!DOCTYPE html >
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=9"/>
    <style type="text/css" media="screen">
    </style>
    <script type="text/javascript">
    </script>
  </head>
  <body>
  </body>
</html>

http://samples.msdn.microsoft.com/workshop/samples/graphicsInHTML5/template.htm (单击“查看源文件”即可查看此标记)。

SVG

SVG 用于描述可缩放矢量图形,这是一个保留在内存中模型中的保留模式图形模型,而内存中模型可通过重新呈现的代码结果进行操作。这不同于即时模式,该模式将稍后讨论。在 HTML5 中同时提供这两种模式。

SVG 是一个保留模式模型,作为对独立供应商(Microsoft 和 Adobe)所提出的两个建议的回应,在 1999 年引入。成立了 W3C SVG 工作组,并且在 2001 年 SVG 规范达到了“建议的状态”。目前,我们按照 SVG 1.1 第 2 版工作,该版本在编写本文时处于“最后征求意见”阶段。

尽管 SVG 可以作为独立文件进行提供,但是最初着重于将它与 HTML 自然集成。

类似于 HTML,SVG 也是使用元素、属性、和样式来构建文档。首次将 <svg> 元素引入到文档中时,该元素的行为非常类似于 <div> 且作为 HTMLDocument 的一部分,但它包含附加接口 SVGDocument(SVGDocument 提供与矢量图形的更深入、更丰富的交互)。

元素

尽管外部 <svg> 包装适合于 HTML 框模型,但是大多数情况下,内部模型都会从该包装中分离出来,因为矢量不局限于简单的框。这种分离要求扩展 SVG 中的属性才能提供丰富的图形。

例如:

<svg height="1000px" width="1000px">	
  <rect id="myRect" height="100px" width="100px" fill="blue"/>
</svg>

http://samples.msdn.microsoft.com/workshop/samples/graphicsInHTML5/bluerect.htm

注意  为了呈现此内容以及以下很多示例,你必须使用支持 SVG 和 Canvas 元素的浏览器(如 Internet Explorer 9)。

之前的 HTML 代码将创建一个正方形,长宽均为 100 像素,并使用蓝色背景进行填充。

SVG 蓝色正方形此 <rect> 元素保留在 HTML 文档的文档对象模型 (DOM) 中。就像其他 HTML 元素一样,可通过多种不同的方式设置 SVG 的样式。下面的示例是一个表。

样式设置

开发人员可能会注意到属性是类似的。SVG 同时具有属性和演示属性。此处看起来描述有点随意,但关键在于可以按照 CSS 样式规则设置演示属性的样式。

四个矩形使用几种不同的方法进行填充。

<!--No fill (defaults the color to #000000)-->
<rect id="myRect1" height="100%" width="100%" >

<!--using the-->
<rect id="myRect2" height="100%" width="100%" class="greenrect"/>

<!--using the style="fill:pink"-->	
<rect id="myRect3" height="100%" width="100%" style="fill:pink"/> 

<!--using the attribute fill="red"-->	
<rect id="myRect4" height="100%" width="100%" fill="red"/>

四个带颜色的 SVG 正方形第一个示例演示省去一个属性会在图形上产生可视效果。在此示例中,颜色默认为黑色。

第二个示例演示使用 class=”greenrect” 来填充矩形。包含的用于填充此矩形的 CSS 的形式为:

rect.greenrect {fill:green;}

第三个示例使用内联样式将填充设置为粉色。最后一个示例使用相应属性填充红色。此示例还演示了 CSS 选择器的用法。样式还包括:

rect:hover {fill:yellow;}

这针对所有矩形建立一个规则,即鼠标悬停在这些矩形之上时颜色更改为黄色。

这些对于有经验的 Web 开发人员来说应该都不是新内容了。此处提供这些示例是为了强调相似性(使用样式、样式表、类和选择器)以及差异(样式不适用于所有属性,仅适用于演示属性、新属性或不一致的属性)。

http://samples.msdn.microsoft.com/workshop/samples/graphicsInHTML5/svgstyling.htm

可编程性

属性 API 及其他 DOM 操作仍应用并遵循当前的属性规则。例外情况是,演示应用程序基于样式所取代的属性(如果适用)。

如果这些属性是通过核心属性或通过其各自的 DOM 方法进行设置的,则将影响这些属性的演示,并且基础 DOM 将相应地发生更改(注意使用 SVG DOM 设置高度的不同语法):

document.getElementById("myDiv").style.height = "200px";
// alternatively
//document.getElementById("myDiv").style="height;200px";

document.getElementById("myRect").height.baseVal.value = 200;
// alternatively
//document.getElementById("myRect").setAttribute("height","200px");

交互

SVG 的另一个关键区分因素是能够进行代码交互且不复杂。正如 SVG 具有一个类似 HTML 的可编程 DOM 一样,它还具有事件模型。检查下面比矩形或正方形更复杂的图形:路径。

使用路径可绘制任意形状,例如在该示例中为表示美国的阿拉斯加州和夏威夷州的两个形状。

阿拉斯加州和夏威夷州http://samples.msdn.microsoft.com/workshop/samples/graphicsInHTML5/svginteractivity.htm

触发创建之前指定的警报的事件。这些复杂形状(像更简单的矩形)也会响应 CSS 选择器。使用一行 CSS 即可实现简单的突出显示机制:

path:hover {fill:yellow;}

Canvas

另一种向用户提供更丰富的图形体验的方法,通过 <canvas> 标记提供,该标记由 Apple for Safari 在 HTML5 中或在其他图形小工具中引入。它在绘制即时模式图形(包括矩形、路径和图像)方面公开更具编程性的体验,与 SVG 类似。即时模式图形呈现是一个“触发即忘”模型,该模型将图形直接呈现到屏幕上,但随后对所完成的操作不保留任何上下文。与保留模式相反,不保存呈现的图形;要在每次需要新框架时描述整个场景,开发人员需要重新调用所有必需的绘图命令,而不考虑实际更改(SVG 已知拥有“场景图”)。

元素

为了使用画布 (Canvas) 功能,Web 开发人员直接引入了一个 Canvas 元素:

<canvas id="myCanvas" width="1200px" height="1200px"></canvas>

然后使用 <canvas> 传统的2D基础库 API 来绘制图像和矢量。

使用 JavaScript 代码执行对画布上图形的操作,通过添加对图形的支持可以获得 Web 开发人员熟悉使用的优势。

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

如前面提到的,存在与 SVG 中相似的形状和对象,举例来说,开发人员可以使用下面的代码来绘制矩形:

ctx.fillStyle = "rgb(0,0,255)";
ctx.fillRect(10, 10, 100, 100);

稍后将讨论这些方法的优缺点以及适当的方案。

最终结果与在 SVG 中相同。http://samples.msdn.microsoft.com/workshop/samples/graphicsInHTML5/canvasintro.htm

Canvas 蓝色正方形但正如 SVG 一样,Canvas 具有更复杂的几何基元,区别在于这些基元采用函数形式。

事件的可编程性

为了能够绘制比矩形更复杂的图形(如前面显示的夏威夷地图),canvas API 提供了一个路径 API,该路径 API 支持与 SVG 中的 <path> 元素相似的命令,只是你要对每一行代码段调用相应的 API,而不是在单个属性中列出它们:

ctx.beginPath();
ctx.moveTo(233.08751,519.30948);
ctx.lineTo(235.02744,515.75293);
ctx.lineTo(237.29070000000002,515.42961);
ctx.lineTo(237.61402,516.23791);
ctx.lineTo(235.51242000000002,519.30948);
ctx.lineTo(233.08751,519.30948);
ctx.closePath();

有关夏威夷地图,请参阅 http://samples.msdn.microsoft.com/workshop/samples/graphicsInHTML5/canvasmap.htm

路径 API 并不局限于 moveTo 和 arc,它包含相同的 SVG 方向相位(包括二次曲线和贝塞尔曲线)。

通过有限的事件和功能可以捕获鼠标在图像上的位置。因为不存在图形保留知识,所以编程人员必须转换 mouseX 标记的单个元素上的 mouseY<canvas> 坐标,然后将该命令相应地传送到位于内存中结构中的形状。第三方库为支持更复杂的路径而存在,这包括内置isPointInPath API,但后者被限制为最后路径绘制。因而与 SVG 不同,既没有任何样式也不支持多个几何图上的命中检测。另外,因为 Canvas 不支持可伸缩性,所以缩放时夏威夷地图将很快失真:

夏威夷地图在缩放时显示失真Canvas 是一个功能强大的低级别 API,开发人员利用它可以提供新的图形体验。

Canvas 与 SVG 的简要摘要

下面是简要摘要,可帮助你确定何时使用 Canvas 而不使用 SVG 或者何时使用 SVG 而不使用 Canvas 来创建矢量图形。

Canvas SVG
基于像素(动态 .png) 基于形状
单个 HTML 元素 多个图形元素,这些元素成为 DOM 的一部分
仅通过脚本修改 通过脚本和 CSS 修改
事件模型/用户交互颗粒化 (x,y) 事件模型/用户交互抽象化 (rect, path)
图面较小时、对象数量较大 (>10k)(或同时满足这二者)时性能更佳 对象数量较小 (<10k)、图面更大(或同时满足这二者)时性能更佳

 

在上表中,考虑这二者在现有软件方面的意象模型。Canvas 类似于 MSPaint,在其中,你可以使用形状和其他工具来绘制和创建图像。SVG 类似于 Office PowerPoint 幻灯片,它具有可编程的支持并且能够添加主题。

何时使用 <canvas>、何时使用 SVG:方案

这一节介绍这两种技术的技术优势和限制,包括用于确定一种技术何时相对于另一种技术更适合的常用方法。应该注意的是,SVG 和 <canvas> 都能实现几乎相同的结果,功能也完全重复。介绍以下特定情况非常重要:<canvas> 明显好于 SVG,或相反,二者组合更加合适,或可以使用和考虑任一技术。

矢量图形方案谱表这些方案比较清晰地描述了更适合使用 SVG 的情况、更适合使用 Canvas 的情况,以及其他介于这之间的情况。它们描述了每种技术的优缺点,以便开发人员可以了解相应技术的行为并针对其应用程序做出好的选择。

从性能方面选择

有时存在一些外部影响,要求独立于(或几乎独立于)功能选择技术。有关使用 Canvas 或 SVG 的问题,存在两个主要区别。

有时开发人员的知识、技能组合和现有资产会对技术的选择起到重大作用。如果开发人员具备低级别图形 API 方面的深层知识,但在 Web 技术方面知识有限,则很可能会选择 Canvas 技术。

另外,性能对于高流量的网站来说是绝对关键的。可以对这两种技术的性能特征加以比较。这可能会要求开发 Canvas 没有附带的辅助功能、自定义样式以及更粒度化的用户交互功能。虽然 Canvas 通常被视为具有高性能,但是并不意味着它就是明显的选择。下图显示了 SVG 对象和 Canvas 对象之间在呈现时间上的差异。

Canvas 与 SVG 性能一般情况下,随着屏幕大小的增大,画布将开始降级,因为需要绘制更多的像素。随着屏幕上的对象数目增多,SVG 将开始降级,因为我们正不断将这些对象添加到 DOM 中。这些度量不一定准确,以下方面的不同一定会引起变化:实现和平台、是否使用完全硬件加速的图形,以及 JavaScript 引擎的速度。

高保真度的复杂矢量文档

高保真度的复杂矢量文档已经成为并将继续成为 SVG 的最有效点,原因主要有两个。存在足够多的极为详细的文档,包括由 CAD 程序生成的那些文档,针对这些文档,SVG 的 scalable 部分提供了独立文档形式或嵌入网页中的文档形式的详细视图。通过该技术还可以进行高保真打印。SVG 的声明性性质向工具、客户端或服务器端提供从数据库生成形状的能力。 最后,我们看到了政府机构的发展,因工程图(为了专利)或工业图(为了城市规划目的)缘故从建议支持转变为对 SVG 的必需支持。这种转变还将继续,因为对于公众使用的电子文档(如下),政府部门越来越不是只喜欢一家供应商:

  • 建筑图、工程图和楼层图
  • 电子图、航空图和示意图
  • 组织结构图
  • 地图
  • 生物图

以下各图显示了前一方案中可以保留的详细信息示例。第一个图像显示可以在测试驱动网站上找到的网页快照。它包含呼吸系统图和元素周期表。

http://ie.microsoft.com/testdrive/Graphics/RealWorldDataAndDiagrams/Default.xhtml

缩小的元素周期表第二个图像显示同一张图放大 1000% 后的效果

放大的元素周期表尽管考虑到观察大的示意图的有用性,但在需要细化到细节处时或者出于工程目的需要打印整个示意图时,具有可缩放性的 S 将变得足够清晰和有价值。出于这些原因,我们将高保真度的复杂矢量文档放在谱表的远端,接近 SVG,如下图中所示。

高保真的文档显示在接近 SVG 的谱表端这些文档也可以受益于交互性,这是 SVG 使这些方案最适合于保留图形模式的第二方面。

增强的 Web 图形

SVG 作为图像格式

SVG 另外还常用于简单图像,无论是应用程序还是网页中的图像,大图像还是小图像。由于 SVG 要加载到 DOM 中,或者创建图像前至少要进行解析,所以性能会稍微有所下降,但相比于呈现网页的成本(大约几毫秒),这种下降是极其微小。

在文件大小方面(为了评估网络流量的目的),下面演示的两个图像是一样的,只差了 1K(SVG 稍微大点,没有压缩)。

两个蓝色球体的图像与以前一样,因为 SVG 作为图像格式是可缩放的,所以如果开发人员想要以更大的比例使用该图像,或者用户使用高 DPI的屏幕,则可移植网络图形 (PNG) 要么会变得异常,要么需要更大形式的文件来实现保真。

两个蓝色球体的图像SVG 因此可以充当非常好的图像替换格式,甚至对网页上最简单的图像也是如此。静态 WebApp/网页图像因此落在谱表的 SVG 端。

静态图像显示在接近于 SVG 的谱表端

像素操作

在谱表的另一端,当使用 Canvas 时可以获得快速的绘图速度,且不需要保留相应信息。存在若干种最适合于 <canvas> 的实时数据方案。使用光线跟踪在像平面上通过像素跟踪光线路径并模拟其与虚拟对象相遇的效果,可以水化图像。 下图显示了这种模拟。

使用 Canvas 的光线跟踪示例

需要很多计算,因此速度依赖于浏览器中的 JavaScript 引擎速度。然而尽管大多数情况下本地代码无可置疑要更快一些,但是随着 JavaScript 引擎逐渐成熟,我们开始看到在像程序集和 C++ 这样的时期内这种差距在缩小。

光线跟踪(通常在 Web 上的背景中完成)获得的效果甚为广泛。范围从创建许多不同的视觉效果(包括根据其他简单矢量图形创建逼真的图像)到应用照片过滤器以去除红眼。

因为 Canvas API 允许开发人员读写像素,所以这里唯一的限制是速度和想象力。上一个示例由 Adam Burmister 提供并且位于 http://labs.flog.co.nz/raytracer/ 上。 在此示例中,可通过大量的库来实现创建最终图像所需的计算,但主结束函数是 fillRect

setPixel: function(x, y, color){
  var pxW, pxH;
  pxW = this.options.pixelWidth;
  pxH = this.options.pixelHeight;

  this.canvas.fillStyle = color.toString();
  this.canvas.fillRect (x * pxW, y * pxH, pxW, pxH);
},

出于此原因,高性能图形(如光线跟踪器)作为 Canvas 方案落在谱表的最左端,如下图所示。

高性能图形在谱表上靠近 Canvas注意生成上述光线跟踪器的作者 注意 因为该方案将产生静态图像,所以桌面软件经过了很好的调整以适合光线跟踪器所需的大量浮动操作。

下至金属像素操作的有趣实现是图像的过滤器应用。过滤器已存在于 Web 上,且需要显著的处理速度(受益于其对图形管道中更深层的硬件加速图形的应用),因此开发人员可以试用边缘检测或其他数学表达式等算法。

实时数据

对于更常见的方案,Canvas 非常适合输出实时数据。请注意如何简便地确定这些方案,因为已经表明使用 Canvas 难以进行用户交互。因此,下面将讨论非交互的实时数据可视化。

今天的天气数据可以通过特定间隔内服务器上生成的图像非常静态地呈现,也可以尽可能快地通过客户端第三方插件呈现。尽管 ECWMF 已经研究过使用 SVG 而不使用服务器生成的图像如何节省成本,但是 Canvas 在天气模式(以及其他快速的实时数据)的大多数图形表示形式方面,明显是赢家。下图显示以图形方式显示在地图上的天气模式。

显示在地图上的天气模式

如你可以从上图中看到的,没有必要存在大的绘图图面,而且屏幕上的对象数量是相当高的。通过使用 Canvas API,可以在不影响 DOM 的情况下快速绘制(和擦除)这些对象。尽管可以使用 SVG Ellipse 完成此操作,但是将它们加载到 DOM 中以及通过动画修改它们的成本是非常高的。事实上,无论你是在图像中还是在数据动画中看到大量的形状(尤其是不相似的形状)要进行分析,通常都会指出 Canvas 是要使用的技术。这里的实际限制是受 CPU 速度和 JavaScript 引擎速度的控制,能多快可视化显示数据。但除了占用 CPU 的光线跟踪方案之外,仍然可以实现合理的动画。Reasonable 描述客户端可以使用 JavaScript 执行的操作与服务器可以通过电线计算和封送的操作之间的相对动画。

此方案似乎是 <canvas> 的关键用例。

复杂场景和实时动画在谱表上偏向 Canvas

像素替换(绿屏)

另一个使用 Canvas 的可能情况是,在视频上进行颜色检测以便用其他场景或图像替换背景色。像光线跟踪器或过滤器一样,因 JavaScript 中当前性能速度限制的缘故,很可能会使用桌面软件预处理任何需要高的最终产品质量的现实方案。但是,由于 <canvas> 是为低级别像素读取和写入设计的,因此诸如 greenscreen 替换之类的方案甚至无法使用 SVG 完成。

从两个视频中读写像素到另一个视频中所需的代码要求使用两个视频、两个画布和一个最终画布。一次捕捉视频上的一帧,然后绘制到两个单独的画布上。这样允许读回数据。

ctxSource1.drawImage(video1, 0, 0, videoWidth, videoHeight);
ctxSource2.drawImage(video2, 0, 0, videoWidth, videoHeight);

因此,下一步是检索每个绘制图像的句柄,以便你可以检查每个单独的像素。

currentFrameSource1 = ctxSource1.getImageData(0, 0, videoWidth, videoHeight);
currentFrameSource2 = ctxSource2.getImageData(0, 0, videoWidth, videoHeight);

获取后,代码将浏览绿屏的像素数组,搜索绿色像素,如果找到,代码将用背景场景中的像素替换所有绿色像素。

for (var i = 0; i < n; i++) 
{
  // Grab the RBG for each pixel:
  r = currentFrameSource1.data[i * 4 + 0];
  g = currentFrameSource1.data[i * 4 + 1];
  b = currentFrameSource1.data[i * 4 + 2];

  // If this seems like a green pixel replace it:
  if ( (r >= 0 && r <= 59) && (g >= 74 && g <= 144) && (b >= 0 && b <= 56) ) // Target green is (24, 109, 21), so look around those values.
  {
    pixelIndex = i * 4;
    currentFrameSource1.data[pixelIndex] = currentFrameSource2.data[pixelIndex];
    currentFrameSource1.data[pixelIndex + 1] = currentFrameSource2.data[pixelIndex + 1];
    currentFrameSource1.data[pixelIndex + 2] = currentFrameSource2.data[pixelIndex + 2];
    currentFrameSource1.data[pixelIndex + 3] = currentFrameSource2.data[pixelIndex + 3];
  }
}

最后,像素数组将写入到目标画布中。

ctxDest.putImageData(currentFrameSource1, 0, 0);

http://samples.msdn.microsoft.com/workshop/samples/graphicsInHTML5/canvasgreenscreen.htm(若要完整地查看 greenscreen 代码,请查看该页的源代码。)

Canvas 与 SVG 谱表

组合/交叉方案

以下方案可以在 SVG 或 Canvas 中完成,都可以获得适当的结果,但你可能会更喜欢一项技术胜过另一项技术。

图表和图形

需要矢量图形的图表和图形的谱表很宽广。大部分这些图形最好使用 SVG 进行创建,因为它们具有下列三个特征之一:

  • 图形是从可以轻松转换为 XML (SVG) 的现有数据生成的
  • 它们需要用户交互
  • 优点是可在网页上设置样式

我们使用可显著增加方案范围的交互功能来扩展高保真文档方案。 其中包括:

  • 交互的组织结构图和流程图
  • 数据图(环形图、条形图、散点图)
  • 交互式地图 – 路径查找
  • 建筑图、工程图和楼层图
  • 航班或音乐厅的座位图

已经确定快速的实时数据处理已针对 Canvas 进行了更好地优化(主要取决于速度)。

二维游戏

制作休闲游戏(此处定义为 Web 上的简单二维游戏)时,开发人员需要在 canvas 和 svg 之间做出选择。因为历史上游戏库一直利用较低级别的图形 API,所以将倾向于选择 <canvas>

当库的其他组成部分(如受欢迎的物理引擎)比图形层要明显深时,图形将变成实现细节。边框、速度、大小和位置等图形几何将传递给引擎,而引擎随后将用速度、碰撞和位置进行响应。图形位于堆栈中的最高层。

通过由同一作者开发的两个游戏来演示独立于游戏逻辑的图形概念,旨在说明 <svg> 和 <canvas>SVG-oids 和 canvas-pinball。一个出色的、独立于游戏引擎的图形层示例是将 canvas-pinball 与 SVG-Dice 进行比较(当两者都使用相同的物理引擎时)。

尽管游戏和演示逻辑是不同的,但是这两个游戏的物理引擎都会跟踪位置、碰撞、速度以及游戏组成部分的其他物理方面。

对于 canvas-pinball,自定义的更高级别的动画管理器通过使用一系列 Canvas API 重新绘制场景。

if (animationsInProgress) {
  ctx.save();
  ctx.lineWidth = 2.0;
  ctx.beginPath();
  ctx.moveTo(89, 322);
  ctx.lineTo(101, 295);
    .
    .
    .
  ctx.stroke();
  ctx.restore();
  ctx.moveTo(tVp.x, tVp.y);
}

对于 SVG Dice,自定义的更高级别的动画管理器使用组转换通过 DOM 在屏幕上重新定位现有图形。

if (animationsInProgress) 
{
  this.rotation += (this.circleBody.m_linearVelocity.x/20);
  var transFormString = "translate(" +
    Math.round(this.circleBody.m_position.x) + "," +
    Math.round(this.circleBody.m_position.y) + ") scale (" +
    this.scale.toString() + ") rotate(" +
    Math.round(this.rotation).toString() + "," +
    Math.round(this.xTrans).toString() + "," +
    Math.round(this.yTrans).toString() + ")";
    this.die2.setAttribute("transform", transFormString);
}

一种技术要重新绘制和重新定位形状,而另一种技术只需重新定位,但需要在内存中维护形状,这会带来成本。此成本对于大多数休闲游戏来说都是相当低的,但预期是使用较低级别的 API 实现即时模式图形的游戏更加让人熟悉。

高级方案

可能大部分功能强大的方案都会涉及组合整个图形、样式和文档技术。

用户界面设计

几年前可能就在争论 SVG 是否是适合用于用户界面设计的技术。这些要求与 SVG 一致。事实上,Linux 操作系统的至少一个前端完全建立在 SVG 之上。滑块、复选框、圆形按钮等控件以及其他标准固有控件集中的非框控件都很适合在矢量图形中使用。但是,随着 CSS 的最近和未来开发(包括圆角、渐变、过滤器和打印机事件),可以通过标准的框模型 HTML 文档中心构造来开发大多数这些控件。其他控件(尤其是使用最新 CSS Grid 和 Flexbox 模型的控件)都更好地面向 HTML 元素,至少作为容器。

此处提供了一个丰富的数据驱动图表的示例。 尽管该示例的输出没有架构好,但显示的最终结果正确。 图形和图表控件是众所周知的难开发,但第三方以及 Microsoft 已经成功了。 通过在客户端或服务器端提供最新的数据绑定抽象,客户端的 Web 呈现主要保持静态或者需要插件,这样可减轻开发人员的负担。 下面我们利用了 SVG 的丰富性来提供增强的用户体验。 无论代码如何(将传递给客户端,又或许在将来更多的声明性交互中使用),图表都用两个关键组件来呈现。 工具和数据。图形工具或背景是基本的静态 SVG:

<rect id="tipsh" x="20" y="100" width="194" height="34" rx="5" ry="5" />
<rect id="tip" x="20" y="100" width="190" height="30" rx="5" ry="5" />
<text id="tiptxt" x="40" y="120" font-size="12" font-family="Arial" fill="#ffffff" visibility="hidden">milliseconds</text>
<polygon id="arrow" points="10,110 20,105 20,115" style="fill:#ffffff" />
<line x1="3" x2="460" y1="359" y2="359" style="stroke:#cccccc;stroke-width:1"/>

然后每个单独的数据点要么传递到客户端并进行操作,要么在服务器上生成:

<text x="10" y="348" font-size="12" font-family="Arial">{Page}.svg</text>
<rect x="115" y="350" width="86" height="8" style="fill:url(#inverseblue);filter:url(#Gaussian_Blur);" rx="12" ry="12"/>
<rect x="115" y="333" width="86" height="17" rx="12" ry="12" onmouseover="changeColor(evt)" onmousemove="changeText(evt,'2 milliseconds')" onmouseout="changeTextNotOver(evt)" />
<text x="171" y="345" font-size="11" font-family="Arial" fill="#ffffff">6.1%</text>

http://samples.msdn.microsoft.com/workshop/samples/graphicsInHTML5/svgchart.htm

结论

通过最新浏览器中提供的现有矢量图形技术的分析功能,可以交互方式使用标准 Web 技术来满足现有的和新的方案。 从今以后,我们将拥有巨大的机会可以让声明性动画支持广告版位。 通过使用方案驱动的功能开发,我们可以在竞争中处于领先地位,并在 Web 应用程序和网页中提供基于标准的图形丰富的体验。

关于手机重力陀螺仪事件响应

DeviceOrientationEvent

DeviceMotionEvent

先通过上面两个链接,了解一下两个事件。
DeviceOrientationEvent 获取设备方向;
DeviceMotionEvent 获取设备移动速度。

 

苹果的文档里面简单描述了几个参数、返回值和相关的方法,但是没有写例子。

下面是一个摇一摇变颜色的例子,可以了解一下用法。

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta content="initial-scale=1.0,user-scalable=no,maximum-scale=1,width=device-width" name="viewport">
<title>摇一摇变颜色</title>
<script type="text/javascript">
var color = new Array('#fff', '#fA0', '#f00', '#C00', '#03f', '#0ff');
if(window.DeviceMotionEvent) {
var speed = 20;
var x = y = z = lastX = lastY = lastZ = 0;
window.addEventListener('devicemotion', function(){
var acceleration =event.accelerationIncludingGravity;
x = acceleration.x;
y = acceleration.y;
if(Math.abs(x-lastX) > speed || Math.abs(y-lastY) > speed) {
document.body.style.backgroundColor = color[Math.round(Math.random()*10)%6];
}
lastX = x;
lastY = y;
}, false);
}
</script>
</head>
<body>
<h1>摇一摇变颜色</h1>
</body>
</html>

devicemotion事件包含的方法有:

type

devicemotion的事件类型。

bubbles

指定该事件的冒泡事件。

cancelable

关闭该事件。

acceleration

设备移动的加速度,分为x、y、z三轴。

accelerationIncludingGravity

设备移动的重力加速度,分为x、y、z三轴。

rotationRate

设备旋转速度,包括alpha、beta、gamma三个参数。

interval

距离上次收到回调通知的时间间隔。

 

deviceorientation事件包含的方法有:

type

deviceorientation的事件类型。

bubbles

指定该事件的冒泡事件。

cancelable

关闭该事件。

alpha

在围绕 z 轴旋转时(即左右旋转时),y 轴的度数差。

beta

在围绕 x 轴旋转时(即前后旋转时),z 轴的度数差。

gamma

在围绕 y 轴旋转时(即扭转设备时),z 轴的度数差。

compassHeading

与正北方向的角度差值。正北为0度,正东为90度,正南为180度,正西为270度。因为0度是正北,所以叫指北针,不是指南针。

compassAccuracy

指北针的精确度,表示偏差为正负多少度。一般是10。

如果要了解的更详细,还有两个参考文章。

参考文章:
http://blog.csdn.net/hursing/article/details/9061991
http://blog.csdn.net/hursing/article/details/9046837

Css3-animation画动画实战与心得

最近接到一个H5动画的任务,大概状况是这样:

整体动画长度超过10s,这是一个难点,也是唯一的难点。

关于动画的动作拆解和场景分离,先不在这里说,主要说下写大量animation的感受和问题。

总结出的问题:

问题1:为浏览器兼容产生了大量的重复代码;

问题2:连贯动画的执行方案;

问题3:如何保存动画执行后的状态。

 

关于系统限制的几个问题

animation所执行的动画执行后会回到原来的状态;

循环状态的animation在大多数浏览器在重播的时候会有时间差;

变化频率较高的动画会收到机能的限制,出现卡顿;

setTimeout方法的延时在触摸手机的时候会暂停。

 

想到的一些解决方案:

1、既要写animation又要写-webkit-animation(@keyframe也是如此),只是想想就知道一个几秒的动画脚本要写多少重复代码了。

我的解决方案是把动画脚本和普通样式分离,然后先只写webkit的脚本(方便调试),然后再起一个文件单独写通用样式,这样维护一个动画脚本就好了,不用每次修改效果都要改两个地方。(上述操作也可以自行写构建脚本自动化完成,less、sass看情况使用~)

2、经过测试,animation里的infinite属性在replay的时候,并不是无缝的,而是有时差的,而且各浏览器状况不一样,所以想用此属性跟其他元素做组合效果要有准备。

3、因为动画每次执行后都会回到最初的状态,所以我们需要一个方法保存执行后的状态,我的方法是用setTimeout同步动画的时间,在合适的时候加一个心得class来保存元素的当前状态以便在下一个场景中进行新的动画。但是在手机端,手指触摸屏幕会让js暂停运行(wp不会),虽然animation也会暂停,但仍会产生不可以预知的错误,具体解决方案还在研究中。

 

总结:

显然,只要方法得当,animation是完全可以胜任长时间动画的,这让我们摆脱了没有flash,动画实现门槛高的窘境,相反从某些角度,css3写一些动画灵活性更强。

折行文本末尾定位元素排版方案

说问题之前,先看一张图。

折行文本样图1

 

图中要求蓝色问号图标显示在文本末尾。

关于这个问题和app的同学讨论过,app同学表示实现有难度,让设计同学改了设计稿,将icon放到第一行文本后面,就如同第二行的“成人票”后面那样。

那么wap端能否实现这个效果呢,闭目思考下…

 

答案:能。

 

我们可以把icon直接写在文本后面,这样不就显示在行尾了么。

如果如此简单,app同学怎会轻易示弱,如果第二行只有icon(文字填满第一行),岂不是很难看。

那么我们绝对定位该icon到末尾。
.icon{position:absolute; right:-20px; bottom:0;}
然后我们希望这个元素能定位到我们想要的地方,那么我们希望这个元素的范围是这个样子的。

折行定位2

 

到此就比较明显了(虽然已开始我也没想到),只要设置该元素为内联属性(display:inline)就可以达到这样的效果了。

 

总结:虽然用了绝对定位,但从结构上来讲也还是合理的,主流浏览器都没问题,所以是个可行的方案。

最近看了《隐秘而伟大》,套用到这个问题上,inline虽然是行内元素的默认属性,但也有伟大的一面呀。

关于小米3安卓4.4ROM浏览器兼容问题

经过一些测试,小米3安卓4.4ROM回有一些不可预计的css和js不兼容问题。

可能是小米的开发在浏览器是做了一些优(wan)化(xiao)。

暂时看比较单行的问题是一个老版本swiper插件的拖拽有问题,更具体的还在测试中。

 

从用户的角度,碰到这种问题,影响了浏览,可以通过对浏览器设置->高级->浏览器标识的调整(应该只要不是默认就可以),来恢复正常浏览。

从开发者,用其他插件类库,或者干脆用自己写的东西,来规避这个问题。

健壮自己的代码与粗心战斗

想说的其实就是个代码容错率的问题。

最近出现了一下几个问题:

  1. cookie明明已经存好了,却无论如何取不到—— 是后端同事传cookie的时候在属性名上加了空格;
  2. 判断页面状态出现错误(不详述)—— 是用indexOf截取判断url的时候关键字过于简单(比如只判断了indexOf(“10”)),导致url被加入其他参数的时候判断目的出错;
  3. 多条件判断逻辑要清晰 —— 经常出现判断遗漏条件、默认执行条件有问题的情况;

以上的问题,思考一下,然后想一些方案来解决。

 

如何应对:

  1. getCookie的时候要对属性名清空格;
  2. 关键字尽量完整,因为这是不可预估的问题,测试环境可以方便测试使用,建议生产环境上干脆使用其他方式来达到目的;
  3. 判断要靠图来解决了,画出逻辑图,可以直观看出各个条件节点,带着图和产品确认逻辑也可以将风险外包(笑);

大学时候软件工程学习了代码的健壮性,但是每个人自律的情况不一样,再加上经验的差异,往往出现各种不可预知的问题。

最近吃了不少亏,但从大方向讲收获更多,以上分享给朋友们。

android 4.4.2 KitKat 更新对wap页面的一些影响

问题写在前面。

有的时候我们要跟app进行通讯或者跳转,会用到设定好的URL Schemes去做跳转。

有的开发者可能习惯了驼峰式命名,所以把地址协议也设置成firstSecond://这样的形式。

以前应该是没什么问题,新版本的安卓会把协议强制转换为小写,那么如果你的脚本对大小写敏感的话就要注意这个问题了。

 

下面列举一下官方的更新说明:

 

支持蓝牙MAP

Android现在支持消息访问协议(MAP)。因此,支持蓝牙功能的汽车可与您的设备交换消息。

支持Chromecast

借助Android设备和Chromecast,您可以在高清电视上尽情欣赏喜爱的精彩在线娱乐内容(例如来自Netflix、YouTube、Hulu Plus和Google Play的内容)。

Chrome网页视图

嵌入网页内容的应用现可使用Chrome快速、准确地呈现此类内容。

可选字幕

Android现在支持可选字幕和翻译字幕。要启用可选字幕,请转至“设置”>“辅助功能”,然后开启“字幕”。

内置设备管理功能

如果您丢失了设备,可以通过Android设备管理器找到该设备或清空设备数据。

经过重新设计的“下载”应用

“下载”应用经过重新设计,提供了新的排序选项、列表和网格视图,方便您管理下载的文件。

轻松切换主屏幕

如果您喜欢对设备进行个性化设置,并已安装一个或多个可供替换的主屏幕,则可以在“设置”>“主屏幕”中轻松切换。

经过重新设计的“电子邮件”应用

“电子邮件”应用经过全新设计,面貌焕然一新!现在,该应用不但提供文件夹嵌套、联系人照片等功能,还改善了邮件浏览体验。

全屏壁纸,支持预览

壁纸现在可延伸至通知栏和系统按钮区域。更换壁纸时,您可以先预览其效果再进行设置。*

HDR+拍摄模式

Nexus 5提供HDR+拍摄模式,可自动快速连拍多张照片,并将这些照片合成一张,实现绝佳的单张效果。白天拍摄的照片鲜活生动、光影分明;夜间拍摄的照片轮廓清晰、噪点寥寥。*

红外线遥控

在搭载红外(IR)遥控器的设备上,Android现在支持应用对电视和其他附近设备进行远程控制。

“快捷设置”中的位置信息设置

通过“快捷设置”中的新选项,您可以从任何地方快速调整您的位置信息设置。

位置信息模式和监测

如果您想要节省电池电量,请转至“设置”>“位置信息”,然后在“准确度高”和“耗电量低”位置信息模式之间切换。您无需在GPS、WLAN和移动网络设置之间切换。要查看最近有哪些应用申请使用您的位置信息,请转至“设置”>“位置信息”。

音频播放更省电

搭载Android 4.4的Nexus 5极大地延长了您收听音乐的时间,音频播放时间最长可达60小时。*

在锁定屏幕上调整音乐和电影播放进度

您可以在锁定屏幕上跳至歌曲或视频的某个片段。只需长按播放或暂停按钮,然后选择所需时间点即可。

安全的应用沙盒

应用沙盒功能已通过Security-Enhanced Linux得以强化。

内置计步功能

在Nexus 5上使用健身应用(如Moves)时,手机就相当于一个计步器,可用来计算步数。Android 4.4和新硬件可让您以更省电的方式评估自己的运动量。

以全新方式支持碰触付款

Android 4.4采用了全新的开放式NFC支付架构,支持所有移动运营商,允许应用管理您云端或设备上的支付信息。现在,您可以使用Google电子钱包或其他应用,在超过一百万家商店中使用碰触付款功能。

改进触摸屏

结合改进后的软件和Nexus 5的最新硬件,Android现在能以前所未有的速度和准确度,响应您的触摸操作。*

移动端上的点击事件

刚接触手机的时候,前端工程师喜欢用click去处理点击/触摸事件。
渐渐地,通过体验和看过一些文章,我们知道手机上还有touch专用事件,于是我们开始专用touchstart或者touchend来处理触摸事件,然后我们就碰到了各种问题…

Click的延迟问题

click从功能上讲问题不大,但是响应有延迟,传说300毫秒,其实根据机能不同会有更长时间的延迟。

据说一些安卓机用click会出现其他的问题,我没碰到过所以不细说了。

各种touch先天不足

touch响应快,但是你碰到屏幕就是一个touchstart事件,离开屏幕就是一个touchend事件,就算你去拖动屏幕也会执行触发这两个事件,产生的问题我们叫误点击。

解决响应时间和误点击的几个方案

首先我这里不谈jqueryMobile。

那么我知道的几个解决方案为:

fastclick,https://github.com/ftlabs/fastclick;

MBP.fastButton,https://github.com/h5bp/mobile-boilerplate

zepto的tap和singleTap事件,http://zeptojs.com/

上面几个方案都可以很好的解决响应和误点击问题。

那么我们进入正题——“连点”问题

什么是“连点”?
当你点击一个层,而这个层因为事件控制而隐藏了,这时候恰巧这个层下面的区域点击的同一个位置也有点击事件被触发了,那么就是“连点”了。

这个问题发生在弹出层的情况比较多。

上面提到的三个方案在新的手机里面都不太容易(总有特殊情况)出现“连点”问题,但是在老的安卓里面,比如我手上的三星Note中fastclick就会出现连点。

而其他方案表现就很好,所以从这个角度fastclick基本被淘汰了。

还有一种“连点”!

连点还有一种情况,就是你可能在事件里面写了个window.location.href跳转,你这个跳转非常快的完成了,然后又恰巧你跳转的页面在你点击的位置也有个点击事件/链接,那么这个事件/链接也会被触发。
这个是点击问题中最丧心病狂的~
而且关键的是除了click和a标签本身,其他方案都无法避免这个问题。

所以请避免使用点击事件做跳转。

父子Dom的点击事件关系

如果我的一个大dom上有个点击事件,dom中的子dom也有个点击事件,那么点击子dom会执行谁的事件呢?

如果你用click和fastclick就都会执行,其他的方案是执行子dom的事件。

综上所述

如果你在项目中用了zepto,请优先用zepto的相关点击事件,来避免可能发生的问题。
当然了fastclick还有其他的响应功能,如果你需要的话可以在合适的时候去使用它。

编写移动端网站你可能要准备的一些方案

很多pc端的页面仔想去编写wap端的页面,但是又因为对可能出现的问题有恐惧的心理而不敢出手?
pc和wap的网站虽然有很多差异,但是我们完全不用产生距离感,只要掌握一些主要问题的解决方案,大胆动手去做就好了。

这里介绍一套《HTML5移动Web开发实践》对wap的一些处理方案。

先下载这套代码和示例

https://github.com/h5bp/mobile-boilerplate

说明里面有对这个demo的说明

Mobile browser optimizations.
CSS normalizations and common bug fixes.
The latest jQuery.
A custom Modernizr build for feature detection and a polyfill for CSS Media Queries.
Home page icon for Android, iOS, Nokia, Firefox
Cross-browser viewport optimization for Android, iOS, Mobile IE, Nokia, and Blackberry.
Open Web App support for Firefox for Android and Firefox OS
Better font rendering in Mobile IE.
iPhone web app meta.
INSTANT button click event.
Textarea autogrow plugin.
Hide URL bar method.
Prevent form zoom onfocus method.
Mobile site redirection.
User Agent Detection.
An optimized Google Analytics snippet.
Apache server caching, compression, and other configuration defaults for Grade-A performance.
Cross-domain Ajax.
“Delete-key friendly.” Easy to strip out parts you don’t need.
Extensive inline and accompanying documentation.

 

对我们比较有用的有(不是按照上面顺序的哦):

移动浏览器的优化;
协助低版本浏览器兼容HTML5、CSS3的Modernizr(如果你是纯移动端开发者可以不考虑modernizr;
跨浏览器的视图优化;
更好的字体渲染;
点击事件的优化;
跨域ajax等。

当你了解并可以熟练使用上述功能后,wap浏览器的开发就是纸老虎了;)

iphone和其他平台载入页面时顺序问题

最近在用scrollTop的时候发现的一些问题。

在document.ready中使用scrollTop()获取当前滚屏的值。

假设页面有大于两屏的高度,先把页面拉到中间,然后刷新页面。

其他平台:

先将页面定位到刷新前的位置,然后获得滚动高度。

wap端(iPhone):

先获得滚动高度,再定位到刷新位置。

 

我在做lazyload的时候,因为这个问题iPhone的初始化出现了问题,在载入页面时无法正确的处理当前页面的图片加载。

 

暂时的解决方法有以下集中,

1、加个时间延迟,这样能保证页面跳转后执行初始化,但是要注意,如果你的时间延迟快过你页面构建的速度(ajax之类),还是无法读取到正确的滚屏高度。

2、价格window.scrollTop(0),因为获得高度默认为0,所以让设置他为0也可以达到相对正确的初始化。如果你要在页面加载的时候改变dom结构慎用。