写 SVG 动画必看!SVG系列文章3-动画标签

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、基础使用

xml 复制代码
<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 的位置:

xml 复制代码
<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:代表过渡次数
xml 复制代码
<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 变换,基本类似,只不过通过标签的方式进行设置:

xml 复制代码
<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 路径运动:

xml 复制代码
<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>

不过上面这个马走得有点假,怎么马儿一直都是水平的啊,这不符合物理学定律,是不科学的。我们可以小小处理下,让表现更真实:

xml 复制代码
<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>

自由组合

实际制作时候的动画,不可能总是一个属性修改。比方说,位置和透明度同时变化,只需要设置多个动画元素即可:

xml 复制代码
<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 基础动画属性

  1. attributeName:要变化的元素属性名称,跟 CSS3 设置 transition-property 过渡一致,不过位移不是 translate 了,而是 x 和 y

  2. 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, 此时就需要明确下归属。

  3. from, to, by, values

      • from:动画的起始值
      • to:指定动画的结束值
      • by:动画的相对变化值
      • values:用分号分隔的一个或多个值,可以看出是动画的多个关键值点

      from, to, by, values 虽然属于一个家族,但是相互之间还是有制约关系的。有以下一些规则:

      • 如果动画的起始值与元素的默认值是一样的,from 参数可以省略。

      • (不考虑valuestoby两个参数至少需要有一个出现。否则动画效果没有。to 表示绝对值,by 表示相对值。拿位移距离,如果 from100, to 值为160则表示移动到 160 这个位置,但是,如果 by 值是 160,则表示移动到 100+160=260 这个位置

      • 如果toby同时出现,则 by 打酱油,只识别 to

      • 如果tobyvalues 都没设置,自然没动画效果。如果任意(包括from)一个属性的值不合法,规范上说是没有动画效果。但是,据我测试,FireFox 浏览器确实如此,但是Chrome特意做了写容错处理。例如,本来是数值的属性,写了个诸如 a 这个不合法的值,其会当作 0 来处理,动画效果依然存在。

      • values可以是一个值或多值。根据我在Chrome浏览器下的测试,是一个值的时候是没有动画效果。多值时候有动画效果。values 值设置并能识别时候,from, to, by的值都会被忽略。

        values 属性是干什么的呢?别看名字挺大众的,其还是有些功力的。

        我们实现动画,不可能就是单纯的从a位置到b位置,有时候,需要去c位置过渡下。此时,实际上有3个动画关键点。而 from, to/by 只能驾驭两个,此时就是 values 大显身手的时候了,例如下面这个聪明的马儿来回跑的效果:

      xml 复制代码
      <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>
  1. repeatCount, repeatDur

    • repeatCount :表示动画执行次数,可以是合法数值或者 indefinite

    • repeatDur :定义重复动画的总时间。可以是普通时间值或者 indefinite

    例如这个:

    xml 复制代码
    <animate attributeName="x" to="60" dur="3s" repeatCount="indefinite" repeatDur="10s" />

    动画只执行完整 3 个 + 一个 1/3 个动画。因为 repeat 总时间就 10s 而已。

  2. dur :常规时间值 | "indefinite",动画持续时间,设置 indefinite 相当于动画压根不执行

  3. 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:

  1. offset-value

  2. syncbase-value :基于同步确定的值吗,语法为:[元素的id].begin/end +/- 时间值

    借用其他元素的 begin 值再加加减减,这个可以准确实现两个独立元素的动画级联效果:

    xml 复制代码
    <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", 就表示 idx 的元素动画结束前一秒开始纵向移动

  1. event-value :表示与事件相关联的值。类似于 PowerPoint 动画的"点击执行该动画。语法是:[元素的id].[事件类型] +/- 时间值

    举个例子,点击下图的圆圈圈,马儿它就会自己跑:

    xml 复制代码
    <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 什么的都是徒劳。

  2. repeat-value :重复多少次之后做什么,语法为:[元素的id].repeat(整数) +/- 时间值

    xml 复制代码
    <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)"idx 的元素的动画重复 2 次后执行:

  1. accessKey-value :定义快捷键,即按下某个按键动画开始。语法为:accessKey("character"). character 表示快捷键所在的字符

    举个例子,按下s键动画走起。SVG代码如下:

    xml 复制代码
    <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浏览器下感受下:www.zhangxinxu.com/study/20140...

  2. wallclock-sync-value :指真实世界的时钟时间定义。时间语法是基于在ISO8601中定义的语法。例如1997-07-16T19:20:30.45+01:00

  3. indefinite :表示"无限等待",需要使用 beginElement() 方法触发或者指向该动画元素的超链接(SVG中的a元素):

    js 代码触发如下:

    html 复制代码
    <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 标签超链接触发如下:

    xml 复制代码
    <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 特殊动画属性

  1. calcMode, keyTimes, keySplines:这几个参数是控制动画先快还是先慢类似这样作用的

    • calcMode :支持4个值:discrete | linear | paced | spline. 中文意思分别是:"离散"|"线性"|"踏步"|"样条"。
      • discretefrom 值直接跳到 to
      • linear :animateMotion元素以外元素的 calcMode 默认值。动画从头到尾的速率都是一致的。
      • paced :通过插值让动画的变化步调平稳均匀。仅支持线性数值区域内的值,这样点之间"距离"的概念才能被计算(如 position, width, height 等)。如果 paced 指定,任何keyTimeskeySplines 值都会打酱油
      • spline :插值定义贝塞尔曲线。spline 点的定义在 keyTimes 属性中,每个时间间隔控制点由 keySplines 定义。
    • keyTimes = <list> :跟上面提到的<list>类似,都是分号分隔一组值。前面提到过 values 也是多值,这里有一些约定的规则:
      • 首先,keyTimes 值的数目要和 values 一致,如果是 from/to/by 动画,keyTimes 就必须有两个值。
      • 然后对于 linearspline 动画,第一个数字要是0, 最后一个是1。 最后,每个连续的时间值必须比它前面的值大或者相等。
      • paced 模式下,keyTimes 会被忽略;keyTimes 定义错误,也会被忽略;durindefinite也会被忽略。
    • keySplines = <list>keySplines 表示的是与 keyTimes 相关联的一组贝塞尔控制点(默认0 0 1 1
      • 每个控制点使用4个浮点值表示:x1 y1 x2 y2.
      • 只有模式是spline时候这个参数才有用,也是分号分隔,值范围0~1,总是比 keyTimes 少一个值。
      • 如果 keySplines 值不合法或个数不对,是没有动画效果的。

    如下4个SVG,只展示重要部分代码:

    xml 复制代码
    <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匹马上半途中你追我赶的经常场面:

拿最后一个SVG说事吧,实际上就是 values, keyTimes, keySplines 三个人之间事情。

  • values 确定动画的关键位置,keyTimes 确定到这个关键点需要的时间
  • keySplines 确定的是每个时间点段之间的贝塞尔曲线,也就是具体的缓动表现

我们平时 CSS3 写的 transition 动画效果,也是这么回事,这是 values 值就两个,所以,keyTimes 只能 是0-1, 贝塞尔曲线就只有一个,要不 ease, 要不 linear 等。

  1. accumulate, additive

    • accumulate :累积的意思。支持参数有:none | sum. 默认值 是none. 如果值是 sum 表示动画结束时候的位置作为下次动画的起始位置。
    • additive :控制动画是否附加。支持参数有:replace | sum. 默认值是 replace. 如果值是 sum 表示动画的基础知识会附加到其他低优先级的动画上

    举两个例子,下面是例子1:

    xml 复制代码
    <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:

    xml 复制代码
    <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 替换。于是,我们就可以是实现一边旋转一边放大的效果:

  1. restart = always | whenNotActive | never

    • always 是默认值,表示总是,也就是点一次圈圈,马儿跑一下
    • whenNotActive 表示动画正在进行的时候,是不能重启动画的
    • never 表示动画只执行一次
  2. min, max :表示动画执行最短和最长时间。支持参数为时间值和"media"(媒介元素有效), max 还支持 indefinite

7、动画的暂停和播放

SVG animation 中是有内置的API可以暂停和启动动画的,语法为:

tips:不能够对使用 img、object、iframe 的标签使用,只能针对内嵌的标签

js 复制代码
// svg 指当前 svg DOM 元素
// 暂停
svg.pauseAnimations();

// 重启动
svg.unpauseAnimations()

参考

相关推荐
轻口味26 分钟前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王1 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发1 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀2 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪2 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef4 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6414 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻4 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云4 小时前
npm淘宝镜像
前端·npm·node.js