原文地址:http://blogs.msdn.com/b/weizhong/archive/2011/07/16/canvas-svg.aspx
思考什么時候使用Canvas 和SVG
?
HTML5 Canvas 和 SVG 是 IE9 中引入的兩項令人激動的圖形功能。上周在拉斯維加斯舉辦的?MIX11 大會對這兩個功能進行了介紹(請參閱深入剖析 HTML5 <canvas>?和現代化您的網站:SVG 遇到 HTML5)。
這些技術可用于解決現代網絡上眾多的圖形場景。由于 Canvas 帶來了眾多激動人心的功能,人們往往會忽略 SVG,而在許多情況下 SVG 可能是更好的選擇。這里我提供一些關于在何時選擇 Canvas、SVG 或二者的組合的想法。
Canvas 和 SVG 總體概述
以下是對 Canvas 和 SVG 的一個總體概述,為關于何時使用一種特定的矢量圖形技術的討論提供了框架。
Canvas?和?SVG?的對比 | |
Canvas | SVG |
基于像素(Canvas 在本質上是一個具有繪圖 API 的圖像元素) | 基于對象模型(SVG 元素與 HTML 元素類似) |
單個 HTML 元素,在行為上類似于 <img> | 多個圖形元素,是文檔對象模型 (DOM) 的一部分 |
視覺呈現通過腳本以編程方式創建和修改 | 視覺呈現使用標記創建并通過 CSS 或通過腳本以編程方式修改 |
事件模型/用戶交互是粗粒度的 – 僅在畫布元素上,交互必須根據鼠標坐標手動編程 | 事件模型/用戶交互基于對象,是在原語圖形元素上的 – 線條、矩形、路徑 |
API 不支持可訪問性,除了畫布,還必須使用基于標記的技術 | SVG 標記和對象模型直接支持可訪問性 |
?
SVG 作為一種在內存模型中持久保存的保留模式圖形模型而著稱。類似于 HTML,SVG 構建一個包含元素、特性和樣式的對象模型。當 <svg> 元素出現在 HTML5 文檔中時,它的行為類似于一個內聯塊,是 HTML 文檔樹的一部分。
Canvas 是一個位圖,包含一個即時模式圖形應用程序編程接口 (API) 來在它之上進行繪制。Canvas 是一種“即發即棄”模型,直接向它的位圖呈現它的圖形,然后對所繪制的形狀沒有任何認知,只會得到最終的位圖。
可以這么認為,Canvas 類似于 Windows GDI API,其中您以編程方式向窗口繪制圖形,而 SVG 類似于包含元素、樣式、事件和基于 DOM 的可編程性的 HTML 標記。Canvas 是過程性的,而 SVG 是聲明性的。
場景
以下幾節介紹兩種技術的技術優勢和不足,包括確定一種技術何時適用于給定任務的一種常用方法。從下圖中可以看出,每個場景落在從 Canvas 到 SVG 之間的一個范圍中,兩種技術中間有一個明確的交叉點。
?
矢量圖領域
高保真度復雜矢量文檔
高保真度復雜矢量文檔已是并將繼續是 SVG 的最佳點。它非常詳細,適用于查看和打印,可以是獨立的,也可以嵌入到網頁中。SVG 的聲明性特征提供了從數據庫到形狀的工具、客戶端或服務器端生成。
Internet Explorer Test Drive?上提供了一個真實圖形演示:
第一幅圖顯示了圖,而第二幅圖顯示了放大到 1000% 的圖
當考慮到觀察大型示意圖的適用性,但需要下鉆到詳細信息或出于工程用途打印整個文檔時,可縮放的矢量圖形中的“可縮放”特征會變得非常清晰。出于這些原因,我們將高保真度復雜矢量文檔放在范圍的 SVG 端。
|
|

