路径

The <path> element is the most powerful element in the SVG library of basic shapes. It can be used to create lines, curves, arcs, and more.

Paths create complex shapes by combining multiple straight lines or curved lines. Complex shapes composed only of straight lines can be created as <polyline> elements. While <polyline> and <path> elements can create similar-looking shapes, <polyline> elements require a lot of small straight lines to simulate curves and don't scale well to larger sizes.

A good understanding of paths is important when drawing SVGs. While creating complex paths using an XML editor or text editor is not recommended, understanding how they work will allow to identify and repair display issues in SVGs.

The shape of a <path> element is defined by one parameter: d. (See more in basic shapes.) The d attribute contains a series of commands and parameters used by those commands.

Each of the commands is instantiated (for example, creating a class, naming and locating it) by a specific letter. For instance, let's move to the x and y coordinates (10, 10). The "Move to" command is called with the letter M. When the parser runs into this letter, it knows it needs to move to a point. So, to move to (10, 10) the command to use would be M 10 10. After that, the parser begins reading for the next command.

All of the commands also come in two variants. An uppercase letter specifies absolute coordinates on the page, and a lowercase letter specifies relative coordinates (e.g., move 10px up and 7px to the left from the last point).

Coordinates in the d parameter are always unitless and hence in the user coordinate system. Later, we will learn how paths can be transformed to suit other needs.

直线命令

There are five line commands for <path> nodes. The first command is the "Move To" or M, which was described above. It takes two parameters, a coordinate (x) and coordinate (y) to move to. If the cursor was already somewhere on the page, no line is drawn to connect the two positions. The "Move To" command appears at the beginning of paths to specify where the drawing should start. For example

M x y
(or)
m dx dy

In the following example there's only a point at (10, 10). Note, though, that it wouldn't show up if a path was just drawn normally. For example

A red dot is drawn on a white square 10 pixels down and 10 pixels to the right. This dot would not normally show but is used as an example of where the cursor will start after the "Move To" command

xml
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">

  <path d="M10 10"/>

  <!-- Points -->
  <circle cx="10" cy="10" r="2" fill="red"/>

</svg>

There are three commands that draw lines. The most generic is the "Line To" command, called with L. L takes two parameters—x and y coordinates—and draws a line from the current position to a new position.

L x y
(or)
l dx dy

There are two abbreviated forms for drawing horizontal and vertical lines. H draws a horizontal line, and V draws a vertical line. Both commands only take one parameter since they only move in one direction.

H x
(or)
h dx

V y
(or)
v dy

An easy place to start is by drawing a shape. We will start with a rectangle (the same type that could be more easily made with a <rect> element). It's composed of horizontal and vertical lines only.

A square with black fill is drawn within a white square. The black square's edges begin at position (10,10), move horizontally to position (90,10), move vertically to position (90,90), move horizontally back to position (10,90), and finally move back to the original position (10, 10).

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

  <path d="M 10 10 H 90 V 90 H 10 L 10 10"/>

  <!-- Points -->
  <circle cx="10" cy="10" r="2" fill="red"/>
  <circle cx="90" cy="90" r="2" fill="red"/>
  <circle cx="90" cy="10" r="2" fill="red"/>
  <circle cx="10" cy="90" r="2" fill="red"/>

</svg>

We can shorten the above path declaration a little bit by using the "Close Path" command, called with Z. This command draws a straight line from the current position back to the first point of the path. It is often placed at the end of a path node, although not always. There is no difference between the uppercase and lowercase command.

Z
(or)
z

So our path above could be shortened to

xml
 <path d="M 10 10 H 90 V 90 H 10 Z" fill="transparent" stroke="black"/>

The relative forms of these commands can also be used to draw the same picture. Relative commands are called by using lowercase letters, and rather than moving the cursor to an exact coordinate, they move it relative to its last position. For instance, since our rectangle is 80×80, the <path> element could have been written as

xml
 <path d="M 10 10 h 80 v 80 h -80 Z" fill="transparent" stroke="black"/>

The path will move to point (10, 10) and then move horizontally 80 points to the right, then 80 points down, then 80 points to the left, and then back to the start.

In these examples, it would probably be simpler to use the <polygon> or <polyline> elements. However, paths are used so often in drawing SVG that developers may be more comfortable using them instead. There is no real performance penalty or bonus for using one or the other.

曲线命令

There are three different commands that can be used to create smooth curves. Two of those curves are Bézier curves, and the third is an "arc" or part of a circle. You might have already gained practical experience with Bézier curves using path tools in Inkscape, Illustrator or Photoshop. There are an infinite number of Bézier curves, but only two simple ones are available in <path> elements: a cubic one, called with C, and a quadratic one, called with Q.

贝塞尔曲线

三次贝塞尔曲线 C 稍微复杂一些。三次贝塞尔曲线每个点需要两个控制点。因此,要创建三次贝塞尔曲线,需要指定三组坐标。

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

这里最后一组坐标(xy)指定了线条的结束位置。另外两组是控制点。(x1y1)是曲线起点处的控制点,(x2y2)是曲线终点处的控制点。控制点本质上描述了从每个点开始的线条的斜率。贝塞尔函数然后创建一个平滑的曲线,从线条开始处的斜率过渡到线条结束处的斜率。

Cubic Bézier Curves with grid

xml
<svg width="190" height="160" xmlns="http://www.w3.org/2000/svg">

  <path d="M 10 10 C 20 20, 40 20, 50 10" stroke="black" fill="transparent"/>
  <path d="M 70 10 C 70 20, 110 20, 110 10" stroke="black" fill="transparent"/>
  <path d="M 130 10 C 120 20, 180 20, 170 10" stroke="black" fill="transparent"/>
  <path d="M 10 60 C 20 80, 40 80, 50 60" stroke="black" fill="transparent"/>
  <path d="M 70 60 C 70 80, 110 80, 110 60" stroke="black" fill="transparent"/>
  <path d="M 130 60 C 120 80, 180 80, 170 60" stroke="black" fill="transparent"/>
  <path d="M 10 110 C 20 140, 40 140, 50 110" stroke="black" fill="transparent"/>
  <path d="M 70 110 C 70 140, 110 140, 110 110" stroke="black" fill="transparent"/>
  <path d="M 130 110 C 120 140, 180 140, 170 110" stroke="black" fill="transparent"/>

</svg>

上面的例子创建了九条三次贝塞尔曲线。当曲线向右移动时,控制点水平方向上逐渐展开。当曲线向下移动时,它们与端点的距离越来越远。需要注意的是,曲线从第一个控制点方向开始,然后弯曲以便它沿着第二个控制点方向到达。

可以将多个贝塞尔曲线串联起来,创建扩展的平滑形状。通常情况下,点一边的控制点将是另一边使用的控制点的镜像,以保持斜率恒定。在这种情况下,可以使用三次贝塞尔曲线的简写版本,由命令 S(或 s)指定。

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

S 生成与之前相同的曲线类型 - 但如果它在另一个 S 命令或 C 命令之后,则假设第一个控制点是之前使用的控制点的镜像。如果 S 命令不在另一个 SC 命令之后,则将光标的当前位置用作第一个控制点。结果与使用相同参数的 Q 命令生成的曲线不同,但相似。

下面展示了这种语法的一个例子,在左侧的图中,指定的控制点以红色显示,推断的控制点以蓝色显示。

A smooth S-shaped curve is drawn from two Bézier curves. The second curve keeps the same slope of the control points as the first curve, which is reflected to the other side.

xml
<svg width="190" height="160" xmlns="http://www.w3.org/2000/svg">
  <path d="M 10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80" stroke="black" fill="transparent"/>
</svg>

