Détail du package

svg-pathdata

nfroidure11.3mMIT8.0.0

Manipulate SVG path data (path[d] attribute content) simply and efficiently.

svg, path, data, parser

readme

svg-pathdata

Manipulate SVG path data (path[d] attribute content) simply and efficiently.

GitHub license Coverage Status

Usage

Install the module:

npm install --save svg-pathdata

Then in your JavaScript files:

import {
  SVGPathData,
  SVGPathDataTransformer,
  SVGPathDataEncoder,
  SVGPathDataParser,
} from 'svg-pathdata';

Reading PathData

const pathData = new SVGPathData(`
  M 10 10
  H 60
  V 60
  L 10 60
  Z`);

console.log(pathData.commands);

// [  {type: SVGPathData.MOVE_TO,       relative: false,  x: 10,  y: 10},
//    {type: SVGPathData.HORIZ_LINE_TO, relative: false,  x: 60},
//    {type: SVGPathData.VERT_LINE_TO,  relative: false,          y: 60},
//    {type: SVGPathData.LINE_TO,       relative: false,  x: 10,  y: 60},
//    {type: SVGPathData.CLOSE_PATH}]

Reading PathData in chunks

const parser = new SVGPathDataParser();

parser.parse('   '); // returns []
parser.parse('M 10'); // returns []
parser.parse(' 10'); // returns [{type: SVGPathData.MOVE_TO, relative: false, x: 10, y: 10 }]

parser.write('H 60'); // returns [{type: SVGPathData.HORIZ_LINE_TO, relative: false, x: 60 }]

parser.write('V'); // returns []
parser.write('60'); // returns [{type: SVGPathData.VERT_LINE_TO, relative: false, y: 60 }]

parser.write('L 10 60 \n  Z');
// returns [
//   {type: SVGPathData.LINE_TO, relative: false, x: 10, y: 60 },
//   {type: SVGPathData.CLOSE_PATH }]

parser.finish(); // tell parser there is no more data: will throw if there are unfinished commands.

Outputting PathData

const pathData = new SVGPathData(`
  M 10 10
  H 60
  V 60
  L 10 60
  Z`);
// returns "M10 10H60V60L10 60Z"

encodeSVGPath({ type: SVGPathData.MOVE_TO, relative: false, x: 10, y: 10 });
// returns "M10 10"

encodeSVGPath({ type: SVGPathData.HORIZ_LINE_TO, relative: false, x: 60 });
// returns "H60"

encodeSVGPath([
  { type: SVGPathData.VERT_LINE_TO, relative: false, y: 60 },
  { type: SVGPathData.LINE_TO, relative: false, x: 10, y: 60 },
  { type: SVGPathData.CLOSE_PATH },
]);
// returns "V60L10 60Z"

Transforming PathData

This library can perform transformations on SVG paths. Here is an example of that kind of use.

Transforming entire paths

new SVGPathData(`
   m 10,10
   h 60
   v 60
   l 10,60
   z`)
  .toAbs()
  .encode();
// return s"M10,10 H70 V70 L80,130 Z"

Transforming partial data

Here, we take SVGPathData from stdin and output it transformed to stdout.

const transformingParser = new SVGPathDataParser().toAbs().scale(2, 2);
transformingParser.parse('m 0 0'); // returns [{ type: SVGPathData.MOVE_TO,       relative: false, x: 0, y: 0 }]
transformingParser.parse('l 2 3'); // returns [{ type: SVGPathData.LINE_TO,       relative: false, x: 4, y: 6 }]

Supported transformations

You can find all supported transformations in src/SVGPathDataTransformer.ts. Additionally, you can create your own by writing a function with the following signature:

type TransformFunction = (command: SVGCommand) => SVGCommand | SVGCommand[];

function SET_X_TO(xValue = 10) {
  return function(command) {
    command.x = xValue; // transform command objects and return them
    return command;
  };
};

// Synchronous usage
new SVGPathData('...')
  .transform(SET_X_TO(25))
  .encode();

// Chunk usage
new SVGPathDataParser().transform(SET_X_TO(25));

Contributing

Clone this project, run:

npm install; npm test

API

Functions

annotateArcCommand()

https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes Fixes rX and rY. Ensures lArcFlag and sweepFlag are 0 or 1 Adds center coordinates: command.cX, command.cY (relative or absolute, depending on command.relative) Adds start and end arc parameters (in degrees): command.phi1, command.phi2; phi1 < phi2 iff. c.sweepFlag == true

intersectionUnitCircleLine()

