SMIL 動畫

不過 SVG 動畫勝過 CSS3 動畫的地方,就在於 SVG 動畫可以讓圖形跟隨路徑移動、旋轉,還可以將動畫影格與時間做更精準的搭配。
甚至在不需要撰寫 javascript 的情形下,就讓動畫具有一些互動效果。 SVG 支援 SMIL(Synchronized Multimedia Integration Language)動畫規範中定義的動畫元件如下:

set

顧名思義 set 就是一個設定而已。但在動畫裡頭,時常會需要用到延遲幾秒後從某個位置出現之類的效果。

下列的範例表示兩秒之後,正方形會移到 x=70 的地方。

<rect width="50" height="50" x="10" y="10" fill="#c00">
  <set attributeName="x" to="40" begin="2s">
</rect>
<rect width="50" height="50" x="10" y="10" fill="none" stroke="#000"/>

animate

animate 元件就真的是一個動畫的元件。下方的範例,設定兩秒內正方形會移到 x=60 的地方 ( dur="2s" ),同時無限次播放 ( repeatCount="indefinite" )。
<rect width="50" height="50" x="10" y="10" fill="#09c">
  <animate attributeName="x" to="60" dur="2s" repeatCount="indefinite">
</rect>
<rect width="50" height="50" x="10" y="10" fill="none" stroke="#000"/>

動畫的目標

指定目標可以使用 hrefxlink:href 屬性。 該屬性採用對元件的 URI 引用,該元件是此動畫的目標,因此將隨著時間的推移進行修改。 目標元件必須是當前 SVG 文檔片段的一部分。
  <circle id="orange-circle"
      r="30" cx="50" cy="50" fill="orange" />
  <rect id="blue-rectangle" width="50" height="50"
      x="25" y="100" fill="#0099cc">
  <animate
           href="#orange-circle"    // 目標元件
           attributeName="cx"
           from="50"
           to="450"
           dur="5s"
           begin="click"    //  單擊開動
           fill="freeze"    //  結束時停住
           id="circ-anim"/>    // 元件 id 以便另一元件引用
  <animate
           href="#blue-rectangle"
           attributeName="x"
           from="50"
           to="425"
           dur="5s"
           begin="circ-anim.begin + 1s"  // 圓球開動後1秒開動
           fill="freeze"
           id="rect-anim"/>

單擊橘色圓形開動

要注意的是,若要使用 xlink:href 來指定連接的 svg 元素,在 <svg> tag 上得先記得宣告 xmlns:xlink="http://www.w3.org/1999/xlink"。

參考A Guide to SVG Animations (SMIL)

animateTransform

<animateTransform> 可以用來控制 transform 屬性,用 animate 無法做到。 跟 CSS 中的 transform 一樣,可以控制 translation、scaling、rotation 跟 skewing。
<rect width="60" height="60" x="50" y="50" fill="#0c0">
   <animateTransform
      attributeName="transform"
      type="rotate"
      from="0,80,80" to="360,80,80"
      dur="2s" repeatCount="indefinite" />
</rect>
<rect width="60" height="60" x="50" y="50" fill="none" stroke="#000">

參考smil-animate-svg

例題:

<animateTransform attributeName="transform"
      type="rotate"
      from="0 0 0" to="360 0 0"
      begin="0s" dur="10s"
      repeatCount="indefinite"
/>
如上面所述,要控制 transform 屬性,所以 attributeName="transform",接著 type 參數就看你想要 transform 的類型是什麼,rotate、scale 都可以。其餘 from、to、begin、dur等參數都與之前的相同,用來指定動畫的起始終點值、時間長度與執行次數。

animateMotion

這個屬性是讓我們的圖形,可以跟隨路徑移動,甚至可以設定跟隨路徑自動旋轉。 當我們設定了 animateMotion,則圖形位置以 path 的起點 M 開始計算,也就是會把 M 當作圖形的 (0,0) 的座標。 因此下面的範例將 x 設為 0,y 設為 -10。
<rect width="20" height="10" x="0" y="-10" fill="#09c">
  <animateMotion dur="5s" path=
  "  M7.4,15.3c17,20.4,48.8,38,91.6,27.8c79.5-18.9,107.4,48.2,69.4,48.2
      c-33.9,0-15.2-58.1,65.4-41.7c26.2,5.3,63.2-19.1,79.1-34.3"
  repeatCount="indefinite" rotate="auto" />
</rect>
<path fill="none" stroke="#000" d="M7.4,15.3c17,20.4,48.8,38,91.6,27.8
      c79.5-18.9,107.4,48.2,69.4,48.2c-33.9,0-15.2-58.1,65.4-41.7
      c26.2,5.3,63.2-19.1,79.1-34.3"/>
 
</!--軌跡-->
<path d="M10,50 q60,50 100,0 q60,-50 100,0"
    stroke="black" stroke-width="2" />