另一种类型的贝塞尔曲线,即使用 Q 调用的二次曲线,实际上比三次曲线更简单。它需要一个控制点,该控制点确定曲线在起点和终点处的斜率。它需要两个参数:控制点和曲线的终点。

注意:q 的坐标增量都是相对于前一点的(也就是说,dxdy 不是相对于 dx1dy1 的)。

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

Quadratic Bézier with grid

xml
<svg width="190" height="160" xmlns="http://www.w3.org/2000/svg">
  <path d="M 10 80 Q 95 10 180 80" stroke="black" fill="transparent"/>
</svg>

与三次贝塞尔曲线一样,有一个简写方式可以将多个二次贝塞尔曲线串联起来,使用 T 调用。

T x y
(or)
t dx dy

此简写方式查看之前使用的控制点,并从该控制点推断出一个新的控制点。这意味着在第一个控制点之后,只需指定端点即可创建相当复杂的形状。

这只有在之前的命令是 QT 命令时才有效。如果不是,则假设控制点与前一点相同,并且只会绘制直线。

Two quadratic curves form one smooth S-shaped curve. The second curve's control points are reflected across the horizontal axis

xml
<svg width="190" height="160" xmlns="http://www.w3.org/2000/svg">
  <path d="M 10 80 Q 52.5 10, 95 80 T 180 80" stroke="black" fill="transparent"/>
</svg>

两种曲线都产生相似的结果,尽管三次曲线允许对曲线的具体形状有更大的自由度。决定使用哪种曲线取决于情况,并取决于线条的对称程度。

圆弧

使用 SVG 可以创建的另一种类型的曲线是圆弧,使用 A 命令调用。圆弧是圆或椭圆的一部分。

对于给定的 x 半径和 y 半径,有两个椭圆可以连接任意两点(只要它们在圆的半径内)。沿着这两个圆中的任何一个,都可以采取两种可能的路径来连接这些点 - 所以在任何情况下,都有四种可能的圆弧可用。

因此,圆弧需要相当多的参数。

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

在开始时,圆弧元素接受 x 半径和 y 半径的两个参数。如果需要,请参阅 <ellipse> 的行为方式。最后两个参数指定结束描边的 x 和 y 坐标。这四个值一起定义了圆弧的基本结构。

第三个参数描述了圆弧的旋转。这最好用一个例子来解释。

SVGArcs_XAxisRotation_with_grid

xml
<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg">
  <path d="M 10 315
           L 110 215
           A 30 50 0 0 1 162.55 162.45
           L 172.55 152.45
           A 30 50 -45 0 1 215.1 109.9
           L 315 10" stroke="black" fill="green" stroke-width="2" fill-opacity="0.5"/>
</svg>

此示例显示了一个 <path> 元素,它以对角线方式穿过页面。在它的中心,切出了两个椭圆圆弧(x 半径 = 30,y 半径 = 50)。在第一个圆弧中,x 轴旋转保持为 0,因此圆弧围绕的椭圆(以灰色显示)垂直向上和向下定向。然而,对于第二个圆弧,x 轴旋转设置为 -45 度。这将椭圆旋转,使其沿路径方向使其短轴对齐,如示例图像中的第二个椭圆所示。

对于上面的未旋转椭圆,只有两个不同的圆弧,而不是四个可供选择,因为从圆弧的起点和终点绘制的线穿过椭圆的中心。在一个稍微修改的示例中,可以看出形成四个不同圆弧的两个椭圆。

Show the 4 arcs on the Ellipse example

xml
<svg xmlns="http://www.w3.org/2000/svg" width="320" height="320">
  <path d="M 10 315
           L 110 215
           A 36 60 0 0 1 150.71 170.29
           L 172.55 152.45
           A 30 50 -45 0 1 215.1 109.9
           L 315 10" stroke="black" fill="green" stroke-width="2" fill-opacity="0.5"/>
  <circle cx="150.71" cy="170.29" r="2" fill="red"/>
  <circle cx="110" cy="215" r="2" fill="red"/>
  <ellipse cx="144.931" cy="229.512" rx="36" ry="60" fill="transparent" stroke="blue"/>
  <ellipse cx="115.779" cy="155.778" rx="36" ry="60" fill="transparent" stroke="blue"/>