Solves a quadratic system of equations of the form a x + b y = c x² + y² = 1 This can be understood as the intersection of the unit circle with a line. => y = (c - a x) / b => x² + (c - a x)² / b² = 1 => x² b² + c² - 2 c a x + a² x² = b² => (a² + b²) x² - 2 a c x + (c² - b²) = 0

arePointsCollinear(p1, p2, p3)

Determines if three points are collinear (lie on the same straight line) and the middle point is on the line segment between the first and third points

createEllipse()

Creates an ellipse path centered at (cx,cy) with radii rx and ry

createRect()

Creates a rectangle path with optional rounded corners

createPolyline()

Creates a polyline from an array of coordinates [x1,y1,x2,y2,...]

createPolygon()

Creates a closed polygon from an array of coordinates

REMOVE_COLLINEAR(commands)

Process a path and remove collinear points

REVERSE_PATH(commands, preserveSubpathOrder)

Reverses the order of path commands to go from end to start IMPORTANT: This function expects absolute commands as input. It doesn't convert relative to absolute - use SVGPathDataTransformer.TO_ABS() first if needed.

annotateArcCommand()

https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes Fixes rX and rY. Ensures lArcFlag and sweepFlag are 0 or 1 Adds center coordinates: command.cX, command.cY (relative or absolute, depending on command.relative) Adds start and end arc parameters (in degrees): command.phi1, command.phi2; phi1 < phi2 iff. c.sweepFlag == true

Kind: global function

intersectionUnitCircleLine()

Solves a quadratic system of equations of the form a x + b y = c x² + y² = 1 This can be understood as the intersection of the unit circle with a line. => y = (c - a x) / b => x² + (c - a x)² / b² = 1 => x² b² + c² - 2 c a x + a² x² = b² => (a² + b²) x² - 2 a c x + (c² - b²) = 0

Kind: global function

arePointsCollinear(p1, p2, p3) ⇒

Determines if three points are collinear (lie on the same straight line) and the middle point is on the line segment between the first and third points

Kind: global function
Returns: true if the points are collinear and p2 is on the segment p1-p3

Param Description
p1 First point [x, y]
p2 Middle point that might be removed
p3 Last point [x, y]

createEllipse()

Creates an ellipse path centered at (cx,cy) with radii rx and ry

Kind: global function

createRect()

Creates a rectangle path with optional rounded corners

Kind: global function

createPolyline()

Creates a polyline from an array of coordinates [x1,y1,x2,y2,...]

Kind: global function

createPolygon()

Creates a closed polygon from an array of coordinates

Kind: global function

REMOVE_COLLINEAR(commands) ⇒

Process a path and remove collinear points

Kind: global function
Returns: New array with collinear points removed

Param Description
commands Array of SVG path commands to process (must be absolute)

REVERSE_PATH(commands, preserveSubpathOrder) ⇒

Reverses the order of path commands to go from end to start IMPORTANT: This function expects absolute commands as input. It doesn't convert relative to absolute - use SVGPathDataTransformer.TO_ABS() first if needed.

Kind: global function
Returns: New SVG commands in reverse order with absolute coordinates

Param Description
commands SVG path commands in absolute form to reverse
preserveSubpathOrder If true, keeps subpaths in their original order

Authors

License

MIT

changelog

8.0.0 (2025-06-16)

Features

  • add removeCollinear method to optimize SVG path data (161e4e1)
  • add SVGShapes utility functions for creating shapes (6fab2d7)

7.2.0 (2025-03-15)

