Danya Lette

SVGPathInfo.js

javascript svg

I made a little Javascript library to quickly get info on an SVG path element. Check it out:

github website.

How To

The available methods are getJSON(), getCommands(), getCommandsArray(), getSubPaths(deep), getRelativePath(), getAbsolutePath() and getGlobalCubicBezier().

Once you’ve included the script in your page, here’s how you start using them:

Begin

First, create a new SVGPathInfo object.

You can pass it a handle to a path element:

var path_elem = document.getElementById('mypath');
var info1 = new SVGPathInfo(path_elem);

Or you can pass it a path string:

var path_string = "M0 0 L0 50L50 50M0 200L200 0";
var info2 = new SVGPathInfo(path_string);

Now you have access to a bunch of SVGPathInfo’s methods:

getJSON()

var path_json = info2.getJSON();

will output

{  
   "0":{  
      "type":"M",
      "string":"M0 0",
      "x":"0",
      "y":"0"
   },
   "1":{  
      "type":"L",
      "string":"L0 50",
      "x":"0",
      "y":"50"
   },
   "2":{  
      "type":"L",
      "string":"L50 50",
      "x":"50",
      "y":"50"
   }
   "3":{  
      "type":"M",
      "string":"M0 200",
      "x":"0",
      "y":"200"
   },
   "4":{  
      "type":"L",
      "string":"L200 0",
      "x":"200",
      "y":"0"
   }
}

getCommands()

var path_commands = info2.getCommands();

This will return the object that is described by the above JSON string.

getCommandsArray()

var path_commands = info2.getCommandsArray();

This returns an array of command strings, rather than an object of command objects:

["M0 0", "L0 50", "L50 50", "M0 200", "L200 0"]

getSubPaths(deep)

var subpaths = info2.getSubPaths(true);
//OR
var subpaths = info2.getSubPaths(); //default: false

This breaks down the path into subpaths, breaking wherever a moveto (M/m) command occurs.

The argument deep is by default false. If deep is false, it returns an array of subpath strings:

["M0 0L0 50L50 50", "M0 200L200 0"]

If deep is true, it returns an array of subpath arrays:

[["M0 0","L0 50","L50 50"], ["M0 200","L200 0"]]

getAbsolutePath()

var abs_path = info2.getAbsolutePath();

Wherever the lowercase form of a command is used, the coordinates that follow the command are relative – their location is specified relative to location of the pen, and not specified absolutely i.e. relative to the point of origin of the svg element (the top left corner).

This function converts the path to the absolute form and returns a string. (Note: my example path is already absolute.)

getRelativePath()

var rel_path = info2.getRelativePath();

This does the opposite of getAbsolutePath() – all absolute commands are modified so as to be specified in relation to the location of the pen.

"m0 0 l0 50 l50 0 m-50 150 l200 -200"

getGlobalCubicBezier()

var gcb_path = info2.getGlobalCubicBezier();

This function converts each command to a cubic Bézier and returns a string.

"M0 0C0 0 0 50 0 50C0 50 50 50 50 50M0 200C0 200 200 0 200 0"

Notes:

Accuracy

There is approximation involved, as is the nature of dealing with Bézier curves, and of course Javascript does famously imprecise maths. However, the result is quite good:

This svg image is the result of generating path strings using SVGPathInfo’s various functions, and assigning the resultant strings to the “d” attribute of path elements. I made the stroke-width of the paths decrease progressively so that all the paths can be seen at once. Here is the JS:

var info = new SVGPathInfo(path1);
document.getElementById('path2').setAttribute("d", info.getRelativePath());
document.getElementById('path3').setAttribute("d", info.getAbsolutePath());
document.getElementById('path4').setAttribute("d", info.getGlobalCubicBezier());

where

  • path1 has the original path (orange with stroke-width='30')
  • path2 has the relative path (grey with stroke-width='18')
  • path3 has the absolute path (pink with stroke-width='10')
  • path4 has the cubic Bézier path (yellow with stroke-width='3')

Validitity

This library does not check the path’s validity. It will likely throw an error or behave unexpectedly if it is provided with an invalid path.

To Do

I have not yet implemented a conversion from the arc command (A,a) to cubic Bézier.