svg path 详解

发布时间:2024年01月18日


path 可能是 SVG 中最常见的形状。svg 提供的基本图形包括矩形(包括圆角矩形)、圆形、椭圆、折线、多边形等基础图形都可以通过 path 来绘制。不仅如此,path 还可以用来绘制一些比较复杂但是很常见的图形比如贝塞尔曲线、二次曲线等。path 的功能很强大,但是使用起来也有点复杂,因此这里详细讲解一下 path 命令的意义及使用。

总览

命令命令表达
Mmoveto 起始
Llineto 直线段
Vvertical lineto 垂直线
Hhorizontal lineto 水平线
Ccurveto 三次贝塞尔曲线
Ssmooth curveto 三次贝塞尔曲线
Qquadratic Bézier curve 二次贝塞尔曲线
Tsmooth quadratic Bézier curveto 二次贝塞尔曲线
Aelliptical Arc 椭圆弧
Zclose path 闭合

命令可以大写,也可以小写,大小写的区别在于,大写表示绝对位置,小写表示相对位置。

直线命令

<path> 元素里面有 5 个画直线的命令,也就是在两个点之间画一条直线段。

命令命令表达效果
Mmoveto 起始移动画笔,但不画线
Llineto 直线段在上一点和当前点直接画一条线段
Vvertical lineto 垂直线垂直方向平移点并连线
Hhorizontal lineto 水平线水平方向平移点并连线
Zclose path 闭合通过连接起始点和终点来闭合曲线

其中能够真正画出线的命令只有三个,分别是 LHV

M

M x y
(or)
m x y

M 需要两个参数,分别是移动到点的坐标 xy。在使用 M 命令后,只会移动画笔,但不会在两点之间画线。所以 M 命令经常出现在路径的开始处,用来指明从何处开始绘制一个路径

H

H x
(or)
h dx

H 命令用于绘制水平线,因为它只在水平方向上移动,因此这个命令只需要一个参数。

V

V y
(or)
v dy

和 H 命令类似,V 命令只在垂直方向上移动,因此只需要一个参数。

Z

Z
(or)
z

Z 命令会从当前点画一条直线到路径的起点,在需要闭合路径的时候,可以将 Z 放置到路径的最后。此外,Z 命令不用区分大小写(因为闭合的方式是确定的,只能是从当前点到路径起点的一条直线段)。

实例

下面例子使用 path 来绘制一个矩形:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg">

<path d="M 10 10 H 90 V 90 H 10 Z" 
style="fill:none;stroke:blue;stroke-width:2" />

<path d="M 10 10 h 80 v 80 h -80 Z"
fill="yellow" />

</svg>

上面的代码中,分别使用绝对位置和相对位置,在同一个地方绘制了两个矩形,一个只有边框,一个只有填充,在浏览器中打开可以看到如下显示结果(虚线表示窗口,后面例子不再做此声明):

下面来解释一下上面两个路径的位置信息是如何对应到图形是的每一点(这一段有点废话,熟悉上面命令的可以不用看,直接下滑看曲线部分的内容)
先来看第一个的路径,路径中所有命令都是使用大写形式,因此命令后的参数均表示绝对位置:

<path d="M 10 10 H 90 V 90 H 10 Z" 
style="fill:none;stroke:blue;stroke-width:2" />

路径中第一个命令 “M 10 10” 表示将画笔移动到坐标 (10, 10) 的位置,我在图中用一个小红点把这个位置标记了出来,这个小红点所在位置就是当前路径的起点:

紧接着第二个命令 “H 90“ 表示,在上一个点的基础上(也就是起始点 (10, 10)),将水平方向上坐标移动到 x=90 的位置,而垂直方向的坐标保持不变,因此,第二个点的坐标是 (90, 10),也就是下图所标识的位置:

第三个命令 “V 90“ ,这是在第二个点 (90, 10) 的基础上,保持水平坐标不变,垂直方向移动到 y=90 的位置:

第四个命令 “H 10“ 修改上一点 (90, 90) 水平方向的坐标为 x=10, 这个时候的路径应该是下面这样,红点是当前位置:

最后一个命令 “Z“ 在起始点和当前点之间连接一条线段,将路径闭合,至此,这个路径绘制完毕。

现在看第二个路径:

<path d="M 10 10 h 80 v 80 h -80 Z"
fill="yellow" />

第二个路径中的命令使用的是小写形式,这表示路径后的参数表示的是当前点相对上一点的偏移距离,也就是相对信息。依旧对这个路径中的命令进行拆解。
第一个命令和上面是一样的,就不重复叙述了,起始点坐标 (10, 10)。
第二个命令 “h 80“ 表示的是,水平方向上偏移长度为 80 的一段距离,因此新的位置为 (10+80, 10):

第三个命令 “ v 80“ ,表示在第二个点 (90, 10) 的基础上,垂直方向 偏移长度为 80 的一段距离:

第四个命令 “h -80“ 将上一点 (90, 90) 在水平方向上反向偏移长度为 80 的距离:

最后一个命令 “Z“ 将当前路径闭合,命令 Z 不区分大小写,因此这里用小写也是可以的。

曲线命令

<path> 中支持贝塞尔曲线和椭圆弧。贝塞尔曲线的类型有很多,但是 <path> 中只存在两种:三次贝塞尔和两次贝塞尔。

命令命令表达
Ccurveto 三次贝塞尔曲线
Ssmooth curveto 三次贝塞尔曲线
Qquadratic Bézier curve 二次贝塞尔曲线
Tsmooth quadratic Bézier curveto 二次贝塞尔曲线
Aelliptical arc 椭圆弧

A

