1、SMIL animation概览
SMIL不是指「水蜜梨」,而是Synchronized Multimedia Integration Language(同步多媒体集成语言)的首字母缩写简称,是有标准的。本文所要介绍的SVG动画就是基于这种语言。
SMIL允许你做下面这些事情:
- 动画元素的数值属性(X, Y, …)
- 动画属性变换(平移或旋转)
- 动画颜色属性
- 沿着运动路径运动
注意到“沿着运动路径运动”这一条没?前面的三条CSS3都是可以有所担当的,最后这一条,呵呵,CSS3只能蹲在墙角画圈圈了!(更正与2020-08-08 目前CSS offset
属性也可以让元素沿着额不规则路径运动)
SVG的动画元素是和SMIL开发组合作开发的。SMIL开发组和SVG开发组合作开发了SMIL动画规范,在规范中制定了一个基本的XML动画特征集合。SVG吸收了SMIL动画规范当中的动画优点,并提供了一些SVG继承实现。
2、基础使用
<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg">
<g>
<text font-family="microsoft yahei" font-size="120" y="160" x="160">马</text>
<animateTransform attributeName="transform" begin="0s" dur="10s" type="rotate" from="0 160 160" to="360 160 160" repeatCount="indefinite"/>
</g>
</svg>
需要注意的是,IE浏览器(包括IE11)是不支持的
3、SVG 动画元素
<set>
三秒后,马 自04-动移动 x 60px 的位置:
<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg">
<g>
<text font-family="microsoft yahei" font-size="120" y="160" x="160">
马
<set attributeName="x" attributeType="XML" to="60" begin="3s" />
</text>
</g>
</svg>
<animate>
- dur:代表过渡时间
- repeatCount:代表过渡次数
<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg">
<g>
<text font-family="microsoft yahei" font-size="120" y="160" x="160">
马
<animate attributeName="x" from="160" to="60" begin="0s" dur="3s" repeatCount="indefinite" />
</text>
</g>
</svg>
<animateColor>
一看就知道是颜色动画。不过,animate可以实现其功能与效果,因此,此属性已经被废弃。
<animateTransform>
这里的 transform
变 换 与 CSS3 的 transform
变换,基本类似,只不过通过标签的方式进行设置:
<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg">
<g>
<text font-family="microsoft yahei" font-size="80" y="100" x="100">马</text>
<animateTransform attributeName="transform" begin="0s" dur="3s" type="scale" from="1" to="1.5" repeatCount="indefinite"/>
</g>
</svg>
<animateMotion>
animateMotion
元素可以让 SVG 各种图形沿着特定的 path
路径运动:
<svg width="360" height="200" xmlns="http://www.w3.org/2000/svg">
<text font-family="microsoft yahei" font-size="40" x="0" y="0" fill="#cd0000">马
<animateMotion path="M10,80 q100,120 120,20 q140,-50 160,0" begin="0s" dur="3s" repeatCount="indefinite"/>
</text>
<path d="M10,80 q100,120 120,20 q140,-50 160,0" stroke="#cd0000" stroke-width="2" fill="none" />
</svg>
不过上面这个马走得有点假,怎么马儿一直都是水平的啊,这不符合物理学定律,是不科学的。我们可以小小处理下,让表现更真实:
<svg width="360" height="200" xmlns="http://www.w3.org/2000/svg">
<text font-family="microsoft yahei" font-size="40" x="0" y="0" fill="#cd0000">马
<animateMotion path="M10,80 q100,120 120,20 q140,-50 160,0" begin="0s" dur="3s" rotate="auto" repeatCount="indefinite"/>
</text>
<path d="M10,80 q100,120 120,20 q140,-50 160,0" stroke="#cd0000" stroke-width="2" fill="none" />
</svg>
自由组合
实际制作时候的动画,不可能总是一个属性修改。比方说,位置和透明度同时变化,只需要设置多个动画元素即可:
<svg width="320" height="200" xmlns="http://www.w3.org/2000/svg">
<text font-family="microsoft yahei" font-size="120" y="160" x="160">马
<animate attributeName="x" from="160" to="60" begin="0s" dur="3s" repeatCount="indefinite" />
<animate attributeName="opacity" from="1" to="0" begin="0s" dur="3s" repeatCount="indefinite" />
</text>
</svg>
4、SVG 基础动画属性
-
attributeName:要变化的元素属性名称,跟 CSS3 设置 transition-property 过渡一致,不过位移不是 translate 了,而是 x 和 y
-
attributeType = “CSS | XML | auto”:
attributeType
支持三个固定参数,CSS
/XML
/auto
. 用来表明attributeName
属性值的列表。x
,y
以及transform
就属于XML
,opacity
就属于CSS
.auto
为默认值- 自动判别的意思(实际上是先当成CSS处理,如果发现不认识,直接XML类别处理)。因此,如果你不确信某属性是XML类别还是CSS类别的时候,建议是不设置
attributeType
值,直接让浏览器自己去判断,几乎无差错。
不知大家有没有和我一样的疑问:“既然浏览器酱可以自己判断属性类别,那这个属性还有什么意义吗?”我琢磨着,可能某些属性,XML能其作用,CSS也能其作用,例如
font-size
, 此时就需要明确下归属。 -
from, to, by, values
-
- from:动画的起始值
- to:指定动画的结束值
- by:动画的相对变化值
- values:用分号分隔的一个或多个值,可以看出是动画的多个关键值点
from
,to
,by
,values
虽然属于一个家族,但是相互之间还是有制约关系的。有以下一些规则:-
如果动画的起始值与元素的默认值是一样的,
from
参数可以省略。 -
(不考虑
values
)to
,by
两个参数至少需要有一个出现。否则动画效果没有。to
表示绝对值,by
表示相对值。拿位移距离,如果from
是100
,to
值为160
则表示移动到160
这个位置,但是,如果by
值是160
,则表示移动到100+160=260
这个位置。 -
如果
to
,by
同时出现,则by
打酱油,只识别to
-
如果
to
,by
,values
都没设置,自然没动画效果。如果任意(包括from
)一个属性的值不合法,规范上说是没有动画效果。但是,据我测试,FireFox 浏览器确实如此,但是Chrome特意做了写容错处理。例如,本来是数值的属性,写了个诸如a
这个不合法的值,其会当作0
来处理,动画效果依然存在。 -
values
可以是一个值或多值。根据我在Chrome浏览器下的测试,是一个值的时候是没有动画效果。多值时候有动画效果。当values
值设置并能识别时候,from
,to
,by
的值都会被忽略。那
values
属性是干什么的呢?别看名字挺大众的,其还是有些功力的。我们实现动画,不可能就是单纯的从a位置到b位置,有时候,需要去c位置过渡下。此时,实际上有3个动画关键点。而
from
,to
/by
只能驾驭两个,此时就是values
大显身手的时候了,例如下面这个聪明的马儿来回跑的效果:
<svg width="320" height="200" xmlns="http://www.w3.org/2000/svg"> <text font-family="microsoft yahei" font-size="120" y="150" x="160"> 马 <animate attributeName="x" values="160;40;160" dur="3s" repeatCount="indefinite" /> </text> </svg>
-
-
repeatCount, repeatDur:
-
repeatCount:表示动画执行次数,可以是合法数值或者
indefinite
-
repeatDur:定义重复动画的总时间。可以是普通时间值或者
indefinite
例如这个:
<animate attributeName="x" to="60" dur="3s" repeatCount="indefinite" repeatDur="10s" />
动画只执行完整
3
个 + 一个1/3
个动画。因为 repeat 总时间就10s
而已。 -
-
dur:常规时间值 |
"indefinite"
,动画持续时间,设置 indefinite 相当于动画压根不执行 -
fill:表示动画间隙的填充方式,支持参数有:
freeze
|remove
。其中remove
是默认值,表示动画结束直接回到开始的地方。freeze
“冻结”表示动画结束后像是被冻住了,元素保持了动画结束之后的状态。
5、begin, end 属性
5.1 基础概念
- begin:指动画开始的时间,可以是单个时间也可以是一组时间值
- end:定义了一个动画的结束时间,使用与 begin 基本一致
例如,beigin="3s;5s"
表示的是 3s
之后动画走一下,6s
时候动画再走一下(如果之前动画没走完,会立即停止从头开始)。所以,如果一次动画时间为 3s
, 即 dur="3s"
,同时没有 repeatCount
属性时候,我们可以看到动画似乎连续执行了2
次。
时间值:支持 “h” | “min” | “s” | “ms”,不添加单位默认为 s
5.2 设置其它值
begin
的单值除了普通 value,还有下面这些类别的 value:
-
offset-value:
-
syncbase-value:基于同步确定的值吗,语法为:
[元素的id].begin/end +/- 时间值
借用其他元素的 begin 值再加加减减,这个可以准确实现两个独立元素的动画级联效果:
<svg width="320" height="200" xmlns="http://www.w3.org/2000/svg"> <text font-family="microsoft yahei" font-size="120" y="160" x="160">马 <animate id="x" attributeName="x" to="60" begin="0s" dur="3s" fill="freeze" /> <animate attributeName="y" to="100" begin="x.end" dur="3s" fill="freeze" /> </text> </svg>
于是,实现了一个马儿折线跑的效果,先横向移动,再无缝纵向移动:
当然,我们还可以增加一些偏移值,例如 begin="x.end-1s"
, 就表示 id
为 x
的元素动画结束前一秒开始纵向移动
-
event-value:表示与事件相关联的值。类似于 PowerPoint 动画的“点击执行该动画。语法是:
[元素的id].[事件类型] +/- 时间值
举个例子,点击下图的圆圈圈,马儿它就会自己跑:
<svg id="svg" width="320" height="200" xmlns="http://www.w3.org/2000/svg"> <circle id="circle" cx="100" cy="100" r="50"></circle> <text font-family="microsoft yahei" font-size="120" y="160" x="160">马 <animate attributeName="x" to="60" begin="circle.click" dur="3s" /> </text> </svg>
主要注意的是,这类与事件关联的SVG需要内联在页面中,否则
click
什么的都是徒劳。 -
repeat-value:重复多少次之后做什么,语法为:
[元素的id].repeat(整数) +/- 时间值
<svg width="320" height="200" xmlns="http://www.w3.org/2000/svg"> <text font-family="microsoft yahei" font-size="120" y="160" x="160">马 <animate id="x" attributeName="x" to="60" begin="0s" dur="3s" repeatCount="indefinite" /> <animate attributeName="y" to="100" begin="x.repeat(2)" dur="3s" fill="freeze" /> </text> </svg>
begin="x.repeat(2)"
指id
为x
的元素的动画重复2
次后执行:
-
accessKey-value:定义快捷键,即按下某个按键动画开始。语法为:
accessKey("character")
.character
表示快捷键所在的字符举个例子,按下
s
键动画走起。SVG代码如下:<svg width="320" height="200" xmlns="http://www.w3.org/2000/svg"> <text font-family="microsoft yahei" font-size="120" y="160" x="160">马 <animate attributeName="x" to="60" begin="accessKey(s)" dur="3s" repeatCount="indefinite" /> </text> </svg>
按下键盘上的字母
"s"
, 理论上动画就会执行。但是,据我测试,我的Chrome浏览器(版本36)上是没有效果的,FireFox浏览器效果杠杠的!所以,如果您的浏览器没有效果,但是手上有火狐,可以复制下面这个地址去FireFox浏览器下感受下:http://www.zhangxinxu.com/study/201408/horse-accesskey-value.svg -
wallclock-sync-value:指真实世界的时钟时间定义。时间语法是基于在ISO8601中定义的语法。例如
1997-07-16T19:20:30.45+01:00
-
indefinite:表示“无限等待”,需要使用
beginElement()
方法触发或者指向该动画元素的超链接(SVG中的a
元素):js 代码触发如下:
<svg id="svg" width="320" height="200" xmlns="http://www.w3.org/2000/svg"> <text font-family="microsoft yahei" font-size="120" y="160" x="160">马 <animate attributeName="x" to="60" begin="indefinite" dur="3s" /> </text> </svg> <script> var animate = document.getElementsByTagName("animate")[0]; if (animate) { document.getElementById("svg").onclick = function() { animate.beginElement(); }; } </script>
a 标签超链接触发如下:
<svg width="320" height="200" font-family="microsoft yahei" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <text font-size="120" y="160" x="160">马 <animate id="animate" attributeName="x" to="60" begin="indefinite" dur="3s" repeatCount="indefinite" /> </text> <a xlink:href="#animate"> <text x="10" y="20" fill="#cd0000" font-size="30">点击我</text> </a> </svg>
5.3 默认值
If no begin is specified, the default value is “0” – the animation begins when the document begins. If there is any error in the argument value syntax for begin, the default value for begin will be used.
意思是,没有 begin
或者 begin
参数解析异常,都当作 0
处理。
6、SVG 特殊动画属性
-
calcMode, keyTimes, keySplines:这几个参数是控制动画先快还是先慢类似这样作用的
- calcMode:支持4个值:
discrete
|linear
|paced
|spline
. 中文意思分别是:“离散”|“线性”|“踏步”|“样条”。- discrete:
from
值直接跳到to
值 - linear:animateMotion元素以外元素的
calcMode
默认值。动画从头到尾的速率都是一致的。 - paced:通过插值让动画的变化步调平稳均匀。仅支持线性数值区域内的值,这样点之间“距离”的概念才能被计算(如
position
,width
,height
等)。如果paced
指定,任何keyTimes
或keySplines
值都会打酱油 - spline:插值定义贝塞尔曲线。
spline
点的定义在keyTimes
属性中,每个时间间隔控制点由keySplines
定义。
- discrete:
- keyTimes =
<list>
:跟上面提到的<list>
类似,都是分号分隔一组值。前面提到过values
也是多值,这里有一些约定的规则:- 首先,
keyTimes
值的数目要和values
一致,如果是from/to/by
动画,keyTimes
就必须有两个值。 - 然后对于
linear
和spline
动画,第一个数字要是0
, 最后一个是1
。 最后,每个连续的时间值必须比它前面的值大或者相等。 paced
模式下,keyTimes
会被忽略;keyTimes
定义错误,也会被忽略;dur
为indefinite
也会被忽略。
- 首先,
- keySplines =
<list>
:keySplines
表示的是与keyTimes
相关联的一组贝塞尔控制点(默认0 0 1 1
)- 每个控制点使用4个浮点值表示:
x1 y1 x2 y2
. - 只有模式是
spline
时候这个参数才有用,也是分号分隔,值范围0~1
,总是比keyTimes
少一个值。 - 如果
keySplines
值不合法或个数不对,是没有动画效果的。
- 每个控制点使用4个浮点值表示:
如下4个SVG,只展示重要部分代码:
<animate attributeName="x" dur="5s" values="0; 20; 160" calcMode="linear" /> <animate attributeName="x" dur="5s" values="0; 20; 160" calcMode="paced"/> <animate attributeName="x" dur="5s" values="0; 80; 160" keyTimes="0; .8; 1" calcMode="linear"/> <animate attributeName="x" dur="5s" values="0; 80; 160" keyTimes="0; .8; 1" calcMode="spline" keySplines=".5 0 .5 1; 0 0 1 1" />
可以看到到4匹马上半途中你追我赶的经常场面:
- calcMode:支持4个值:
拿最后一个SVG说事吧,实际上就是 values
, keyTimes
, keySplines
三个人之间事情。
values
确定动画的关键位置,keyTimes
确定到这个关键点需要的时间keySplines
确定的是每个时间点段之间的贝塞尔曲线,也就是具体的缓动表现
我们平时 CSS3 写的 transition
动画效果,也是这么回事,这是 values
值就两个,所以,keyTimes
只能 是0-1
, 贝塞尔曲线就只有一个,要不 ease
, 要不 linear
等。
-
accumulate, additive:
- accumulate:累积的意思。支持参数有:
none
|sum
. 默认值 是none
. 如果值是sum
表示动画结束时候的位置作为下次动画的起始位置。 - additive:控制动画是否附加。支持参数有:
replace
|sum
. 默认值是replace
. 如果值是sum
表示动画的基础知识会附加到其他低优先级的动画上
举两个例子,下面是例子1:
<img ...> <animateMotion begin="0" dur="5s" path="[some path]" additive="sum" fill="freeze" /> <animateMotion begin="5s" dur="5s" path="[some path]" additive="sum" fill="freeze" /> <animateMotion begin="10s" dur="5s" path="[some path]" additive="sum" fill="freeze" /> </img>
这里轮到第二个动画的时候,路径是从第一个动画路径结束地方开始的,于是,3个动画完美无缝连接起来了。
例子2:
<animateTransform attributeName="transform" type="scale" from="1" to="3" dur="10s" repeatCount="indefinite" additive="sum"/> <animateTransform attributeName="transform" type="rotate" from="0 30 20" to="360 30 20" dur="10s" fill="freeze" repeatCount="indefinite" additive="sum"/>;
这里,两个动画同时都是
transform
,都要使用一个type
属性,好在这个例子additive="sum"
是累加的而不是replace
替换。于是,我们就可以是实现一边旋转一边放大的效果: - accumulate:累积的意思。支持参数有:
-
restart = always | whenNotActive | never:
always
是默认值,表示总是,也就是点一次圈圈,马儿跑一下whenNotActive
表示动画正在进行的时候,是不能重启动画的never
表示动画只执行一次
-
min, max:表示动画执行最短和最长时间。支持参数为时间值和
"media"
(媒介元素有效),max
还支持indefinite
7、动画的暂停和播放
SVG animation 中是有内置的API可以暂停和启动动画的,语法为:
tips:不能够对使用 img、object、iframe 的标签使用,只能针对内嵌的标签
// svg 指当前 svg DOM 元素
// 暂停
svg.pauseAnimations();
// 重启动
svg.unpauseAnimations()
参考: