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,形成垂直线
radialGradient
径向渐变,是一种从中心点开始,向四周扩散的渐变效果。通过<radialGradient>
元素来定义的。放射性渐变可以指定中心点、焦点、形状和大小,以及渐变颜色和位置。
在SVG中使用放射性渐变需要以下几个步骤:
-
定义渐变:首先,在SVG的
<defs>
元素内定义一个<radialGradient>
元素,设置渐变的ID、中心点、焦点、形状和大小。 -
设置渐变颜色: 在
<radialGradient>
元素内,使用<stop>
元素设置渐变颜色和位置。 -
应用渐变: 将定义好的渐变应用到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>
动画
代码解读
<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 容器,宽度和高度通过width
和height
属性动态设置。 - 定义部分 (
<defs>
):- 路径 (
<path>
):定义了一个路径,ID 为border-box-8-path-${id}
,路径数据由pathD
提供,填充颜色为透明。这个路径是通过传入的宽度跟高度计算得来的,生成一个矩形边框。 - 径向渐变 (
<radialGradient>
):定义了一个从白色到透明的径向渐变,ID 为border-box-8-gradient-${id}
。 - 遮罩 (
<mask>
):定义了一个遮罩,图形为使用上述径向渐变填充的圆形,通过<animateMotion>
实现圆沿着矩形边框移动的动画效果。
- 路径 (
- 背景多边形 (
<polygon>
):定义了一个矩形背景,填充颜色由props.backgroundColor
提供,位置和大小通过points
属性动态设置。 - 路径使用 (
<use>
):- 第一个
<use>
标签引用了之前定义的路径,设置了较小的stroke-width
和颜色props.color[0]
。
- 第一个
- 第二个
<use>
标签同样引用了路径,但设置了较大的stroke-width
和不同的颜色props.color[1]
,并且应用了之前定义的圆形遮罩。同时,通过<animate>
标签实现了虚线动画效果,虚线从无到有再回到无的循环动画。
整体来看,这段代码实现了一个带有动态虚线边框效果的矩形组件,适用于需要视觉效果突出的场景。
<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>
部分,定义了一些过滤器、路径、渐变和遮罩。
- 过滤器 (
<filter>
):- 使用
feMorphology
和feGaussianBlur
创建一个模糊效果。 - 使用
feFlood
和feComposite
创建一个发光效果。 - 使用
feMerge
将发光效果和原始图形合并。
- 使用
- 路径 (
<path>
):- 定义了一个路径,用于后续的使用。
- 径向渐变 (
<radialGradient>
):- 定义了一个从白色到透明的径向渐变,用于遮罩效果。
- 遮罩 (
<mask>
):- 使用一个带有径向渐变的圆形来创建一个遮罩效果。
- 使用
animateMotion
使圆形沿着路径移动,产生动画效果。