?
SVG 作為一種圖像格式
SVG 的另一個常見用途是用于網頁內的靜態圖像。使用目前的高 DPI 顯示器,開發人員必須考慮圖形的質量。下面的圖像表示通過 CSS 設置了樣式的可能的 <li> 項目符號圖像。下面的圖像在外觀和文件大小上幾乎完全相同。
?
左側是 SVG 圖形,右側是它的 PNG 呈現
如果開發人員希望大規模重用該圖像,或者如果最終用戶使用了高 DPI 屏幕,光柵圖像將變得失真,或者需要更大的文件才能保持保真度。
?
左側是放大的 SVG 圖形,右側是放大的 4K PNG
因此,SVG 是網頁上最簡單圖像的一種好替換格式。Canvas 沒有適用的替換格式可用。
|
|
|

?
在范圍的另一端,Canvas 具有很高的呈現速度,不需要保留所繪制的內容。當首次引入 Canvas 時,開發了許多有趣的實驗。我將這些實驗劃分為 3 種不同的場景。
像素操作
因為 Canvas 專門用于繪制和操作基于像素的繪圖面,所以一些 Canvas 實驗和展示包括復雜的算法,以實現令人印象深刻的圖形效果,比如光線跟蹤或濾鏡。
下面的示例由 Adam Burmister 編寫。該實驗通過跟蹤光線在一個圖像平面上創建了一幅圖像,模擬它遇到虛擬物體的效果。
作者本身提供了以下警告:“這會消耗大量 CPU 資源。您的瀏覽器可能看起來會停止響應。”因此,盡管 Canvas API 能夠生成這樣的圖片,但這可能并不是一個好想法。正如網站作者 Adam Burmister?所總結的,“光線跟蹤[是]有史以來最糟糕的?JavaScript?應用。”
其他場景范圍的像素操作也可以這么說。下面的函數將一個畫布中的綠色像素替換為另一個具有相同大小的畫布中的像素。這樣的函數可用于創建視頻的“綠屏”效果。
function GreenScreenAtoB(a, b) {
var aImageData = a.getImageData(0, 0, a.canvas.width, a.canvas.height);
var bImageData = b.getImageData(0, 0, b.canvas.width, b.canvas.height);
var aPixels = aImageData.data;
var bPixels = bImageData.data;
?
if (aPixels.length != bPixels.length) {
window.alert("Canvases do not have the same number of pixels");
return bImageData;
??? }
?
var pixelCount = bPixels.length;
for (var pixelIndex = 0; pixelIndex < pixelcount; pixelIndex += 4) {
// grab the RGBA components of each pixel in b
var r = bPixels[pixelIndex + 0];
var g = bPixels[pixelIndex + 1];
var b = bPixels[pixelIndex + 2];
var a = bPixels[pixelIndex + 3];
?
// if the b pixel is green, replace it with a pixel from a
if (r == 0 && g == 255 && b == 0 && a == 255) {
bPixels[pixelIndex + 0] = aPixels[pixelIndex + 0];
bPixels[pixelIndex + 1] = aPixels[pixelIndex + 1];
bPixels[pixelIndex + 2] = aPixels[pixelIndex + 2];
bPixels[pixelIndex + 3] = aPixels[pixelIndex + 3];
??????? }
??? }
?
return bImageData;
}
這是一個有趣的實驗,但是與上面的光線跟蹤示例一樣,目前的機器性能會拖后腿。我列舉這些示例有一個主要原因:這種像素操作使用 SVG 無法實現。它是兩種技術之間的區別性因素。一種技術處理像素,而另一種處理模型。
無論是從簡單的矢量圖形創建真實的圖像還是為視頻創建綠屏效果,在大多數情況下,這些圖形場景都不適合在如今的網絡上進行快速部署。但是,某些場景具有足夠的響應能力(比如應用濾鏡來刪除照片中的紅眼)。這些像素操作場景在范圍中與畫布場景一樣位于最左端。
|
|
|
|

