UI設計師福利之零基礎入門SVG路徑動畫(看最後的更正部分)

先看一個動畫效果,這種小飛機沿路徑飛行(路徑部分線段變成綠色是錄屏軟件出了問題)。json

plane
plane

這種動畫效果最多見於發送信息後,兩個不一樣位置之間的導航指向等等,總之使用場景仍是不少的。對於SVG動畫來講,這種效果是最最簡單不過,只須要一個路徑外加幾個屬性的簡單設置就能完成,簡單到不算飛機圖形的話,兩句代碼,而整個SVG文件只有1K左右大小,咱們由淺入深,從基礎開始,開啓SVG路徑動畫之門。bash

咱們把動畫元素拆解一下,由兩個部分組成,一個是路徑,一個是沿路徑運動的圖形元素。svg

1.path路徑得到

關於path路徑,SVG官方的定義以下:函數

  • M = moveto
  • L = lineto
  • H = horizontal lineto
  • V = vertical lineto
  • C = curveto
  • S = smooth curveto
  • Q = quadratic Bézier curve
  • T = smooth quadratic Bézier curveto
  • A = elliptical Arc
  • Z = closepath
    這些還不是最恐怖的,最恐怖的莫過於下面的三次貝塞爾曲線和二次貝塞爾曲線Q。

三次貝塞爾曲線
三次貝塞爾曲線

二次貝塞爾曲線
二次貝塞爾曲線

各位UI設計師們,線性代數可還會?徹底不記得了?很好,由於上面這些嚇唬人的知識在這個路徑動畫中通通用不着(你特麼是在逗我?(¯﹃¯))(瞭解貝塞爾曲線的繪圖原理多用於曲線非簡單規律變化的複雜動畫,不過如今有Airb
nb的Lottie神器了,用AE來作複雜的動畫轉成json文件是捷徑,數學大神們除外。)
咱們說過了,AI裏面的路徑在導出SVG時一樣會生成對應的<path>標籤。若是你是第一次看個人關於SVG動畫的文章也沒有關係,咱們一步步分解。
第一步:AI繪製一條由起點A到終點B的曲線,隨便描個邊。工具


AI導出SVG的文件中,僅保留 <path>標籤部分。個人以下:

<path fill="none" stroke="#78EADF" stroke-width="30" stroke-linecap="round" stroke-miterlimit="10" d="M66.9,517 c0,0-37.8-194,125.1-161.9S427.6,371.5,350,205.7S439.3,23.4,544,62.2"/>複製代碼

關於路徑描邊的各個屬性值再也不贅述,注意標籤中d=""部分,後面咱們的路徑動畫時要調用的就是這個路徑。動畫

path路徑的參數由AI導出的SVG路徑中的d生成。ui

2.路徑動畫<animateMotion>

關於路徑動畫最基礎的語法簡單到以下:url

<animateMotion path="" dur=""/>
<!--dur定義動畫時間-->複製代碼

其中path即爲咱們在AI中繪製路徑自動生成的d="" 所包含的定義路徑曲線的部分。
如今,若是我定義一個最簡單的圓形circle,加上路徑動畫屬性,已經能夠實現動畫效果了,代碼以下:spa

<circle fill="#F8B62D" r="20">
<animateMotion path="M66.9,517 c0,0-37.8-194,125.1-161.9S427.6,371.5,350,205.7S439.3,23.4,544,62.2" dur="3s"/> 
</circle>複製代碼

動畫效果以下:設計

沿路徑移動的圓形
沿路徑移動的圓形

這裏還有一個方法,就是咱們給藍色路徑定義一個id,而後路徑動畫來引用這個id,代碼以下:

<!--road爲咱們定義的路徑id-->
<path id="road" fill="none" stroke="#78EADF" stroke-width="30" stroke-linecap="round" stroke-miterlimit="10" d="M66.9,517 c0,0-37.8-194,125.1-161.9S427.6,371.5,350,205.7S439.3,23.4,544,62.2"/>
<circle fill="#F8B62D" r="20">
<animateMotion  dur="3s">
<mpath xlink:href="#road"/> <!--經過路徑連接屬性調用定義的路徑-->
</animateMotion> 
</circle>複製代碼

這兩種方法都可,重點是第二種方法,後面將要揭祕。

3.任意圖形的路徑動畫

看了上面的是否是感受so easy,但這確定不是咱們的需求,開始拋磚引玉,好比,我準備作一個沿路徑奮力爬行的小瓢蟲的動畫。先準備素材,在AI中繪製一隻小瓢蟲,好比圖層我命名beatles

