数据大屏项目(四):svg动画应用案例

2,266 阅读3分钟

概要:本文主要结合之前svg知识汇总,通过例子实现svg的动画。主要记录动画绘制的思路,以及相关源码实现的原理,相关属性的解释。

svg+css实现动画

svg结合css,实现环形进度条、方形进度条

思路:不管是方形进度条还是圆形进度条,原理都是先画出两个相同的圆或者矩形,一个作为底部,另一个实现动画。然后通过属性stroke-dasharray控制外层显示长度。然后通过css定义keyframe的from完全不可见,to完全可见的动画,通过animation补间动画实现。实现后发现不是从圆的顶点开始运动的,而是从圆的坐标点运动的,则可以通过svg的transform:matrix(a b c d e f)属性进行坐标转换实现。

stroke-dasharray

stroke-dasharray="x y"表示x个像素的实线,可见路径。 y像素是空白格

环形进度条实现

  <svg width="200" height="200" viewBox="0 0 400 400">
    <!-- 半径是1006 -->
    <circle cx="200" cy="200" r="160" stroke-width="30" stroke="#D1D3D7" fill="transparent"></circle>
    <circle transform="matrix(0 -1 1 0 0 400)" class="circle" cx="200" cy="200" r="160" stroke-width="30" stroke="blue" fill="transparent"></circle>
  </svg>

721000.gif

方形进度条实现

  <svg width="200" height="200" viewBox="0 0 200 200">
    <rect x="0" y="0" width="200" height="200" fill="none" stroke="grey" stroke-width="8"></rect>
    <rect class="circle" x="0" y="0" width="200" height="200" fill="none" stroke="blue" stroke-width="8"  transform="matrix(0,1,-1,0,200,0)"></rect>
  </svg>

css动画样式公用

  @keyframes circle {
    from {
      stroke-dasharray: 1006 0;
    }
    to {
      stroke-dasharray: 0 1006;
    }
  }
  .circle {
    animation: circle 5s linear infinite;
  }

00001-05.gif

svg结合css,实现logo描边动画

思路:先利用svg元素的svgDom.getTotalLength()计算出LoGO的路径长度,然后利用stroke-dasharray stroke-dashoffset两个属性控制绘制过程动画。然后在其他补间过程实现颜色变化的一个效果。 计算LOGO长度

  const path = document.getElementById('singlePath')
  const pathLen = path.getTotalLength()
  console.log(pathLen);

stroke-dashoffset

stroke-dashoffset:n。 将元素自右向左位移n像素

  <svg viewBox="0 0 1024 1024" width="200" height="200">
    <path id="singlePath" class="singlePath" fill="#ccc" d="M512.1129 963.711577c-23.93473 0-48.095259-9.031974-66.385006-27.32172L109.964278 600.62624C-11.289967 479.371996-15.805954 283.603969 99.803308 164.381918c61.643219-63.449614 153.54355-95.287321 245.66968-84.900551 66.385006 7.451378 124.867034 36.353693 166.414112 81.513561 40.86968-44.934068 98.674311-74.062183 164.607718-81.73936 93.029327-10.838368 185.607056 20.999338 248.153473 85.35215 115.609261 119.222051 111.093275 314.990077-10.38677 436.244322L578.272106 936.389857c-18.289746 18.289746-42.224476 27.32172-66.159206 27.32172zM311.828886 145.188975c-61.869019 0-122.83484 24.386329-163.478721 66.385005-90.093936 92.803528-85.803749 245.89548 9.483573 341.182801l335.763616 335.763616c9.935171 9.935171 27.095921 9.935171 36.805292 0l335.763616-335.763616c95.287321-95.287321 99.577508-248.379272 9.483573-341.182801-46.966262-48.772657-120.351047-73.836384-191.477839-65.481808-62.772216 7.225579-113.351268 38.385888-142.479383 87.384344-6.096582 10.16097-17.612348 16.709151-29.353914 16.709151-12.418964-0.903197-23.257332-6.322381-29.579713-16.257552 0 0-0.225799-0.225799-0.2258-0.451599-29.579713-48.546858-82.190959-80.384564-144.737376-87.384344-8.580375-0.451599-17.386549-0.903197-25.966924-0.903197z" p-id="803"></path>
  </svg>
  <style>
    .singlePath {
      fill: none;
      stroke: #333;
      stroke-width: 1;
      animation: singlePath 5s linear infinite forwards;
    }
    @keyframes singlePath {
      10% {
        stroke-dasharray: 5564;
        stroke-dashoffset: 5564;
      }
      50% {
        stroke-dasharray: 5564;
        stroke-dashoffset: 0;
      }
      70% {
        stroke: green;
        fill:green
      }
      85% {
        stroke: blue;
        fill:blue
      }
      100% {
        stroke: red;
        fill:red
      }
    }
  </style>

GIF 2021-7-21 15-19-52.gif

svg中smil动画案例

混合动画

一个方块沿着路径来回运动,并且运动的过程中发生颜色的改变。 实现思路:在方块下面加多种运动,animateMotion轨迹运动标签中begin的用法理解

begin用法

  • 没有begin或者begin参数解析异常,都当作0处理。

  • begin指动画开始的时间,begin的定义是分号分隔的一组值。单值只是其中的情况之一,表示时间延时。 例如,beigin="3s;5s"表示的是3s之后动画走一下。6s时候动画再走一下(如果之前动画没走完,会立即停止从头开始)。所以,如果一次动画时间为3s, 即dur="3s",同时没有repeatCount属性时候,我们可以看到动画似乎连续执行了2次。

  • begin的单值除了普通value,还有下面这些类别的value

  1. offset-value 表示偏移值,数值前面有+或-。 应该指相对于dom的begin值而言
  2. syncbase-value 于同步确定的值。语法为:[元素的id].begin/end +/- 时间值。 就是说借用其他元素的begin值再加加减减,这个可以准确实现两个独立元素的动画级联效果
 <svg width="320" height="200">
    <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>

可以看到,后面attributeName为y的元素的begin值是x.end. x.end中的x就是上面一个animate元素的id值,而end是动画元素都有的一个属性,动画结束的时间。因此,begin="x.end"意思就是,当id为x的元素动画结束的时候,我执行动画。非常类似于PowerPoint动画的“上一个动画之后”的选项。

我们还可以增加一些偏移值,例如begin="x.end-1s", 就表示id为x的元素动画结束前一秒开始纵向移动。

  1. event-value 与事件相关联的值。类似于PowerPoint动画的“点击执行该动画”。语法是:[元素的id].[事件类型] +/- 时间值. 举个例子,点击下图的圆圈圈,马儿它就会自己跑!
 <svg id="svg" width="320" height="200">
    <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>

begin="circle.click", 其中circle为circle元素(黑色圆)的id,click表示点击事件, 如果你想点击圆圈圈2秒钟后马儿才跑,很简单,偏移时间加上就可以begin="circle.click+2s"。主要注意的是,这类与事件关联的SVG需要内联在页面中,否则click什么的都是徒劳。

轨迹运动混合动画

<svg width="200" height="200">
        <rect x="0" y="0" fill="red" width="10" height="10">
          <!-- 这里如果写成begin="0",那么只会执行一次来回 -->
          <animateMotion
            id="forward-rect"
            path="M10 10 L110 10 L110 110 L10 110"
            dur="2s"
            rotate="0"
            fill="freeze"
            begin="0; back-rect.end + 0.5s"></animateMotion>
          <!-- begin="forward-reat.end" 获取到上个动画的结束时间-->
          <animateMotion
            id="back-rect"
            path="M10 110 L110 110 L110 10 L10 10"
            dur="2s"
            rotate="0"
            fill="freeze"
            begin="forward-rect.end + 0.5s"></animateMotion>
          <animate
            id='red-to-blue'
            attributeName="fill"
            attributeType="XML"
            from="red"
            to="blue"
            dur="2s"
            fill="freeze"
            begin="0; blue-to-red.end + 0.5s"></animate>
          <animate
            id='blue-to-red'
            attributeName="fill"
            attributeType="XML"
            from="blue"
            to="red"
            dur="2s"
            fill="freeze"
            begin="red-to-blue.end + 0.5s"></animate>
        </rect>
        <path
          d="M10 10 L110 10 L110 110 L10 110"
          fill="none"
          stroke="pink"
        ></path>
      </svg>

GIF 2021-7-21 15-57-57.gif

点击变色位移运动

    <svg viewBox="0 0 200 200" width="200" height="200">
      <g id="rect1">
        <rect x="0" y="0" rx="0" ry="0" width="100" height="100" fill="red">
          <animate
            attributeType="XML"
            attributeName="fill"
            from="red"
            to="green"
            begin="rect1.click"
            dur="2s"
            fill="freeze"/></rect>
      </g>
      <animateTransform
        attributeType="XML"
        attributeName="transform"
        type="translate"
        from="0, 0"
        to="50, 50"
        begin="rect1.click"
        dur="2s"
        fill="freeze"/>
      <rect x="0" y="100" width="100" height="100" fill="blue">
        <animate
          attributeType="XML"
          attributeName="fill"
          from="blue"
          to="yellow"
          begin="rect1.click"
          dur="2s"
          fill="freeze"/>
      </rect>
    </svg>

GIF 2021-7-21 16-04-31.gif