Bug Fixes

  • correct skew functions to use Math.tan for angle calculations and update tests for accuracy (cb52591)
  • correct type (62ac9ac)
  • correctly offset relative arcs that produce more than one bezier (#91) (72ad8cf)
  • math: correct conversion of arc.xRot to rad (#85) (5014647)
  • remove no longer needed test utils (#87) (5ae667e)

Features

  • math: handle zero radius arcs by converting to lines (b3a0358)
  • mathUtils: enhance collinearity check to verify middle point on segment (83f6454)
  • modernize build pipeline and dev dependencies (#88) (b9c184c)
  • reverse path (#82) (a2258f2)
  • SVGPathData: normalize bezier curves to lines and add collinearity check (e4fc254)

7.1.0 (2024-08-30)

Features

7.0.1 (2024-08-27)

Bug Fixes

  • correct condition check for 'y2' in ROUND function (9f332a6)

7.0.0 (2024-07-29)

Bug Fixes

  • core: remove unused files (03cd8c0)
  • docs: fix the readme layout (69c7692)

chore

BREAKING CHANGES

  • dependencies: Requires Node20+ and ESM support in your project.

6.0.3 (2021-09-18)

6.0.2 (2021-09-17)

6.0.1 (2021-09-12)

6.0.0 (2021-04-02)

5.0.5 (2020-06-06)

5.0.4 (2020-02-14)

Bug Fixes

  • parser: fix parsing merged numbers with arc flags (d55d9f0)

5.0.3 (2020-02-04)

5.0.2 (2018-06-05)

5.0.1 (2018-06-03)

5.0.0 (2018-06-02)

4.0.1 (2017-08-22)

4.0.0 (2017-08-22)

3.2.3 (2017-08-13)

3.2.2 (2017-08-13)

3.2.1 (2017-08-13)

3.2.0 (2017-08-12)

3.1.1 (2017-08-12)

3.1.0 (2017-05-19)

3.0.0 (2017-05-02)

2.0.3 (2017-04-21)

2.0.2 (2017-04-05)

Bug Fixes

  • build: Fix tests and regenerate the changelog (fa281fa)

build

  • metapak-nfroidure: Add metapak-nfroidure (6be898c)

Code Refactoring

BREAKING CHANGES

  • dist: No more dist, please transpile in your own builds.
  • metapak-nfroidure: Since the eslint --fix option were used, there may be some breaking features but this very old codebase really need a total cleanup.

v2.0.0 (2017/02/22 08:23 +00:00)

  • 8a33721 2.0.0 (@NaridaL)
  • 8c840ab Changed x1/y1 and x2/y2 around for C and c commands. (@NaridaL)
  • #20 Normalization and Sanitation Transformers (@NaridaL)
  • 214f5ee Added transformers: (@NaridaL)

v1.0.4 (2016/11/07 15:18 +00:00)

  • bb3beb7 1.0.4 (@huerlisi)
  • #13 Ignore the coverage/ directory in git (@nfroidure)
  • #14 Use master branch travis badge in README (@nfroidure)
  • 56cbd18 Use master branch travis badge in README (@huerlisi)
  • 5293f0b Ignore the coverage/ directory in git (@huerlisi)
  • #9 Support transforming arc commands (@rhendric)
  • #11 Moveto commands start a new subpath (@rhendric)
  • #10 Remove Grunt references from Travis (@rhendric)
  • 9906542 Support transforming arc commands (@rhendric)
  • 25d1dc9 Fix test expectations (@rhendric)
  • c9e3747 Remove Grunt references from Travis (@rhendric)
  • efc5f29 Moveto commands start a new subpath (@rhendric)

v1.0.3 (2015/11/20 20:08 +00:00)

  • d52943d 1.0.3 (@nfroidure)
  • 06fbcd1 Cannot use preversion lint right now, too much work (@nfroidure)
  • 7d3d11e Suppressing some linting errors (@nfroidure)
  • 7337440 Updating deps (@nfroidure)
  • 17a3934 Removing grunt (@nfroidure)
  • 06d6a69 Adding eslint config file (@nfroidure)

v1.0.2 (2015/10/10 10:57 +00:00)

  • 3aa2cd6 1.0.2 (@nfroidure)
  • 179416d Fixing the arc reverted issue #44 (@nfroidure)

v1.0.1 (2015/06/27 08:41 +00:00)

  • a8f1fb6 1.0.1 (@nfroidure)
  • 027ba05 Suppressing hints (@nfroidure)
  • 183ccd8 Cleaning up repo (@nfroidure)
  • 7418a31 Update deps, set the engines to Node > 0.10 (@nfroidure)

v1.0.0 (2014/11/16 16:05 +00:00)

  • d043a52 1.0.0 (@nfroidure)
  • da9671b Fixing rel 2 abs for multipath pathdatas (@nfroidure)
  • 68d0e70 Adding the forgotten licence file closes #7 (@nfroidure)
  • 2b7bd20 Updating version number (@nfroidure)
  • 2b1e277 Removing unecessary dependency (@nfroidure)
  • cf3f3e4 Do not use data event anymore (@nfroidure)
  • 5cb5c80 Improved transform functions (@nfroidure)
  • 1f567e1 Improved transform function (@nfroidure)
  • 4724965 New version (@nfroidure)
  • 2d726ec Fucking grunt-browserify (@nfroidure)
  • 3587d82 Adding forgottent tests (@nfroidure)
  • 5a29acb Removing errors that cannot happen (@nfroidure)
  • 3425078 Adding forgotten new operator for errors (@nfroidure)
  • 54b7538 No more EOF and STATE_ENDED for the parser (@nfroidure)
  • f2609e3 Fixing encoder output to buffer modewq (@nfroidure)
  • 2c03487 Improving code coverage, allowing constructors omission (@nfroidure)
  • 237898e Updating dependencies (@nfroidure)
  • d35369c Fix matrix transformation formula closes #2 (@nfroidure)
  • e218385 Fixing tests, improving A to C transformer (@nfroidure)
  • 49fe80a New version 0.0.4 (@nfroidure)
  • a0e8a63 Added stats (@nfroidure)
  • #3 Depend on readable-stream from npm (@Raynos)
  • #4 clean up the scripts (@calvinmetcalf)
  • 0c2cfde change | to && (@calvinmetcalf)
  • 071215f clean up the scripts (@calvinmetcalf)
  • 19a4daa convert other files to readable-stream too (@Raynos)
  • 50dd97a depend on readable-stream in p.json (@Raynos)
  • 181f63b Use readable-stream instead (@Raynos)
  • ce11d07 Readme fix (@nfroidure)
  • c521987 Added coverage tests (@nfroidure)
  • 11d22fc Added a round transformation (@nfroidure)
  • 0bf6fa4 Do not parse incomplete L,M,S incomplete commands anymore (@nfroidure)
  • 653a4d3 Improved sapegin test (@nfroidure)
  • 60ee34e Added sapegin test (@nfroidure)
  • 908da2a Added arc to curve conversionwq (@nfroidure)
  • b341fde Main file is the src not the build (@nfroidure)
  • 0d8608e Version updated (@nfroidure)
  • 28a1cd1 Tests updated (@nfroidure)
  • 63ac182 Fix for X/Y transforms (@nfroidure)
  • b4196ce Removed unnecessary absolute conversions (@nfroidure)
  • 4a38ad0 Added x symetry (@nfroidure)
  • e34a0e3 Based y symetry on other transformations (@nfroidure)
  • 392152d Checking transformations arguments (@nfroidure)
  • 177f586 Updated REAMDE and package.json (@nfroidure)
  • 60a2819 Some transformations converted to their idioins matrixes (@nfroidure)
  • a24a2a5 Skew transformations added2 (@nfroidure)
  • 930b9c4 Skew transformations added (@nfroidure)
  • 7bc0390 Rotation transformation added (@nfroidure)
  • 3191815 Added scale transformation (@nfroidure)
  • 0e15916 Added translation transformation (@nfroidure)
  • 6cfd826 Fix for y symetry problems (@nfroidure)
  • 7d0576c Support decpoint separated numbers 2 (@nfroidure)
  • 92391ec Support sign separated numbers 2 (@nfroidure)
  • 5b536c1 Support sign separated numbers (@nfroidure)
  • d37ea0a Added ySymetry transformer2 (@nfroidure)
  • 647fdf4 Added ySymetry transformer (@nfroidure)
  • 377518f Added toRel transformer2 (@nfroidure)
  • dd00037 Added toAbs transformer2 (@nfroidure)
  • d0d8332 Added toAbs transformer (@nfroidure)
  • b1e24a6 Now based on Node stream module (@nfroidure)
  • 1bfbeea Updated dependencies (@nfroidure)
  • a267550 Added the distribution file (@nfroidure)
  • b8f0c7e Added encoding use samples (@nfroidure)
  • bbd8955 Switch to line to n+1 move to declarated commands (@nfroidure)
  • 667f390 Added an encoder (@nfroidure)
  • 78ef5ce Contributing (@nfroidure)
  • c6d4db4 Added usage in the README file (@nfroidure)
  • bd69b1c Const naming uniformized (@nfroidure)
  • 3b21f06 New Grunt/Package files (@nfroidure)
  • f84959e Small refactoring (@nfroidure)
  • 726e85f Added eliptic arc commands error detection tests (@nfroidure)
  • 7bb6671 Added eliptic arc commands (@nfroidure)
  • 7099de1 Added smooth quadratic curve to commands (@nfroidure)
  • 97c7575 Added quadratic curve to commands (@nfroidure)
  • 0499dcb Added curve to commands2 (@nfroidure)
  • fdb154e Added curve to commands (@nfroidure)
  • 111c42c Better syntax error handling (@nfroidure)
  • 52727ae Added smooth curveto commands (@nfroidure)
  • 4fae609 Added line to and closepath commands parsing (@nfroidure)
  • d7cdfad Move to commands parsing added (@nfroidure)
  • d10264e parse mthod returns commands (@nfroidure)
  • 280ffe0 Build info (@nfroidure)
  • ac6b856 Added vertical/horizontal commands2 (@nfroidure)
  • f785f6b Added vertical/horizontal commands (@nfroidure)
  • 2f9b8da Full support for numbers parsing (@nfroidure)
  • 699bf87 Fixed tests (@nfroidure)
  • 04450cc First Commit (@nfroidure)