Short answer: you can't.
SVG only has built in Quadratic (2nd order) and Cubic curves (3rd order), whereas the curve you're showing is Quartic (4th order). SVG has no generic "N term Bezier" draw instruction, so you're going to have to compromise here.
Some options:
- convert the curve to a (series of) cubic curves and render those instead. This is a pretty hard problem and not really recommended.
- sample your curve at enough points such that the polygon through those points looks like a curve at the resolution and zoom level people will be looking at it. This is easy to do, but of course you no longer have a "curve", you now have a polygon.
- as above, but fewer points, and then compute the Catmull-Rom curve sequence that goes through those points, then convert those CR curves to cubic Bezier (they're the same type of function, and can be 1:1 transformed from one to the other). This is nicer than 2 because you have a curve, but it might not look quite the same as the original. Of course the more points you use, the better the result will be.
- use a canvas to draw your Nth degree Bezier curve, build an image out of the result using the
toDataURL
function and then load that image as image in your SVG. This will work perfectly fine, but if you use created SVG path styling, making the canvas generate the same style could be a challenge.
- this list can get very long, so let's stop here for now.
Bottom line: if you need to show higher order Bezier curves, SVG is not an appropriate technology to use (I'd recommend just doing your animation using the canvas, or better yet, something like d3.js or paper.js. Probably the latter).
And if you end up rolling your own, the sampling function is ludicrously simple. Curves are parametric, controlled by a value t
that runs from 0 to 1 (inclusive), and can be written as a nested linear interpolation:
getCurvePoint(t, points) {
if (points.length === 1) return points[0];
var newpoints = [];
for(var i=0,j=1; j<points.length; i++,j++) {
newpoints[i] = lerp2d(t, points[i], points[j]);
}
return getCurvePoint(t,newpoints);
}
with the lerp
function being the standard linear interpolation function:
lerp(ratio, start, end) {
return ratio*start + (1-ratio)*end;
}
lerp2d(ratio, start, end) {
return {
x: lerp(ratio, start.x, end.x),
y: lerp(ratio, start.y, end.y)
};
}
And a simple jsbin example: http://jsbin.com/pesutibefu/edit?html,js,output using points
var points = [
{x:50, y:100},
{x:50, y:250},
{x:210, y:250},
{x:250, y:50},
{x:380, y:150}
];
gives us:
Although a Paper.js sketch would be easier to work with if you need animated pretty paths, with draggable control points, etc.
M
attribute, andC
defines your beginning curve with your points following for the first arc andZ
ends it all. You might play with something like this to gain a little familiarity. Or if it's static I often just create those assets in Adobe Illustrator and export to SVG. However without seeing what you've tried, or knowing points etc, this question really is pretty broad. – NourishC
only allows to build a cubic Bezier curve, i.e by 4 control points. I need to build Bezier curve by arbitrary number of control points: 3, 4, 5, 6 and etc. – MixtureS
to retain slope. Or better yet, go multiple quadratic withT
and even go a step further to define points inQ
but there's multiple docs/tutorials out there to explain better than I would have time to in comments here. – NourishS
,T
andQ
? – Mixture<polyline fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" points="1.704,33.237 35.511,8.239 59.09,63.636 86.647,1.704 98.295,40.624 "/>
but then where's your curves? a 5 point curve would be more like<path fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" d="M1.704,33.237c0,0,23.664-27.76,33.807-24.998 c14.523,3.953,8.64,53.561,23.58,55.396C75.911,65.7,69.734,2.759,86.647,1.704c10.136-0.633,11.648,38.92,11.648,38.92"/>
– Nourish