<g>
  </!-- Rick 飛船 svg-->
  <animateMotion
    path="M10,50 q60,50 100,0 q60,-50 100,0"
    begin="0s" dur="10s" repeatCount="indefinite"
  />
</g>

完整程式: rick-animate-motion

animateMotion 還有個特別的屬性值 rotate,
用來指定是否要隨著路徑移動的同時,
旋轉綁定的 svg 物件,可以設定為 auto 或 auto-reverse:

<animateMotion
  path="M10,50 q60,50 100,0 q60,-50 100,0"
  begin="0s" dur="10s" repeatCount="indefinite"
  rotate="auto"
/>
完整程式: spaceship-path

四種 SVG 動畫元件,除了個別拿來使用外,這些元件是能夠組合在一起使用的。
只要個別把對應的動畫套用在想要的 svg shape 上即可。

舉例來說,可以讓 Rick 旋轉的同時,顏色改變、眼睛轉動(可右鍵看 svg 原始碼,在裡面可以找到多個動畫元件):

<animate
      attributeName="fill" from="#B0DDF7" to="#f79a0e"  // 顏色改變
      dur="3s" repeatCount="indefinite" />
<animate
      attributeName="cx" from="56.7573" to="64.7573"  // 眼睛轉動
      dur="2s" repeatCount="indefinite" />
<animateTransform attributeName="transform"  // Rick 旋轉
  type="rotate" from="0 0 0" to="360 0 0"
  begin="0s" dur="10s" repeatCount="indefinite"
/>

SVG SMIL animation 重點參數介紹

from, to, by, values

from 跟 to 在前面的範例中都有看到,功能指定動畫變化的移動區間,從(from)某個值變化到(to)另個值;
而 by 則是代表位移量,相對於明確告知要變動到哪個值,我們可以用 by 告訴 svg 要變動”多少的量“,

例如前面 animateTransform 的例子,我們可以改為:

<animateTransform attributeName="transform"
  type="rotate"
  from="0 0 0" by="360"
  begin="0s" dur="10s"
  repeatCount="indefinite"
/>
再來看看 values,這個剛剛的範例都沒出現,它的功用是來補足 from、to、by 的不足。
不足的點在於, from、to、by 只能指定兩個值之間的變化,從 a 變化到 b,而 values 可以給定多個值,
用分號 ; 隔開,就能有 a -> b -> c -> b -> a 這樣的變化,舉個例子:
<animateTransform attributeName="transform"
  type="translate"
  values="20;120;20"
  begin="0s" dur="3s"
  repeatCount="indefinite"
/>

begin, end

begin 跟 end 分別用來控制何時開始執行動畫,何時停止動畫,在上面的例子中我們都只用到時間,像是 begin="2s", 但其實這兩個參數能給的值有非常多的種類,而且能向 values 一樣賦予多個值,只要用 ; 隔開即可:
<!-- Rick head -->
<g>
  <animateTransform attributeName="transform"
    type="scale"
    values="1;1.2;1"
    begin="ship.end" dur="3s"
    repeatCount="indefinite"blue
  />
</g>
<!-- spaceship -->
<g>
  <animateTransform
    id="ship" attributeName="transform"
    type="translate"
    values="20;120;20"
    begin="rickhead.click" dur="3s"
  />
</g>

單擊太空船中的 rick 頭啟動

例題: spaceship3

calcMode, keyTimes, keySplines

mpath

<animateMotion> 元件的 <mpath> 子元件提供了引用外部 元件作為運動路徑定義的能力。
<path id="path1" fill="none" stroke="#000"
    d="M7.4,15.3c17,20.4,48.8,38,91.6,27.8
      c79.5-18.9,107.4,48.2,69.4,48.2c-33.9,0-15.2-58.1,65.4-41.7
      c26.2,5.3,63.2-19.1,79.1-34.3"/>
<rect width="20" height="10" x="0" y="-10" fill="#09c">
  <animateMotion dur="5s" repeatCount="indefinite" rotate="auto" />
    <mpath xlink:href="#path1"/>
  </animateMotion>
</rect>

additive

如果針對同一個 SVG shape 的屬性做多個連續變化時,就要使用 additive 這個參數。
additive 參數告知 SVG 是否要累加(sum)動畫效果,或是取代(replace),預設是 replace。
  <circle id="growndot" r="50" fill="#02324b" transform="translate(50 50)" />
  <animateTransform id="grow" xlink:href="#growndot" attributeName="transform"
      type="scale" additive="sum" from="0 0" to="1 1" begin="0s" dur="3s"
      repeatCount="indefinite" end="click" />

例如:透過 animateTransform 先將圖案放大再旋轉。

<animateTransform attributeName="transform"
  type="scale"
  by="1.1"
  begin="0s" dur="5s"
  repeatCount="indefinite"
  additive="sum"
/>

<animateTransform attributeName="transform"
  type="rotate"
  from="0 0 0" to="360 0 0"
  begin="0s" dur="5s"
  repeatCount="indefinite"
  additive="sum"
/>

參考資料