【笔记】SVG动画初见

最近通过一些微信公众号了解到现在SVG还可以通过各种标签实现动画,如果脑洞够大,动画可以非常fancy。于是乎还是手痒简单学习了一下,在此记录一下SVG动画相关的一些标签和属性备忘。

首先MDN的这个SVG文档还是很全面的,随时忘了就去这里查一下也方便。

animate

说到动画,自然先用到的就是animate标签了,该标签用于控制SVG在具体某个属性上变化的动画,比如宽度、高度、透明度、圆心的位置等等。

指定控制目标

animate标签默认是控制其直接父标签的,因此加在一个<g>标签中就是控制该组中所有的SVG对象,该<g>标签的初始状态也就是很多属性的默认值。

不过也有xlink:href属性,可以指明要控制的标签。这样也方便把所有animate标签集中管理:

<animate xlink:href="#cool_shape" ...=""></animate>
...
<rect id="cool_shape" ...="" />

应注意若使用xlink:href属性指明动画目标,还是要求对应的对象和animate标签在同一个svg中。

设置动画属性

attributeName

既然animate控制的是在某个属性值上变化的动画,就要先通过attributeName指定变化的元素属性名称。主要也就两类:

  • 可以是元素直接暴露的SVG属性,比如stroke-width(描边宽度);
  • 可以是CSS属性,比如opacity(透明度);

attributeType

attributeType用于指定设置的属性对应的类型,可选值有CSS | XML | auto,默认值为auto,即自动判断。SVG和CSS中确实有很多同名属性,不过目前使用过程中没有设置过attributeType,让浏览器自动判断还没出过问题。

设置属性值具体变化

设置好了要变换的属性,就要设置该属性值的变化节点来定义动画。

from/to/by

最简单的设置属性值的变化就是通过这三个属性进行:

  • from: 表示动画开始时的属性值,默认为None,会根据控制目标开始时的状态获取;
  • to: 表示动画结束时的属性值,默认为None;
  • by: 表示动画结束时,相对于开始时的差值,若通过to定义了结束时的绝对属性值,则会忽视by。默认为None;

values

一个动画往往是多段动画的组合,若只能定义起始状态就要重复组合多个动画,自然比较麻烦。此时可以通过values定义一系列属性值的变化,将在同一属性值上变动的多段动画组合起来,属性值之间通过;分割。设置了values则忽视from/to/by这些单一起始位点的定义。

使用CSS定义动画,可以通过设置animation-direction:alternate使动画可以往复运动。animate标签没有类似的属性直接定义往复运动,不过也可以通过values属性,设置结束值等于起始值,也一样可以实现往复运动的效果。比如经典的呼吸灯效果,就是让透明度在0到1之间往复变化嘛:

<animate attributeName='opacity' dur='2s' values="1;0;1" repeatCount="indefinite"/>

additive

默认情况下additive="replace",也就是from/to/by设置的值都是绝对值。而当设置additive="sum"后,from/to/by设置的值就是相对于动画开始前对象的值。个人认为设置绝对值相对更加清晰,目前较少设置该属性。

accumulate

默认情况下accumulate=none,即动画重复都是重头开始的。而若设置accumulate="sum",则通过repeatCount设置的动画重复次数,每一次重复是基于上一次的结果开始的。如设置圆心位置向右移动10px,重复3次,若设置accumulate="sum",动画总体效果是圆心位置向右移动了30px。目前常用于大规模复制(而不是重复)同样的动画,如以同样的步幅向一个方向前进。

设置动画时间和循环方式

dur

正如其名,该属性就定义了动画的持续时间(duration)。除了常用的时间,如1s,也可以定义为indefinite,即无限时间。默认值即为indefinite,因此SVG动画常常需要明确指定该属性。

keyTimes

若通过values定义了一系列属性值的变化,则还可以通过keyTimes定义一个时间节点的列表,来定义每个属性值节点对应的时间。单位是dur定义时长的百分比,因此值为0-1之间的小数,第一个值一定是0,最后一个一定是1。值之间通过;分割,列表长度与values长度一致。不定义keyTimes则默认在values各个属性值变化之间平均分配dur持续时间。

begin/end

begin确定动画开始的时刻,可以是一个;分割的列表,表示会分别在这些时刻开始动画。具体的值有以下几种方式:

  • 相对于页面完成加载后的时间,如0.1s;
  • 发生在执行动画的svg对象上的事件,最常用click;
  • 另一个动画的某个时间节点,如某个id="test"的动画结束则可用test.end表示;
  • 上述方式还可以组合使用,如click+1s表示点击后延迟1s开始;

end则确定动画结束的时刻。如果是列表,则长度必须与begin一致,值的定义方式也与begin一样。注意end确定的是svg对象退出动画状态的时间。若end相对begin的时间长度小于dur,则动画会提前停止。反之动画效果跟没有设置end一样,但svg对象的状态却仍然是动画中,直到end设置的时间。

fill

fill表示在动画结束后,是否保持在结束状态。可选值remove|freezeremove表示动画结束后,恢复到动画开始时的状态,默认为该值;freeze则表示动画结束后,则保持在结束状态,也就是下一个动画的起始状态。

repeatCount

repeatCount设置了动画重复的次数,也可以设置为indefinite表示一直不断循环播放。

注意若begin为一个列表,动画就会多次开始,但又设置了repeatCount,动画还会在每次开始时都重复同样的次数。时间线相对较混淆,最好不要混合使用。

restart

