在上一篇文章中,我们介绍了SVG动画的一些基本内容。这些动画都是基于W3C SMIL动画规范。这篇文章中我们接着继续往下介绍。
 控制动画的easing效果:calcMode和keySplines
                            在CSS中,我们可以使用animation-timing-function改变动画的均匀动画模式,制作带easing效果的动画。timing函数可以是预定义的关键字,或者是一个贝兹曲线。对于贝兹曲线我们可以通过一些工具来创建,例如cubic-bezier.com提供的在线工具。
在SMIL中,可以使用calcMode属性来指定动画片段效果。所有元素默认的动画片段效果是linear,除了animateMotion。除了linear值,你还可以设置的值有:discrete,paced和spline。
- linear:线性动画会在多个指定值之间平均分配时间,然后在每个停止点之间进行匀速动画。你可以使用- keyTimes属性来指定不同的时间点,但是每一步动画还都是线性的。- keyTimes属性要使用分号隔开,它的值和整个- values列表的值一一对应。它的第一个值必须是0,最后一个值必须是1。
- discrete:该值指定动画从一个值跳到另一个值时中间没有任何补间动画。它有点类似CSS中的- steps()函数。
- paced:它和- linear类似,但是它会忽略由- keyTimes指定的中间过渡时间。paced动画会计算各个值之间的距离,并根据相应的时间来创建整个动画的平均速度。只有某些类型的值可以使用- paced属性:颜色或者简单的数字/长度值。
- spline:spline属性允许你改变两个值之间的动画过渡效果的速度。keySplines 属性实际上是定义各个动画过渡效果的easing函数。
下面的例子展示了calcMode属性取值分别为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属性来指定动画帧,但是只需要指定开始和结束的动画帧:0和1,不需要指定中间的值。
增加和累计动画
有时候我们需要定义一个动画从前一个动画结束的地方开始执行,或者使用前一个动画的累计值作为它的一个值来制作动画效果。在SVG中,我们可以通过additive和accumulate属性来达到这些效果。
当你将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属性只是指定from和to的值是否相对于当前的值。additive属性的取值有两个:sum和replace。replace取值时默认值,它的意思是from和to的值是否替换当前值/原始值。它可能会造成动画开始之前出现一个奇怪的跳跃动作。
下面是一个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值来 定义动画间隔
begin和end属性都可以接收一组用分号隔开的值。begin和end属性的这些值一一对应。
下面的例子中指定了多个开始和结束值,矩形会在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"/>                              
                            
                            上面的代码中需要注意的地方是,即使你设置了repeatCount为indefinite,它也会被end属性覆盖,不会无限循环。
<animate>实例:变形动画
在SMIL中,SVG <path>元素的d属性是可以被动画的元素属性之一。d属性是你绘制的图形的轮廓的数据。我们可以通过这个属性来制作SVG路径变形动画。
要制作SVG路径变形动画,你可以指定attributeName属性为d,然后设置from和to值来指定开始和结束图形。你也可以使用values属性来指定中间值。
下面是一个路径变形动画的小例子:
本文和上一篇文章介绍了有关SMIL中<animate>元素的相关知识,下一篇文章开,我们将介绍SVG路径动画方面的知识。
 
                                    
                                     
                                    
                                     
                                    
                                    