前言
欢送关注同名公众号《熊的猫》,后续文章会同步更新!
其实在大部分的我的项目中都有 间接 或 间接 应用到 SVG 和 Canvas,然而在大多数时候咱们只是抉择 简略理解 或 间接跳过,这有问题吗?没有问题, 毕竟砖还是要搬的
!
话说回来,前端其实还是须要对 SVG 和 Canvas 进行学习的,因为其实你始终都在用,多理解不会让你有什么损失,最根本的能够防止:
- 不至于当 UI 扔给你一个不合乎设计稿色彩的 SVG 时摸不着头脑
- 不至于无奈通过 CSS 为 SVG 图自定义其色值时无从下手
- 甚至不晓得为什么要在我的项目中将展现 SVG 的内容封装成组件
- …
再往上些就能够基于 SVG 进行自定义编码,例如实现各种基于 SVG 的动画需要、在可视化大屏我的项目中的利用等等。
相干文章其实早就想写(),但因为各种起因没有真正输入,本篇文章以 SVG 为次要内容正式开启探索之旅。在草稿箱里挺长时间了
文中如有不正确之处,可在评论区斧正!!!
SVG 简介
是什么?
SVG 的全称是 Scalable Vector Graphics(即 可缩放矢量图形),它基于 XML 标记语言,用于形容二维的 矢量图形。
同时 SVG 是一个基于文本的凋谢网络规范,其 图像内容 和 相干行为 会被定义于 XML 文本文件之中,并可能和 CSS、DOM、JavaScript 等网络规范进行连接。
以上是 官网解释 ,那么再给一个 非官方解释:
人话就是说 SVG 是一种可缩放矢量图形,它能够用 类 HTML(即 XML) 来示意,也就是 可编码,因而你能够在 DOM
中间接应用,能够通过 CSS
管制款式,能够通过 JavaScript
动静批改。
具备什么劣势?
其实通过上述的简介,你就不难看出 SVG 至多有以下两个长处():说多了记不住没意义
- 可缩放矢量图形
- 可编码性
可缩放矢量图形
点阵图 / 位图
通常咱们经见的 如 JPEG(后缀名为 .jpg
或 .jpeg
)和 PNG 属于 点阵图 / 位图
也就是 由很多的像素组成的图形,平时看到的大多图片数属于点阵图,但因为像素十分高,每个点十分小,人的眼睛看不清那一个个的点,所以没有感知,但其实都是用点组成的,通常将它们始终放大,就看到区别了,如下:
-
原始尺寸图片
-
通过画图软件放大
从以上来看 点阵图 / 位图 毛病之一就是 不适宜进行有限放大,因为会导致本来人眼不可见的像素被放大,导致视觉上看起来图片 含糊 / 失真。
然而也正是因为 点阵图 / 位图 由不同的像素块组成的,因而能够给不同的像素块填充不同色彩,使得整个图形色调能够十分丰盛。
矢量图形
而 矢量图形 是用 数学向量、依据几何个性 来绘制图形,矢量能够是 一个点 或 一条线,它是通过 多个对象的组合生成 的,对其中的每一个对象的记录形式,都是以数学 函数 来实现的。
并且每个对象都是一个 相互独立的实体 ,意味着屡次挪动和扭转它的属性时不会影响图例中的其它对象,仍能够在维持它原有清晰度和蜿蜒度,也就是说它们能够按 最高分辨率 显示到 输出设备 上。
因而,矢量图形的长处如下:
-
文件占用外在空间较小
- 矢量图实际上保留的是
点、线、矩形
等元素的信息,咱们可能看到图像是因为在咱们关上矢量图时,由计算机依据这些信息计算出来的,而点阵图 / 位图
则是保留各个点的图像信息
- 矢量图实际上保留的是
-
放大后不失真(不会变含糊)
- 因为它和分辨率无关,无论咱们挪动或扭转它的属性多少次,它都能够在维持它原有清晰度和蜿蜒度
可编码性
可编码性应该不难理解,齐全能够通过上面这个图来解释(一图胜千言):
SVG 的可编码性使得它绝对于 点阵图 / 位图 具备更强的灵活性,只有依照其对应的规定去批改 点、线 等相干信息,咱们就能够扭转图形,而不像 点阵图 / 位图 意义比方只是想要不同色彩的同一张图片用于切换时,还得独自筹备两张图片等等。
SVG 的应用场景
icon 图标
在我的项目中某些图标也会应用 SVG 的格局,最常见的例如在 iconfont
上可自行抉择是否以 SVG 的形式应用:
而在我的项目中应用 SVG 文件时,通常须要对应的 loader 解决,例如 vite 中的 vite-svg-loader
、webpakc 中的 svg-sprite-loader
等,还会封装成组件的模式去应用,实际上就是通过 <svg>、<symbol>、<use>
依据 name
作为标识实现援用,这里就不再开展。
平面图绘制
在我的项目中须要进行平面图绘制,如须要绘制 线、多边形、图片 等等,比方须要实现前端疏导页性能,其中的遮罩层及高亮矩形局部就是基于 SVG 实现的,详情可见往期文章 不应用第三方库怎么实现【前端疏导页】性能?
动画绘制
通常会存在须要与用户产生共鸣或互动的场景,特地是须要满足创意性排版的需要等,最常见比方公司年度回顾、一些重要内容的营销宣传等,也可基于 SVG 的形式来实现。
当然你也能够基于 greensock(一个业界出名的工具套件)实现疾速应用基于 SVG 的动画模式,如下:
SVG 根本形态元素
SVG 图像是应用各种元素创立的,这些元素别离利用于矢量图像的构造、绘制与布局,因而和 SVG 元素相干的内容是须要去理解的,但内容不算少,按 A-Z 的程序大略包含以 A、C、D、E、F、G、H、I、L、M、P、R、S、T、U、V
等作为前缀的元素,按类别还能够分类为:
- 根本形态元素
- 容器元素
- 描述性元素
- 滤镜元素
- 字体元素
- …
在本文中咱们将焦点关注在 根本形态元素 上。
<circle>
圆形元素
<circle>
是用来创立圆,它是基于一个圆心和一个半径,对应属性为:
- cx 示意圆心的 X 坐标
- cy 示意圆心的 Y 坐标
- r 示意半径
<svg>
<circle cx="50" cy="50" r="50"></circle>
</svg>
从上图能够看得出来 <svg>
默认的宽高为 300 * 150。
那么如果想要其余 html 元素一样增加 边框色 和 背景色,该怎么办呢?
SVG 元素可不是应用 border-color 和 background-color 属性实现的,而是通过 stroke 和 fill 来实现的:
<svg>
<circle cx="50" cy="50" r="50" fill="pink" stroke="green"></circle>
</svg>
<rect>
矩形元素
<rect>
元素用来创立矩形,基于一个角地位以及它的宽和高,还能够用来创立圆角矩形,其对应属性有:
- x 示意 x 轴坐标
- y 示意 y 轴坐标
- rx 用于定义程度轴向的圆角半径尺寸
- ry 用于定义纵轴向的圆角半径尺寸
惯例矩形:
<svg>
<rect x="25" y="25" width="100" height="100" fill="pink" stroke="green"></rect>
</svg>
圆角矩形:
<svg>
<rect x="25" y="25" width="100" height="100" rx="10" fill="pink" stroke="green"></rect>
</svg>
矩形 变 圆形:正方形时将 rx 或 ry 设置为宽高的一半即可,长方形时可变椭圆
<svg>
<rect x="25" y="25" width="100" height="100" rx="50" fill="pink" stroke="green"></rect>
</svg>
<ellipse>
椭圆元素
<ellipse>
元素用来创立一个椭圆,基于一个 核心坐标、x
半径、y
半径:
- cx 定义一个中心点的 x 轴坐标
- cy 定义一个中心点的 y 轴坐标
- rx 用于定义程度轴向的圆角半径尺寸
- ry 用于定义纵轴向的圆角半径尺寸
<svg>
<ellipse cx="150" cy="75" rx="100" ry="50" fill="pink" stroke="green"></ellipse>
</svg>
椭圆 变 圆形:只须要将 rx 和 ry 设置为雷同值即可
<svg>
<ellipse cx="150" cy="75" rx="50" ry="50" fill="pink" stroke="green"></ellipse>
</svg>
<line>
线条元素
<line>
用来创立一条连贯两个点的线,其属性有:
- x1 示意第一个点的 x 坐标
- x2 示意第二个点的 x 坐标
- y1 示意第一个点的 y 坐标
- y2 示意第二个点的 y 坐标
值得注意的是:须要为 stroke
赋对应的色值,否则是无奈察看到成果
<svg>
<line x1="50" y1="20" x2="150" y2="100" stroke="red"></line>
</svg>
<polyline>
折线元素
<polyline>
是用来创立一系列直线,也就是连贯多个点,它通常创立的是一个凋谢的形态,即最初一点不与第一点相连,如果须要闭合模式能够应用 <polygon>
元素。
其专有属性为:
- points 用于示意多个点的坐标:x1,y1 x2,y2 x3,y3 … xn,yn
<svg>
<polyline
points="0,40 40,40 40,80 80,80 80,120 120,120 120,160"
fill="white"
stroke="red"
stroke-width="4"
></polyline>
</svg>
<polygon>
多边形元素
<polygon>
元素定义了一个由一组首尾相连的直线线段形成的闭合多边形形态,最初一点连贯到第一点,其属性和 <polygon>
统一,不同在于体现上。
例如同一个例子在 <polygon>
的体现如下:
<svg>
<polygon
points="0,40 40,40 40,80 80,80 80,120 120,120 120,160"
fill="white"
stroke="red"
stroke-width="4"
></polygon>
</svg>
<path>
门路元素
<path>
元素是用来定义形态的通用元素,所有的根本形态都能够用 path 元素来创立。
其专有属性包含:
-
d 用于定义一个要绘制的门路,门路定义是一个 门路命令(
下文中会介绍
) 组成的列表,其中的每一个命令由命令字母和用于表示命令参数的数字组成<svg> <path fill="#f40" stroke="#000" d="M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z" /> </svg>
门路命令
门路命令是对要绘制的门路的阐明,每一个命令由代表命令的字母和代表参数的 数字 组成,SVG 定义了六种门路命令类型,一共 20 条命令。
- 挪动到:
M
、m
- 画线至:
L
、l
、H
、h
、V
、v
- 三次方贝塞尔曲线:
C
、c
、S
、s
- 二次方贝塞尔曲线:
Q
、q
、T
、t
- 椭圆曲线:
A
、a
- 关闭门路:
Z
、z
不难发现命令是辨别大小写的(即大小写敏感 ), 大写 的命令指定 相对坐标 , 小写 命令指定 绝对坐标(绝对以后地位的)。
命令中的数字能够应用 正数 模式,只不过代表的意思不同:
- 对 角度 而言 正数 示意是 逆时针
- 在 相对坐标 中,-x 和 -y 均示意为负坐标
- 在 绝对坐标 中,-x 值为 向左 挪动,负的 -y 值为 向上 挪动
MoveTo 命令
顾名思义,就是指从 以后点 挪动到 下一点 ,即从 以后地位(Po {xo, yo}) 挪动到 新地位(Pn {xn, yn}),并且 Pn 与 Po 之间不会绘制连接线:
- M 相对坐标,将以后地位挪动到坐标
x
,y
- m 绝对坐标,将以后地位沿 x 轴挪动
dx
,沿 y 轴挪动dy
,即Pn = {xo + dx, yo + dy}
<svg>
<path
fill="none"
stroke="#f40"
stroke-width="10"
d="M 10,10 h 30
m 0,10 h 30
m 0,10 h 30
M 40,20 h 30
m 0,10 h 30
m 0,10 h 30
m 0,10 h 30
m -30,10 h 30
m -60,10 h 30
m -60,10 h 30
m -60,10 h 30
m -60,10 h 30"
/>
</svg>
Lineto 命令
Lineto 指令将绘制一条直线段,从 以后地位 (Po {xo, yo})
移到 指定地位 (Pn {xn, yn})
, 指定地位(Pn) 将变成下一个命令中的 以后地位(Po)**:
-
L 在 以后地位 和 指定地位
x
,y
之间绘制 一条线段- 即
Po = Pn = {x, y}
- 即
-
I 在 以后地位 和 指定地位
x
,y
之间绘制 一条线段,指定地位 为 以后地位 沿 x 轴偏移dx
、沿 y 轴偏移dy
处- 即
Po = Pn = {xo + dx, yo + dy}
- 即
-
H 在 以后地位 与 指定地位 之间绘制一条 程度线段,指定地位 由
x
参数 和 以后地位的y
坐标指定- 即
Po = Pn = {x, yo}
- 即
-
h 在 以后地位 与 指定地位 之间绘制一条 程度线段,指定地位 由 以后地位 沿 x 轴偏移
dx
的x
坐标 和 以后地位 的y
坐标指定- 即
Po = Pn = {xo + dx, yo}
- 即
-
V 在 以后地位 与 指定地位 之间绘制一条 垂直线段,指定地位 由
y
参数和 以后地位 的x
坐标指定- 即
Po = Pn = {xo, y}
- 即
-
v 在 以后地位 与 指定地位 之间绘制一条 垂直线段,指定地位 由 以后地位 沿 y 轴偏移
dy
的y
坐标 和 以后地位 的x
坐标指定- 即
Po = Pn = {x, yo + dy}
- 即
<svg>
<path
fill="none"
stroke="#f40"
stroke-width="10"
d="M 10,10
L 100,100
V 10
H 30"
/>
</svg>
三次贝塞尔曲线
三次 贝塞尔曲线 是应用 四个点 定义的平滑曲线,绘制实现后 起点(Pn) 将成为下一个命令中的 以后地位(Po):
-
起始点(以后地位) — 第一个点
(Po = {xo, yo})
-
起点 — 第二个点
(Pn = {xn, yn})
-
起始控制点 — 第三个点
(*Pcs* = {xcs, ycs})
(管制在终点左近的曲线的曲率) -
起点控制点 — 第四个点
(Pce = {xce, yce})
(管制在起点左近的曲线的曲率)
其对应的命令如下:
-
C
- 在 以后地位 和 起点 x,y 之间绘制一条三次贝塞尔曲线,起始控制点 通过 x1,y1 指定, 起点控制点 通过 x2,y2 指定
- 参数模式为
(x1,y1, x2,y2, x,y)
,各点示意 **`Po = Pn = {x, y};
Pcs = {x1, y1};Pce = {x2, y2}`**
-
c
- 在 以后地位 和 起点 (以后地位沿 x 轴偏移 dx、沿 y 轴偏移 dy 处)之间绘制一条三次贝塞尔曲线, 起始控制点 为以后地位沿 x 轴偏移 dx1、沿 y 轴偏移 dy1 处; 起点控制点 为以后地位沿 x 轴偏移 dx2、沿 y 轴偏移 dy2 处
- 参数模式为
(dx1,dy1, dx2,dy2, dx,dy)
,各点示意Po = Pn = {xo + dx, yo + dy};Pcs = {xo + dx1, yo + dy1};Pce = {xo + dx2, yo + dy2}
-
S
- 在 以后地位 和 起点 x,y 之间绘制一条平滑的三次贝塞尔曲线,起点控制点 通过 x2,y2 指定, 起始控制点 是上一条曲线命令的起点控制点在以后地位上的 反射点 ;若上一条命令不是曲线命令,则其与曲线的 起始点(以后地位) 雷同
- 参数模式为
(x2,y2, x,y)
-
s
- 在 以后地位 和 起点 (以后地位沿 x 轴偏移 dx、沿 y 轴偏移 dy 处)之间绘制一条平滑的三次贝塞尔曲线, 起点控制点 为以后地位沿 x 轴偏移 dx2、沿 y 轴偏移 dy2 处; 起始控制点 是上一条曲线命令的起点控制点在以后地位上的 反射点 ;若上一条命令不是曲线命令,则其与曲线的 起始点(以后地位) 雷同
- 参数模式为
(dx2,dy2, dx,dy)
<svg>
<path
fill="none"
stroke="red"
d="M 10,90
C 30,90 25,10 50,10
S 70,90 90,90"
/>
<path
fill="none"
stroke="red"
d="M 110,90
c 20,0 15,-80 40,-80
s 20,80 40,80"
/>
</svg>
二次贝塞尔曲线
二次 贝塞尔曲线 是应用 三个点 定义的平滑曲线,绘制实现后 起点(Pn) 将成为下一个命令中的 以后地位(Po):
- 起始点(以后地位)
Po = {xo, yo}
— 第一个点 - 起点
Pn = {xn, yn}
— 第二个点 -
控制点 — 第三个点
Pc = {xc, yc}(管制曲率)
其对应命令如下:
-
Q
- 在 以后地位 和 起点 x,y 之间绘制一条二次贝塞尔曲线,控制点 通过 x1,y1 指定
- 参数模式为
(x1,y1, x,y)
,各点示意Po = Pn = {x, y};Pc = {x1, y1}
-
q
- 在 以后地位 和 起点 (以后地位沿 x 轴偏移 dx、沿 y 轴偏移 dy 处)之间绘制一条二次贝塞尔曲线, 控制点 为 以后地位(曲线的起始点)沿 x 轴偏移 dx1、沿 y 轴偏移 dy1 处
- 参数模式为
(dx1,dy1, dx,dy)
,各点示意Po = Pn = {xo + dx, yo + dy};Pc = {xo + dx1, yo + dy1}
-
T
- 在 以后地位 和 起点 x,y 之间绘制一条平滑的二次贝塞尔曲线,控制点 是上一条曲线命令的控制点在以后地位上的 反射点 ;若上一条命令不是曲线命令,则其与曲线的 起始点(以后地位) 雷同
- 参数模式为
(x, y)
,各点示意Po = Pn = {x, y}
-
t
- 在 以后地位 和 起点 (以后地位沿 x 轴偏移 dx、沿 y 轴偏移 dy 处)之间绘制一条平滑的二次贝塞尔曲线, 控制点 是上一条曲线命令的控制点在以后地位上的 反射点 ;若上一条命令不是曲线命令,则其与曲线的 起始点(以后地位) 雷同
- 参数模式为
(dx, dy)
,各点示意Po = Pn = {xo + dx, yo + dy}
<svg>
<path
fill="none"
stroke="red"
d="M 10,50
Q 25,25 40,50
t 30,0 30,0 30,0 30,0 30,0"
/>
</svg>
椭圆曲线
椭圆曲线 实际上就是用来定义为椭圆的一部分的曲线,当须要绘制 高度规定的曲线 时应用 椭圆曲线 相比于 贝塞尔曲线 会更容易:
-
A
- 在 以后地位 和 坐标
x
,y
之间绘制一条椭圆曲线,用于绘制圆弧的椭圆核心依据命令的其余参数确定,参数模式 (rx ry angle large-arc-flag sweep-flag x y) - 坐标
x
,y
将成为下一个命令中的以后地位
- 在 以后地位 和 坐标
-
a
- 在 以后地位 和 指定地位 之间绘制一条椭圆曲线, 指定地位 为以后地位沿 x 轴偏移
dx
、沿 y 轴偏移dy
处,用于绘制圆弧的椭圆核心依据命令的其余参数确定,参数模式 (rx ry angle large-arc-flag sweep-flag dx dy) - 坐标
dx
,dy
将成为下一个命令中的以后地位
- 在 以后地位 和 指定地位 之间绘制一条椭圆曲线, 指定地位 为以后地位沿 x 轴偏移
A 和 a 独特参数示意如下:
rx
和ry
是椭圆的两个半径angle
示意椭圆绝对于x
轴的旋转角度-
large-arc-flag
和sweep-flag
容许抉择必须绘制的弧线,因为其余参数能够绘制4
条可能的弧线large-arc-flag
容许抉择 一个 大弧线 (1)或 一个 小弧线(0)sweep-flag
容许抉择一条 顺时针 旋转的 弧线 (1)或一条 逆时针 旋转的 弧线(0)
<svg stroke-width="4">
<path
fill="none"
stroke="red"
d="M 150,50
A 150 50 10 1 0 14,10"
/>
<path
fill="none"
stroke="lime"
d="M 150,50
A 150 50 10 1 1 14,10"
/>
<path
fill="none"
stroke="purple"
d="M 150,50
A 150 50 10 0 1 14,10"
/>
<path
fill="none"
stroke="pink"
d="M 150,50
A 150 50 10 0 0 14,10"
/>
</svg>
ClosePath
ClosePath 命令将从 以后地位 绘制一条 直线 到 门路中的 第一个点,其对应的命令为 Z 或 z,没有什么参数,并且大小写不敏感。
<svg stroke-width="3">
<path
fill="pink"
stroke="red"
d="M 150,50
l -10,50 80,0
z"
/>
</svg>
根底案例实际
因为文章篇幅无限,第一个案例会说得细一些,后续的案例就不再一一详细分析了。
环形进度条
这个应该是比拟常见的一个需要了,然而如果不让应用组件库你打算怎么实现?
要是没有理解 SVG 之前,恐怕连这么个看似简略的成果都不好实现,然而当初咱们能够借助 SVG 来实现,或者咱们先来看看组件库是怎么实现的:
以上是 ElementUi 中的实现,没错就是 SVG,当初你晓得其实你我的项目里始终都有在用 SVG 了吧!
简略剖析
- 整体能够看成是 两个圆形 重叠,因而能够通过
<circle>
元素实现(也能够抉择<path>
元素,如上述给出的例图) -
<circle>
元素默认是会绘制整个圆,然而进度条必定不是一开始就是 100% 的,因而能够应用 stroke-dashoffset 属性 来将残缺的圆变成局部的,然而间接应用 stroke-dashoffset 属性是不会失效的,因为它要配合 stroke-dasharray 属性 一起来应用stroke-dashoffset
:指定 dash 模式 到 门路开始 的间隔stroke-dasharray
:管制用来描边的 点划线 的图案范式,其实你齐全能够联合border: 1px solid dash
来了解,就是用于将一段间断的内容变成非间断的,设置了它就开启了 dash 模式
动态实现
<svg stroke-width="5">
<!-- 背景圆形 -->
<circle cx="150" cy="75" r="50" stroke="#ebeef5" fill="none"></circle>
<!-- 进度条 -->
<circle
class="process-circle"
cx="150"
cy="75"
r="50"
stroke="#20a0ff"
transform="rotate(-90 150 75)"
fill="none"
stroke-dasharray="314"
stroke-dashoffset="314"
></circle>
</svg>
增加动画
通过以上的形式就实现了一个动态的环形进度条了,接下来就须要它动起来,因为 stroke-dasharray(在这它的值其实就是圆的周长
) 和 stroke-dashoffset 的属性值是须要动静生成的,因而咱们得增加一些 JavaScript 代码:
function setProcessCircle(percent = 0) {const processCircle = document.querySelector('.process-circle')
// 获取圆的周长
const circumference = processCircle.getTotalLength()
// 把周长赋值给 strokeDasharray
processCircle.style.strokeDasharray = circumference
// 动静计算 offset 赋值给 strokeDashoffset
// 为了反对 percent = 0 | '0%',所以应用 parseInt 转换
processCircle.style.strokeDashoffset =
circumference * (1 - parseInt(percent) / 100)
}
效果图中的 html + css
局部就不贴出来了,容易占篇幅。
loading 动画
例如 ElementUI 中 区域加载 的 loading 模式如下:
简略剖析
- 察看整体不难发现只须要一个圆形,即应用
<circle>
元素即可 - 其蓝色局部始终在 缩短 或 增长,这点能够通过 stroke-dasharray 和 stroke-dashoffset 属性来实现,同时增加
transition
过渡动画即可 - 最初是每个 缩短 或 增长 的地位不是雷同的,那么能够间接用过动画
animation
和roate
来实现停的旋转即可
具体实现
// html
<svg stroke-width="3">
<circle
cx="50"
cy="50"
r="20"
fill="none"
class="circle-loading"
></circle>
</svg>
// style
<style>
.circle-loading {
stroke-dasharray: 90, 150;
stroke-dashoffset: 0;
stroke: #409eff;
stroke-linecap: round;
animation: loading-dash 1.5s ease-in-out infinite,
laoding-color 1.5s ease-in-out infinite;
}
@keyframes laoding-color {
0% {stroke: #de3e35;}
25% {stroke: #ffa500;}
50% {stroke: #ffff00;}
75% {stroke: #008000;}
100% {stroke: #0000ff;}
}
@keyframes loading-dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -40px;
}
to {
stroke-dasharray: 90, 150;
stroke-dashoffset: -120px;
}
}
</style>
按钮动效
简略剖析
- 外层包裹的矩形能够通过
<rect>
元素实现 - 矩形的线条完好不残缺,能够通过 stroke-dasharray 和 stroke-dashoffset 属性来实现
- 当鼠标搁置下来时,产生的动画可通过 animation、stroke-dasharray、stroke-dashoffset 等属性联合即可
具体实现
// html
<svg class="svg-wrap">
<text class="text" x="60" y="75">CLICK HERE</text>
<rect class="rect" x="40" y="35" />
</svg>
// style
<style>
.svg-wrap {
stroke-width: 3px;
background-color: black;
}
.rect {
height: 60px;
width: 220px;
stroke: #fff;
fill: transparent;
stroke-dasharray: 220 60;
stroke-dashoffset: -260;
stroke-width: 4px;
}
.text {
fill: #1287f4;
font-size: 30px;
}
.svg-wrap:hover .rect {animation: line-move 0.5s linear forwards;}
.svg-wrap:hover .text{
fill: #fff;
transition: all 1s ease-in-out;
}
@keyframes line-move {
0% {
stroke-dasharray: 220 60;
stroke-dashoffset: -260;
stroke-width: 4px;
stroke: #e32727;
}
to {
stroke-dasharray: 560;
stroke-dashoffset: 0;
stroke-width: 2px;
stroke: #1234f4;
}
}
</style>
简单案例实战
以上的根底案例因为波及的计算不多,因而咱们能够人工进行计算宽、高、偏移等等数据,然而针对简单的内容,很多参数就不是那么容易计算出来了,因而,咱们须要一些工具来疾速失去一些必要参数,而后咱们在基于这些必要参数取做批改,让其产生更丰盛的成果即可。
工具举荐
和 SVG 相干的工具就当初来说曾经遍地开花了(就如同当初的 ChatGPT、文心一言
),通过搜索引擎查找都能找进去很多,这里也不谈这些工具的优劣了,上面简略列举一些:
- figma:反对浏览器在线,反对客户端下载
- sketch:反对浏览器在线,反对客户端下载(Mac)
- Adobe Illustrator:反对浏览器在线,反对客户端下载
- Pixso:号称 Sketch 的新抉择,简直还原了 Sketch 的业余性能
- …
上面的示例都是基于 figma 来演示的,不再后续赘述。
文字动效
还是同样的第一个案例这里尽量讲具体点,后续案例就不再述说过于具体的内容了。
应用 figma 创立文字门路如下
因为文字内容的门路很难间接计算解决,因而咱们能够通过 figma 来帮忙咱们生成相应的文字门路,大抵操作如下:
解决 SVG 代码内容
失去的 SVG 内容大抵如下,代码内容比拟多这里用图片代替,其中各个内容的对应关系如下所示:
其中的 <mask>
须要去掉,否则文字的色彩值将无奈填充。
stroke-dasharray & stroke-dashoffset 属性
因为咱们须要让文字具备断续连贯的能力,这里还是得应用后面提到 stroke-dasharray 和 stroke-dashoffset 属性来实现,它们的性能后面曾经形容过了,也用了几次了,如果你不记得了能够回过头去看看。
然而这里的 stroke-dasharray 和 stroke-dashoffset 的值到底该设置成多少呢?
首先肯定是设置成每个文字的长度,那么问题就变成了怎么获取文字的长度了,不必放心,还记得在实现 环形进度条 时用到的 getTotalLength() 办法吗?
这里咱们依然能够应用它来获取每个文字的长度了,代码如下:
const paths = document.querySelectorAll('path')
for (const [ptah,index] of paths) {console.log(`path 的门路长度 = ${ptah.getTotalLength()}`)
}
输入后果:path 的门路长度 = 179.47874450683594 S
path 的门路长度 = 150.7733917236328 V
path 的门路长度 = 274.966064453125 G
path 的门路长度 = 442.99505615234375 文
path 的门路长度 = 514.3809204101562 字
接下来为每个 path 设置款式:
#svg-text > path:nth-of-type(1) {
stroke-dasharray: 179.479;
stroke-dashoffset: 179.479;
}
#svg-text > path:nth-of-type(2) {
stroke-dasharray: 150.773;
stroke-dashoffset: 150.773;
}
#svg-text > path:nth-of-type(3) {
stroke-dasharray: 274.966;
stroke-dashoffset: 274.966;
}
#svg-text > path:nth-of-type(4) {
stroke-dasharray: 442.995;
stroke-dashoffset: 442.995;
}
#svg-text > path:nth-of-type(5) {
stroke-dasharray: 514.381;
stroke-dashoffset: 514.381;
}
设置了这些值之后,文字内容就会不可见了,而这也是 动画的初始状态。
animation 动画
后面种种操作曾经实现了动画的初始状态,接下来咱们要增加上 animation 动画,外围扭转的就是 stroke-dashoffset 的值,就是把它设置成 0,文字内容就会被从暗藏变成显示,再增加过渡工夫就实现了,反复内容就不贴出来了:
#svg-text > path:nth-of-type(1) {
/* ... */
animation: text-line 2s ease forwards;
}
#svg-text > path:nth-of-type(2) {
/* ... */
animation: text-line 2s ease forwards 300ms;
}
#svg-text > path:nth-of-type(3) {
/* ... */
animation: text-line 2s ease forwards 600ms;
}
#svg-text > path:nth-of-type(4) {
/* ... */
animation: text-line 2s ease forwards 900ms;
}
#svg-text > path:nth-of-type(5) {
/* ... */
animation: text-line 2s ease forwards 1200ms;
}
#svg-text{
stroke: #d205f7;
fill: none;
animation: fill-color 2.5s ease-in forwards;
}
@keyframes text-line {
to {stroke-dashoffset: 0;}
}
@keyframes fill-color{
to{
stroke: transparent;
fill: #d205f7;
}
}
反复的事交给 JavaScript
下面才 5 个文字就须要写那么多的款式,属实不能忍,于是咱们能够将反复的局部交给 JavaScript 代码去解决:
<style>
#svg-text {
stroke: #d205f7;
stroke-width: 2px;
fill: none;
animation: fill-color 2.5s ease-in forwards;
}
@keyframes text-line {
to {stroke-dashoffset: 0;}
}
@keyframes fill-color {
to {
stroke: transparent;
fill: #d205f7;
}
}
</style>
<script>
function init() {const paths = Array.from(document.querySelectorAll('path'))
paths.forEach((path, index) => {const len = path.getTotalLength()
path.style.strokeDasharray = len
path.style.strokeDashoffset = len
path.style.animation = `text-line 2.5s ease-in forwards ${index * 300}ms`
})
}
init()
</script>
静止轨迹
简略剖析
实现以上成果须要包含以下几个内容:
- 获取 指标物 的 SVG 代码
- 绘制 静止门路
-
让指标物 沿着门路静止
获取指标物的 SVG 代码
这个能够间接从 iconfont 上抉择对应的内容,而后复制它的 SVG 代码。
绘制静止门路
静止门路的绘制咱们依然能够通过 SVG 工具 figma 来获取,值得注意的是默认的门路是用还是填充的,真正在利用时能够通过 stroke="transparent"
将门路色彩变成通明色,整体感官更好,大抵如下:
让指标物沿着门路静止
针对这种按特定静止轨迹进行的动画,也不须要你去一点点计算了,咱们能够借助 GreenSock 中的 motionpath 插件来实现,在其对应的文档中有具体的介绍,外围就是引入以下两个内容:
<div id="app">
<!-- 鸟 -->
<svg
id="bird"
t="1679665908640"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="14202"
width="100"
height="100"
>
省略内容
</svg>
<!-- 门路 -->
<svg
width="719"
height="419"
viewBox="0 0 719 419"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
id="path"
d="M1 268C146.006 483.259 245.695 450.805 336 268C518.233 -96.9549 599.902 -63.7284 718 222"
stroke="transparent"
/>
</svg>
</div>
<script src="https://unpkg.co/gsap@3/dist/gsap.min.js"></script>
<script src="https://unpkg.com/gsap@3/dist/MotionPathPlugin.min.js"></script>
<script>
// 注册插件
gsap.registerPlugin(MotionPathPlugin);
// 开启动画
gsap.to("#bird", {
duration: 5,
repeat: 12,
repeatDelay: 1,
yoyo: true,
ease: "power1.inOut",
motionPath: {
path: "#path",
align: "#path",
alignOrigin: [0.5, 0.5],
},
});
</script>
最初
欢送关注同名公众号《熊的猫》,后续文章会同步更新!
以上就是本文无关 SVG 根底局部的介绍和应用了,不晓得你是入门了,还是被门绊了一下,还是那句话:心愿本文对你所有帮忙!!!