当前位置主页 > 资料库 > 前端教程 > SVG进阶 | SVG动画-SMIL(二)

SVG进阶 | SVG动画-SMIL(二)

06-24

上一篇文章中,我们介绍了SVG动画的一些基本内容。这些动画都是基于W3C SMIL动画规范。这篇文章中我们接着继续往下介绍。

控制动画的easing效果:calcModekeySplines

在CSS中,我们可以使用animation-timing-function改变动画的均匀动画模式,制作带easing效果的动画。timing函数可以是预定义的关键字,或者是一个贝兹曲线。对于贝兹曲线我们可以通过一些工具来创建,例如cubic-bezier.com提供的在线工具。

在SMIL中,可以使用calcMode属性来指定动画片段效果。所有元素默认的动画片段效果是linear,除了animateMotion。除了linear值,你还可以设置的值有:discretepacedspline

  • linear:线性动画会在多个指定值之间平均分配时间,然后在每个停止点之间进行匀速动画。你可以使用keyTimes属性来指定不同的时间点,但是每一步动画还都是线性的。keyTimes属性要使用分号隔开,它的值和整个values列表的值一一对应。它的第一个值必须是0,最后一个值必须是1。
  • discrete:该值指定动画从一个值跳到另一个值时中间没有任何补间动画。它有点类似CSS中的steps()函数。
  • paced:它和linear类似,但是它会忽略由keyTimes指定的中间过渡时间。paced动画会计算各个值之间的距离,并根据相应的时间来创建整个动画的平均速度。只有某些类型的值可以使用paced属性:颜色或者简单的数字/长度值。
  • spline:spline属性允许你改变两个值之间的动画过渡效果的速度。keySplines 属性实际上是定义各个动画过渡效果的easing函数。

下面的例子展示了calcMode属性取值分别为linearpaceddiscrete时的动画效果:

linear paced discrete

点击圆形可以重新开始动画。

接下来我们详细讨论一下spline属性。

在CSS中,你可以在帧动画的每一个keyframe中指定动画timing函数,这样可以更好的控制每一帧的动画效果。最好的例子是一个弹性小球运动的帧动画效果,它的CSS代码类似下面的样子:

@keyframes bounce {
    0% {
        top: 0;
        animation-timing-function: ease-in;
    }
    15% {
        top: 200px;
        animation-timing-function: ease-out;
    }
    30% {
        top: 70px;
        animation-timing-function: ease-in;
    }
    45% {
        top: 200px;
        animation-timing-function: ease-out;
    }
    60% {
        top: 120px;
        animation-timing-function: ease-in;
    }
    75% {
        top: 200px;
        animation-timing-function: ease-out;
    }
    90% {
        top: 170px;
        animation-timing-function: ease-in;
    }
    100% {
        top: 200px;
        animation-timing-function: ease-out;
    }
}                              
                            

easing关键字可以转换为相应的贝兹曲线函数:

  • ease-in = cubic-bezier(0.47, 0, 0.745, 0.715)
  • ease-out = cubic-bezier(0.39, 0.575, 0.565, 1)

下面我们要在SVG中使用keyTimes属性来制作和上面CSS相同的弹性小球效果:

<animate 
    xlink:href="#orange-circle"
    attributeName="cy"
    from="50"
    to="250" 
    dur="3s"
    begin="click"
    values="50; 250; 120;250; 170; 250; 210; 250"
    keyTimes="0; 0.15; 0.3; 0.45; 0.6; 0.75; 0.9; 1"
    fill="freeze" 
    id="circ-anim" />                              
                            

小球的动画将从被点击开始,最后结束动画时会被冻结。接下来,为了制作指定动画帧的效果,我们使用keySplines属性。

keySplines属性的值是一组和keyTimes列表值对应的贝兹曲线控制点。这个贝兹曲线为三次贝兹曲线。每一个控制点由4个值组成:x1 x2 y1 y2,各个控制点之间用分号隔开。控制点的值必须在0-1之间。只有在calcMode设置为spline的时候,这些值才有效,否则会被忽略。

我们可以使用贝兹曲线工具来获取相应的贝兹曲线的值,下面是一个截图:

贝兹曲线

从上图可以看到,红色的控制点的值为:018.73,蓝色控制点的值为.87.24。这些值就是我们将要在keySplines中使用的值。

在SMIL中,这些值可以使用逗号隔开,或者直接用空格隔开。keyTimes的值指定相应的时间点,keySplines的值则指定控制点。

所以,我们要在SVG中制作弹性小球效果,代码类似下面的样子:

<animate 
    xlink:href="#orange-circle"
    attributeName="cy"
    from="50"
    to="250" 
    dur="3s"
    begin="click"
    values="50; 250; 120;250; 170; 250; 210; 250"
    keyTimes="0; 0.15; 0.3; 0.45; 0.6; 0.75; 0.9; 1"
    keySplines=".42 0 1 1;
                0 0 .59 1;
                .42 0 1 1;
                0 0 .59 1;
                .42 0 1 1;
                0 0 .59 1;
                .42 0 1 1;
                0 0 .59 1;"
    fill="freeze" 
    id="circ-anim"/>                             
                            

上面的代码的返回结果如下,点击橙色的小球查看动画效果:

如果你只想为整个动画指定一个全局的easing效果,你仍然需要使用keyTimes属性来指定动画帧,但是只需要指定开始和结束的动画帧:01,不需要指定中间的值。

增加和累计动画

有时候我们需要定义一个动画从前一个动画结束的地方开始执行,或者使用前一个动画的累计值作为它的一个值来制作动画效果。在SVG中,我们可以通过additiveaccumulate属性来达到这些效果。