繪製甲蟲
繪製甲蟲

而後獲得一堆<g id="beatles">……</g>的SVG代碼。
接下來就很簡單了,用甲蟲的圖形來替換上面動畫中的圓形,其餘不變。獲得代碼以下:

<g id="beatles">
……<!--此處省略繪製甲蟲的代碼若干-->
<animateMotion path="M66.9,517 c0,0-37.8-194,125.1-161.9S427.6,371.5,350,205.7S439.3,23.4,544,62.2" dur="3s"/> 
</g>複製代碼

期待已久的時刻來了,正常思路,咱們的小瓢蟲能夠沿着路徑爬行了。各位看官先不要激動,此時,你看到的動畫應該是這個樣子的(爲了方便觀察,我把畫布調整了大小,留出足夠的空間)。

偏移了路線的小甲蟲
偏移了路線的小甲蟲

小甲蟲,你要去哪裏?你快回來。再看咱們的代碼,沒毛病,甲蟲的位置明明就是擺在路徑的起點上。不過咱們仍能發現的一個規律是:雖然小瓢蟲跑偏了,但跑的姿式彷佛仍是對的。爲何圓形沒事,換個複雜的圖形就不能夠了呢?咱們上面圓形按照路徑移動時,並無定義圓形的圓心位置(cx和cy值),僅定義了半徑r。好了,接下來要放大招了,這是你之後製做SVG路徑動畫的關鍵。

4.任意圖形的位置校訂

先來看一句話: 定義了路徑動畫的圖形會把路徑的起點做爲原點。讀起來拗口且難懂,炒個栗子吧。我繪製的路徑起點座標爲X=66.9,Y=517,對於瞭解SVG路徑的小夥伴們都知道,其實就是path的起點M值。那對於甲蟲來講,(66.9,517)纔是它座標系的原點,而不是(0,0)。以下圖所示,整個座標系向右偏移了66.9px,向下偏移了517px。

偏移後的座標系
偏移後的座標系

因此最終的效果就是甲蟲沿着偏移後的灰色路徑移動。
知道了緣由就能夠對症下藥了。

4.1 方法1——把甲蟲拉回它應該在的位置

既然知道偏移的值,再把它放回去,放回去的話就很簡單了,咱們只要把甲蟲移動到畫布的左上角原點的位置(即x=0,y=0)

移動圖形到原點處
移動圖形到原點處

此時再導出SVG,除了甲蟲圖形代碼替換,獲得下面的效果:


小瓢蟲強勢迴歸!

4.2 方法2——使用SVG的defs元素

這個方法至關於方法1的擴展,你可使用defs來定義圖形,use標籤來調用,一樣須要圖形位於畫布原點,代碼以下:

<defs>
<g id="beatles">
……<!--此處爲繪製瓢蟲的代碼-->
</g>
</defs>
<use xlink:href="#beatles" x="0" y="0">
<animateMotion  dur="3s">
<mpath xlink:href="#road"/> <!--方法2和方法1因爲路徑是同一條,因此都適合用調用路徑的方法-->
</animateMotion>
</use>複製代碼

用defs來定義圖形的好處是,你可使用use標籤在不一樣位置重複調用這個圖形,好比我下面說明運動速率時擺放的5只小甲蟲。
由方法1和方法2咱們得出一個結論,圖形繪製的時候無所謂位置,只要最後在畫布的左上角原點就能夠了

4.3 方法3——從新定義移動路徑

上面的那個方法雖然能夠實現正常路徑運動,但實際中存在一個問題(個人動畫播放時使用了無限循環,因此看不出)。當動畫設置了延遲開始(eg. begin="2s")時,甲蟲在動畫開始前並非乖乖的待在起點A,而是移動後的位置,畫布左上角,2s後動畫開始播放,甲蟲纔回到A點。來看下面這種解決方案,從新定義圖形的移動路徑。
跟着我左右右手一個慢動做,右手左手慢動做重播……咱們用相同的方法來移動,不過,此次咱們移動的是路徑,記得選擇「複製」,或者乾脆點,直接把起點拖到畫布的原點。

移動路徑
移動路徑

而後爲了方便區分,建議你給移動後的新路徑區分一下描邊方法。

新路徑
新路徑

好了,甲蟲按兵不動,導出SVG時,複製後的路徑那一堆代碼咱們只須要d值,個人路徑動畫代碼也就變成了下面的樣子:

<animateMotion path="M0,0 c0,0-37.8-194,125.1-161.9s235.7,16.5,158.1-149.3s89.2-182.3,194-143.5" dur="3s"/>複製代碼

如今,全部都恢復正常,咱們的小甲蟲又能夠乖乖的從A爬到B了,並且不管什麼時候,起點和終點都是咱們預期值。(但這個方法有個很大的bug,後面再說)

做爲有追求的設計師,這個動畫效果是否是感受low到爆?首先,瓢蟲移動速度不符合物理規律,勻速運動,其次,身體沒有相應的轉動,生硬不生動。好了,來,加上這幾個屬性,改善一下。

5. 運動速率的設定

先給animateMotion加上下面的代碼:

calcMode="spline"  keySplines="" keyTimes="0;1"複製代碼

calcMode屬性定義動畫的類型,一共四個屬性值,其餘不說了,"spline"要搭配後面的keySplineskeyTimes屬性一塊兒使用,以上代碼的意思是宣告「我要來爲所欲爲的控制運動速率了!」
keySplines值的設定與CSS的貝塞爾曲線相同。
關於運動速率的貝塞爾曲線(說好了不提它,又來!)有個在線工具能夠藉助:cubic-bezier.com/

cubic-bezier工具
cubic-bezier工具

這裏你能夠自定義運動速率曲線並查看效果,不過若是不是須要一些特別的效果,建議使用如下幾個固定值:
"慢-快-慢 ease":".25,.1,.25,1"
"線性 linear":"0,0,1,1"這個是默認值,能夠不用定義。
"慢開始 ease-in":".42,0,1,1"
"慢結束 ease-out":"0,0,.58,1"
"慢-正常-慢 ease-in-out":".42,0,.58,1"
我作一個甲蟲水平移動的動畫,來對比一下這五種不一樣的速率曲線的效果。

不一樣運動速率曲線的甲蟲
不一樣運動速率曲線的甲蟲

同時出發,但中間速度有差,異曲同工,又同時到達終點。
這裏我搞了個事情出來,把速率曲線畫成了下面這個樣子:

任意繪製的曲線
任意繪製的曲線

因此個人keySplines=".28,1.89,.56,-1.32"。如今個人甲蟲移動方式是這樣的:

自定義移動速率曲線的甲蟲
自定義移動速率曲線的甲蟲

怎麼樣,是否是還算有趣。花樣能夠不少,自行嘗試。

keyTimes值(0;1)是最簡單的一種,沒有對運動過程進行分割,若是你想玩出更深的套路,能夠把路徑截成好幾段,而後定義不一樣的keySplines值。再炒個栗子。
keyTimes="0;0.66;1" keySplines=".42,0,1,1;0,0,1,1;" 就是路徑的前2/3,我但願用ease-in函數定義速度,路徑的後1/3線性速度,但在銜接處會抖一下,由於實在使用場景不多,因此keyTimes值就用最基礎的就好。

6. 跟隨路徑曲度的旋轉方向

這個簡單,只有一句代碼:rotate="auto",此時的路徑動畫已經實現的有模有樣了。

跟隨路徑曲度的圖形的旋轉
跟隨路徑曲度的圖形的旋轉

前面提到過,4.3方法3——從新定義移動路徑,有個bug的問題,就是這裏,由於旋轉方向是依據路徑的走向,若是使用移動事後的路徑,那旋轉的效果簡直不忍直視。
這裏有一個悖論,方法1和方法2,正常旋轉,但初始的甲蟲的位置不能在起點,方法3,初始位置在起點,但不能正常旋轉。(抓狂ing……)使用過程當中選哪一個選哪一個,好糾結。
好了,設計師們,不用糾結,選1和2,由於……
……
由於……
咱們能夠用js定義動畫開始的時間,哈哈,根本不須要begin屬性。

好了,開始放能夠複用的代碼並註釋,一切不能複用的SVG動畫代碼都是耍流氓!

<svg width="" height="">
<path id="road" fill="none" d=""/><!--路徑所有由AI直接生成-->
<g>
……
<!--此處爲若干圖形代碼-->
<animateMotion  dur=""  repeatCount="" rotate="auto"  calcMode="spline" keyTimes="0;1" keySplines="" ><mpath xlink:href="#road"/></animateMotion>
</g>
</svg>複製代碼

嗯,over,就是介麼簡單。剩下的只是填空。
好比dur定義所有動畫須要的時間,keySplines定義運動速率類型,repeatCount定義播放次數,上面都有一一解釋。

