UI設(shè)計師福利之零基礎(chǔ)入門SVG路徑動畫

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

plane
plane

這種動畫效果最常見于發(fā)送信息后,兩個不同位置之間的導(dǎo)航指向等等塘辅,總之使用場景還是很多的扣墩。對于SVG動畫來說荆责,這種效果是最最簡單不過做院,只需要一個路徑外加幾個屬性的簡單設(shè)置就能完成键耕,簡單到不算飛機圖形的話郁竟,兩句代碼棚亩,而整個SVG文件只有1K左右大小讥蟆,我們由淺入深修然,從基礎(chǔ)開始愕宋,開啟SVG路徑動畫之門中贝。

我們把動畫元素拆解一下邻寿,由兩個部分組成绣否,一個是路徑蒜撮,一個是沿路徑運動的圖形元素段磨。

1.path路徑獲得

關(guān)于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設(shè)計師們特姐,線性代數(shù)可還會唐含?完全不記得了捷枯?很好淮捆,因為上面這些嚇唬人的知識在這個路徑動畫中統(tǒng)統(tǒng)用不著(你特么是在逗我攀痊?(ˉ﹃ˉ))(了解貝塞爾曲線的繪圖原理多用于曲線非簡單規(guī)律變化的復(fù)雜動畫苟径,不過現(xiàn)在有Airb
nb的Lottie神器了涩笤,用AE來做復(fù)雜的動畫轉(zhuǎn)成json文件是捷徑蹬碧,數(shù)學大神們除外恩沽。)
我們說過了罗心,AI里面的路徑在導(dǎo)出SVG時同樣會生成對應(yīng)的<path>標簽渤闷。如果你是第一次看我的關(guān)于SVG動畫的文章也沒有關(guān)系飒箭,我們一步步分解弦蹂。
** 第一步:AI繪制一條由起點A到終點B的曲線,隨便描個邊翅溺。**


AI導(dǎo)出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"/>

關(guān)于路徑描邊的各個屬性值不再贅述密末,注意標簽中d=""部分严里,后面我們的路徑動畫時要調(diào)用的就是這個路徑刹碾。

path路徑的參數(shù)由AI導(dǎo)出的SVG路徑中的d生成迷帜。

2.路徑動畫<animateMotion>

關(guān)于路徑動畫最基礎(chǔ)的語法簡單到如下:

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

其中path即為我們在AI中繪制路徑自動生成的d="" 所包含的定義路徑曲線的部分戏锹。
現(xiàn)在锦针,如果我定義一個最簡單的圓形circle奈搜,加上路徑動畫屬性馋吗,已經(jīng)可以實現(xiàn)動畫效果了,代碼如下:

<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"/> <!--通過路徑鏈接屬性調(diào)用定義的路徑-->
</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>

期待已久的時刻來了唱捣,正常思路,我們的小瓢蟲可以沿著路徑爬行了网梢。各位看官先不要激動震缭,此時战虏,你看到的動畫應(yīng)該是這個樣子的(為了方便觀察膛堤,我把畫布調(diào)整了大小次企,留出足夠的空間)堵第。

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

小甲蟲针余,你要去哪里行您?你快回來。再看我們的代碼橡疼,沒毛病历帚,甲蟲的位置明明就是擺在路徑的起點上禽拔。不過我們?nèi)阅馨l(fā)現(xiàn)的一個規(guī)律是:雖然小瓢蟲跑偏了茧痕,但跑的姿勢似乎還是對的舀患。為什么圓形沒事,換個復(fù)雜的圖形就不可以了呢?我們上面圓形按照路徑移動時,并沒有定義圓形的圓心位置(cx和cy值)灸姊,僅定義了半徑r父晶。好了茎匠,接下來要放大招了,這是你以后制作SVG路徑動畫的關(guān)鍵圈盔。

4.任意圖形的位置校正

先來看一句話: 定義了路徑動畫的圖形會把路徑的起點作為原點娩梨。讀起來拗口且難懂,炒個栗子吧流礁。我繪制的路徑起點坐標為X=66.9霎桅,Y=517著角,對于了解SVG路徑的小伙伴們都知道囚痴,其實就是path的起點M值。那對于甲蟲來說,(66.9,517)才是它坐標系的原點员淫,而不是(0,0)刃宵。如下圖所示坦袍,整個坐標系向右偏移了66.9px缝其,向下偏移了517px嘴高。

偏移后的坐標系
偏移后的坐標系

所以最終的效果就是甲蟲沿著偏移后的灰色路徑移動喇闸。
知道了原因就可以對癥下藥了唆樊。

4.1 方法1——把甲蟲拉回它應(yīng)該在的位置

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

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

此時再導(dǎo)出SVG舆瘪,除了甲蟲圖形代碼替換片效,得到下面的效果:


小瓢蟲強勢回歸!

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

這個方法相當于方法1的擴展英古,你可以使用defs來定義圖形淀衣,use標簽來調(diào)用,同樣需要圖形位于畫布原點召调,代碼如下:

