SVG paths have a pretty good set of shape commands, enough to let you draw any 2D shape you might want in an authoring tool: horizontal, vertical, and diagonal straight lines, elliptical arc segments, and cubic and quadratic BÃ©zier curves. BÃ©ziers are great, giving you precise control over the position and curve interpolation of each point in a concise format, using control points (“handles”), and are easily chained together to create complex shapes.
But let’s say you have a series of points, and you want to draw a smooth line between them, e.g. for stock data, an audio wave, or a mathematical graphing equation. BÃ©ziers are not as handy there, because not all the points needed to define a BÃ©zier spline are on the curve itself. Obviously, you can decompose any set of points into a set of BÃ©ziers, but that takes math, and who wants to do that? (Put your hand down, nerd. I’m talking to the normals.)
Sometimes, you just want to lay down a set of points, and let the browser draw a smooth curve (unlike polylines, where each segment is just a straight line between the points). Like this:
Mouse over the line above to see the equivalent cubic BÃ©zier points. They are off the line. Off the line! Oh, Math, why do you do this to me?
One thing that’s always bothered me about SVG… there should be more simple ways of doing things, and this is one of things. Over the years, I’ve idly asked math-minded folks about how to achieve this, and the answers always soared right over my pointy little head. I probably didn’t ask the question the right way.
But a few months ago, I was chatting with Ben Fry, one of the creators of Processing (the graphics programming language), and he mentioned Catmull-Rom curves as a possible solution. I took note of that, and later read up on them; they seemed a pretty good fit for my use case. In my spare time I looked for any libraries out there to convert Catmull-Rom curves to BÃ©zier splines; I found references that talked about the the conversion using inverted matrixes, but no simple code to be had. I’m lazy, and busy, and the problem wasn’t urgent, so I kept putting it off.
Here is a scientific chart showing how awesome the SVG <path> element is, with values derived from the overall awesomeness by different path commands, rendered using an experimental Catmull-Rom path command:
As you can see, adding Catmull-Rom curves would increase the awesomeness of SVG paths by almost 50%. That is a lot more awesome!
The syntax is pretty intuitive… it’s just the command ‘R’ followed by a set of coordinate points:
<path stroke="#BADA55" stroke-width="2" fill="none" d="M20,380 R58,342 100,342 100,300 140,250 190,210 220,197 250,184 280,155 310,260 404,20"/>
And the path syntax isn’t just used for the ‘d’ attribute of <path> elements. It’s also used for laying out text-paths, and the shapes of SVG Font glyphs. And it’s used in animation, both for motion paths and (in the case of BÃ©ziers) for timing functions in the ‘keysplines’ easing attribute that controls the rate of animation. So, making it easier to hit specific points for paths could have side benefits for all those uses as well.
I’m really interested in feedback from others on the usefulness of this idea. I’m not married to the idea of Catmull-Rom curves specifically (Fun fact: Ed Catmull is now the president of the Walt Disney and Pixar animation studios; I believe Rom became an astronaut, was captured by aliens and turned into a cyborg, and is now a Spaceknight), just in the idea of adding this type of point-on-the-path command. So, if you support the notion of adding this in SVG 2, or have a better idea along the same lines, send an email to the SVG Working Group’s public list, email@example.com, to let us know.
Looking at Spiro curves a bit closer (just the image, not the code), it seems that there are actually different node types illustrated, not simply an undifferentiated set of coordinate points as in my interpretation of the Catmull-Rom algorithm. This means that, from an syntax standpoint, those segments would need additional parameters in addition to the coordinate points on the curve, which somewhat undercuts the simplicity.
Given that SVG already has a ‘Lineto’ command, I set out to see how closely I could match the letter “a” in Raph Levien’s example, using just my Catmull-Rom and Lineto segments, and with minimal effort:
Mouse over the raster image to hide the SVG path. There are definite artifacts, and I am running into some known limitations of my script implementation in how it interpolates the last coordinate segment, but with not much effort, I was able to get pretty close.
This is not to belittle Spiro at all… Spiro generates painfully elegant curves. It’s just to compare apples to apples.