SVG动画

http://www.htmleaf.com/ziliaoku/qianduanjiaocheng/201506262114.html

在前面的两篇文章中我们介绍了SVG动画中的<animate>元素的使用方法。在SMIL动画中,我们可以使用<animateMotion>元素来制作路径动画效果。路径动画是指一个元素沿着指定的路径运动。

<animateMotion>元素接收的属性和<animate>元素相同,另外他还可以接收三个属性:keyPointsrotatepath。还有它们的calcMode属性有所不同:<animateMotion>元素的calcMode属性的默认值是paced,而不是linear

 使用path属性来指定运动路径

path属性用于指定一条运动路径。它和<path>元素上的d属性的格式和含义基本相同。

下面来看一个例子,一个圆形将沿着下面的路径进行运动:

圆形沿这条路径运动的代码如下:

< animateMotion
     xlink:href = "#circle"
     dur = "1s"
     begin = "click"
     fill = "freeze"
     path="M0,0c3.2-3.4,18.4-0.6,23.4-0.6c5.7,0.1,10.8,0.9,16.3,2.3    c13.5,3.5,26.1,9.6,38.5,16.2c12.3,6.5,21.3,16.8,31.9,25.4c10.8,8.7,21,18.3,31.7,26.9c9.3,7.4,20.9,11.5,31.4,16.7
     c13.7,6.8,26.8,9.7,41.8,9c21.4-1,40.8-3.7,61.3-10.4c10.9-3.5,18.9-11.3,28.5-17.8c5.4-3.7,10.4-6.7,14.8-11.5
     c1.9-2.1,3.7-5.5,6.5-6.5" />                             

这条路径在开始绘制曲线之前,虚拟画笔被移动到坐标系的(0,0)位置。这里需要注意的是圆形的圆心在坐标系的(0,0)位置,而不是左上角位置。注意它们之间的细微差别。path属性的坐标系统是相对于元素当前位置的。

上面代码的结果如下,点击圆形查看路径动画效果:

如果你指定的路径不是从(0,0)开始,那么圆形会在开始运动之前突然跳动到你指定的位置之上。例如,假设你在AI软件中绘制了一条曲线,并将它导出为一个SVG路径数据。输出的路径会类似下面的样子:

< path fill = "none" stroke = "#000000" stroke-miterlimit = "10" d="M100.4,102.2c3.2-3.4,18.4-0.6,23.4-0.6c5.7,0.1,10.8,0.9,16.3,2.3
     c13.5,3.5,26.1,9.6,38.5,16.2c12.3,6.5,21.3,16.8,31.9,25.4c10.8,8.7,21,18.3,31.7,26.9c9.3,7.4,20.9,11.5,31.4,16.7
     c13.7,6.8,26.8,9.7,41.8,9c21.4-1,40.8-3.7,61.3-10.4c10.9-3.5,18.9-11.3,28.5-17.8c5.4-3.7,10.4-6.7,14.8-11.5
     c1.9-2.1,3.7-5.5,6.5-6.5"/>                             

上面的代码中,路径的开始坐标为(100.4,102.2)。如果我们使用这条路径作为运动路径,那么圆形会在运动之前向右跳动约100个单位,向下跳动约102个单位。然后才开始沿着路径运动。

 使用<mpath>元素来指定运动路径

我们还可以使用另一种方法来指定运动路径。除了使用path属性,我们可以使用<mpath>元素来引用一条外部的路径。<mpath>元素是<animateMotion>元素的子元素,它可以通过xlink:href属性来引用外部的路径。

< animateMotion xlink:href = "#circle" dur = "1s" begin = "click" fill = "freeze" >
   < mpath xlink:href = "#motionPath" />
</ animateMotion >                             

作为运动路径的<path>元素可以定义在文档的任何地方。甚至可以将它定义在<defs>元素中,并且不用将它渲染在画布上。

在下面的例子中,我们将运动路径绘制在画布上,一个圆形放置在路径的开始位置。但是,当点击圆形后,它不会沿着路径进行运动。点击下面的圆形看看效果:

< svg width = "500" height = "350" viewBox = "0 0 550 350" >
   < path id = "motionPath-2" fill = "none" stroke = "#000000" stroke-miterlimit = "10" d="M91.4,104.2c3.2-3.4,18.4-0.6,23.4-0.6c5.7,0.1,10.8,0.9,16.3,2.3
     c13.5,3.5,26.1,9.6,38.5,16.2c12.3,6.5,21.3,16.8,31.9,25.4c10.8,8.7,21,18.3,31.7,26.9c9.3,7.4,20.9,11.5,31.4,16.7
     c13.7,6.8,26.8,9.7,41.8,9c21.4-1,40.8-3.7,61.3-10.4c10.9-3.5,18.9-11.3,28.5-17.8c5.4-3.7,10.4-6.7,14.8-11.5
     c1.9-2.1,3.7-5.5,6.5-6.5"/>
   < circle id = "circle-2" r = "20" cx = "100" cy = "100" fill = "tomato" />
    
   < animateMotion
            xlink:href = "#circle-2"
            dur = "1s"
            begin = "click"
            fill = "freeze" >
     < mpath xlink:href = "#motionPath-2" />
   </ animateMotion >
</ svg >                             

为什么会这样呢?这是因为圆形的位置被path路径上的数据转换了。注意路径的开始位置是M91.4,104.2,而不是(0,0)。

一个解决的办法是将圆形放置在(0,0)坐标位置。即<circle>元素的cxcy属性都为0。这样当使用路径的数据来转换它的时候,会得到正确的结果,圆形会沿路径进行运动。

另一个方法是使用transform属性来转换圆形的坐标系统,使它在运动之前被转换为0坐标。

下面的例子是上面那个例子的修正版本,同时做了一些修改:使用闭合路径,并使运行无限循环运动。

< svg width = "500" height = "350" viewBox = "0 0 500 350" >
   < path id = "motionPath" fill = "none" stroke = "#000000" stroke-miterlimit = "10" d="M202.4,58.3c-13.8,0.1-33.3,0.4-44.8,9.2
     c-14,10.7-26.2,29.2-31.9,45.6c-7.8,22.2-13.5,48-3.5,70.2c12.8,28.2,47.1,43.6,68.8,63.6c19.6,18.1,43.4,26.1,69.5,29.4
     c21.7,2.7,43.6,3.3,65.4,4.7c19.4,1.3,33.9-7.7,51.2-15.3c24.4-10.7,38.2-44,40.9-68.9c1.8-16.7,3.4-34.9-10.3-46.5
     c-9.5-8-22.6-8.1-33.2-14.1c-13.7-7.7-27.4-17.2-39.7-26.8c-5.4-4.2-10.4-8.8-15.8-12.9c-4.5-3.5-8.1-8.3-13.2-11
     c-6.2-3.3-14.3-5.4-20.9-8.2c-5-2.1-9.5-5.2-14.3-7.6c-6.5-3.3-12.1-7.4-19.3-8.9c-6-1.2-12.4-1.3-18.6-1.5
     C222.5,59,212.5,57.8,202.4,58.3"/>
   
   < circle id = "circle" r = "10" cx = "0" cy = "0" fill = "tomato" />
    
   < animateMotion
            xlink:href = "#circle"
            dur = "5s"
            begin = "0s"
            fill = "freeze"
            repeatCount = "indefinite" >
     < mpath xlink:href = "#motionPath" />
   </ animateMotion >
</ svg >                             

可以看到,我们将圆形的圆心修改为cx="0" cy="0"之后,得到了正确的结果。

 <animateMotion>的覆盖规则

由于animateMotion有多种方式可以实现相同的效果,我们需要明确在同时使用这些元素的时候,哪些属性会被覆盖。

覆盖的规则如下:

  • 对于定义一个运动路径,mpath元素会覆盖path属性,也会覆盖values属性,还会覆盖frombyto属性。
  • 对于确定的点对应的keytimes属性,keytimes属性会覆盖path,还会覆盖frombyto属性。
 通过rotate来设置元素沿路径运动的方向

在上面的例子中,一个圆形沿着一条封闭的路径不停的运动。如果运动的不是一个圆形,而是一个有一定运动方向的元素,比如说是一个小车图标,会发生什么事情呢?

在下面的例子中,我们就使用一个小车来代替圆形。这个小车有一个<g>元素组成。另外为了让小车沿着路径运动,我们还添加了一个transform属性,让它的初始位置在(0,0)位置。

代码如下:

< svg width = "500" height = "350" viewBox = "0 0 500 350" >
   < path id = "motionPath" fill = "none" stroke = "#000000" stroke-miterlimit = "10" d="M202.4,58.3c-13.8,0.1-33.3,0.4-44.8,9.2
     c-14,10.7-26.2,29.2-31.9,45.6c-7.8,22.2-13.5,48-3.5,70.2c12.8,28.2,47.1,43.6,68.8,63.6c19.6,18.1,43.4,26.1,69.5,29.4
     c21.7,2.7,43.6,3.3,65.4,4.7c19.4,1.3,33.9-7.7,51.2-15.3c24.4-10.7,38.2-44,40.9-68.9c1.8-16.7,3.4-34.9-10.3-46.5
     c-9.5-8-22.6-8.1-33.2-14.1c-13.7-7.7-27.4-17.2-39.7-26.8c-5.4-4.2-10.4-8.8-15.8-12.9c-4.5-3.5-8.1-8.3-13.2-11
     c-6.2-3.3-14.3-5.4-20.9-8.2c-5-2.1-9.5-5.2-14.3-7.6c-6.5-3.3-12.1-7.4-19.3-8.9c-6-1.2-12.4-1.3-18.6-1.5
     C222.5,59,212.5,57.8,202.4,58.3"/>
   < g id = "car" transform = "translate(-234.4, -182.8)" >
       < path d = "M234.4,182.8c-3.5,0-6.4,2.9-6.4,6.4c0,3.5,2.9,6.4,6.4,6.4c3.5,0,6.4-2.9,6.4-6.4C240.8,185.6,238,182.8,234.4,182.8z" />
       < circle cx = "234.4" cy = "189.2" r = "2.8" />
       < path d = "M263,182.8c-3.5,0-6.4,2.9-6.4,6.4c0,3.5,2.9,6.4,6.4,6.4c3.5,0,6.4-2.9,6.4-6.4C269.4,185.6,266.6,182.8,263,182.8z" />
       < circle cx = "263" cy = "189.2" r = "2.8" />
       < path d="M275,171.4c-2.8-0.7-5.2-3-6.3-5.1l-3.9-7.4c-1.1-2.1-3.9-3.8-6.3-3.8h-22.6c-2.4,0-5,1.8-5.7,4.1l-2.4,7
           c-0.2,0.9-1.8,5.5-5,5.5c-2.4,0-5,3.1-5,5.5v8.2c0,2.4,1.9,4.3,4.3,4.3h4.5c0-0.2,0-0.3,0-0.5c0-4.3,3.5-7.8,7.8-7.8
           c4.3,0,7.8,3.5,7.8,7.8c0,0.2,0,0.3,0,0.5h13.1c0-0.2,0-0.3,0-0.5c0-4.3,3.5-7.8,7.8-7.8s7.8,3.5,7.8,7.8c0,0.2,0,0.3,0,0.5h8.1
           c2.4,0,4.3-1.9,4.3-4.3v-6.5C283.2,172,277.3,172,275,171.4z"/>
       < path d = "M241.8,170.3h-12.5c0.7-1.1,1.1-2.2,1.2-2.6l2-5.9c0.6-1.9,2.8-3.5,4.8-3.5h4.5V170.3z" />
       < path d = "M246.1,170.3v-12h10.4c2,0,4.4,1.5,5.3,3.3l3.3,6.3c0.4,0.8,1.1,1.7,2,2.4H246.1z" />
   </ g >
   < animateMotion
            xlink:href = "#car"
            dur = "3s"
            begin = "0s"
            fill = "freeze"
            repeatCount = "indefinite" >
     < mpath xlink:href = "#motionPath" />
   </ animateMotion >
</ svg >                             

现在,小车沿着路径开始运动,但是看起来十分的怪异:

之所以看起来怪异,是因为小车的方向是固定的,不会根据曲线的方向而改变。为了修正它,我们可以使用rotate属性。

