路径命令
路径命令是对要绘制的路径的说明,每一个命令由代表命令的字母和代表参数的 数字 组成,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
将成为下一个命令中的当前位置
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> 复制代码