<defs>
<g id="beatles">
……<!--此處為繪制瓢蟲的代碼-->
</g>
</defs>
<use xlink:href="#beatles" x="0" y="0">
<animateMotion  dur="3s">
<mpath xlink:href="#road"/> <!--方法2和方法1由于路徑是同一條膨桥,所以都適合用調(diào)用路徑的方法-->
</animateMotion>
</use>

用defs來定義圖形的好處是,你可以使用use標簽在不同位置重復(fù)調(diào)用這個圖形唠叛,比如我下面說明運動速率時擺放的5只小甲蟲只嚣。
由方法1和方法2我們得出一個結(jié)論,圖形繪制的時候無所謂位置艺沼,只要最后在畫布的左上角原點就可以了册舞。

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

上面的那個方法雖然可以實現(xiàn)正常路徑運動,但實際中存在一個問題(我的動畫播放時使用了無限循環(huán)障般,所以看不出)调鲸。當動畫設(shè)置了延遲開始(eg. begin="2s")時盛杰,甲蟲在動畫開始前并不是乖乖的待在起點A,而是移動后的位置线得,畫布左上角饶唤,2s后動畫開始播放徐伐,甲蟲才回到A點贯钩。來看下面這種解決方案,重新定義圖形的移動路徑办素。
跟著我左右右手一個慢動作角雷,右手左手慢動作重播……我們用相同的方法來移動,不過性穿,這次我們移動的是路徑勺三,記得選擇“復(fù)制”,或者干脆點需曾,直接把起點拖到畫布的原點吗坚。

移動路徑
移動路徑

然后為了方便區(qū)分,建議你給移動后的新路徑區(qū)分一下描邊方法呆万。

新路徑
新路徑

好了商源,甲蟲按兵不動,導(dǎo)出SVG時谋减,復(fù)制后的路徑那一堆代碼我們只需要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"/>

現(xiàn)在,所有都恢復(fù)正常出爹,我們的小甲蟲又可以乖乖的從A爬到B了庄吼,而且無論何時,起點和終點都是我們預(yù)期值严就。(但這個方法有個很大的bug总寻,后面再說)

作為有追求的設(shè)計師,這個動畫效果是不是感覺low到爆梢为?首先渐行,瓢蟲移動速度不符合物理規(guī)律,勻速運動抖誉,其次殊轴,身體沒有相應(yīng)的轉(zhuǎn)動,生硬不生動袒炉。好了旁理,來,加上這幾個屬性我磁,改善一下孽文。

5. 運動速率的設(shè)定

先給animateMotion加上下面的代碼:

calcMode="spline"  keySplines="" keyTimes="0;1"

calcMode屬性定義動畫的類型驻襟,一共四個屬性值,其他不說了芋哭,"spline"要搭配后面的keySplineskeyTimes屬性一起使用沉衣,以上代碼的意思是宣告“我要來隨心所欲的控制運動速率了!”
keySplines值的設(shè)定與CSS的貝塞爾曲線相同减牺。
關(guān)于運動速率的貝塞爾曲線(說好了不提它豌习,又來!)有個在線工具可以借助:http://cubic-bezier.com/

cubic-bezier工具
cubic-bezier工具

這里你可以自定義運動速率曲線并查看效果拔疚,不過如果不是需要一些特別的效果肥隆,建議使用以下幾個固定值:
"慢-快-慢 ease":".25,.1,.25,1"
"線性 linear":"0,0,1,1"這個是默認值,可以不用定義稚失。
"慢開始 ease-in":".42,0,1,1"
"慢結(jié)束 ease-out":"0,0,.58,1"
"慢-正常-慢 ease-in-out":".42,0,.58,1"
我做一個甲蟲水平移動的動畫栋艳,來對比一下這五種不同的速率曲線的效果。

不同運動速率曲線的甲蟲
不同運動速率曲線的甲蟲

同時出發(fā)句各,但中間速度有差吸占,殊途同歸,又同時到達終點凿宾。
這里我搞了個事情出來矾屯,把速率曲線畫成了下面這個樣子:

任意繪制的曲線
任意繪制的曲線

所以我的keySplines=".28,1.89,.56,-1.32"。現(xiàn)在我的甲蟲移動方式是這樣的:

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

怎么樣菌湃,是不是還算有趣问拘。花樣可以很多惧所,自行嘗試骤坐。

keyTimes值(0;1)是最簡單的一種,沒有對運動過程進行分割下愈,如果你想玩出更深的套路纽绍,可以把路徑截成好幾段,然后定義不同的keySplines值势似。再炒個栗子拌夏。
keyTimes="0;0.66;1" keySplines=".42,0,1,1;0,0,1,1;" 就是路徑的前2/3,我希望用ease-in函數(shù)定義速度履因,路徑的后1/3線性速度障簿,但在銜接處會抖一下,因為實在使用場景很少栅迄,所以keyTimes值就用最基礎(chǔ)的就好站故。

6. 跟隨路徑曲度的旋轉(zhuǎn)方向

這個簡單,只有一句代碼:rotate="auto",此時的路徑動畫已經(jīng)實現(xiàn)的有模有樣了西篓。