rotate属性有三个参数:

  • auto:元素自动根据运动路径的角度(曲线的切线方向)来改变它的运动方向。
  • auto-reverse:这是auto在曲线的切线方向上的镜像。
  • 一个数值:目标元素具有一个恒定的运动角度,这个角度由指定的数值决定。

为了修正上面例子的BUG,我们设置rotate="auto"

< animateMotion
    xlink:href = "#car"
    dur = "3s"
    begin = "0s"
    fill = "freeze"
    repeatCount = "indefinite"
    rotate = "auto" >                             

现在,得到的结果如下面的样子:

如果你想让小车沿路径的外围运动,可以设置rotate="auto-reverse"

< animateMotion
    xlink:href = "#car-3"
    dur = "3s"
    begin = "0s"
    fill = "freeze"
    repeatCount = "indefinite"
    rotate = "auto-reverse" >                             

现在,小车沿路径运动的效果看起来就比较正常了。但是还有一点小问题:小车是反方向沿路径进行运动的。要修正它,我们需要将小车沿Y轴翻转。我们可以通过在将小车在Y轴方向上缩放"-1"来实现翻转效果。

< g id = "car" transform = "scale (-1, 1) translate(-234.4, -182.8)" >                             

得到的结果如下面的样子:

 文字路径动画

使文字在任意路径上运动和其它SVG元素的路径动画有所不同,它使用的是<animate>元素,而不是<animateMotion>元素。

首先我们需要将文字定位在路径上。这可以通过在<text>元素中嵌套>textPath>元素来实现。然后使用>textPath>元素来指向一条实际的路径作为运动路径。被引用的路径可以是画布上的一条路径,也可以定义在<defs>中。

< svg width = "500" height = "350" viewBox = "0 0 500 350" >
   < path id = "myPath" fill = "none" stroke = "#000000" stroke-miterlimit = "10" d="M91.4,104.2c3.2-3.4,18.4-0.6,23.4-0.6c5.7,0.1,10.8,0.9,16.3,2.3
     c13.5,3.5,26.1,9.6,38.5,16.2c12.3,6.5,21.3,16.8,31.9,25.4c10.8,8.7,21,18.3,31.7,26.9c9.3,7.4,20.9,11.5,31.4,16.7
     c13.7,6.8,26.8,9.7,41.8,9c21.4-1,40.8-3.7,61.3-10.4c10.9-3.5,18.9-11.3,28.5-17.8c5.4-3.7,10.4-6.7,14.8-11.5
     c1.9-2.1,3.7-5.5,6.5-6.5"/>
   < text >
     < textpath xlink:href = "#myPath" >
       Text laid out along a path.
     </ textpath >
   </ text >
</ svg >                             

得到的结果如下所示:

Text laid out along a path.

要制作文字的路径动画,我们将使用<animate>元素的startOffset来制作动画。

code>startOffset代表文字在路径上的偏移。0%表示路径的开始,100%代表路径的结束。如果设置为50%,文字将移动到路径的一半。

< svg width = "500" height = "350" viewBox = "0 0 500 350" >
   < path id = "myPath" fill = "none" stroke = "#000000" stroke-miterlimit = "10" d="M91.4,104.2c3.2-3.4,18.4-0.6,23.4-0.6c5.7,0.1,10.8,0.9,16.3,2.3
     c13.5,3.5,26.1,9.6,38.5,16.2c12.3,6.5,21.3,16.8,31.9,25.4c10.8,8.7,21,18.3,31.7,26.9c9.3,7.4,20.9,11.5,31.4,16.7
     c13.7,6.8,26.8,9.7,41.8,9c21.4-1,40.8-3.7,61.3-10.4c10.9-3.5,18.9-11.3,28.5-17.8c5.4-3.7,10.4-6.7,14.8-11.5
     c1.9-2.1,3.7-5.5,6.5-6.5"/>
   < text >
     < textpath xlink:href = "#myPath" >
       Text laid out along a path.
       
       < animate attributeName = "startOffset" from = "0%" to = "100%" begin = "0s" dur = "5s" repeatCount = "indefinite" keyTimes = "0;1" calcMode = "spline" keySplines = "0.1 0.2 .22 1" />
     </ textpath >
   </ text >
</ svg >                             

上面的代码的返回结果是:

Text laid out along a path.
 返回SVG教程目录
 相关阅读

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值