Skip to content

Instantly share code, notes, and snippets.

@balint42
Last active August 29, 2015 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save balint42/fdb1d7d2e16fe11ac785 to your computer and use it in GitHub Desktop.
Save balint42/fdb1d7d2e16fe11ac785 to your computer and use it in GitHub Desktop.
convert SVG ellipse parameters javascript function

Convert SVG ellipse parameters

Javascript function for converting the parameters that come with an SVG elliptic arc, namely the starting point ps, the end point pe, the horizontal radius rh, the vertical radius rv, the rotation in degree rot, the large arc flag fa, the sweep flag fs. These are converted to the ellipse center point pc and a point containing the elliptic arc start and end rotations in degrees, phi1 and phi2. Thus the function returns an array with two points. The term point always refers to a JS object of the type {x:number1, y:number2}.

More precisely this code is the rough (some input checking rules are ignored) implementation of this standard.

/**
* @brief convSvgEllipseParams calculates the center point and the start angle
* and end angle of an ellipse from the obscure SVG parameters of an
* elliptic arc. It returns an array with two points, the center
* point and a point with the start and end angles.
* The term "point" means a JS object { x:number1, y:number2 }
*
* @author Balint Morvai <balint@morvai.de>
* @license http://en.wikipedia.org/wiki/MIT_License MIT License
* @param ps starting point
* @param pe end point
* @param rh horizontal radius
* @param rv vertical radius
* @param rot rotation in degree
* @param fa large arc flag
* @param fs sweep flag
* @return array
*/
var convSvgEllipseParams = function(ps, pe, rh, rv, rot, fa, fs) {
// function for calculating angle between two vectors
var angle = function(u, v) {
var sign = ((u.x * v.y - u.y * v.x) > 0) ? 1 : -1;
return sign * Math.acos(
(u.x * v.x + u.y * v.y) /
(Math.sqrt(u.x*u.x + u.y*u.y) * Math.sqrt(u.x*u.x + u.y*u.y))
);
}
// sanitize input
rot = rot % 360;
rh = Math.abs(rh);
rv = Math.abs(rv);
// do calculation
var cosRot = Math.cos(rot);
var sinRot = Math.sin(rot);
var x = cosRot * (ps.x - pe.x) / 2 + sinRot * (ps.y - pe.y) / 2;
var y = -1 * sinRot * (ps.x - pe.x) / 2 + cosRot * (ps.y - pe.y) / 2;
var rh2 = rh * rh; var rv2 = rv * rv; var x2 = x * x; var y2 = y * y;
var fr = ((fa == fs) ? -1 : 1) * Math.sqrt(
(rh2 * (rv2 - y2) - rv2 * x2) /
(rh2 * y2 + rv2 * x2)
);
var xt = fr * rh * y / rv;
var yt = -1 * fr * rv * x / rh;
var cx = cosRot * xt - sinRot * yt + (ps.x + pe.x) / 2;
var cy = sinRot * xt + cosRot * yt + (ps.y + pe.y) / 2;
var vt = { x:(x-xt)/rh, y:(y-yt)/rv };
var phi1 = angle({ x:1, y:0 }, vt);
var phiD = angle(vt, { x:(-x-xt)/rh, y:(-y-yt)/rv }) % 360;
var phi2 = phi1 + phiD;
return [{ x:cx, y:cy }, { x:phi1, y:phi2 }];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment