ellipse() bezier
A JS polyfill for ctx.ellipse()
by dirtyd77
HTML
<canvas id="canvas" width=400 height=400></canvas>
JavaScript
// Compare ctx.ellipse() with a polyfill using cubic bezier curves.
//
// The real ellipse is drawn in thick light red, and the bezier curves
// are drawn in thin black. Clicking and dragging allows to compare the
// function over different ellipses shapes.
//
// This code is in the public domain (CC0).
var ctx = canvas.getContext('2d');
// canvas.ellipse function, with a 4 pixel bigger x and y radius
function drawRealEllipse(x, y, rx, ry, angle) {
ctx.beginPath();
ctx.ellipse(x, y, rx, ry, angle, 0, 2 * Math.PI);
ctx.lineWidth = 7;
ctx.strokeStyle = 'rgba(255, 0, 0, 0.25)';
ctx.stroke();
}
// approximation using four cubic splines
function drawApproximateEllipse(x, y, rx, ry, angle) {
var c = 0.551784; // see http://www.tinaja.com/glib/ellipse4.pdf
/* ctx.translate(x, y) */
/* ctx.rotate(angle) */
ctx.beginPath();
ctx.moveTo(-rx, 0) // start point of first curve
ctx.bezierCurveTo(-rx, ry * c, -rx * c, ry, 0, ry);
ctx.bezierCurveTo( rx * c, ry, rx, ry * c, rx, 0);
ctx.bezierCurveTo( rx, -ry * c, rx * c, -ry, 0, -ry);
ctx.bezierCurveTo(-rx * c, -ry, -rx, -ry * c, -rx, 0);
/* ctx.rotate(-angle) */
/* ctx.translate(-x, -y) */
ctx.lineWidth = 1;
ctx.strokeStyle = 'rgba(0, 0, 0, 1.0)';
ctx.stroke();
}
function drawBoth(x, y, rx, ry, angle) {
drawRealEllipse(x, y, rx, ry, angle);
drawApproximateEllipse(x, y, rx, ry, angle);
}
drawBoth(200, 200, 50, 100, 30);
// adding interactive testing
var mx1 = 200,
my1 = 200,
isDown = false;
canvas.onmousedown = function() {
isDown = true;
}
canvas.onmouseup = function() {
isDown = false;
}
canvas.onmousemove = function(e) {
if (!isDown) return;
mx2 = e.clientX;
my2 = e.clientY;
ctx.clearRect(0, 0, 400, 400);
drawBoth((mx1 + mx2) / 2, (my1 + my2) / 2,
Math.abs(mx2 - mx1) / 2, Math.abs(my2 - my1) / 2, 25);
}