今天一起来了解一下,怎么在不靠其它套件的状况下,单纯的制作SVG动画。
资料来源: https://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/
能让SVG
不靠JavaScript与CSS
就能动起来是因为使用了SMIL(Synchronized Multimedia Integration Language)
,是W3C的标准之一,旨在以XML格式提供多媒体的交互表现(白话点其实就是动画),是Web上动画的开路先锋,启发了Web animation与CSS animation。SVG与SMIL的开发团队合作,让SVG能利用SMIL达到如下效果:
光是这些特性就够我们组合出很多种的动画了,还不需要JavaScript与CSS的辅助。
使用方法也不难,只要在SVG元素内置入以下四种元素即可操作动画:
接着我们针对这四种元素一一介绍。
\
利用元素你能够指定在一段时间后,改变svg的一个属性,例如2秒后将Rick的眼睛变成往下看:
疑?你说他本来就是往下看的?
那是因为set不会重复执行,从你加载这篇文章到看到这个位置为止,相信已经超过2秒,所以已经是执行后的结果,建议你右键单击->“在新分页中开启图片”,实际体验一下,再不然看看下面的gif也行:
将元素放在你想要套用效果的svg shape内即可。
attributeName指定你要更动的属性;to代表变化值;begin代表从加载后的什么时候开始执行。
除了attributeName外,有另一个参数叫attributeType,用来告诉浏览器你要动画化的属性值是属于XML(e.g. cy),还是CSS(e.g. opacity),不指定的话,浏览器会自己猜。不过呢,这个参数也已经deprecated了,所以实际上我们不再需要它。
元素让你能针对单一属性变化套用动画补间效果。用法一样是放在你想要套用效果的svg shape内:
与相比,多了from属性来指定要从哪个值开始做变化,dur指定动画的执行时间,repeatCount指定要重复几次,这边我们设定indefinite让他无限回放(若看不到效果请以分页开新图片):
利用animate,让Rick的眼睛向右看。
也可以用来改变颜色:
也因为可以用来改变颜色,所以本来有个元素就被取代掉了,现在已经deprecated了。
可以用来控制transform属性,用animate无法做到。跟CSS中的transform一样,可以控制translation、scaling、rotation跟skewing。
可以让 Rick 头转起来,
(注:经实测,animateTransform 在手机上似乎不支援,请用桌面版浏览器查看此范例)
如上面所述,要控制 transform
属性,所以 attributeName="transform"
,接着 type
参数就看你想要 transform 的类型是什么,rotate
、scale
都可以。其余 from
、to
、begin
、dur
等参数都与之前的相同,用来指定动画的起始终点值、时间长度与执行次数。
最后一个元素,animateMotion
,让 svg 沿着轨迹 path 移动(若看不到效果请以分页开新图片):
<path d="M10,50 q60,50 100,0 q60,-50 100,0" stroke="black" stroke-width="2" />
<g>
<animateMotion path="M10,50 q60,50 100,0 q60,-50 100,0" begin="0s"
dur="10s" repeatCount="indefinite" />
g>
上述程式码内的
只是为了让大家看清楚路径与实际动画的轨迹无关,实际使用上只要给定 animateMotion
一条 path
属性值,包含 animateMotion
元素的 svg 就会跟着该路径移动。
其他属性值跟其他元素雷同,不过 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" />
此外,除了给定 path
属性值外,其实也能够利用既有的
来当作 animateMotion
的路径,但是得透过 mpath
这个 sub-element:
<path id="path1" d="M10,50 q60,50 100,0 q60,-50 100,0" stroke="black" stroke-width="2" />
<g>
<animateMotion begin="0s" dur="10s"
repeatCount="indefinite">
<mpath xlink:href="#path1" />
animateMotion>
g>
要注意的是,若要使用 xlink:href
来指定连接的 svg 元素,在你的 tag 上得先记得宣告
xmlns:xlink="http://www.w3.org/1999/xlink"
。
<svg width="300" height="200" viewBox="0 0 500 300" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
svg>
有了 xlink:href
,我们也就不用像之前范例中所做的一样,一定得把 animate
元素放在要绑定的 svg shape 内,可以透过 id
与 xlink:href
来连结,例如第一个
的范例可改为:
<circle id="eyes" cx="56.7573" cy="92.8179" r="2" fill="black" stroke="black" stroke-width="1">
circle>
<set xlink:href="#eyes" attributeName="cy" to="105.7318" begin="2s" />
至此我们介绍完了四种 SVG animation element,除了个别拿来使用外,这些元素是能够组合在一起使用的,就只要个别把对应的 animate element 套用在想要的 svg shape 上即可,举例来说,可以让 Rick 旋转的同时,发色改变、眼睛转动(可右键看 svg 原始码,在里面可以找到多个 animate element):
在上面的 Demo 里面,我们可以发现 SVG animate element 有很多参数可以使用,范例中只用到了一部分,但其实这些参数能设定的值都有不少变化,想要清楚知道每一个参数的用途与范例,推荐参考这篇文章 - https://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/
写得非常好非常详细。
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" />
看到这边你应该会注意到,by
跟 to
功能上有点重复,所以彼此之间有优先权,如果同时有指定 to
与 by
,则只会套用到 to
的值。
再来看看 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="2s"
,但其实这两个参数能给的值有非常多的种类,而且能向 values
一样赋予多个值,只要用;
隔开即可:
begin =
每种类型的详细介绍,我推荐直接看网上的整理
这边我只说明几个我觉得比较实用的。
。从字面有点难懂,主要是用其他 animate
元素的 begin/end
值再做加减,举个例子就比较好懂:
<g>
<animateTransform attributeName="transform"
type="scale"
values="1;1.2;1"
begin="ship.end"
dur="3s"
repeatCount="indefinite" />
g>
<g>
<animateTransform id="ship"
attributeName="transform"
type="translate"
values="20;120;20"
begin="0s" dur="3s" />
g>
这次范例中的 svg 内有两个 animate 元素,给定针对太空船做动画的元素一个 id 值 ship
,然后在 Rick 的动画元素上利用 begin="ship.end"
,就可以让 Rick 头的动画等到太空船的动画做完后再启动,效果如下:
另一个我觉得实用的值是 event-value
,看名字就知道,是可以依照 event
来启动或终结动画,用法与 syncbase-value
雷同,给定元素 id,然后根据该元素触发的事件让动画 begin
或是 end。几乎所有 DOM element 支援的 event 都能使用
最后是 indefinite
,如果你的 begin
值为 indefinite
,代表无限等待,这时就需要透过 [animate 元素].beginElement()
来触发,或是用tag 的
xlink:href="#[animate 元素 id]"
来启动。
这三个参数主要让你能够更细微的调整动画的速度变化。
calcMode
有四种模式:discrete
、linear
、paced
、spline
。
discrete 顾名思义就是离散的,from
值跳到 to
值不做补间; linear 跟 paced 我觉得效果雷同,都是让让补间动画的速度维持一致(linear)与平均(paced); spline
则是使用贝式曲线,需要搭配 keyTimes
与 keySplines
来使用。
keyTimes
就是关键影格,跟前面提过的 values
一样,可以接受多个以分号区隔的值,定义动画的关键时间点,搭配不同的 calcMode
就能在不同的时间点有不同的速度效果。
keySpline
是当你 calcMode
设定为 spline
时,用来定义贝式曲线的四个控制点的。
感兴趣的小伙伴可以直接看这篇文章:https://www.zhangxinxu.com/study/201408/svg-animation-calcmode.html
看到最后,不知道你会不会有个疑问:如果我想针对同的 SVG shape 的同个属性做多个连续变化时该怎么办?
例如:透过 animateTransform
先将图案放大再位移。
这时就要靠 additive
这个参数出马了,additive
参数告知 SVG 是否要累加(sum
)动画效果,或是取代(replace
),预设是 replace
。
例子:
<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" />
今天花了不小的篇幅介绍了 SVG SMIL animation,感谢看到这边的各位,制作 Demo 的过程对我来说很有趣,也学习了怎么绘制 SVG,从网路上的其他资源也查到许多详细的资料,收获不少!希望对看到这篇文章的你们也能有所启发,除了常用的 Web animation 与 CSS animation 外,有机会也试试用 SVG 直接作动画吧!
资料来源:
https://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/