標籤:

SVG及SVG路徑動畫

SVG

可縮放矢量圖形(Scalable Vector Graphics,SVG),是一種用來描述二維矢量圖形的XML 標記語言,是一個W3C標準,所以大多數情況它符合HTML的特性,且能夠與CSS等其他W3C標準協同工作。通過它的名字也不難看出,在需要保證不同尺寸、不同解析度的屏幕上的一致體驗時,SVG是個很好的選擇。

SVG作為一種圖像格式,與JPEG、PNG等其他圖像格式相比較的優勢在於其尺寸更小且可壓縮性更強,支持多種工具打開和修改,最重要的是它的可縮放性,保證了SVG圖像可在各種尺寸的屏幕上保證圖像質量,也可以在任何解析度下被高質量的列印。與同屬二維矢量圖形的FLASH相比,SVG是一個W3C標準,基於XML,是開放的,而FLASH是封閉的,基於二進位格式的。

SVG圖像是使用大量的包括動畫元素、形狀元素、容器元素等在內的SVG元素創建的,這些元素用於構建、繪製矢量圖形。SVG屬性包括動畫屬性,圖形事件屬性,文檔事件屬性等,SVG屬性可以用來修改SVG元素,這些屬性決定了元素的呈現方式及細節。同時對應不同的SVG元素,也有豐富的SVG DOM API,提供了對元素屬性的訪問及操作元素的方法。

下面通過一個簡單實例及代碼具體了解一下SVG:

對應的SVG文件代碼如下

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">n<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" version="1.1">n<rect x="20" y="20" rx="20" ry="20" width="250" height="100" style="fill:red;stroke:black;stroke-width:5;opacity:0.5"/> n</svg>n

代碼的第一行引用了一個外部的 SVG DTD文件。該 DTD 位於 W3C,含有所有允許的 SVG 元素。

SVG 代碼以 <svg> 元素開始,包括開啟標籤 <svg> 和關閉標籤 </svg> ,這是根元素。 xmlns 屬性定義了該 SVG的 命名空間。version 屬性可定義所使用的 SVG 版本,width 和 height 屬性可設置此 SVG 文檔的寬度和高度。

SVG 的 <rect>元素 用來創建一個矩形。x 和 y 屬性定義矩形左上角的 x 和 y 坐標。rx 和 ry 屬性定義圓角在水平及垂直方向上的半徑。width 和 height 屬性控制矩形的寬高。style屬性中的fill值設置形狀內的顏色,stroke 和 stroke-width 控制如何顯示形狀的輪廓。

SVG路徑

如果說SVG中最強大的元素,那麼就非<path>(路徑元素)莫屬了。path元素是用來定義形狀的通用元素。所有的基本形狀都可以用path元素來創建。

<!-- A right-angled triangle -->n<path d="M10 10 L75 10 L75 75 Z" />n

你可以想像一支在屏幕上繪畫的虛擬的畫筆,而path元素中的屬性就用來控制這支筆。上面的示例代碼中,首先畫筆畫了一條以為(10,10)(M10 10)為起始位置,以(75,10)(L75 10)為終止位置的直線,接著又畫一天直線至(75,75)(L75 75),最後的z表示畫筆回到起始坐標點形成閉合路徑。

其中的 M 和 L 屬於繪圖指令,M規定了起始點的位置,L 則表示畫一條直線至指定位置,還有許多其他的繪圖指令如A(圓弧)、Q(二次貝塞爾曲線)、C(三次貝塞爾曲線)等等,這些豐富的指令可以幫助你在SVG中創建複雜精緻的矢量圖形。

SVG路徑與CSS

讓靜態的SVG路徑元素動起來,我們首先要利用SVG的兩個屬性:stroke-dasharraystroke-dashoffset

屬性stroke-dasharray可以控制圖案描邊路徑的樣式,在你不想要連續的直線作為路徑時,你可以使用這個屬性得到不同樣式的虛線。

由於SVG圖像是瀏覽器DOM的一部分,而stroke-dasharray作為控制外觀的元素,也可以用在CSS中。類似地,stroke-dashoffset屬性(指定了dash模式到路徑開始的距離)也可以使用CSS來控制。這兩個SVG屬性組合在一起,可以生成SVG動畫,使路徑看起來正在逐漸被繪製。

以這個二次bezier曲線為例:

<path fill="transparent" stroke="#000000" stroke-width="5" d="M10 80 Q 77.5 10, 145 80 T 280 80" class="path"></path>n

要使這條路徑動畫化,就像它在屏幕上逐漸和平滑地繪製一樣,我們必須使stroke-dasharray屬性的值等於路徑長度,也就是說虛線曲線上每一個實線段和縫隙的長度都等於整個路徑的長度。

接下來,我們將使stroke-dashoffset屬性設置為0。這將使路徑在屏幕上顯示為一個實曲線(我們本質上是在看虛線的第一個實線段)。通過設置與曲線長度相等的stroke-dashoffset,我們最終會得到一條看不見的曲線。

現在,結合CSS3的animation改變stroke-dashoffset屬性,可以使曲線逐漸出現在屏幕上,如下:

<?xml version="1.0" standalone="no"?>n<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" n"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">nn<svg dth="300px" height="175px" version="1.1" xmlns="http://www.w3.org/2000/svg">n<style type="text/css" >n.path {n stroke-dasharray: 320;n stroke-dashoffset: 0;n animation: dash 1s linear infinite;n}n@keyframes dash {nfrom {n stroke-dashoffset: 320;n}n to {n stroke-dashoffset: 0;n}n}n</style>n<path fill="transparent" stroke="#000000" stroke-width="5" d="M10 80 Q 77.5 10, 145 80 T 280 80" class="path"></path>n</svg>n

如你所見,我們只是在改變dash偏移量以使虛線部分動態的出現,便實現了動畫的效果,使用同樣的原理結合多條路徑可以達到更複雜的動畫效果,如下:

<?xml version="1.0" standalone="no"?>n<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" n"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">nn<svg dth="300px" height="175px" version="1.1" xmlns="http://www.w3.org/2000/svg">n<style type="text/css" >n.line1 {n stroke-dasharray: 340;n stroke-dashoffset: 40;n animation: dash 1.5s linear alternate infinite;n}n.line2 {n stroke-dasharray: 320;n stroke-dashoffset: 320;n animation: dash2 1.5s linear alternate infinite;n}n@keyframes dash {n from {n stroke-dashoffset: 360;n }n to {n stroke-dashoffset: 40;n }n}n@keyframes dash2 {n from {n stroke-dashoffset: 280;n }n to {n stroke-dashoffset: -40;n }n}n</style>nn<path fill="transparent" stroke="#000000" stroke-width="4" d="M10 80 Q 77.5 10, 145 80 T 280 80" class="path"></path>n<path fill="transparent" stroke="#FF2851" stroke-width="4" d="M10 80 Q 77.5 10, 145 80 T 280 80" class="line2"></path>n<path fill="transparent" stroke="#000000" stroke-width="4" d="M10 80 Q 77.5 10, 145 80 T 280 80" class="line1"></path>n</svg>n

stroke-dasharraystroke-dashoffset是兩個非常強大的屬性,可以使SVG路徑產生大量的動畫效果。

沿SVG路徑的動畫對象

同樣的只是利用SVG和CSS,您可以做的一件更酷的事,使對象或元素沿SVG路徑運動。這裡又需要了解兩個新的可以作用於SVG的CSS屬性:

offset-path:指定元素的運動路徑。 offset-distance:定義了元素在路徑上運動的距離,單位是數值或百分比。

結合這兩個屬性,您可以得到這樣的動畫:

<style type="text/css" >n.ball {n width: 10px;n height: 10px;n background-color: red;n border-radius: 50%;nn offset-path: path(M10 80 Q 77.5 10, 145 80 T 280 80);n offset-distance: 0%;nn animation: red-ball 2s linear alternate infinite;n}n@keyframes red-ball {nfrom {n offset-distance: 0%;n}n to {n offset-distance: 100%;n}n}n</style>n<svg dth="300px" height="175px" version="1.1" xmlns="http://www.w3.org/2000/svg">n<path fill="transparent" stroke="#888888" stroke-width="1" d="M10 80 Q 77.5 10, 145 80 T 280 80" class="path"></path>n</svg>nn<div class="ball"></div>n

如你所見,我們有一個新的元素div.ball,並讓該元素沿路徑運動。

這個元素可以是任何類型的,一個div,一個圖像,文本,等等。使用了offset-pathoffset-distance,您可以為元素提供一個運動路徑並控制運動的距離,達到動畫的效果。

需要注意的是,offset-pathoffset-distance目前仍屬於實驗中的功能,瀏覽器的兼容性很不樂觀。

使用JavaScript做SVG動畫

在使用JavaScript對SVG元素做動畫時,完全可以把SVG元素當做普通的DOM元素處理,而不再需要將路徑長度硬編碼在CSS中。運用豐富的第三方SVG動畫庫,我們也可以更容易地實現上面提到的動畫效果。

例如Snap.svg,不僅讓使用JavaScript繪製SVG圖形變得更容易,同時只需要調用.animate({})這個API,非常簡單。另外一個庫anime.js,讓你只通過幾行代碼就可以實現讓一個元素沿著SVG路徑運動。Vivus已經為你做了大部分操作來生成複雜的動畫,它採取了一種不同的調用方式,僅需要通過配置項的方式去生成SVG路徑動畫。你只需要用SVG元素的id來定義一個Vivus對象,然後就交給Vivus來處理剩下的事情。

擴展閱讀

打造SVG動畫的三種途徑:three ways to animate SVG

SMIL(Synchronized Multimedia Integration Language)相關知識:SMIL,A Guide to SVG Animations (SMIL)

參考文獻: A How-to Guide to SVG Animation MDN web docs-SVG


推薦閱讀:

外刊君談中國第三屆CSS大會
翻譯 | 編寫SVG的口袋指南(上)
d3.js: 在曲線路徑上添加文本標記的正確方式

TAG:SVG |