?
Hybrid and Crossover
最有趣的用例不會指明明確獲勝者。這些用例可分為兩種主要場景:圖表/圖形/映射和二維游戲。
圖表和圖形需要矢量圖,Canvas 或 SVG 都可以使用。但是,由于 SVG 固有的功能,它常常是更好的選擇。
SVG 圖表/圖形/映射場景
網絡上一個流行的圖表和圖形子集包括:
- 交互式組織圖和流程圖
- 交互式地圖 – 路徑查找
- 建筑樓層平面圖
- 工程示意圖
- 航線或活動場所座位布局
- 一般數據或財務圖表(柱狀圖、條形圖、折線圖、散點圖、環形圖等)
對于所有這些,SVG 是首選技術的原因在于:
- 它們可以通過將 XML 轉換為 SVG,從現有數據輕松生成
- 靜態版本可從工具(包括?Inkscape、Adobe Illustrator、Microsoft Visio 和各種 CAD 程序)導出
- 它們需要準確的用戶交互
- 第三方內容提供商可使用 CSS 樣式為 Web 作者進行自定義
- 它們需要可訪問性
為了更準確地演示,我們看一下在美國地圖上選擇一個州的場景。
網頁上此圖顯示不出來,請插入該圖
上面顯示的阿拉斯加州詳細地圖是公共領域,可在?Wikimedia Commons?上看到。
在 SVG 中,阿拉斯加州使用一個 <path> 元素表示,該元素的“d”特性中包含大約 162,500 字符的地理數據。
<path id="AK" fill="#cdc3cc" d="M 777.5514,1536.1543 C 776.4904,1535.0933 776.7795,1530.0041 777.9416,1529.2859 C 781.3258,1527.1943 787.2657,1532.4522 784.8317,1535.3849 …" />
對于 Canvas,此形狀可使用一系列 JavaScript 調用創建:
function drawAlaska() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(777.5514, 1536.1543);
ctx.bezierCurveTo(776.4904, 1535.0933, 776.7795, 1530.0041, 777.9416, 1529.2859);
ctx.bezierCurveTo(781.3258, 1527.1943, 787.2657, 1532.4522, 784.8317,1535.3849);
??? //
// 2,875 more path-drawing directives
??? //
ctx.bezierCurveTo(1689.8261, 12.13753, 1689.1395, 12.17333, 1685.8848, 10.52683);
ctx.closePath();
ctx.fillStyle = "#cdc3cc";
ctx.fill();
}
實際上,它需要 2,878 條路徑繪制指令(moveTo、lineTo 和 bezierCurveTo)來繪制復雜的阿拉斯加州地圖。當然,可以實現此地圖的低分辨率版本。懷俄明州和科羅拉多州所需的代碼要少得多。 :-)
SVG 基于地圖的應用程序通常包含一種涉及到懸停效果、選擇、項目之間的縮進和縮放的交互式體驗。在使用 SVG 時,比如用于處理鼠標事件,這些操作僅需要輕量型的 HTML 概念:
<path id="AK" fill="#cdc3cc" οnmοusedοwn="window.alert('Alaska');" d="M 777.5514,1536.1543 …" />
或者使用 CSS 創建一個懸停突出顯示效果:
path#AK:hover { fill:yellow; }
此交互式地圖類型的一個示例可以在 Test Drive 演示?Atlas zur Europawahl 2004 in Deutschland?中看到,2004 年德國的歐洲選舉結果的可視化。
在 Canvas 中,創建這些效果需要使用事件對象的鼠標坐標對您自己的點擊檢測進行編碼。可以使用任何形狀。盡管有 isPointOnPath() API,但它僅適用于創建的最后一條路徑。
代碼能夠并確實以圖形庫的形式存在,以在圖形上啟用具體的點擊檢測,能夠正常地使用像素數據來檢測點擊和懸停。它們也可供 SVG 使用,如果在設計中利用了 SVG 功能,將具有更高的性能。
|
|
|
|
|