当你将additive的值设置为sum时,这些值将都相对于动画属性的原始值。举个例子,对于我圆形运动的例子,假设它的初始位置cx为50,当你设置from="0"to="100"的时候,那么原来的0实际上是50,100实际上是150。换句话来说,实际上它的from="50"to="150"

下面是一个additive="sum"的例子,点击圆形查看动画效果:

<animate 
   xlink:href="#orange-circle-2"
   attributeName="cx"
   from="0"
   to="100" 
   additive="sum"
   repeatCount="3"
   calcMode="spline"
   keyTimes="0;1"
   keySplines=".42 0 1 1"
   dur="1s"
   begin="click"
   fill="freeze" />                              
                            

additive属性只是指定fromto的值是否相对于当前的值。additive属性的取值有两个:sumreplacereplace取值时默认值,它的意思是fromto的值是否替换当前值/原始值。它可能会造成动画开始之前出现一个奇怪的跳跃动作。

下面是一个additive="replace"的例子,点击圆形查看动画效果:

<animate 
   xlink:href="#orange-circle-3"
   attributeName="cx"
   from="0"
   to="100" 
   additive="replace"
   repeatCount="3"
   calcMode="spline"
   keyTimes="0;1"
   keySplines=".42 0 1 1"
   dur="1s"
   begin="click"
   fill="freeze" />                              
                            

如果我们想第二次动画从第一次动画结束的地方开始,可以使用accumulate属性。

accumulate属性用于控制动画是否累积。默认值是none,意思是如果动画重复,会从头开始执行动画。如果你设置它的值为sum,那么它的下一次动画将从上一次动画结束的地方开始执行。

下面是一个accumulate="sum"的例子,点击圆形查看动画效果:

<animate 
   xlink:href="#orange-circle-4"
   attributeName="cx"
   from="0"
   to="100" 
   additive="sum"
   accumulate="sum"
   repeatCount="3"
   calcMode="spline"
   keyTimes="0;1"
   keySplines=".42 0 1 1"
   dur="1s"
   begin="click"
   fill="freeze" />                             
                            

如果动画的模板元素不支持增加,或不是重复动画,accumulate属性会被忽略。另外,如果动画元素中只指定了to属性,accumulate属性也会被忽略。

指定动画的结束时间

我们除了可以指定动画什么时候开始执行,也可以通过end属性来指定它什么时候结束。例如,你可以指定一个动画无限循环,然后指定在另外一个动画开始的时候这个动画立刻结束。end属性的取值和begin属性的取值类似,你可以指定绝对或相对时间,重复值,事件值等等。

在下面的例子中,橙色的圆形在30秒时间内移动到画布的另一端。绿色的圆形也可以动画,但它炫耀点击才开始运动。当绿色的圆形开始运动的时候,橙色的圆形将立刻停止运动。

<animate 
       xlink:href="#orange-circle-5"
       attributeName="cx"
       from="50"
       to="450" 
       dur="30s"
       begin="0s"
       end="gCircAnim.begin"
       fill="freeze" 
       id="oCircAnim"/>
<animate 
       xlink:href="#green-circle-5"
       attributeName="cx"
       from="50"
       to="450" 
       dur="1s"
       begin="click"
       fill="freeze"
       id="gCircAnim"/>                              
                            

如果你错过了上面的动画,点击上面的按钮来重置动画。

在同一个元素上执行两个不同的动画时,也可以使用上面的方法来在一个动画开始时结束另一个动画。例如有一个圆形在不断的变换颜色,当圆形被点击的时候,它开始运动。我们需要圆形一开始运动,它的颜色就停止变化。

<animate 
       xlink:href="#orange-circle-6"
       attributeName="cx"
       from="50"
       to="450" 
       dur="1s"
       begin="click"
       fill="freeze" 
       id="move"/>
<animate 
       xlink:href="#orange-circle-6"
       attributeName="fill"
       from="#0099CC"
       to="deepPink" 
       dur="5s"
       repeatCount="indefinite"
       begin="0s"
       end="move.begin"
       fill="freeze"
       id="changeColor"/>                              
                            
使用多个Begin和End值来 定义动画间隔

beginend属性都可以接收一组用分号隔开的值beginend属性的这些值一一对应。

下面的例子中指定了多个开始和结束值,矩形会在0秒,5秒,9秒和17秒的时候开始旋转,对应的结束时间分别为2秒,8秒,15秒和25秒。

<animateTransform 
   xlink:href="#deepPink-rectangle"
   attributeName="transform" 
   attributeType="XML"
   type="rotate"
   from="0 75 75"
   to="360 75 75" 
   dur="2s"
   begin="0s; 5s; 9s; 17s;"
   end="2s; 8s; 15s; 25s;"
   fill="freeze" 
   restart="whenNotActive"/>                              
                            

上面的代码中需要注意的地方是,即使你设置了repeatCountindefinite,它也会被end属性覆盖,不会无限循环。

<animate>实例:变形动画

在SMIL中,SVG <path>元素的d属性是可以被动画的元素属性之一。d属性是你绘制的图形的轮廓的数据。我们可以通过这个属性来制作SVG路径变形动画。

要制作SVG路径变形动画,你可以指定attributeName属性为d,然后设置fromto值来指定开始和结束图形。你也可以使用values属性来指定中间值。

下面是一个路径变形动画的小例子:

本文和上一篇文章介绍了有关SMIL中<animate>元素的相关知识,下一篇文章开,我们将介绍SVG路径动画方面的知识。

返回SVG教程目录
相关阅读
Previous:
上一篇:SVG进阶 | SVG动画-SMIL(一)
Next:
下一篇:SVG进阶 | SVG路径动画-SMIL
返回顶部