Q:

How to normalize SVG path data (cross browser)?

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?

A:

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.

A:

EDIT: I got the Raphaël bug fixed and made thorough testing with animated and non-animated complex paths, so I think it is wise to use Raphaël for path normalization. The explanation of bug and it's fix is here: https://stackoverflow.com/a/13079377/1691517. The Raphaël's path2curve function can easily convert all path commands (also A ie Arc) to normalized form (ie Cubic curves). It's nice, that Cubics can represent all path commands!

The other way is to use new Raphaël, where is an interesting function Raphael.path2curve(), which converts all path commands to Cubic curves, but it has some bug. The following image visualizes the bug:

The functional example is here and the code is as follows:
<style>path {fill:none}</style>
<script src="http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<div id="res" style="width:800px"></div>
<div id="raphael"></div>

<script>
window.onload = function () {
var paper = Raphael("raphael", 400, 400);
var original_path = "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";
var arr=Raphael.path2curve(original_path);
var normalized_path = arr.toString();

var path1 = paper.path(normalized_path).attr({stroke: "red", "stroke-width":6});
var path2 = paper.path(original_path).attr({stroke: "black", "stroke-width":2});

document.getElementById("res").innerHTML="ORIGINAL PATH (black):<br>"+original_path+"<br><br>NORMALIZED PATH (red):<br>"+normalized_path;
}
</script>​

It would be very nice to could make a path normalization in Raphaël, because it supports large amount of browsers and uses arrays instead of DOM path segments (= speed and backward compatibility). I made a bug report. Hope it is fixed in some future release.

