在上一篇文章中,我们介绍了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路径动画方面的知识。