A rx ry x-axis-rotation large-arc-flag sweep-flag x y
(or)
a rx ry x-axis-rotation large-arc-flag sweep-flag dx dy

各参数表示的含义见下面表格:
椭圆弧的各个参数
命令 M 用于用于绘制弧形,弧形可以视为圆形或椭圆形的一部分。rxry 分别是 x 轴和 y 轴半径,x-axis-rotation 表示弧形的旋转情况,可以参考下面的例子:

<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg">

<path d="M 10 200 
         L 40 170 
         A 20 40 0 0 1 85 125 
         L 110 100 
         A 20 40 -45 0 1 145 65
         L 190 20" 
        stroke="black" fill="yellow"
        stroke-width="2" />
</svg>

上面文件在浏览器中打开显示结果如下,路径中包含两段椭圆弧,其中第一段的旋转角度 x-axis-rotation=0,第二段的旋转角度 x-axis-rotation=-45°,所以这是一个旋转了 45 度的椭圆,注意这里用的是角度而不是弧度(虚椭圆弧是我另外补充的,主要是为了能够看得更清晰一些):

在一般情况下,给定 rxry、弧线起点和弧线终点四个参数时,可以画出两个椭圆,四种弧形(如果交线刚好穿过椭圆中心,此时两个椭圆重合,那就是两种弧形,那属于特殊情况,这里讨论的是普遍情况),如下图所示:

上面提到的四种弧线由 large-arc-flag(角度大小)sweep-flag(弧线方向) 这两个参数实现的。下图展示了这四种情况:
四种情况的弧型

弧形可以简单地创建圆形或者椭圆形图标,比如可以创建若干片弧形组成一个饼图。不过如果需要绘制完整的圆或者椭圆,使用 svg 提供的 circle 或者 ellipse 元素会更容易一些。

Q

Q x1 y1, x y
(or)
q dx1 dy1, dx dy

Q 用来绘制二次贝塞尔曲线,它需要两个参数:控制点坐标和终点坐标,用于确定起点和终点的曲线斜率。

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<path d="M 10 80 Q 95 10 180 80" 
    stroke-width="2" stroke="black" fill="none" />
<text x="105" y="15" fill="red">(95, 10)</text>
<circle cx="95" cy="10" r="2" fill="red" />
<path d="M 10 80 L 95 10 L 180 80" stroke="red" 
    stroke-dasharray="3,3" fill="none" />
</svg>

上面代码绘制了如下一条曲线,这里我标出了控制点的位置:

(95, 10)

T

可以通过将若干贝塞尔曲线连接起来,从而创建出一条很长的平滑曲线。通常情况下,一个点某一侧的控制点是它另一侧的控制点的对称(以保持斜率不变),因此可以使用一个简写的贝塞尔曲线命令 T

T x y
(or)
t dx dy

T 命令可以用来创建与前面一样的贝塞尔曲线,如果 T 命令跟在一个 Q 或者 T 命令后面,则它的控制点会被假设成前一个命令曲线的控制点的中心对称点。

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg">

<path d="M 10 80 Q 95 10 180 80 T 280 75"
    stroke-width="2" stroke="black" fill="none" />
    
</svg>

上面代码绘制了一段连续的曲线,其中标记为蓝色的控制点是根据前一个控制点推断出来的。

(95, 10) (265, 150)

这就是说,在第一个控制点后面,可以只定义终点,就创建出一个相当复杂的曲线,需要注意的是,T 命令前面必须是 Q 命令或者另一个 T 命令,才能达到这种效果,如果 T 单独使用,那么控制点就会被认为和终点是同一个点,所以画出来的将是一条直线。(可以自己写个代码试试,这里不做举例)

C

另一种稍微复杂一点的曲线是三次贝塞尔曲线 C,三次贝塞尔曲线需要定义一个点和两个控制点,所以需要设置三组坐标参数:

C x1 y1, x2 y2, x y
(or)
c dx1 dy1, dx2 dy2, dx dy

前两组坐标表示起点和终点的控制点,最后一组坐标 (x,y)/(dy,dy) 表示的是曲线的终点,参考下面的例子:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg">

<g stroke="black" fill="none" stroke-width="2">
	<path d="M 40 40 C 75 80, 125 80, 160 40" />
    <g transform="translate(180, 0)">
    	<path d="M 40 40 C 75 80, 125 10, 160 40" />
    </g>
</g>
</svg>

上面代码绘制了如下两条曲线,这里我标出了两个控制点、起点和终点。注意观察,曲线沿着起点到第一个控制点的方向伸出,逐渐弯曲,然后沿着第二个控制点到终点的方向结束。

S

S x2 y2, x y
(or)
s dx2 dy2, dx dy

二次贝塞尔曲线 Q 有一个快捷命令 T,同样 C 也有一个快捷命令 S。不同的是,如果 S 命令跟在一个 C 或 S 命令后面,则它的第一个控制点会被假设成前一个命令曲线的第二个控制点的中心对称点。如果 S 命令单独使用,前面没有 C 或 S 命令,那当前点将作为第一个控制点。参考下面的代码:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg">

<path d="M 20 80 C 50 20, 80 20, 115 80 S 160 140, 180 80" 
    stroke="black" fill="none" />

</svg>

下图显示了示例代码中的曲线及控制点,其中蓝色标记点就是根据前一段曲线的第二个控制点推断出来的。

虽然三次贝塞尔曲线拥有更大的自由度,但是两种曲线能达到的效果总是差不多的。具体使用哪种曲线取决于需求以及对曲线对称性的依赖程度。

文章来源:https://blog.csdn.net/wenrui7868/article/details/135531575
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。