svg连线的动画效果渐变的实现方式

131 阅读4分钟

 最近打算给我手写的可视化编辑器的拓扑图的连线加个动画效果,因为市场那边说没动画,没那么好忽悠客户,安排!!!一开始加了虚线滑动的形式发现真坤儿丑!而且平平无奇。后面用渐变的实现方式还挺好看的,所以记录一下。

各位爷先看效果:

原理:

一个渐变,然后移动渐变。简单吧!!!首先学如下两个标签。后面我用demo附上源码详细讲讲

<linearGradient>(这个就是渐变)

 定义一个线性颜色渐变。线性渐变会沿着一条直线在不同的颜色之间进行平滑过渡。
由以下几部分组成:
  1. <linearGradient> 标签本身: 定义渐变的容器。

  2. id 属性: 必不可少,用于在其他元素中引用这个渐变。

  3. x1, y1, x2, y2 属性: 定义渐变的起始点和结束点,决定了渐变的方向。

  4. <stop> 子标签: 定义渐变中的颜色停止点。

    属性描述必填/可选示例值
    offset颜色停止点的位置。一个 0 到 1 之间的数字(表示百分比),或一个百分比字符串(例如 0% 到 100%)。 0 或 0% 表示渐变线的起始点,1 或 100% 表示结束点。必填0, 0.5, 1, 25%, 75%
    stop-color停止点的颜色。任何有效的 CSS 颜色值。必填red, #FF0000, rgb(255, 0, 0)
    stop-opacity停止点的不透明度。一个 0 到 1 之间的数字。默认值是 1 (完全不透明)。可选0, 0.5, 1
  5. gradientUnits:坐标的单位类型,默认为 objectBoundingBox(相对于图形大小),可设为 userSpaceOnUse(绝对坐标)。

<animateTransform>(这个就是用来移动渐变)

用于处理 形变动画 的元素,支持对图形或渐变进行平移、旋转、缩放、倾斜等变换操作。

属性描述
attributeName transform,动画图形元素的变换。gradientTransform, 渐变本身的变换
type变换类型,可选值:translatescalerotateskewXskewY
from起始值(例如 0 0 表示平移起点)。
to结束值(例如 100 100 表示平移终点)。
dur动画持续时间(单位:秒)。
repeatCount动画重复次数(indefinite 表示无限循环)。
begin动画开始时间(支持时间值或事件触发,如 click)。

还有个属性是values,就是定义多个关键帧的。跟from和to的功能一样,只不过from和to表示两个关键帧也就是开始和结束。

demo效果:

源码(vue复制即可运行):

<template>
  <div class="container">
    <svg ref="svgCanvas" class="svg-canvas" :width="1920" :height="800">
      <!-- 定义区:存放渐变、滤镜等可复用的元素 -->
      <defs>
        <!-- 线性渐变 -->
        <linearGradient
          id="currentGradient"
          gradientUnits="userSpaceOnUse"
          x1="50"
          y1="50"
          x2="550"
          y2="100"
        >
          <!-- 0%位置:完全透明 -->
          <stop offset="0%" stop-color="transparent" />
          <!-- 20%位置:完全透明 -->
          <stop offset="20%" stop-color="transparent" />
          <!-- 35%位置:淡红色 -->
          <stop offset="35%" stop-color="red" stop-opacity="0.2" />
          <!-- 45%位置:中等红色 -->
          <stop offset="45%" stop-color="red" stop-opacity="0.6" />
          <!-- 50%位置:最亮红色(电流中心) -->
          <stop offset="50%" stop-color="red" stop-opacity="1" />
          <!-- 55%位置:中等红色 -->
          <stop offset="55%" stop-color="red" stop-opacity="0.6" />
          <!-- 65%位置:淡红色 -->
          <stop offset="65%" stop-color="red" stop-opacity="0.2" />
          <!-- 80%位置:完全透明 -->
          <stop offset="80%" stop-color="transparent" />
          <!-- 100%位置:完全透明 -->
          <stop offset="100%" stop-color="transparent" />

          <!-- 动画变换:让渐变移动产生电流流动效果 -->
          <animateTransform
            attributeName="gradientTransform"
            type="translate"
            values="-500 0; 500 0"
            dur="2s"
            repeatCount="indefinite"
          />
        </linearGradient>
      </defs>

      <!-- 背景路径:背景板,没这玩意也行,主要是突出效果 -->
      <polyline
        points="50,50 550,50"
        fill="none"
        stroke="#333333"
        stroke-width="10"
      ></polyline>

      <!-- 渐变路径:这个就是渐变的路径 -->
      <polyline
        points="50,50 550,50"
        fill="none"
        stroke="url(#currentGradient)"
        stroke-width="8"
      ></polyline>
    </svg>
  </div>
</template>

流程:

(1)定义个一个渐变linearGradient,x,y是初始位置,也是渐变的初始方向,xy的值一般是被引用路径的起点和结束点,如polyline的points所展示的点。

(2)然后子元素定义一个animateTransform控制渐变的位移变换,values 定义了 渐变坐标系的整体平移方向, values值”;“号为一组,前为x后为y,作用是位移,比如渐变的水平方向的长度现在是dx(550 - 50),那我就-500往左位移这样渐变在起始帧就是隐藏的,结束帧为500,那么这个过程就是移动渐变-500到500的过程。

(3)stroke="url(#currentGradient)"路径引用渐变

延伸:

假设如上源码,points的值改为"50,50 180,100, 250,190 550,50",animateTransform的values是否需要跟polyline的 points对应, 如每一段都有对应的values值对应?

答案:不需要, 只要 渐变的移动方向 与 路径的整体延伸方向 一致,动画效果就会自然覆盖整个路径,无需逐段匹配。

animateTransform 作用的是渐变本身,不是路径

  • values="-500 0; 500 0" 是在移动整个渐变
  • 渐变是一个独立的"颜色分布系统"

就相当于stroke="url(#currentGradient)"引用渐变时,告诉svg你用这个渐变描绘我的路径。SVG 渲染器会把当前时间点上,渐变所处的那个位置和状态下的图案,映射并拉伸到你的 polyline 路径的整个长度上。