SVG相关知识点

607 阅读3分钟

polygon

SVG 中的 <polygon> 元素用于绘制多边形

<polygon
  points="x1,y1 x2,y2 x3,y3 ..."   <!-- 多边形各个顶点的坐标 -->
  fill="fill-color"                <!-- 多边形的填充颜色 -->
  stroke="stroke-color"            <!-- 多边形的边框颜色 -->
  stroke-width="width"             <!-- 多边形的边框宽度 -->
/>
  • points 属性定义了多边形各个顶点的坐标,多个顶点的坐标以空格分隔,并且每对坐标使用逗号分隔。

path d

path标签通过属性d来定义路径,d由字母和数字构成,数字表示坐标点,字母负责表示如何连接这些坐标点。

<path d="M100,100 L200,200 L200,400" fill="#333" stroke="#000" />

M100,100 -> 以(100,100)坐标点为起点
L200,200 -> 从(100,100)向(200,200)画一条直线
L200,400 -> 从(200,200)向(200,400)画一条直线

在path标签的d属性中,一共有10个命令可以使用,下面5个命令是基础,比较简单。

M 移动到(moveTo) x,y 开始点坐标
Z 闭合路径(closepath) 将路径的开始和结束点用直线连接
L 直线(lineTo) x,y 当前节点到指定(x,y)节点,直线连接
H 水平直线 x 保持当前点的y坐标不变,x轴移动到x,形成水平线
V 垂直直线 y 保持当前点的x坐标不变,y轴移动到y,形成垂直线

