SVG 的動畫相當有趣也相當靈活,甚至可以互動,感覺上已經超越單純的動畫了
跟動畫相關的指令有 set, animate, animateTransform, animateMotion
set
首先先來一個 set 的範例
attributeName="屬性"
begin="開始的時機"
to="要改的值"
begin 可以用 1s(1秒) , 100ms (0.1秒) , 或各種 event, 當時機為 時間 時,代表的是該物件出現後開始計算時間
詳細的資料可以看這裡
<div id="a120201_svg1">
<svg height="70">
<defs>
<g id="a120201_g1">
<rect id="a120201_rect1" width="50" height="50" x="10" y="10" fill="#f00">
<set attributeName="x" to="20" begin="1s"></set>
<set attributeName="x" to="30" begin="2s"></set>
<set attributeName="x" to="40" begin="3s"></set>
<set attributeName="x" to="50" begin="4s"></set>
<set attributeName="x" to="60" begin="5s"></set>
<set attributeName="x" to="70" begin="6s"></set>
<set attributeName="x" to="80" begin="7s"></set>
<set attributeName="x" to="90" begin="8s"></set>
</rect>
</g>
</defs>
<use xlink:href="#a120201_g1"></use>
</svg>
</div>
<div id="a120201_svg2">
</div>
<br>
<button id="a120201_b1" style="font-size:1em;background-color:#aff">GO</button>
<script>
$(function()
{
$("#a120201_b1").on("click",function()
{
let i;
let hh="";
for (i=0;i<30;i++)
{
hh+='<set attributeName="x" to="'+(i*10+20)+'" begin="'+((i+1)*50)+'ms"></set>';
}
$("#a120201_rect1").html(hh);
$("#a120201_svg1").css("display","none");
$("#a120201_svg2").html('<svg width="100%" height="70">'
+$("#a120201_g1").html()+'</svg>');
});
})
</script>
animate
attributeName="屬性"
begin="開始的時機"
end="結束的時機"
from="開始的值",(可以用 values 取代)
to="結束的值",(可以用 values 取代)
by="相對from的值",例如 from="30", to="50" 最後的值是 50 , 如果用 by="50" , 最後的值是 80
values="要改變的值" ,可以用分號區挌,指定多個值,例如: "10;50;10"
keyTimes="運行時間比",用分號區格,為 0 到 1 的數值,用來指定每一個 values 運行時間
keySplines="貝式曲線的時間",四個值,和 css 的 Cubic Bezier 很像,必須設定 calcMode="spline" 才有作用
calcMode="模式",discrete, linear (預設) , paced, spline
dur="時間"
max="時間",動畫執行到這個時間後停止
repeatCount="重覆次數",indefinite 為不斷重覆
restart="觸發 begin 後的動作",always(預設),whenNotActive(啟動狀態不重新開始),never(不重新啟動)
fill="end 觸發後的狀態",freeze(凍結在目前狀態),remove(回到初始狀態)
accumulate="累加",none(預設),sum(累加), 在累加狀態時,動畫 repeat 不會回到初始狀態
先來一個簡單的範例,values 和 keyTimes 的數量必須一樣,keyTimes 的時間比由 0 到 1 ,數值必須越來越大
紅色方塊沒有設定 keyTimes ,時間比例和數值是平均分布,
等同 keyTimes="0;0.33;0.67;1"
紫色方塊設定 calcMode="discrete",沒有動畫直接跳過去
綠色方塊設定 keyTimes="0;0.6;0.9;1" ,一開始走很慢,後面跑很快
橘色方塊設定 calcMode="paced" , 行走速度不受分段影響
藍色方塊設定了 keySplines ,要記得加上 calcMode="spline"
<svg width="300" height="300">
<rect fill="#f00" x="10" y="10" width="40" height="40">
<animate attributeName="x" values="10;50;200;10" begin="0s" dur="2s" repeatCount="indefinite"></animate>
</rect>
<rect fill="#a0f" x="10" y="60" width="40" height="40">
<animate attributeName="x" values="10;50;200;10" begin="0s" dur="2s" calcMode="discrete" repeatCount="indefinite"></animate>
</rect>
<rect fill="#0a0" x="10" y="110" width="40" height="40">
<animate attributeName="x" values="10;50;200;10" begin="0s" dur="2s" keyTimes="0;0.6;0.9;1" repeatCount="indefinite"></animate>
</rect>
<rect fill="#fa0" x="10" y="160" width="40" height="40">
<animate attributeName="x" values="10;50;200;10" begin="0s" dur="2s" keyTimes="0;0.6;0.9;1" calcMode="paced" repeatCount="indefinite"></animate>
</rect>
<rect fill="#00f" x="10" y="210" width="40" height="40">
<animate attributeName="x" values="10;200;10" begin="0s" dur="2s" keyTimes="0;0.5;1" keySplines="0.5 0 0.5 1;0 0.5 0.75 0" calcMode="spline" repeatCount="indefinite"></animate>
</rect>
</svg>
begin , end
svg 動畫中的 begin 和 end 很有意思,可以做到基本的互動,讓動晝不再只是動畫,
可以用 <a xlink:href="#id">click</a>
來觸發 begin ,也可以從 html 去觸發,方法如下:
詳細 API 可以參考這裡
document.getElementById('animate ID').beginElement();
begin 和 end 的值如下:
時間(1s,100ms) 時間到開始執行
id.[event] 例如 id.click ,當 id 被點擊時觸發,可以用 id.click+1s 表示點擊後過1秒
id.begin 當 id 動畫開始時
id.end 當 id 動畫結束時
id.repeat(n) 當 id 動畫重覆 n 次後,(經實測,在 iphone 及 safari 無作用)
[event 列表]
focus, blur, focusin, focusout, activate, auxclick,
click, dblclick, mousedown, mouseenter, mouseleave,
mousemove, mouseout, mouseover, mouseup,
wheel, beforeinput, input, keydown, keyup,
compositionstart, compositionupdate, compositionend,
load, unload, abort, error, select, resize, scroll,
來看一個範例
<style>
.a120203_s1
{
font-size:20px;
dominant-baseline:hanging;
}
</style>
<button onclick="document.getElementById('a120203_a1').beginElement();" style="font-size:1.5em;">HTML 的點我開始</button><br><br>
<svg width="300" height="200">
<a xlink:href="#a120203_a1">
<rect x="8" y="18" width="84" height="22" fill="#ff0"></rect>
<text x="10" y="20" class="a120203_s1">點我開始</text>
</a>
<g id="a120203_end1">
<rect x="98" y="18" width="84" height="22" fill="#0ff"></rect>
<text x="100" y="20" class="a120203_s1">點我停止</text>
</g>
<g id="a120203_c1" stroke-width="1" fill="#000">
<text x="250" y="76">方塊一</text>
<text x="250" y="126">方塊二</text>
<animate attributeName="stroke" values="#000;#f00;#fa0;#00f" dur="2s" repeatCount="indefinite" begin="a120203_c1.mouseover" end="a120203_c1.mouseout" fill="freeze"></animate>
</g>
<rect fill="#f00" x="10" y="50" width="40" height="40">
<animate id="a120203_a1" attributeName="x" values="10;200;10" begin="indefinite;a120203_a1.repeat(3)" end="a120203_end1.click" dur="2s" repeatCount="indefinite"></animate>
<set attributeName="fill" to="#0f0" begin="a120203_a1.repeat(1)"></set>
<set attributeName="fill" to="#ff0" begin="a120203_a1.repeat(2)"></set>
<set attributeName="fill" to="#f00" begin="a120203_a1.repeat(3)"></set>
</rect>
<rect fill="#00f" x="10" y="100" width="40" height="40">
<animate attributeName="x" values="10;200;10" begin="a120203_a1.end+600ms" end="a120203_end1.click" dur="2s" repeatCount="indefinite"></animate>
</rect>
</svg>
accumulate
這個累加的設定,我還沒想到應用的地方,範例如下 :
每次 repeat 顏色都會改變,有加 accumulate="sum" 的方塊,在 repeat 時並沒有回到初始狀態, 而是以當前位置為原點,by=10 跑到 by=50 (以第一次 repeat 來說,會從 x=60 開始)
這個範例在 chrome 和 firefox 的結果又有點不同,我覺得 firefox 比較正確
<svg width="300" height="200">
<text x="10" y="20">accumulate="none"</text>
<rect fill="#f00" x="10" y="30" width="40" height="40">
<animate id="a120204_a1" attributeName="x" values="10;50" begin="0s;a120204_a1.repeat(3)" dur="2s" repeatCount="indefinite"></animate>
<set attributeName="fill" to="#0f0" begin="a120204_a1.repeat(1)"></set>
<set attributeName="fill" to="#fa0" begin="a120204_a1.repeat(2)"></set>
<set attributeName="fill" to="#f00" begin="a120204_a1.repeat(3)"></set>
</rect>
<text x="10" y="110">accumulate="sum"</text>
<rect fill="#f00" x="10" y="120" width="40" height="40">
<animate id="a120204_a2" attributeName="x" values="10;50" begin="0s;a120204_a2.repeat(3)" dur="2s" repeatCount="indefinite" accumulate="sum"></animate>
<set attributeName="fill" to="#0f0" begin="a120204_a2.repeat(1)"></set>
<set attributeName="fill" to="#fa0" begin="a120204_a2.repeat(2)"></set>
<set attributeName="fill" to="#f00" begin="a120204_a2.repeat(3)"></set>
</rect>
</svg>
animateTransform
除了本來 animate 的參數外,還多了幾個
type="transform 的種類"
additive="取代或累加",replace(預設), sum(效果累加)
範例如下 :
圖1: 設定 transform scale 從 1 到 2<br>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" style="background-color:#ffa">
<rect x="40" y="40" width="40" height="40" fill="#f00">
<animateTransform attributeName="transform" type="scale" values="1;2" dur="2s" begin="0s" repeatCount="indefinite"></animateTransform>
</rect>
</svg><br><br>
圖2: 設定 transform scale 從 1 到 2 ,並且 translate 移動方塊中心點,這個時候必須加上 <font color="#00f">additive="sum"</font> ,兩個 transform 的設定才會累加<br>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" style="background-color:#ffa">
<rect x="40" y="40" width="40" height="40" fill="#f00">
<animateTransform attributeName="transform" type="translate" values="0,0;-60,-60" dur="2s" begin="0s" repeatCount="indefinite" additive="sum"></animateTransform>
<animateTransform attributeName="transform" type="scale" values="1;2" dur="2s" begin="0s" repeatCount="indefinite" additive="sum"></animateTransform>
</rect>
</svg>
圖2: 設定 transform scale 從 1 到 2 ,並且 translate 移動方塊中心點,這個時候必須加上 additive="sum" ,兩個 transform 的設定才會累加
animateMotion
這個功能相當有趣,可以規劃一條路徑,讓物件跟著路徑跑,除了本來 animate 的參數外,還多了一些參數
path="和 path 的 d 相同"
rotate="角度",auto(隨著路線自動轉)|auto-reverse(隨著路線自動轉再加 180 度)
keyPoints="設定中間點",為 0 到 1 的值,搭配 keyTimes 來調整每一段的速度,要記得設定 calcMode 才有作用
除了參數外,在 animateMotion 中可以使用 mpath 來取代參數 path , 這樣可以利用 xlink:href 來使用別處定義好的路徑
先來一個範例:
紅球用參數 path 來設定路徑,藍色方塊和綠三角使用 mpath 來串接 #a12026_p1 這條路徑, 綠三角有設定 keyPoints 和 keyTimes,讓路徑不同區段有不同速度
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200">
<g stroke="#000" fill="none">
<path id="a120206_p1" d="M30,30 Q30 300 230,30z"></path>
<circle cx="0" cy="0" r="10" fill="#f006">
<animateMotion dur="6s" repeatCount="indefinite" rotate="auto" path="M30,30 Q30 300 230,30z"></animateMotion>
</circle>
<rect x="-30" y="0" width="60" height="20" fill="#00f6">
<animateMotion dur="6s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#a120206_p1"></mpath>
</animateMotion>
</rect>
<path d="M0,0 L10,30 L-10,30z" fill="#0f06">
<animateMotion dur="6s" repeatCount="indefinite" rotate="auto-reverse" keyPoints="0;0.65;1" keyTimes="0;0.9;1" calcMode="linear">
<mpath xlink:href="#a120206_p1"></mpath>
</animateMotion>
</path>
</g>
</svg>
那麼最後就用一個SVG的時鐘做為這一篇的結束
<style>
#a120207_g1
{
stroke:#00f
}
#a120207_d1
{
stroke:#f00
}
</style>
<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" stroke="#000">
<circle id="a120207_o1" cx="150" cy="150" r="140" fill="none" stroke="#000" stroke-width="2"></circle>
<g id="a120207_g3">
<g id="a120207_g2">
<g id="a120207_g1">
<line x1="10" y1="150" x2="40" y2="150" stroke-width="3"></line>
<defs>
<line id="a120207_d1" x1="10" y1="150" x2="20" y2="150"></line>
</defs>
<use xlink:href="#a120207_d1" transform="rotate(6,150,150)"></use>
<use xlink:href="#a120207_d1" transform="rotate(12,150,150)"></use>
<use xlink:href="#a120207_d1" transform="rotate(18,150,150)"></use>
<use xlink:href="#a120207_d1" transform="rotate(24,150,150)"></use>
</g>
<use xlink:href="#a120207_g1" transform="rotate(30,150,150)"></use>
<use xlink:href="#a120207_g1" transform="rotate(60,150,150)"></use>
</g>
<use xlink:href="#a120207_g2" transform="rotate(90,150,150)"></use>
</g>
<use xlink:href="#a120207_g3" transform="rotate(180,150,150)"></use>
<line id="a120207_hh" x1="150" y1="150" x2="150" y2="80" stroke-width="10">
<animateTransform attributeName="transform" type="rotate" values="0,150,150;360,150,150" dur="1440s" repeatCount="indefinite"></animateTransform>
</line>
<line id="a120207_mm" x1="150" y1="150" x2="150" y2="50" stroke-width="6">
<animateTransform attributeName="transform" type="rotate" values="0,150,150;360,150,150" dur="120s" repeatCount="indefinite"></animateTransform>
</line>
<line id="a120207_ss" x1="150" y1="150" x2="150" y2="30" stroke-width="2" stroke="#f00">
<animateTransform attributeName="transform" type="rotate" values="0,150,150;360,150,150" dur="2s" repeatCount="indefinite"></animateTransform>
</line>
<circle id="o2" cx="150" cy="150" r="8"></circle>
</svg>
沒有留言:
張貼留言