好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

在 上一篇文章 中,我们介绍了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 时的动画效果:

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"/>
  阅读:67次