?
Canvas 圖表/圖形場景
Canvas 為圖表和圖形場景提供了自己的空間。要設置此場景的上下文,我們需要了解 SVG 和 Canvas 的性能特征。
有時,一些外部影響因素要求選擇一種(幾乎)與功能獨立的技術。對于 SVG 和 Canvas,有兩個主要的區別。
開發人員知識、技能集和現有的資產將在技術選擇中扮演著重要角色。如果在創建游戲期間,開發人員擁有深厚的低級圖形 API 知識和有限的 Web 技術知識,那么可能的技術選擇是 Canvas(稍后將詳細介紹)。對于游戲移植,一些工具支持從第三方實現遷移到 Canvas。
如果性能至關重要,常常要求精確到毫秒級,那么有必要對比兩種技術的性能特征。這并不意味著 Canvas(通常被視為具有很高的性能)是顯而易見的選擇。但是,對于具有必須在像素級別繪制的大量數據的應用程序,Canvas 顯然是更好的選擇。
下面的天氣地圖不需要較大的表面區域,屏幕上的對象數量非常多。使用 Canvas,無需更新 DOM 即可快速繪制這些對象。
盡管上圖完全可以在 SVG 中創建,使用圓圈或橢圓元素表示點,但將數千個元素加載到 DOM 中可能要花費很多時間。無論您是看到大量像素還是圖像,這都是表明 Canvas 是要使用的技術的好線索——無論這是天文學、生物細胞運動還是音頻調制顯示。這里對數據可視化速度的限制是 CPU 速度、Canvas 實現速度和 JavaScript 實現速度。
|
|
|
|
|
|

?
二維游戲
休閑游戲是我們要探索的最復雜的場景。一些初始觀察結果如下:
- 游戲庫利用了較低級的圖形 API
- 開發人員的游戲行業技能集針對這些較低級的 API 進行了調優
- 許多游戲在很大程度上是基于圖像或子畫面的
- Adobe 等供應商正在開始支持導出 Canvas
- 休閑游戲通常不需要復雜的點擊測試
- 休閑游戲通常沒有大量的“對象”
在游戲庫中(例如,流行的力學引擎),圖形模型是獨立的,并且圖形成為了一種實現細節。圖形幾何特征,比如邊界、速度、大小和位置都提供給引擎,隨后引擎使用速度、碰撞和位置進行響應。圖形僅用于在屏幕上獲取計算的場景。
圖形與游戲邏輯獨立的概念在兩個游戲中得到了展示,這兩個游戲由同一個人開發,旨在分別強調 SVG 和 <canvas>:SVG-oids?和?canvas-pinball。
盡管游戲和演示邏輯是不同的,但二者都利用了相同的力學引擎,該引擎跟蹤位置、碰撞、速度和游戲組件的其他力學方面。最后,一個人可以使用 SVG 繪制(或移動)游戲元素,其他人可以使用 Canvas 重新繪制它們。
如今為 HTML5 構建的大部分 2D 休閑游戲都使用了 Canvas,所以我們將此場景放在交叉點上靠近 Canvas 的一端。
|
|
|
|
|
|
|

?
混合場景
休閑游戲屬于混合場景,因為它能夠利用兩種技術的優勢。對于輕松的點擊檢測和用戶交互,SVG 幾何結構的一個最不透明的層可用于定位元素,而底層 Canvas 可非常快地定位相關圖像并提供實時動畫。
休閑游戲領域外部越來越多的人發現使用混合場景很有吸引力。當一個場景同時包含生動的動態圖形和動畫的需要 (Canvas) 以及豐富的用戶交互的需要 (SVG) 時,這兩種技術都應該使用。一個代表場景就是?The Beauty of the Web網站上展示的來自我們的一家合作伙伴的?Brain Power?網站。這個 Brain Power 網站(以及 The Beauty of the Web 上的其他特色網站)已發現了此恰當的平衡。
對于 Brain Power 的用戶交互和顯示部分,該網站利用了更高級的 SVG 幾何結構:
<polygon id="SensoryCortex" points="253,80,266,93,…" />
對于實時動畫和特殊效果,可以使用 Canvas:
<canvas id="cnvDisplay" width="1920" height="1099" />
結束語
對最新的現代瀏覽器中可用的現有矢量圖技術的分析表明,可以通過一種交互式方式使用標準 Web 技術創建新的場景。
|
|
|
|
|
|
|
|

?
Web 的持續演化將不斷繼續,在其核心位置包含更加豐富的圖形。我們提供了一種關于將這些技術應用到特定場景的觀點。最后,Canvas 和 SVG 都是包含豐富圖形的 HTML5 Web 的重要組件。
我們期待聽到您如何將這些新 HTML5 技術應用到您的網站。包含 URL 并請通過包含 HTML5 doctype、<!DOCTYPE html> 和使用功能檢測(而不是瀏覽器檢測)來了解支持 SVG 還是 Canvas;確保您的頁面適用于 IE9。