跟隨路徑曲度的圖形的旋轉(zhuǎn)
跟隨路徑曲度的圖形的旋轉(zhuǎn)

前面提到過愈腾,4.3方法3——重新定義移動路徑,有個bug的問題岂津,就是這里虱黄,因為旋轉(zhuǎn)方向是依據(jù)路徑的走向,如果使用移動過后的路徑吮成,那旋轉(zhuǎn)的效果簡直不忍直視橱乱。
這里有一個悖論,方法1和方法2赁豆,正常旋轉(zhuǎn)仅醇,但初始的甲蟲的位置不能在起點,方法3魔种,初始位置在起點,但不能正常旋轉(zhuǎn)粉洼。(抓狂ing……)使用過程中選哪個選哪個节预,好糾結(jié)。
好了属韧,設(shè)計師們安拟,不用糾結(jié),選1和2宵喂,因為……
……
因為……
我們可以用js定義動畫開始的時間糠赦,哈哈,根本不需要begin屬性锅棕。

好了拙泽,開始放可以復(fù)用的代碼并注釋,一切不能復(fù)用的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定義播放次數(shù)蕴纳,上面都有一一解釋。

那么利用路徑動畫个粱,都能實現(xiàn)什么效果呢古毛,來繼續(xù)看:

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

現(xiàn)在我要實現(xiàn)一個小甲蟲漸行漸遠的效果,為了讓效果看起來更逼真几蜻,我把底圖描邊路徑重新做了一下喇潘,然后把keySplines="0,0,.58,1"即運動速率為ease-out慢結(jié)束体斩,如下:

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

這個效果實現(xiàn)也不過再加一句縮放動畫代碼

<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颖低。
你可以搞得很復(fù)雜絮吵,比如伴隨甲蟲腿的擺動,但涉及到復(fù)合動畫忱屑,好麻煩蹬敲,這也是我為什么沒有用一只帶腿的甲蟲的原因,哈哈莺戒。

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

結(jié)合描邊動畫和蒙版伴嗡,我們可以實現(xiàn)下面這種效果:

結(jié)合蒙版描邊動畫
結(jié)合蒙版描邊動畫

一架一路辛苦播撒小豆的飛機。
動畫拆解:先繪制一個點狀組成的螺旋線路徑从铲,然后給這個螺旋線加一個蒙版瘪校,把描邊動畫賦給蒙版,描邊路徑即為螺旋線路徑名段,顏色為白色阱扬,相當于通過蒙版動態(tài)畫一根白色螺旋線來實現(xiàn)點狀螺旋線路徑同步顯示出來。小飛機就按我們上面介紹過的的路徑動畫來定義伸辟。
感興趣的話可以把下邊的代碼拿去復(fù)用:

<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; /*為了讓飛機稍微領(lǐng)先麻惶,設(shè)置了蒙版動畫0.2秒的延遲*/
}
</style>
<mask id="helix">
<!--蒙版調(diào)用定義的描邊動畫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值的設(shè)定要與描邊動畫保持一致信夫,如果上面animation定義了ease窃蹋,則這里也要對應(yīng)改成".25,.1,.25,1"-->
<mpath xlink:href="#road"/>
</animateMotion>
</g>

</svg>

知識點總結(jié):
①動畫的路徑直接通過AI繪制后導(dǎo)出的SVG的d值獲得。
②圖形元素移動到畫布原點后再生成對應(yīng)的SVG代碼静稻。
③通過定義calcMode警没、keyTimes以及 keySplines來修改運動速度。
④定義rotate屬性來實現(xiàn)跟隨路徑曲率的旋轉(zhuǎn)效果姊扔。
⑤與其他動畫的組合惠奸,需要多多的創(chuàng)意。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末恰梢,一起剝皮案震驚了整個濱河市佛南,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嵌言,老刑警劉巖嗅回,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異摧茴,居然都是意外死亡绵载,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來娃豹,“玉大人焚虱,你說我怎么就攤上這事《妫” “怎么了鹃栽?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長躯畴。 經(jīng)常有香客問我民鼓,道長,這世上最難降的妖魔是什么蓬抄? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任丰嘉,我火速辦了婚禮,結(jié)果婚禮上嚷缭,老公的妹妹穿的比我還像新娘饮亏。我一直安慰自己,他們只是感情好峭状,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布克滴。 她就那樣靜靜地躺著,像睡著了一般优床。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上誓焦,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天胆敞,我揣著相機與錄音,去河邊找鬼杂伟。 笑死移层,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的赫粥。 我是一名探鬼主播观话,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼越平!你這毒婦竟也來了频蛔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤秦叛,失蹤者是張志新(化名)和其女友劉穎晦溪,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挣跋,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡三圆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舟肉。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡修噪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出路媚,到底是詐尸還是另有隱情黄琼,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布磷籍,位于F島的核電站适荣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏院领。R本人自食惡果不足惜弛矛,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望比然。 院中可真熱鬧丈氓,春花似錦、人聲如沸强法。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饮怯。三九已至闰歪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蓖墅,已是汗流浹背库倘。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留论矾,地道東北人教翩。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像贪壳,于是被迫代替她去往敵國和親饱亿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容