可縮放矢量圖形(Scalable Vector Graphics,SVG)是一種用於描述與比例無關的圖形的 XML 格式,可以很好地支持免費軟件和商業工具。在本期文章中,David 將介紹使用 SVG 編寫腳本和動畫,還將涉及通過 DOM 處理 SVG 等內容。SVG 由於是 XML 格式,因此可以支持通常用 XML 工具和庫進行的轉換和生成。
在 SVG 於 2001 年左右首次出現以前,已有相當多功能強大的矢量圖形格式。Postscript 及其類似產品 PDF 廣泛應用於許多應用程序。其他特定於應用程序的格式包括基於 Postscript 的 Adobe Illustrator (.ai)、CorelDRAW (.cdr)、Computer Graphics Metafile (.cgm)、Windows Metafile (.wmf)、AutoCAD (.dxf)、Hewlett-Packard Graphics Language (.hpgl)、WordPerfect (.wpg) 等。對於甚至可以組合動畫、聲音和交互性的矢量繪圖,則常使用 Macromedia 的 SWF/Flash 在萬維網上發布相關內容。
SVG 與所有其他格式的主要區別在於,前者是 XML 的一個應用程序。盡管對於同等的圖形,使用 SVG 描述比使用多數其他矢量格式描述要復雜得多,但對於編程操作而言,SVG 則是一種更通用的工具。尤其是,您可以在使用 ECMAScript 和其他文檔對象模型 (DOM) 的 Web 浏覽器(或其他應用程序)中操縱 SVG。而且同樣重要的是,您可以使用熟悉的 XML 技術(如 XSLT)或 XML 支持庫轉換和生成 SVG。可以將 SVG 與其他使用名稱空間的 XML 格式混合。而且,甚至可以使用層疊樣式表 (CSS) 限定 SVG 的樣式。總之,在 XML 和 Web 空間,SVG 是一個友好的播放器。
除了是 XML 格式以外,SVG 還是一個由 W3C 發布的完全開放的標准(請參閱 參考資料)。與上述多數矢量格式不同,SVG 是完全免費的,沒有任何版權或專利權限制,而且其規范完全 有文檔記錄。與其他 W3C 標准類似,規范文檔本身是 受版權保護的 —— 但根據 W3C 的非限制性條款的規定,允許廣泛傳播以及免費復制和使用(例如,規范中沒有附帶禁止公開協議)。
入門
令人高興的是,您可以在多數新式 Web 浏覽器中查看 SVG,可以在本機也可以通過插件查看。精確的支持狀態在不斷變動,但通過正確的技術,您應能夠使用 Firefox/Mozilla、KHtml(Konqueror 和 Safari)、Opera 或 AMaya 查看 SVG。使用 Adobe 或 Corel 的插件,甚至還可以讓 Internet Explorer 顯示 SVG。還存在一些獨立的 SVG 查看器,特別是使用免費軟件 Batik SVG 工具包(是 apache XML 項目的一部分 —— 請參閱“參考資料”)。
在許多情況下,SVG 文件是作為獨立的文檔查看的。在這樣的情況下,這些文件表現為 MIME 類型 image/svg+XML
,並通常有一個文件擴展名 .svg。Gzip 壓縮的 SVG 文件應有擴展名 .svgz,可由多數啟用 SVG 的工具直接支持。SVG 文件只是具有適當 DTD 的 XML 文件。您將在下面幾個例子中了解到這一點。
然而,可能更為常見的是,您可以將一個 SVG 文檔嵌入較大的文檔中,特別是嵌入 XHTML 頁。其他復合 XML 格式(如 OASIS OpenDocument)也可以(或將支持)將 SVG 嵌入其中。將 SVG 圖形嵌入 (X)Html 頁有三種方式:
<object>
標簽
<embed>
標簽
不過,具體使用哪一種方式有效取決於您的浏覽器和版本。例如,我創建了下面的 XHtml 文檔(使用 doctype 來支持名稱空間嵌入):
清單 1. XHTML 文檔 (svg-nested.Html)
<?xml version="1.0" standalone="no"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"
"http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>SVG as embedded object and nested namespace</title>
</head>
<body>
<h2>Object tag</h2>
<object type="image/svg+xml" data="standalone.svg">
Your browser is currently unable to display SVG images.
</object>
<h2>Nested namespace</h2>
<svg:svg version="1.1" width="5cm" height="4cm"
XMLns:svg="http://www.w3.org/2000/svg">
<svg:title>Four rectangles</svg:title>
<svg:rect x="0.5cm" y="0.5cm" width="2cm" height="1cm"/>
<svg:rect x="0.5cm" y="2cm" width="1cm" height="1.5cm"/>
<svg:rect x="3cm" y="0.5cm" width="1.5cm" height="2cm"/>
<svg:rect x="3.5cm" y="3cm" width="1cm" height="0.5cm"/>
<!-- Show outline of canvas using 'rect' element -->
<svg:rect x=".01cm" y=".01cm" width="4.98cm" height="3.98cm"
fill="none" stroke="blue" stroke-width=".02cm" />
</svg:svg>
<h2>Embed tag</h2>
<embed id="svg3" src="standalone.svg" />
</body>
</Html>
通過嘗試,Safari/KHTML 在浏覽器中表現最好。盡管如此,如果文件使用 .Html 擴展名,而不是 .XML 擴展名命名,結果會更好。總之,<embed>
也許是最成功的方法。您可能會看到文檔呈現為:
圖 1. Web 浏覽器顯示的 svg-nested.Html
另外,本文提供的示例是組合基本形狀、文本、顏色等內容的較為簡單的示例 —— 但 SVG 完全能夠表現復雜和引人入勝的繪圖。為了提高讀者的興趣,下面是 Ghostscript 和其他工具中包括的著名的 PostScript 老虎圖片,它使用 SVG 呈現(我僅調整了它的總體大小):
圖 2. Web 浏覽器將老虎圖像顯示為 SVG
SVG 文檔的特點
前面的 XHTML 例子(參閱 清單 1)為您顯示了非常基本的 SVG 繪圖。引用的外部文件 (standalone.svg) 所包含的元素與 XHtml 中嵌入的相同,只是去掉了標簽中額外的名稱空間限定符。SVG 為您提供了許多圖形元件,而且每個圖元都有可以進一步指定圖形的多種 XML 屬性:顏色、大小、位置、填充、輪廓等。不過,直觀的圖形元件(如橢圓、矩形或多邊形)或者一些可能包括立方體或二次貝塞爾曲線等的更為復雜的 <path>
元素,常常包括在 <g>
元素中,以便將若干個圖元組合在一起。<g>
組的優點是,您可以對它進行整體縮放、移動、設定樣式或修改。 對組的修改通用於其中的形狀集合(包括嵌入的 <g>
組)。在編寫 SVG 文檔腳本時這特別有用。
始終如一
有關 SVG 文檔需要注意的一點是,它們並非完全 是真正的 XML。從語句上說,SVG 確實是 XML,但在 SVG 屬性中,SVG 繪圖信息內容的重要部分包含在逗號和空格分隔的數據中。這裡所說的信息內容 並不是指 XML Infoset,僅指它包含什麼?的更加非正式的概念。這樣做是一種合理的折衷方法,因為對定義曲線的每個點或句柄都使用子元素將會使 SVG 更加繁瑣。但是,XML 級處理技術(如 XSLT)因此能夠不用真正處理太多的路徑數據。例如,下面是一個二次貝塞爾曲線路徑元素:
<path d="M200,300 Q400,50 600,300 T1000,300"
fill="none" stroke="red" stroke-width="5" />
下面是一個描述五角星形的多邊形:
<polygon fill="red" stroke="blue" stroke-width="10"
points="350,75 379,161 469,161 397,215
423,301 350,250 277,301 303,215
231,161 321,161" />
添加樣式
前面提到過您可以使用 CSS 選擇器和語法來修改 SVG 繪圖的外觀。對於 Html 和其他支持 CSS 的格式,既可以指定內嵌 CSS 信息,也可以作為對外部樣式表的引用。下面是一個非常簡單的內嵌 CSS 的例子:
清單 2.一個 簡單的 CSS 例子 (inline-styled.svg)
<?xml version="1.0" standalone="no"?>
<!-- By ref:
<?xml-stylesheet href="mystyle.css" type="text/css"?>
-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="10cm" height="5cm" vIEwBox="0 0 1000 500"
XMLns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<style type="text/CSS"><![CDATA[
rect {
fill: red;
stroke: blue;
stroke-width: 3
} ]]>
</style>
</defs>
<rect x="200" y="100" width="600" height="300"/>
</svg>
盡管使用 CSS 無疑可以限定整個標簽的樣式,但您可能會發現,對 CSS 和 SVG 使用類選擇器會更好。例如,您可以在樣式表中定義各種類型的矩形,然後將一個 class
XML 類屬性附加到繪圖中的每個矩形,而不用重復使用為類定義的整個顏色、填充、描邊和其他屬性列表。只須更改樣式表,就可以更改圖表的整體外觀,使之更適用於不同的環境。
重復使用元素
除使用 CSS 之外,清單 2 顯示了 SVG 另一種很好的功能:您可以在 SVG 文檔中包括預定義的內容 —— 在呈現的文檔內或文檔之外定義的內容。
使用預定義內容作為 SVG 繪圖一部分的方法之一是使用 <image>
元素。在概念上,SVG 中的 <image>
與 Html 中的 <img>
非常類似:該元素只須指示呈現客戶機在當前的 SVG 環境中繪制外部圖像的內容 —— 其本身可能是 SVG 或者是 JPEG 或 PNG 格式的光柵圖像。您幾乎可以像調整一個規則的圖形元素那樣來調整外部圖像的大小和改變其位置。例如:
清單 3. 在當前圖像中包括一個外部 SVG 繪圖
<image x="200" y="200" width="100px" height="100px"
xlink:href="http://example.org/external.svg">
比 <image>
標簽更有意思的也許是令人叫好的 <defs>
和 <use>
元素。首先,您可以使用 CSS 例子中所看到的內容 創建 SVG 元素,這些元素在定義時沒有直接呈現 —— 通常,SVG 呈現模型嚴格按照 SVG 文檔中出現的順序繪制每個對象,每個對象均覆蓋最後一個。但 <style>
不是典型的樣式,以後不能真正呈現其本身。
您可以在諸如 <defs>
節中包括想要包括的任何圖形元素,其中包括 <g>
組和 <symbol>
元素(符號與組類似;由於本文篇幅所限,這裡不對其區別進行說明)。在定義的外部,您可以使用在 <defs>
節中定義的圖形元素 —— 甚至可使用在外部 SVG 文檔的 <defs>
節中定義的圖形元素。例如:
清單 4. 使用預定義的圖形元素
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="7cm" height="3cm" vIEwBox="0 0 70 30" version="1.1"
xmlns="http://www.w3.org/2000/svg"
XMLns:xlink="http://www.w3.org/1999/xlink">
<desc>'use' with a 'transform' attribute</desc>
<defs>
<rect id="MyRect" x="0" y="0" width="40" height="5"/>
</defs>
<use xlink:href="#MyRect" transform="translate(10,23) rotate(-30)" />
<use xlink:href="#MyRect" transform="translate(20,3) rotate(30)" />
<use xlink:href="http://example.org/foo.svg#OtherRect"/>
</svg>
在 清單 4 中,定義相同的矩形使用兩種不同的轉換呈現,然後還呈現了外部定義的元素。(id
名稱表明它也是一個矩形,但從該片斷中不能明顯確定 —— 事實上,外部內容可以在呈現之間更改)。
動畫和腳本
剛才已提到,使用 ECMAScript 可以編寫 SVG 腳本。原則上,這可讓 SVG 文檔與用戶操作交互。為了支持 Web 應用程序空間,SVG 還包含一個用於超鏈接的與 Html 類似的 <a>
元素。根據鼠標在特定的圖形元素上單擊,SVG 中的簡單交互可以修改文檔。清單 5 中的例子雖然很普通,但您可以方便地讓 SVG 圖形響應。例如,在下面的流程圖中的圖形或對象區域上單擊:
清單 5. 讓 SVG 形狀響應單擊
<svg>
<title>ECMAScript function for an onclick event</title>
<desc>SimplifIEd from
http://www.w3.org/TR/SVG11/images/script/script01.svg</desc>
<script type="text/ecmascript"> <![CDATA[
function circle_click(evt) {
var circle = evt.target;
var currentRadius = circle.getAttribute("r");
if (currentRadius == 100)
circle.setAttribute("r", currentRadius*2);
else
circle.setAttribute("r", currentRadius*0.5);
} ]]>
</script>
<!-- Act on each click event -->
<circle onclick="circle_click(evt)" cx="300" cy="225" r="100" fill="red"/>
</svg>
您還可以使用 ECMAScript 和 DOM 讓 SVG 圖形產生動畫效果。例如,清單 6 中的代碼可以使文本產生一個好看的效果,即增加和更改不透明度:
清單 6. 使用 JavaScript 讓 SVG 產生動畫效果
<svg vIEwBox="0 0 400 200"
onload="StartAnimation(evt)" version="1.1"
XMLns="http://www.w3.org/2000/svg">
<script type="text/ecmascript"><![CDATA[
var txt, step=0;
function StartAnimation(evt) {
txt = evt.target.ownerDocument.getElementById("Text");
ShowAndGrowElement();
}
function ShowAndGrowElement() {
step = step+1;
if (step > 200) return;
// Scale text string gradually until it is 20 times larger
txt.setAttribute("transform", "scale("+ step/10 +")" );
// Make the string more opaque
txt.setAttribute("opacity", step/200);
// Call ShowAndGrowElement again 50 milliseconds later.
setTimeout("ShowAndGrowElement()", 50)
}
window.ShowAndGrowElement = ShowAndGrowElement
]]></script>
<g transform="translate(50,150)" fill="red" font-size="7">
<text id="Text">SVG</text>
</g>
</svg>
純粹的 SVG 腳本
使用 ECMAScript 可為您提供完美的編程靈活性,但如果您所需要的只是動畫,SVG 還提供了 <animate>
和相關的標簽(如 <animateMotion>
或 <animateColor>
)。它們都非常靈活,可讓您以各種方式分別賦予 SVG 文檔中每個元素動畫效果。例如,清單 6 中的代碼可產生與 清單 5 中所示技術相同的增加和呈現不透明效果:
清單 6. 單獨使用 SVG 表現動畫效果
<svg vIEwBox="0 0 400 200" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(50,150)" fill="red" font-size="7">
<text id="Text">SVG
<animateTransform attributeName="transform" attributeType="XML"
type="scale" from="0" to="20" begin="0s" dur="10s"
fill="freeze" />
<animate attributeName="opacity" attributeType="CSS"
from="0" to="1" begin="0s" dur="10s" repeatCount="1" />
</text>
</g>
</svg>
結束語
本文初步探討了 SVG 格式的一些基本知識。撰寫本文讓我對 SVG 作為一種格式而感到興奮不已。Web 確實需要矢量格式以與比例無關的方式有效地傳達復雜圖形。再加上腳本、動畫、鏈接和所有其他內容使 SVG 更加有用。所幸的是,多數 Web 浏覽器現在