I have tried to find a way to implement cross browser path normalizer. There IS a native way which is described here and functional example is here, but it works only in newest Opera (but not in IE, FF, Safari, Chrome).
The native way uses pathElm.normalizedPathSegList
and it converts all relative coordinates to absolute ones and represents all path segment types as a following subset of types: M,L,C,z.
I have found only one javascript code and jsfiddled functional example of it, but it works only in IE and FF. Chrome gives "Uncaught Error: INDEX_SIZE_ERR: DOM Exception 1". How this could be fixed to work also in Opera, Safari and Chrome or is there any other way for normalizing SVG paths?
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> s.
What is path normalization? Normalizing a path involves modifying the string that identifies a path or file so that it conforms to a valid path on the target operating system. Normalization typically involves: Canonicalizing component and directory separators. Applying the current directory to a relative path.
The d attribute defines a path to be drawn. A path definition is a list of path commands where each command is composed of a command letter and numbers that represent the command parameters.
EDIT: Do not use this! I tested it more and realized that the A->C conversion is not reliable in all cases and also some other path command combinations fail. Please use this instead!
Finally got it to work in Safari, Opera, IE9, Firefox and Chrome: http://jsfiddle.net/timo2012/M6Bhh/41/
The function normalizes SVG path's data, so that all path segments are converted to M, C, L and z ( = absolute coordinates, which means that all relative coordinates are converted to absolute ones). All other segments are trivial and 100% accurate, but arc (A) is a special case and you can select whether arcs are converted to lines (L), quadratic curves (Q) or cubic curves (C). The most accurate are lines, but then we lose resolution independence. Quadratics for some reason fails in certain arcs, but cubics are more accurate.
If we have the following path:
<svg width="400" height="400">
<path stroke="red" stroke-width="3" d="M30 30 S40 23 23 42 L23,42 C113.333,113.333 136.667,113.333 150,80 t40,50 T230,240 q20 20 54 20 s40 23 23 42 t20,30 a20,30 0,0,1 -50,-50"/>
</svg>
and normalize it using:
var path = document.querySelector('path');
path.normalizePath(3, 0.1); // 3 = C = cubic curves. Best alternative, rather good accuracy and path data remains reasonable sized
the normalized version is this:
<svg width="400" height="400">
<path stroke="red" stroke-width="3" d="M 30 30 C 30 30 40 23 23 42 L 23 42 C 113.333 113.333 136.667 113.333 150 80 C 150 80 163.333 96.6667 190 130 C 216.667 163.333 230 200 230 240 C 243.333 253.333 261.333 260 284 260 C 284 260 324 283 307 302 C 307 302 313.667 312 327 332 C 324.811 336.924 321.997 341.154 318.719 344.448 C 315.441 347.741 311.762 350.033 307.893 351.194 C 304.024 352.355 300.04 352.361 296.169 351.213 C 292.298 350.064 288.616 347.783 285.333 344.5 C 282.05 341.217 279.23 336.996 277.035 332.078 C 274.839 327.161 273.311 321.642 272.537 315.839 C 271.763 310.035 271.759 304.06 272.525 298.254 C 273.291 292.448 274.811 286.924 277 282"/>
</svg>
If we layout both on top of each other the result is this (red is normalized and black is original):
Other possibilities are these:
path.normalizePath(1,0.5); // A->L, Many lines, high accuracy. Very good accuracy, but not so resolution independent, because when scaled, the corners become visible
path.normalizePath(1,40); // A->L, Few lines, less accuracy
path.normalizePath(2,0.5); // A->Q, quadratic curves. I tested this, but not good. Fails in some cases.
And what are the benefits of this?
The native way for normalizing path data is not implemented yet in all browsers, so we are on our own so far. And when the native way is implemented, we are not sure that all browsers makes it same way. The SVG documentation speaks of converting arcs to lines, but this is not a good way, because SVG:s main advantage - resolution independence - will be lost. We should have a full control how normalization of arcs is done, and this script provides a way to it.
When data is normalized, it can be altered exactly the same way as coordinates in bitmap images. If we want to warp (Arc, Arch, Bulge, Shell, Flag, Wave, Fish, Rise, Fisheye, Inflate, Squeeze, Twist) paths in a Illustrator way or distort paths to achieve perspective illusion, the normalized path data can be modified reliably.
The code is based on YannickBochatay's script and I made it more cross browser.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With