参考:SVG矢量绘图 path路径详解(基本画法

radialGradient

径向渐变,是一种从中心点开始,向四周扩散的渐变效果。通过<radialGradient>元素来定义的。放射性渐变可以指定中心点、焦点、形状和大小,以及渐变颜色和位置。

在SVG中使用放射性渐变需要以下几个步骤:

  1. 定义渐变:首先,在SVG的<defs>元素内定义一个<radialGradient>元素,设置渐变的ID、中心点、焦点、形状和大小。

  2. 设置渐变颜色:<radialGradient>元素内,使用<stop>元素设置渐变颜色和位置。

  3. 应用渐变: 将定义好的渐变应用到SVG图形上,例如矩形、圆形或路径,通过fill或stroke属性引用渐变的ID。

参考: SVG 渐变 - 放射性

defs

defs相当于Vue的components组件,用于path、渐变效果、蒙板、图形等的复用。

mask

在SVG中一般会把蒙板定义在defs标签中。蒙板不会直接渲染,只会在引用的地方起作用,所以display,opacity等属性对于mask元素来说都是不起作用的。

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <linearGradient id="Gradient">
      <stop offset="0" stop-color="white" stop-opacity="0" />
      <stop offset="1" stop-color="white" stop-opacity="1" />
    </linearGradient>
    <mask id="Mask">
      <rect x="0" y="0" width="200" height="200" fill="url(#Gradient)"  />
    </mask>
  </defs>

  <rect x="0" y="0" width="200" height="200" fill="green" />
  <rect x="0" y="0" width="200" height="200" fill="red" mask="url(#Mask)" />
</svg>

image.png

动画

image.png

image.png

代码解读

<svg class="border-svg-container" :width="width" :height="height">
      <defs>
        <path :id="`border-box-8-path-${id}`" :d="pathD" fill="transparent"></path>
        <radialGradient :id="`border-box-8-gradient-${id}`" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stop-color="#fff" stop-opacity="1"></stop>
          <stop offset="100%" stop-color="#fff" stop-opacity="0"></stop>
        </radialGradient>
        <mask :id="`border-box-8-mask-${id}`">
          <circle cx="0" cy="0" r="50" :fill="`url(#border-box-8-gradient-${id})`">
            <animateMotion :dur="props.dur" :path="pathD" rotate="auto" repeatCount="indefinite"></animateMotion>
          </circle>
        </mask>
      </defs>
      <polygon
        :fill="props.backgroundColor"
        :points="`5, 5 ${width - 5}, 5 ${width - 5} ${height - 5} 5, ${height - 5}`"
      ></polygon>
      <use stroke-width="1" :xlink:href="`#border-box-8-path-${id}`" :stroke="props.color[0]"></use>
      <use
        stroke-width="3"
        :xlink:href="`#border-box-8-path-${id}`"
        :mask="`url(#border-box-8-mask-${id})`"
        :stroke="props.color[1]"
      >
        <animate
          attributeName="stroke-dasharray"
          :from="`0, ${length}`"
          :to="`${length}, 0`"
          :dur="props.dur"
          repeatCount="indefinite"
        ></animate>
      </use>
   </svg>

这段代码定义了一个 Vue 组件中的 SVG 元素,用于创建一个带有动画效果的边框。具体功能和结构如下:

  • SVG 容器<svg class="border-svg-container" :width="width" :height="height"> 定义了一个 SVG 容器,宽度和高度通过 widthheight 属性动态设置。
  • 定义部分 (<defs>)
    • 路径 (<path>):定义了一个路径,ID 为 border-box-8-path-${id},路径数据由 pathD 提供,填充颜色为透明。这个路径是通过传入的宽度跟高度计算得来的,生成一个矩形边框。
    • 径向渐变 (<radialGradient>):定义了一个从白色到透明的径向渐变,ID 为 border-box-8-gradient-${id}
    • 遮罩 (<mask>):定义了一个遮罩,图形为使用上述径向渐变填充的圆形,通过 <animateMotion> 实现圆沿着矩形边框移动的动画效果。

优速GIF大师2024-12-24 09-55-48.gif

  • 背景多边形 (<polygon>):定义了一个矩形背景,填充颜色由 props.backgroundColor 提供,位置和大小通过 points 属性动态设置。
  • 路径使用 (<use>)
    • 第一个 <use> 标签引用了之前定义的路径,设置了较小的 stroke-width 和颜色 props.color[0]

1735005515850.png

  • 第二个 <use> 标签同样引用了路径,但设置了较大的 stroke-width 和不同的颜色 props.color[1],并且应用了之前定义的圆形遮罩。同时,通过 <animate> 标签实现了虚线动画效果,虚线从无到有再回到无的循环动画。

整体来看,这段代码实现了一个带有动态虚线边框效果的矩形组件,适用于需要视觉效果突出的场景。

优速GIF大师2024-12-24 10-02-39.gif

<svg :width="width" :height="height" class="border-svg-container">
      <defs>
        <filter :id="`border-box-2-filterId-${id}`" height="150%" width="150%" x="-25%" y="-25%">
          <feMorphology operator="dilate" radius="2" in="SourceAlpha" result="thicken"></feMorphology>
          <feGaussianBlur in="thicken" stdDeviation="3" result="blurred"></feGaussianBlur>
          <feFlood result="glowColor" :flood-color="props.color[1]"></feFlood>
          <feComposite in="glowColor" in2="blurred" operator="in" result="softGlowColored"></feComposite>
          <feMerge>
            <feMergeNode in="softGlowColored"></feMergeNode>
            <feMergeNode in="SourceGraphic"></feMergeNode>
          </feMerge>
        </filter>
        <path :id="`border-box-2-path-${id}`" :d="pathD" fill="transparent"></path>
        <radialGradient :id="`border-box-2-gradient-${id}`" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stop-color="#fff" stop-opacity="1"></stop>
          <stop offset="100%" stop-color="#fff" stop-opacity="0"></stop>
        </radialGradient>
        <mask :id="`border-box-2-mask-${id}`">
          <circle cx="0" cy="0" r="50" :fill="`url(#border-box-2-gradient-${id})`">
            <animateMotion :dur="props.dur" :path="pathD" rotate="auto" repeatCount="indefinite"></animateMotion>
          </circle>
        </mask>
      </defs>
      <polygon :fill="backgroundColor" :points="polygonPoint1"></polygon>
      <polyline :filter="`url(#border-box-2-filterId-${id})`" :points="polylinePoint1" :stroke="props.color[0]"></polyline>
      <polygon fill="transparent" :points="polygonPoint2" :stroke="props.color[0]"></polygon>
      <polygon fill="transparent" :points="polygonPoint3" :stroke="props.color[0]"></polygon>
      <polygon
        :fill="`rgba(${getRgbValueFromHex(props.color[1])},0.3)`"
        :filter="`url(#border-box-2-filterId-${id})`"
        :points="polygonPoint4"
        :stroke="props.color[0]"
      ></polygon>
      <polygon :filter="`url(#border-box-2-filterId-${id})`" opacity="1" :points="polygonPoint5" :fill="props.color[0]">
        <animate attributeName="opacity" values="1;0.7;1" dur="2s" begin="0s" repeatCount="indefinite"></animate>
      </polygon>
      <polygon :filter="`url(#border-box-2-filterId-${id})`" opacity="0.7" :points="polygonPoint6" :fill="props.color[0]">
        <animate attributeName="opacity" values="0.7;0.4;0.7" dur="2s" begin="0s" repeatCount="indefinite"></animate>
      </polygon>
      <polygon :filter="`url(#border-box-2-filterId-${id})`" opacity="0.5" :points="polygonPoint7" :fill="props.color[0]">
        <animate attributeName="opacity" values="0.5;0.2;0.5" dur="2s" begin="0s" repeatCount="indefinite"></animate>
      </polygon>
      <polygon :filter="`url(#border-box-2-filterId-${id})`" opacity="1" :points="polygonPoint8" :fill="props.color[0]">
        <animate attributeName="opacity" values="1;0.7;1" dur="2s" begin="0s" repeatCount="indefinite"></animate>
      </polygon>
      <polygon :filter="`url(#border-box-2-filterId-${id})`" opacity="0.7" :points="polygonPoint9" :fill="props.color[0]">
        <animate attributeName="opacity" values="0.7;0.4;0.7" dur="2s" begin="0s" repeatCount="indefinite"></animate>
      </polygon>
      <polygon :filter="`url(#border-box-2-filterId-${id})`" opacity="0.5" :points="polygonPoint10" :fill="props.color[0]">
        <animate attributeName="opacity" values="0.5;0.2;0.5" dur="2s" begin="0s" repeatCount="indefinite"></animate>
      </polygon>
      <text
        :x="width / 2"
        y="32"
        :fill="fontColor"
        :font-size="fontSize"
        text-anchor="middle"
        dominant-baseline="middle"
        class="border-box-2-title"
      >
        {{ props.title }}
      </text>
      <polygon :filter="`url(#border-box-2-filterId-${id})`" :points="polygonPoint11" :fill="props.color[0]"></polygon>
      <polygon :filter="`url(#border-box-2-filterId-${id})`" :points="polygonPoint12" :fill="props.color[0]"></polygon>
      <use
        stroke-width="3"
        :xlink:href="`#border-box-2-path-${id}`"
        :mask="`url(#border-box-2-mask-${id})`"
        :stroke="props.color[2]"
      >
      </use>
</svg>

SVG 中的 <defs> 部分,定义了一些过滤器、路径、渐变和遮罩。

  1. 过滤器 (<filter>):
    • 使用 feMorphologyfeGaussianBlur 创建一个模糊效果。
    • 使用 feFloodfeComposite 创建一个发光效果。
    • 使用 feMerge 将发光效果和原始图形合并。
  2. 路径 (<path>):
    • 定义了一个路径,用于后续的使用。
  3. 径向渐变 (<radialGradient>):
    • 定义了一个从白色到透明的径向渐变,用于遮罩效果。
  4. 遮罩 (<mask>):
    • 使用一个带有径向渐变的圆形来创建一个遮罩效果。
    • 使用 animateMotion 使圆形沿着路径移动,产生动画效果。