那麼利用路徑動畫,都能實現什麼效果呢,來繼續看:

7.1 路徑動畫功能擴展——伴隨圖形變化

如今我要實現一個小甲蟲漸行漸遠的效果,爲了讓效果看起來更逼真,我把底圖描邊路徑從新作了一下,而後把keySplines="0,0,.58,1"即運動速率爲ease-out慢結束,以下:

漸行漸遠的甲蟲
漸行漸遠的甲蟲

這個效果實現也不過再加一句縮放動畫代碼

<animateTransform dur="" attributeName="transform"  fill="freeze" type="scale" from="1 1" to="0.5 0.5" />複製代碼

時間與路徑動畫保持一致,type="scale" from="1 1" to="0.5 0.5"表示寬高縮小到原來1/2。
你能夠搞得很複雜,好比伴隨甲蟲腿的擺動,但涉及到複合動畫,好麻煩,這也是我爲何沒有用一隻帶腿的甲蟲的緣由,哈哈。

7.2 路徑動畫功能擴展——搭配描邊動畫+蒙版

結合描邊動畫和蒙版,咱們能夠實現下面這種效果:

結合蒙版描邊動畫
結合蒙版描邊動畫

一架一路辛苦播撒小豆的飛機。
動畫拆解:先繪製一個點狀組成的螺旋線路徑,而後給這個螺旋線加一個蒙版,把描邊動畫賦給蒙版,描邊路徑即爲螺旋線路徑,顏色爲白色,至關於經過蒙版動態畫一根白色螺旋線來實現點狀螺旋線路徑同步顯示出來。小飛機就按咱們上面介紹過的的路徑動畫來定義。
感興趣的話能夠把下邊的代碼拿去複用:

<svg  width="600" height="600" >
<style>
@keyframes dash {
to {
stroke-dashoffset: 0;
}
}
#helix{
stroke-dasharray:2006;  /*2006爲螺旋線的長度*/
stroke-dashoffset:2006; 
animation: dash 4s linear forwards;  /*蒙版動畫的速率和時間與飛機路徑動畫保持一致*/
animation-delay:0.2s; /*爲了讓飛機稍微領先,設置了蒙版動畫0.2秒的延遲*/
}
</style>
<mask id="helix">
<!--蒙版調用定義的描邊動畫helix,d=""包含部分爲螺旋線的路徑-->
<path fill="none" stroke="#fff" stroke-width="16" stroke-linecap="round" d=""/>
</mask>
<path mask="url(#helix)" id="road" fill="none" stroke="#78EADF" stroke-width="16" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="0,30" d=""/>
<g id="plane">
…<!--此處飛機代碼若干-->
<animateMotion fill="freeze"   dur="4s"  rotate="auto"  calcMode="spline" keyTimes="0;1" keySplines="0,0,1,1" ><!--keySplines值的設定要與描邊動畫保持一致,若是上面animation定義了ease,則這裏也要對應改爲".25,.1,.25,1"-->
<mpath xlink:href="#road"/>
</animateMotion>
</g>
</svg>複製代碼

知識點總結:
①動畫的路徑直接經過AI繪製後導出的SVG的d值得到。
②圖形元素移動到畫布原點後再生成對應的SVG代碼。
③經過定義calcMode、keyTimes以及 keySplines來修改運動速度。
④定義rotate屬性來實現跟隨路徑曲率的旋轉效果。
⑤與其餘動畫的組合,須要多多的創意。

補充部分(更正):

CSS3有路徑動畫屬性!有路徑動畫屬性!有路徑動畫屬性!在寫這篇文章時,一直覺得路徑動畫是CSS3惟一不可取代SIML實現的動畫,直到今天,我看到了這個,抑制不住的激動٩(๑>◡<๑)۶,我CSS3終於動畫部分大統一了。

@keyframes move{              
0%{offset-distance:0%; }
100%{offset-distance:100%; }
 }
#move{
offset-path:path('');
animation:move 1s ease ;
}複製代碼

是的,你沒有看錯,就是offset-pathoffset-distance兩個屬性。offset-path用於定義路徑部分,offset-distance控制元素在路徑上的運動距離。

至此,SVG+CSS3動畫終於得以完美,全部動畫部分均由CSS3來控制,SVG僅用來提供基礎圖形。由於不記得都在哪些文章中提到過路徑動畫了,因此無法一一更正,這是初始篇,因此但願全部的閱讀這篇文章的人都能看到,不要被我帶坑裏哦。

相關文章
相關標籤/搜索