</svg>

注意,每个蓝色椭圆都是由两个圆弧形成的,取决于顺时针或逆时针移动。每个椭圆都有一个短圆弧和一个长圆弧。这两个椭圆只是彼此的镜像。它们沿着从起点到终点的线翻转。

如果起点和终点的距离超过了椭圆的 xy 半径所能到达的距离,则椭圆的半径将被最小程度地扩展,以便它可以到达起点和终点。此页面底部的交互式 codepen 很好地演示了这一点。为了确定椭圆的半径是否足够大以至于需要扩展,需要求解方程组,例如 Wolfram Alpha 上的这个方程组。此计算适用于起点和终点为 (110215)→(150.71170.29) 的未旋转椭圆。解 (xy) 是椭圆的中心。如果椭圆的半径太小,则解将是 虚数。第二个计算适用于起点和终点为 (110215)→(162.55162.45) 的未旋转椭圆。解有一个小的虚数部分,因为椭圆只是略微扩展了。

上面提到的四种不同的路径由接下来的两个参数标志决定。如前所述,路径仍然可以围绕两个可能的椭圆进行,并且在两个椭圆上都有两个不同的可能路径,因此有四种可能的路径。第一个参数是 large-arc-flag。它决定圆弧是否大于或小于 180 度;最终,此标志决定圆弧将围绕给定圆圈向哪个方向移动。第二个参数是 sweep-flag。它决定圆弧是从正角度还是负角度开始移动,这本质上选择将围绕哪个圆圈进行移动。下面的示例显示了所有四种可能的组合,以及每种情况下的两个圆圈。

Four examples are shown for each combination of large-arc-flag and sweep-flag for two circles overlapping, one in the top right, the other in the bottom left. For sweep-flag = 0, when large-arc-flag = 0, the interior arc of the top right circle is drawn, and when large-arc-flag = 1, the exterior arc of the bottom left circle is drawn. For sweep-flag = 1, when large-arc-flag = 0, the interior arc of the bottom left circle is drawn, and when large-arc-flag = 1, the exterior arc of the top right circle is drawn.

xml
<svg width="325" height="325" xmlns="http://www.w3.org/2000/svg">
  <path d="M 80 80
           A 45 45, 0, 0, 0, 125 125
           L 125 80 Z" fill="green"/>
  <path d="M 230 80
           A 45 45, 0, 1, 0, 275 125
           L 275 80 Z" fill="red"/>
  <path d="M 80 230
           A 45 45, 0, 0, 1, 125 275
           L 125 230 Z" fill="purple"/>
  <path d="M 230 230
           A 45 45, 0, 1, 1, 275 275
           L 275 230 Z" fill="blue"/>
</svg>

圆弧是一种在绘图中创建圆或椭圆片段的简单方法。例如,饼图需要为每个片段使用不同的圆弧。

如果从 <canvas> 过渡到 SVG,圆弧可能是最难学习的东西,但也是功能最强大的。完整的圆和椭圆是 SVG 圆弧难以绘制的唯一形状。因为绕圆的任何路径的起点和终点都是同一点,所以可以选择无限多个圆,而实际路径是未定义的。可以通过使路径的起点和终点略微倾斜,然后用另一个路径段连接它们来近似这些形状。例如,可以使用每个半圆的圆弧来绘制一个圆。在这一点上,使用真正的 <circle><ellipse> 节点通常更容易。此交互式演示可能有助于理解 SVG 圆弧背后的概念:https://codepen.io/lingtalfi/pen/yaLWJG(仅在 Chrome 和 Firefox 中测试过,可能无法在你的浏览器中运行)。