SVG图形可以使用动画元素来制作动画效果。这些动画元素最初被定义在W3C的SMIL(Synchronized Multimedia Integration Language-同步多媒体集成语言)动画规范中。这些元素包括:
<animate>
:它允许你在指定的时间内动画标量的属性。
<set>
:在指定的时间之后执行指定的动画。它对于非常数字的属性动画非常有用。
<animateMotion>
:沿指定的路径移动元素。
<animateColor>
:在指定的时间内修改元素的颜色。这是一个过时的元素,虽然在SVG1.1规范中仍在使用,但是到SVG2.0规范会被移除。
除了在SMIL规范定义的动画元素,SVG还包括了与SMIL动画规范兼容的扩展动画元素。这些扩展包括<animateMotion>
元素的功能扩展和额外的动画元素。
<animateTransform>
:允许你在指定时间内对某个SVG transformation 属性执行动画,例如transform
属性。
path
:这是属性,不是<path>
元素。
<mpath>
:可以和animateMotion
元素结合来引用一条路径作为运动路径。mpath元素包含在animateMotion
元素中。
keypoints
:属性。作为animateMotion
元素的一个属性来控制路径动画的动画速度。
rotate
:属性。作为animateMotion
元素的一个属性用于控制路径动画中元素是否自动根据其X轴切线方向来改变运动方向。
浏览器支持
浏览器对SMIL动画的支持非常的好,它可以在除了IE浏览器和Opera Mini浏览器之外的所有现代浏览器中工作。完整的支持列表可以查看Can I Use。
如果你需要为SMIL动画提供一个回退方法,你可以使用Modernizr。如果浏览器不支持SMIL,你可以为它们提供一些回退方法。
通过xlink:href
指定动画目标
不论使用4个动画元素中的哪一个,你都需要为它指定一个动画目标。可以使用xlink:href
属性来指定动画目标。这个属性指向将要执行动画的元素。这个元素必须在当前的SVG文档中。
<rect id="cool_shape" ... />
<animate xlink:href="#cool_shape" ... />
动画元素也可以嵌套在SVG元素中。如果没有为动画元素指定xlink:href
属性,那么动画的目标元素就是当前动画元素的直接父元素。
<rect id="cool_shape" ... >
<animate ... />
</rect>
因此,你可以将动画元素嵌入到SVG元素中,也可以单独写动画元素,然后使用xlink:href
属性指向要指向动画的SVG元素。
指定动画的属性
所有的动画元素都有attributeName
属性,这个属性用于指定当前要指向动画的属性的名称。例如你想在水平方向上移动一个<circle>
元素的位置,你可以指定attributeName
属性为cx
。attributeName
只有一个值,因此,你每次只能执行一个属性动画。如果你想执行多个属性动画,需要为元素指定多个动画。
你还可以使用attributeType
属性来为属性指定名称空间。例如可以设置为“CSS”,意思是这些属性可以在CSS中找到。
如果attributeType
属性没有被明确指定货被设置为auto
,浏览器会首先查找CSS属性列表中是否有匹配的值,如果没有找到,会去XML名称空间中去查找。
例如下面的例子,在一个SVG矩形上执行opacity
属性动画,因为opacity
属性也是一个CSS属性,attributeType
属性可以设置为CSS名称空间。
<rect>
<animate attributeType="CSS" attributeName="opacity"
from="1" to="0" dur="5s" repeatCount="indefinite" />
</rect>
在指定时间内执行元素属性动画
我们从一个简单的位移动画开始,将一个圆形从一个位置移动到另一个位置。我们可以通过改变圆形的cx
属性来实现这个动画。
制作这个动画效果需要使用<animate>
元素。它用于在某个时间内动画某个元素的属性。通常属性值为数字或颜色的时候,我们都用<animate>
来制作动画。至于有哪些属性可以被执行动画,可以查看W3C的文档。
为了在指定时间内将一个值修改为另一个值,我们要使用from
,to
和dur
属性。另外,你还可以使用begin
属性来指定动画从何时开始。看下面的代码:
<circle id="my-circle" r="30" cx="50" cy="50" fill="orange" />
<animate
xlink:href="#my-circle"
attributeName="cx"
from="50"
to="450"
dur="1s"
begin="click"
fill="freeze" />
在上面的代码中,我们定义了一个橙色的圆形,然后在这个圆形上执行一个动画。圆形的X轴方向的中心从最初的50个单位移动到450个单位。
begin
属性设置为click
,意思是圆形在被鼠标点击时才开始动画。你也可以将这个值设置为一个时间值,例如:begin="0s"
,那么圆形会在页面一加载完成就开始动画。如果想为动画添加一些延迟效果,可以将这个值设置为正数值。例如:begin="2s"
,那么动画会在页面加载之后2秒才开始执行。
我们甚至还可以将begin
的值定义为click + 1s
的形式,这是,动画会在圆形被鼠标点击1秒之后才开始执行。
dur
属性相当于CSS中的animation-duration
。
from
和to
属性也和CSS帧动画@keyframe
块中的from
和to
相同。
@keyframes moveCircle {
from { /* 开始值 */ }
to { /* 结束值 */ }
}
fill
属性(这里要弄清楚它和元素填充属性中的fill
属性是不同的)和CSS中的animation-fill-mode
属性类似,用于指定元素在动画结束之后是否返回它的初始状态。它有两个取值:
上面的代码的返回结果如下,用鼠标点击圆形看看效果:
通过restart
属性重置动画
restart
属性可以防止动画在激活之后被重新开始执行。它有3个可选值:
always
:动画可以在任何时候被重置。这是默认值。
whenNotActive
:只有在动画没有被激活的时候才能被重置。例如在动画结束之后。
never
:在整个SVG执行的过程中,元素动画不能被重置。
同步动画
加入你需要修改一个圆形的坐标和它的颜色,并且颜色的改变发生在圆形移动结束的时候,可以设置颜色改变动画的begin
属性的值等于它移动的dur
值。在CSS动画中我们一般也是这样做的。
在SMIL中,提供了一种非常好的事件处理特性。在前面我们就已经说过,begin
属性的取值可以类似click + 5s
的形式。这个值可以称为“事件值”。在这个例子中它是由一个事件和一个“时钟值(clock value)”组成。为什么是时钟值而不是简单的时间值呢?因为在W3C的文档中,它的取值可以类似“10min”或“1:30”(等于1个小时30分钟),甚至是“03:30:20”(3个小时30分钟20秒)。注意,并不是所有的浏览器都支持这个“时钟值”的。
事件值可以接收的另一种值是另一个动画的ID。如果你有两个动画,你想同步它们,在一个动画之后再执行另一个动画,你可以使用这种方法,最大的好处是不需要知道动画的持续时间。
来看下面的例子,一个蓝色的矩形在圆形开始移动后1秒钟才开始移动。这里通过分别给它们设置一个ID号,然后在begin
事件中使用这个ID号,代如如下:
<circle id="orange-circle" r="30" cx="50" cy="50" fill="orange" />
<rect id="blue-rectangle" width="50" height="50" x="25" y="200" fill="#0099cc"></rect>
<animate
xlink:href="#orange-circle"
attributeName="cx"
from="50"
to="450"
dur="5s"
begin="click"
fill="freeze"
id="circ-anim" />
<animate
xlink:href="#blue-rectangle"
attributeName="x"
from="50"
to="425"
dur="5s"
begin="circ-anim.begin + 1s"
fill="freeze"
id="rect-anim" />
begin="circ-anim.begin + 1s"
意思是告诉浏览器矩形在圆形开始运动1秒钟后才开始运动。下面是上面代码的返回结果:
点击上面的圆形开始执行动画,矩形会在圆形运动后1秒钟才开始运动。
你还可以使用end
事件来设置矩形在圆形结束动画之后才开始运动。
<animate
xlink:href="#blue-rectangle"
attributeName="x"
from="50"
to="425"
dur="5s"
begin="circ-anim.end"
fill="freeze"
id="rect-anim"/>
你甚至还可以更进一步指定矩形在圆形动画结束前多少时间才开始运动。
<animate
xlink:href="#blue-rectangle"
attributeName="x"
from="50"
to="425"
dur="5s"
begin="circ-anim.end - 3s"
fill="freeze"
id="rect-anim"/>
使用repeatCount
来重复动画次数
如果你想多次执行一个动画,可以使用repeatCount
属性。你可以指定你想要重复动画的次数,或者使用indefinite
关键字来指定无限动画。例如我们需要重复圆形的移动动画2次,代码如下:
<animate
xlink:href="#orange-circle"
attributeName="cx"
from="50"
to="450"
dur="5s"
begin="click"
repeatCount="2"
fill="freeze"
id="circ-anim" />
下面是返回结果,另外添加了一个无限运动的矩形。
通过repeatDur
来限制重复动画的时间
在将一个动画设置为无限循环的动画之后,我们可以使用repeatDur
属性来限制重复动画的时间。这个时间从从文档被创建开始计算,在到达指定的时间之后,动画将停止。
例如,下面的例子指定圆形在文档被创建之后1分30秒之后停止动画。
<animate
xlink:href="#orange-circle"
attributeName="cx"
from="50"
to="450"
dur="2s"
begin="0s"
repeatCount="indefinite"
repeatDur="01:30"
fill="freeze"
id="circ-anim" />
基于动画次数来同步动画
在SMIL中,你可以基于一个动画的重复次数来同步另一个动画。例如,你可以在一个动画重复N此之后开始另一个动画。
下面的例子在圆形重复动画2次之后开始执行无限循环动画。
<animate
xlink:href="#blue-rectangle"
attributeName="x"
from="50"
to="425"
dur="5s"
begin="circ-anim.repeat(2)"
fill="freeze"
id="rect-anim" />
如果你错过了上面的动画,可以点击重置按钮来再次观看动画效果。
使用keyTimes
和values
来控制动画帧
在CSS中,我们可以通过动画帧来控制动画的执行。例如下面的代码,动画元素的left
属性,总距离300像素,然后中间设置两个动画帧,分别使元素在50%和80%的时候运动到指定的位置。
@keyframes example {
0% {
left: 0;
}
50% {
left: 320px;
}
80% {
left: 270px;
}
100% {
left: 300px;
}
上面的动画分别在动画的持续时间内的0%,50%,80%和100%时间点控制元素的移动位置,效果类似一个弹性效果。
在SMIL中,你也可以使用相同的方式来控制帧动画。但是书写的语法和CSS完全不同。
要指定帧动画,你需要使用keyTimes
属性。然后使用values
属性为动画帧指定值。
如果我们想实现上面CSS帧动画实现的效果,代码应该像下面的样子:
<animate
xlink:href="#orange-circle"
attributeName="cx"
from="50"
to="450"
dur="2s"
begin="click"
values="50; 490; 350; 450"
keyTimes="0; 0.5; 0.8; 1"
fill="freeze"
id="circ-anim" />
keyTimes
属性和values
属性都是使用分号隔开的一组数值。它们一一对应。在keyTimes
中的每一个浮点数代表元素的运动时间偏移,浮点数的取值在0-1之间。这和CSS中的百分比时间点是相同的。
下面是上面的例子的返回结果:
点击上面的圆形查看动画效果。
SMIL动画还有很多内容,我们将在下一篇文章中继续介绍。