restart设置动画何时可以重新开始,有如下几种具体设置:

  • always: 默认值,表示动画可以在任何时候重新开始,包括上一次动画还没结束就可以重头再来;
  • whenNotActive: 表示动画仅可以在动画结束时才可以重新开始;
  • never: 表示动画不可以重新开始,除非刷新整个页面。但并不影响repeatCount

repeatDur

repeatDur通过时间限制动画的重复次数,设置的值表示动画可以持续的总时间,也可以设置为indefinite,表示不限制动画重复的时长。repeatDurrepeatCount二者如果都设置了,则取可以重复的最小值。比如一个时长1s的动画,repeatCount="5"repeatDur="3s",则只会重复3次。repeatDur不是dur的整数倍那也就在中间截止。

min/max

repeatDur类似,min/max两个属性则限制了动画最短/最长的运行时间。个人一般更愿意通过dur/begin/repeatCount等控制时间,不常用这些属性来提前停止动画,或使SVG元件即使动画结束但仍保持在动画状态。

calcMode(插值计算方法)

由于是动画,属性值相对时间是连续变化的。而之前所描述的属性均只设置了属性值和时间的节点,节点间属性值随时间变化的方式就要通过calcMode来定义,有如下几种方式:

  • linear: 只在两个相邻的values和对应的keyTimes之间进行简单线性插值,即在节点间匀速变化,默认值;
  • discrete: 不进行插值计算,直接在离散值之间跳跃,动画看起来就是“突变”的;
  • paced: 类似linear,同样做线性插值,不过忽视keyTimeskeySplines属性,直接简单将所有values相对dur进行线性插值,全局均匀变化;
  • spline: 通过三次贝塞尔曲线(cubic bezier)计算节点间的插值,需要通过keyTimes定义时间节点;keySplines定义节点间贝塞尔曲线的控制点(control points),因此长度比keyTimesvalues都少1。如:
    <animate attributeName="cx" dur="4s" calcMode="spline" repeatCount="indefinite" values="60; 110; 60; 10; 60" keyTimes="0; 0.25; 0.5; 0.75; 1" keySplines="0.5 0 0.5 1; 0.5 0 0.5 1; 0.5 0 0.5 1; 0.5 0 0.5 1" />
    
    具体的贝塞尔曲线和对应的效果可以使用这个小工具预览一下

animateTransform

只用animate控制某些属性值变化的动画自然还是不够的,animateTransform可以用来控制SVG的位移、旋转、缩放等的变化动画。其中属性与animate基本相同,其中attributeName="transform"固定不变,type决定具体的transform方式,属性值values/from/to则为transform方式对应的参数值,如:

  • 平移:translate(x,y=0),分别向x和y轴移动指定距离,y可选,默认为0;
  • 缩放:scale(x,y=x),分别在x轴和y轴放大指定倍数,y可选,默认与x相同;
  • 旋转:rotate(ang,x=0,y=0),按照指定点(x,y)顺时针旋转ang角度,默认按照整个svg的原点旋转;
  • 斜切:
    • skewX(ang),沿x轴斜切ang角度;
    • skewY(ang),沿y轴斜切ang角度;

举例:

<!-- 转一圈10秒,持续旋转 -->
<animateTransform attributeName="transform" type="rotate" from="0 60 70" to="360 60 70" dur="10s" repeatCount="indefinite"/>
<!-- 沿x轴反复左右摆动 -->
<animateTransform attributeName="transform" begin="0.1" dur="2s" repeatCount="indefinite" type="translate" values="0;10;0"></animateTransform>
<!-- 从5倍大小缩小至正常 -->
<animateTransform attributeName="transform" begin="0.1" dur="0.2s" type="scale" values="5;1" fill="freeze" restart="never"></animateTransform>

值得注意的是,各种transform变化默认相对图像原点进行。而常常想要每个对象相对自身的中心进行变化,需要加上下列css样式:

transform-box: fill-box;
transform-origin: center;

不过这些css样式目前还在实验阶段,对一些老旧的浏览器兼容性不好。

animateMotion

path / mpath

animateMotion标签控制SVG对象在指定的路径上移动。其中的path属性就定义了移动路径:

<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
  <path fill="none" stroke="lightgrey"
    d="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z" />

  <circle r="5" fill="red">
    <animateMotion dur="10s" repeatCount="indefinite"
      path="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z" />
  </circle>
</svg>

如上例,移动路径常常复用的一个已经绘制出来的路径,因此可以在animateMotion标签中使用mpath标签来链接到已有的路径:

<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
  <path id="movePath" fill="none" stroke="lightgrey"
    d="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z" />

  <circle r="5" fill="red">
    <animateMotion dur="10s" repeatCount="indefinite">
      <mpath xlink:href="#movePath"/>
    </animateMotion>
  </circle>
</svg>

值得注意的是,运动路径与运动对象的位置是相对的,即运动路径的原点就是运动目标的原点。因此若运动路径和运动目标画在同一张图上,那么运动开始前运动目标的中心最好就在整张图像的原点,如上述几个例子。这样运动开始时,目标才会真正移动到运动路径上开始运动。或者反过来将运动路径从原点开始绘制,之后运动目标才可以在它所在的位置上按照运动路径的形状开始运动,不过这种情况下运动路径一般就不方便绘制出来展示。

keyPoints

keyPointskeyTimes配合,可以用于精细控制对象在路径上不同部分的速度。如keyPoints="0;0.5;1" keyTimes="0;0.15;1",表示运动完路径的前半部分花费15%的时间,运动后半部分花费85%的时间。

rotate

rotate用于控制移动对象沿路劲运动时的朝向,默认为0,即移动时朝向始终不变。可选autoauto-reverse,使对象的朝向可以自动朝向或反向移动路径。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值