让SVG 自己动起来!SMIL animation动画详解

今天一起来了解一下,怎么在不靠其它套件的状况下,单纯的制作SVG动画。

资料来源: https://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/

SVG animation with SMIL

能让SVG不靠JavaScript与CSS就能动起来是因为使用了SMIL(Synchronized Multimedia Integration Language),是W3C的标准之一,旨在以XML格式提供多媒体的交互表现(白话点其实就是动画),是Web上动画的开路先锋,启发了Web animation与CSS animation。SVG与SMIL的开发团队合作,让SVG能利用SMIL达到如下效果:

  1. 动画化元素的数值属性(x,y值等等)
  2. 动画化元素的transform属性(平移、旋转)
  3. 动画化元素颜色
  4. 轨迹路线移动动画,类似于CSS中的offset-path

光是这些特性就够我们组合出很多种的动画了,还不需要JavaScript与CSS的辅助。
使用方法也不难,只要在SVG元素内置入以下四种元素即可操作动画:

接着我们针对这四种元素一一介绍。

SVG animation element介绍与示范

\

利用元素你能够指定在一段时间后,改变svg的一个属性,例如2秒后将Rick的眼睛变成往下看:

让SVG 自己动起来!SMIL animation动画详解_第1张图片

疑?你说他本来就是往下看的?

那是因为set不会重复执行,从你加载这篇文章到看到这个位置为止,相信已经超过2秒,所以已经是执行后的结果,建议你右键单击->“在新分页中开启图片”,实际体验一下,再不然看看下面的gif也行:

让SVG 自己动起来!SMIL animation动画详解_第2张图片

相关代码如下:




将元素放在你想要套用效果的svg shape内即可。

attributeName指定你要更动的属性;to代表变化值;begin代表从加载后的什么时候开始执行。

除了attributeName外,有另一个参数叫attributeType,用来告诉浏览器你要动画化的属性值是属于XML(e.g. cy),还是CSS(e.g. opacity),不指定的话,浏览器会自己猜。不过呢,这个参数也已经deprecated了,所以实际上我们不再需要它。

元素让你能针对单一属性变化套用动画补间效果。用法一样是放在你想要套用效果的svg shape内:




与相比,多了from属性来指定要从哪个值开始做变化,dur指定动画的执行时间,repeatCount指定要重复几次,这边我们设定indefinite让他无限回放(若看不到效果请以分页开新图片):

利用animate,让Rick的眼睛向右看。

让SVG 自己动起来!SMIL animation动画详解_第3张图片

也可以用来改变颜色:

让SVG 自己动起来!SMIL animation动画详解_第4张图片

也因为可以用来改变颜色,所以本来有个元素就被取代掉了,现在已经deprecated了。

可以用来控制transform属性,用animate无法做到。跟CSS中的transform一样,可以控制translation、scaling、rotation跟skewing。

让SVG 自己动起来!SMIL animation动画详解_第5张图片

可以让 Rick 头转起来,
(注:经实测,animateTransform 在手机上似乎不支援,请用桌面版浏览器查看此范例)


如上面所述,要控制 transform 属性,所以 attributeName="transform",接着 type 参数就看你想要 transform 的类型是什么,rotatescale 都可以。其余 fromtobegindur等参数都与之前的相同,用来指定动画的起始终点值、时间长度与执行次数。

最后一个元素,animateMotion,让 svg 沿着轨迹 path 移动(若看不到效果请以分页开新图片):

让SVG 自己动起来!SMIL animation动画详解_第6张图片


<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 物件,可以设定为 autoauto-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 内,可以透过 idxlink: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):

让SVG 自己动起来!SMIL animation动画详解_第7张图片

SVG SMIL animation 重点参数介绍

在上面的 Demo 里面,我们可以发现 SVG animate element 有很多参数可以使用,范例中只用到了一部分,但其实这些参数能设定的值都有不少变化,想要清楚知道每一个参数的用途与范例,推荐参考这篇文章 - https://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/ 写得非常好非常详细。

from, to, by, values

fromto 在前面的范例中都有看到,功能也如同字面般好懂,就是指定动画变化的移动区间,从(from)某个值变化到(to)另个值;而 by 则是代表位移量,相对于明确告知要变动到哪个值,我们可以用 by 告诉 svg 要变动”多少的量“,例如前面 animateTransform 的例子,我们可以改为:

<animateTransform attributeName="transform"
type="rotate" from="0 0 0" by="360" 
begin="0s" dur="10s" repeatCount="indefinite" />

看到这边你应该会注意到,byto 功能上有点重复,所以彼此之间有优先权,如果同时有指定 toby,则只会套用到 to 的值。

再来看看 values,这个刚刚的范例都没出现,它的功用是来补足 fromtoby 的不足。不足的点在于, fromtoby 只能指定两个值之间的变化,从 a 变化到 b,而 values 可以给定多个值,用分号;隔开,就能有 a -> b -> c -> b -> a 这样的变化,举个例子:

<animateTransform attributeName="transform" 
type="translate" values="20;120;20" begin="0s" dur="3s" 
repeatCount="indefinite" />

rick-animate-values.svg

begin, end

beginend 分别用来控制何时开始执行动画,何时停止动画,在上面的例子中我们都只用到时间,像是 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 头的动画等到太空船的动画做完后再启动,效果如下:

rick-animate-begin-syncbase.svg

另一个我觉得实用的值是 event-value,看名字就知道,是可以依照 event 来启动或终结动画,用法与 syncbase-value 雷同,给定元素 id,然后根据该元素触发的事件让动画 begin 或是 end。几乎所有 DOM element 支援的 event 都能使用

最后是 indefinite,如果你的 begin 值为 indefinite,代表无限等待,这时就需要透过 [animate 元素].beginElement()来触发,或是用tag 的 xlink:href="#[animate 元素 id]" 来启动。

calcMode, keyTimes, keySplines

这三个参数主要让你能够更细微的调整动画的速度变化。

calcMode 有四种模式:discretelinearpacedspline

discrete 顾名思义就是离散的,from 值跳到 to 值不做补间; linearpaced 我觉得效果雷同,都是让让补间动画的速度维持一致(linear)与平均(paced); spline 则是使用贝式曲线,需要搭配 keyTimeskeySplines 来使用。

keyTimes 就是关键影格,跟前面提过的 values 一样,可以接受多个以分号区隔的值,定义动画的关键时间点,搭配不同的 calcMode 就能在不同的时间点有不同的速度效果。

keySpline 是当你 calcMode 设定为 spline 时,用来定义贝式曲线的四个控制点的。

感兴趣的小伙伴可以直接看这篇文章:https://www.zhangxinxu.com/study/201408/svg-animation-calcmode.html

additive

看到最后,不知道你会不会有个疑问:如果我想针对同的 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动画详解_第8张图片

结论

今天花了不小的篇幅介绍了 SVG SMIL animation,感谢看到这边的各位,制作 Demo 的过程对我来说很有趣,也学习了怎么绘制 SVG,从网路上的其他资源也查到许多详细的资料,收获不少!希望对看到这篇文章的你们也能有所启发,除了常用的 Web animation 与 CSS animation 外,有机会也试试用 SVG 直接作动画吧!

资料来源:
https://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/

你可能感兴趣的:(前端)