Paths represent the outline of a shape which can be filled, stroked, (see Filling, Stroking and Paint Servers) used as a clipping path (see Clipping, Masking and Compositing), or for any combination of the three.
A path is described using the concept of a current point. In an analogy with drawing on paper, the current point can be thought of as the location of the pen. The position of the pen can be changed, and the outline of a shape (open or closed) can be traced by dragging the pen in either straight lines or curves.
Paths represent an outline of an object which is defined in terms of moveto (set a new current point), lineto (draw a straight line), curveto (draw a curve using a cubic bezier), arc (elliptical or circular arc) and closepath (close the current shape by drawing a line to the last moveto) elements. Compound paths (i.e., a path with subpaths, each consisting of a single moveto followed by one or more line or curve operations) are possible to allow effects such as "donut holes" in objects.
A path is defined in SVG using the 'path' element.
<!ENTITY % pathExt "" > <!ELEMENT path (%descTitle;,(animate|set|animateMotion|animateColor|animateTransform %geExt;%pathExt;)*) > <!ATTLIST path id ID #IMPLIED xml:lang NMTOKEN #IMPLIED xml:space (default|preserve) #IMPLIED class NMTOKENS #IMPLIED style CDATA #IMPLIED transform CDATA #IMPLIED %graphicsElementEvents; system-required NMTOKEN #IMPLIED system-language CDATA #IMPLIED d CDATA #REQUIRED nominalLength CDATA #IMPLIED > |
Attribute definitions:
A path is defined by including a 'path' element which contains a d="(path data)" attribute, where the d attribute contains the moveto, line, curve (both cubic and quadratic beziers), arc and closepath instructions. The following example specifies a path in the shape of a triangle. (The M indicates a moveto, the L's indicate lineto's, and the z indicates a closepath:
<?xml version="1.0" standalone="yes"?> <svg width="4in" height="3in" xmlns = 'http://www.w3.org/Graphics/SVG/SVG-19991203.dtd'> <path d="M 100 100 L 140 100 L 120 140 z"/> </svg>
Path data values can contain newline characters and thus can be broken up into multiple lines to improve readability. Because of line length limitations with certain related tools, it is recommended that SVG generators split long path data strings across multiple lines, with each line not exceeding 255 characters. Also note that newline characters are only allowed at certain places within a path data value.
The syntax of path data is very abbreviated in order to allow for minimal file size and efficient downloads, since many SVG files will be dominated by their path data. Some of the ways that SVG attempts to minimize the size of path data are as follows:
The path data syntax is a prefix notation (i.e., commands followed by parameters). The only allowable decimal point is a period (".") and no other delimiter characters are allowed. (For example, the following is an invalid numeric value in a path data stream: "13,000.56". Instead, say: "13000.56".)
In the tables below, the following notation is used:
The following sections list the commands.
The "moveto" commands (M or m) establish a new current point. The effect is as if the "pen" were lifted and moved to a new location. A path data segment must begin with either one of the "moveto" commands or one of the "arc" commands. Subsequent "moveto" commands (i.e., when the "moveto" is not the first command) represent the start of a new subpath:
Command | Name | Parameters | Description |
---|---|---|---|
M (absolute) m (relative) |
moveto | (x y)+ | Start a new sub-path at the given (x,y) coordinate. M (uppercase) indicates that absolute coordinates will follow; m (lowercase) indicates that relative coordinates will follow. If a relative moveto (m) appears as the first element of the path, then it is treated as a pair of absolute coordinates. If a moveto is followed by multiple pairs of coordinates, the subsequent pairs are treated as implicit lineto commands. |
The "closepath" (Z or z) causes an automatic straight line to be drawn from the current point to the initial point of the current subpath. "Closepath" differs in behavior from what happens when "manually" closing a subpath via a "lineto" command in how 'stroke-linejoin' and 'stroke-linecap' are implemented. With "closepath", the end of the final segment of the subpath is "joined" with the start of the initial segment of the subpath using the current value of 'stroke-linejoin' . If you instead "manually" close the subpath via a "lineto" command, the start of the first segment and the end of the last segment are not joined but instead are each capped using the current value of 'stroke-linecap':
Command | Name | Parameters | Description |
---|---|---|---|
Z or z |
closepath | (none) | Close the current subpath by drawing a straight line from the current point to current subpath's most recent starting point (usually, the most recent moveto point). |
The various "lineto" commands draw straight lines from the current point to a new point:
Command | Name | Parameters | Description |
---|---|---|---|
L (absolute) l (relative) |
lineto | (x y)+ | Draw a line from the current point to the given (x,y) coordinate which becomes the new current point. L (uppercase) indicates that absolute coordinates will follow; l (lowercase) indicates that relative coordinates will follow. A number of coordinates pairs may be specified to draw a polyline. At the end of the command, the new current point is set to the final set of coordinates provided. |
H (absolute) h (relative) |
horizontal lineto | x+ | Draws a horizontal line from the current point (cpx, cpy) to (x, cpy). H (uppercase) indicates that absolute coordinates will follow; h (lowercase) indicates that relative coordinates will follow. Multiple x values can be provided (although usually this doesn't make sense). At the end of the command, the new current point becomes (x, cpy) for the final value of x. |
V (absolute) v (relative) |
vertical lineto | y+ | Draws a vertical line from the current point (cpx, cpy) to (cpx, y). V (uppercase) indicates that absolute coordinates will follow; v (lowercase) indicates that relative coordinates will follow. Multiple y values can be provided (although usually this doesn't make sense). At the end of the command, the new current point becomes (cpx, y) for the final value of y. |
These three groups of commands that draw curves:
The cubic bezier commands are as follows:
Command | Name | Parameters | Description |
---|---|---|---|
C (absolute) c (relative) |
curveto | (x1 y1 x2 y2 x y)+ | Draws a cubic bezier curve from the current point to (x,y) using (x1,y1) as the control point at the beginning of the curve and (x2,y2) as the control point at the end of the curve. C (uppercase) indicates that absolute coordinates will follow; c (lowercase) indicates that relative coordinates will follow. Multiple sets of coordinates may be specified to draw a polybezier. At the end of the command, the new current point becomes the final (x,y) coordinate pair used in the polybezier. |
S (absolute) s (relative) |
shorthand/smooth curveto | (x2 y2 x y)+ | Draws a cubic bezier curve from the current point to (x,y). The first control point is assumed to be the reflection of the second control point on the previous command relative to the current point. (If there is no previous command or if the previous command was not an C, c, S or s, assume the first control point is coincident with the current point.) (x2,y2) is the second control point (i.e., the control point at the end of the curve). S (uppercase) indicates that absolute coordinates will follow; s (lowercase) indicates that relative coordinates will follow. Multiple sets of coordinates may be specified to draw a polybezier. At the end of the command, the new current point becomes the final (x,y) coordinate pair used in the polybezier. |
The quadratic bezier commands are as follows:
Command | Name | Parameters | Description |
---|---|---|---|
Q (absolute) q (relative) |
quadratic bezier curveto | (x1 y1 x y)+ | Draws a quadratic bezier curve from the current point to (x,y) using (x1,y1) as the control point. Q (uppercase) indicates that absolute coordinates will follow; q (lowercase) indicates that relative coordinates will follow. Multiple sets of coordinates may be specified to draw a polybezier. At the end of the command, the new current point becomes the final (x,y) coordinate pair used in the polybezier. |
T (absolute) t (relative) |
Shorthand/smooth quadratic bezier curveto | (x y)+ | Draws a quadratic bezier curve from the current point to (x,y). The control point is assumed to be the reflection of the control point on the previous command relative to the current point. (If there is no previous command or if the previous command was not an Q, q, T or t, assume the control point is coincident with the current point.) T (uppercase) indicates that absolute coordinates will follow; t (lowercase) indicates that relative coordinates will follow. At the end of the command, the new current point becomes the final (x,y) coordinate pair used in the polybezier. |
The elliptical arc commands are as follows:
Command | Name | Parameters | Description |
---|---|---|---|
A (absolute) a (relative) |
elliptical arc | (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+ | Draws an elliptical arc from the current point to (x, y). The size and orientation of the ellipse is defined two radii (rx, ry) and an x-axis-rotation, which indicates how the ellipse as a whole is rotated relative to the current coordinate system. The center (cx, cy) of the ellipse is calculated automatically to satisfy the constraints imposed by the other parameters. large-arc-flag and sweep-flag contribute to the automatic calculations and help determine how the arc is drawn. |
The elliptical arc command draws a section of an ellipse which meets the following constraints:
(We need examples to illustrate all of this! Here is one for the moment.
Suppose you have a circle with center (5,5) and radius 2 and you wish to
draw an arc from 0 degrees to 90 degrees. Then one way to achieve this would
be M 7,5 A 2,2 0 0 1 5,7
. In this example, you move to the
"0 degree" location on the circle, which is (7,5), since the center is at (5,5)
and the circle has radius 2. Since we have circle, the two radii are the same, and in
this example both are equal to 2. Since our sweep is 90 degrees, which is less than 180,
we set large-arc-flag to 0. We want to draw the sweep in a positive angle
direction, so we set sweep-flag to 1. Since we want to draw the arc to the point which is
at the 90 degree location of the circle,
we set (x,y) to (5,7).)
The following notation is used in the BNF description of the grammar for path data:
The following is the BNF for SVG paths.
svg-path: wsp* subpaths? wsp* subpaths: subpath | subpath subpaths subpath: moveto subpath-elements? subpath-elements: subpath-element | subpath-element wsp* subpath-elements subpath-element: closepath | lineto | horizontal-lineto | vertical-lineto | curveto | smooth-curveto | quadratic-bezier-curveto | smooth-quadratic-bezier-curveto | elliptical-arc moveto: ( "M" | "m" ) wsp* moveto-argument-sequence moveto-argument-sequence: coordinate-pair | coordinate-pair comma-wsp? lineto-argument-sequence closepath: ("Z" | "z") lineto: ( "L" | "l" ) wsp* lineto-argument-sequence lineto-argument-sequence: coordinate-pair | coordinate-pair comma-wsp? lineto-argument-sequence horizontal-lineto: ( "H" | "h" ) wsp* horizontal-lineto-argument-sequence horizontal-lineto-argument-sequence: coordinate | coordinate comma-wsp? horizontal-lineto-argument-sequence vertical-lineto: ( "V" | "v" ) wsp* vertical-lineto-argument-sequence vertical-lineto-argument-sequence: coordinate | coordinate comma-wsp? vertical-lineto-argument-sequence curveto: ( "C" | "c" ) wsp* curveto-argument-sequence curveto-argument-sequence: curveto-argument | curveto-argument comma-wsp? curveto-argument-sequence curveto-argument: coordinate-pair comma-wsp? coordinate-pair comma-wsp? coordinate-pair smooth-curveto: ( "S" | "s" ) wsp* smooth-curveto-argument-sequence smooth-curveto-argument-sequence: smooth-curveto-argument | smooth-curveto-argument comma-wsp? smooth-curveto-argument-sequence smooth-curveto-argument: coordinate-pair comma-wsp? coordinate-pair quadratic-bezier-curveto: ( "Q" | "q" ) wsp* quadratic-bezier-curveto-argument-sequence quadratic-bezier-curveto-argument-sequence: quadratic-bezier-curveto-argument | quadratic-bezier-curveto-argument comma-wsp? quadratic-bezier-curveto-argument-sequence quadratic-bezier-curveto-argument: coordinate-pair comma-wsp? coordinate-pair smooth-quadratic-bezier-curveto: ( "T" | "t" ) wsp* smooth-quadratic-bezier-curveto-argument-sequence smooth-quadratic-bezier-curveto-argument-sequence: coordinate-pair | coordinate-pair comma-wsp? smooth-quadratic-bezier-curveto-argument-sequence elliptical-arc: ( "A" | "a" ) wsp* elliptical-arc-argument-sequence elliptical-arc-argument-sequence: elliptical-arc-argument | elliptical-arc-argument comma-wsp? elliptical-arc-argument-sequence elliptical-arc-argument: nonnegative-number comma-wsp? nonnegative-number comma-wsp? number comma-wsp? flag comma-wsp? flag comma-wsp? coordinate-pair coordinate-pair: coordinate comma-wsp? coordinate coordinate: number nonnegative-number: integer-constant | floating-point-constant number: sign? integer-constant | sign? floating-point-constant flag: "0" | "1" comma-wsp: (wsp+ comma? wsp*) | (comma wsp*) comma: "," integer-constant: digit-sequence floating-point-constant: fractional-constant exponent? | digit-sequence exponent fractional-constant: digit-sequence? "." digit-sequence | digit-sequence "." exponent: ( "e" | "E" ) sign? digit-sequence sign: "+" | "-" digit-sequence: digit | digit digit-sequence digit: "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" wsp: (#x20 | #x9 | #xD | #xA)
The processing of the BNF must consume as much of a given BNF production as possible, stopping at the point when a character is encountered which no longer satisfies the production. Thus, in the string "M 100-200", the first coordinate for the "moveto" consumes the characters "100" and stops upon encountering the minus sign because the minus sign cannot follow a digit in the production of a "coordinate". The result is that the first coordinate will be "100" and the second coordinate will be "-200".
Similarly,
for the string "M 0.6.5", the first coordinate of the "moveto"
consumes the characters
"0.6" and stops upon encountering the second decimal point
because the production of a "coordinate" only allows one
decimal point. The result is that the first coordinate will
be "0.6" and the second coordinate will be ".5".
Various operations, including text on a path and motion animation and various stroke operations, require that the user agent compute the distance along the geometry of a graphics element, such as a 'path'.
Exact mathematics exist for computing distance along a path, but the formulas are highly complex and require substantial computation. It is recommended that authoring products and user agents employ algorithms that produce as precise results as possible; however, to accommodate implementation differences and to help distance calculations produce results that approximate author intent, the nomimalLength attribute can be used to provide the author's computation of the total length of the path so that the user agent can scale distance-along-a-path computations by the ratio of nomimalLength to the user agent's own computed value for total path length.
A "moveto" operation within a 'path'
element is defined to have zero length. Only the various
"lineto", "curveto" and "arcto" commands contribute to path length
calculations.
The SVGPathElement interface corresponds to the 'path' element.
interface SVGPathElement : SVGStyledAndTransformedElement { attribute SVGLength nominalLength; // Create an empty SVGPathSeg, specifying the type via a number. // All values initialized to zero. SVGPathSeg createSVGPathSeg(in unsigned short pathsegType) raises(DOMException); // Create an empty SVGPathSeg, specifying the type via a single character. // All values initialized to zero. SVGPathSeg createSVGPathSegFromLetter(in DOMString pathsegTypeAsLetter) raises(DOMException); // Create an SVGPathSeg, specifying the path segment as a string. // For example, "M 100 200". All irrelevant values are set to zero. SVGPathSeg createSVGPathSegFromString(in DOMString pathsegString) raises(DOMException); // This set of methods allows retrieval and modification // to the path segments attached to this path object. // All 20 defined types of path segments are available // through these attributes and methods. readonly attribute unsigned long number_of_pathsegs; SVGPathSeg getSVGPathSeg(in unsigned long index); DOMString getSVGPathSegAsString(in unsigned long index); // Replace all existing entries with a single entry. void initialize(in SVGPathSeg newSVGPathSeg) raises(DOMException); void clear(); // Clear all entries, giving an empty list SVGPathSeg insertBefore(in SVGPathSeg newSVGPathSeg, in unsigned long index) raises(DOMException); SVGPathSeg replace(in SVGPathSeg newSVGPathSeg, in unsigned long index) raises(DOMException); SVGPathSeg remove(in unsigned long index) raises(DOMException); SVGPathSeg append(in SVGPathSeg newSVGPathSeg) raises(DOMException); // This alternate set of methods also allows retrieval and modification // to the path segments attached to this path object. // These attributes and methods provide a "normalized" view of // the path segments where the path is expressed in terms of // the following subset of SVGPathSeg types: // kSVG_PATHSEG_MOVETO_ABS (M), kSVG_PATHSEG_LINETO_ABS (L), // kSVG_PATHSEG_CURVETO_CUBIC_ABS (C) and kSVG_PATHSEG_CLOSEPATH (z). // Note that number_of_pathsegs and number_of_normalized_pathsegs // are not always the same. In particular, elements such as arcs may // be expanded into multiple kSVG_PATHSEG_CURVETO_CUBIC_ABS (C) // pieces when retrieved in the "normalized" view of the path object. readonly attribute unsigned long number_of_normalized_pathsegs; SVGPathSeg getNormalizedSVGPathSeg(in unsigned long index); DOMString getNormalizedSVGPathSegAsString(in unsigned long index); SVGPathSeg insertNormalizedBefore(in SVGPathSeg newSVGPathSeg, in unsigned long index) raises(DOMException); SVGPathSeg replaceNormalized(in SVGPathSeg newSVGPathSeg, in unsigned long index) raises(DOMException); SVGPathSeg removeNormalized(in unsigned long index) raises(DOMException); SVGPathSeg appendNormalized(in SVGPathSeg newSVGPathSeg) raises(DOMException); // This set of methods performs various distance-along-a-path calculations. float getTotalLength(); SVGPoint getPointAtLength(in float distance); SVGPathSeg getPathSegAtLength(in float distance); }; |
The SVGPathSeg interface corresponds to a single command within a path data specification.
interface SVGPathSeg { // Path Segment Types const unsigned short kSVG_PATHSEG_UNKNOWN = 0; // ? const unsigned short kSVG_PATHSEG_CLOSEPATH = 1; // z const unsigned short kSVG_PATHSEG_MOVETO_ABS = 2; // M const unsigned short kSVG_PATHSEG_MOVETO_REL = 3; // m const unsigned short kSVG_PATHSEG_LINETO_ABS = 4; // L const unsigned short kSVG_PATHSEG_LINETO_REL = 5; // l const unsigned short kSVG_PATHSEG_CURVETO_CUBIC_ABS = 6; // C const unsigned short kSVG_PATHSEG_CURVETO_CUBIC_REL = 7; // c const unsigned short kSVG_PATHSEG_CURVETO_QUADRATIC_ABS = 8; // Q const unsigned short kSVG_PATHSEG_CURVETO_QUADRATIC_REL = 9; // q const unsigned short kSVG_PATHSEG_ARC_ABS = 10; // A const unsigned short kSVG_PATHSEG_ARC_REL = 11; // a const unsigned short kSVG_PATHSEG_LINETO_HORIZONTAL_ABS = 12; // H const unsigned short kSVG_PATHSEG_LINETO_HORIZONTAL_REL = 13; // h const unsigned short kSVG_PATHSEG_LINETO_VERTICAL_ABS = 14; // V const unsigned short kSVG_PATHSEG_LINETO_VERTICAL_REL = 15; // v const unsigned short kSVG_PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16; // S const unsigned short kSVG_PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17; // s const unsigned short kSVG_PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18; // T const unsigned short kSVG_PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19; // t readonly attribute unsigned short pathsegType; readonly attribute DOMString pathsegTypeAsLetter; // Attribute values for a path segment. // Each pathseg has slots for any possible path seg type. attribute float x; // end point for pathseg attribute float y; // end point for pathseg attribute float x0,y0; // for bezier control points attribute float x1,y1; // for bezier control points attribute float r1,r2; // radii for A/a attribute float angle; // A/a attribute boolean largeArcFlag; // for A/a attribute boolean sweepFlag; // for A/a readonly attribute Path parentPath; readonly attribute SVGDocument ownerSVGDocument; readonly attribute SVGPathSeg previousSibling; readonly attribute SVGPathSeg nextSibling; }; |