Transferred from: Alloyteam,
www.alloyteam.com/2015/07/canvas-hua-tuo-yuan-di-fang-fa/
Although the title is to draw an ellipse, let's first say the circle in the canvas
I'm sure you're not unfamiliar with canvas's circle of paintings.
Ogc.arc (0, 2*math.pi, false);
As shown above, the direct call to the API can be, but the computer is using raster, using the Bresenham algorithm to draw round, which we put to the end, first of all, the use of the parameters of the circle of the equation to draw a circle
Circle (OGC, 400, 300, 100);
function Circle (context, x, Y, a) {//x,y is the coordinate; A is the radius
var r = 1/a; ① Note: Here R can be written dead, but the values written in different cases are different
Context.beginpath ();
Context.moveto (x + A, y);
for (var i = 0; i < 2 * Math.PI i + = r) {
Context.lineto (x + A * Math.Cos (i), y + A * Math.sin (i));
}
Context.closepath ();
Context.fill ();
}
Principle is what, believe that the trigonometric functions good children's shoes understand easily, if do not know, note ①, I change the value of R, I believe it immediately ~
R and 2*math.pi Coordination is the precision of the circle, in the radius of 100, R take 1/10 on it, universal words can be written to death, written r = 1/a; so that the radius is large or small, the circle will be very fine, but the performance will have a great impact
Now take a look at the main character of the article, for the circle to see the ellipse
function Ellipseone (context, x, Y, A, b) {
var step = (A > B)? 1/A: 1/b;
Context.beginpath ();
Context.moveto (x + A, y);
for (var i = 0; i < 2 * Math.PI i + = Step) {
Context.lineto (x + A * Math.Cos (i), y + b * Math.sin (i));
}
Context.closepath ();
Context.fill ();
}
The circle is basically the same, but the circle has only one radius, and the ellipse is divided into long and short axes.
Look at the effect ~
All right, draw the ellipse success, the end of the article ~
How can it be..
The end of this is too no product, just the method one, the following to see the other
Method two, Uniform compression method
This is my favorite method, easy to understand, compared method one, performance is also a lot faster, the first paste code ~
function Ellipsetwo (context, x, Y, A, b) {
Context.save ();
var r = (A > B)? A:B;
var ratiox = A/R;
var ratioy = B/R;
Context.scale (Ratiox, Ratioy);
Context.beginpath ();
Context.arc (X/ratiox, Y/ratioy, R, 0, 2 * Math.PI, FALSE);
Context.closepath ();
Context.restore ();
Context.fill ();
}
The principle is to use the scale to compress a standard circle, Ratiox is the horizontal scaling ratio, Ratioy is the longitudinal axis scaling ratio, because the two values are different, so that the standard circle is scaled to an ellipse
Remember save () and restore () restores the context environment, so easy to understand the method
The following two methods are very tall, using the three-time Bezier curve method
Methods three, four, Besselfa
function Ellipsethree (context, x, Y, A, b) {
var ox = 0.5 * A,
Oy = 0.6 * b;
Context.save ();
Context.translate (x, y);
Context.beginpath ();
Context.moveto (0, B);
Context.beziercurveto (Ox, B, A, oy, a, 0);
Context.beziercurveto (A,-oy, OX,-B, 0,-B);
Context.beziercurveto (-ox,-B,-A,-oy,-A, 0);
Context.beziercurveto (-A, Oy,-ox, B, 0, B);
Context.closepath ();
Context.fill ();
Context.restore ();
}
function Ellipsefour (context, x, Y, A, b) {
var k = 0.5522848,
Ox = k * A,
Oy = k * b;
Context.translate (x, y);
Context.beginpath ();
Context.moveto (-A, 0);
Context.beziercurveto (-A, Oy,-ox,-B, 0,-B);
Context.beziercurveto (Ox, B, A,-oy, a, 0);
Context.beziercurveto (A, oy, Ox, B, 0, B);
Context.beziercurveto (-ox, B, A, oy,-a, 0);
Context.closepath ();
Context.fill ();
}
The core of Besselfa is the selection of two control points, but it has a fatal problem, when the linewidth is wider, the ellipse is flat, the long axis is more sharp, there will be no smooth situation
If you do not know what the Bezier words on their own Baidu ... This does not explain ...
And then there's the last. A grating method to draw the ellipse, the grating method to draw the circle is very simple, the ellipse is very troublesome, the following is the simplest kind of ellipse, is equal to the linewidth 1px
function ellipsefive (context, x, Y, A, b) {
var data = context.getimagedata (0, 0, 800, 600);
var imagedata = Data.data;
var tx = 0;
var ty = b;
var d = b*b + a*a* (-B + 0.25);
var mx = a * A/MATH.SQRT (A * a + b * b);
while (TX <= MX) {
if (d < 0) {
D + + b * b * (2 * tx + 3);
} else {
ty--;
D + + b * b * (2 * TX + 3) + 2 * A * A * (1-ty);
}
tx++;
Setpix (x + tx, y + ty);
Setpix (x + tx, y-ty);
Setpix (x-tx, y + ty);
Setpix (X-TX, y-ty);
}
D = b * b * (TX + 0.5) * (TX + 0.5) + A * A * (ty-1) * (ty-1)-A * A * b * b;
while (Ty > 0) {
if (d < 0) {
tx++;
D + + b*b* (2 * TX + 2) + a*a* ( -2 * ty + 3);
}
else {
D + + a*a* ( -2 * ty + 3);
}
ty--;
Setpix (x + tx, y + ty);
Setpix (x-tx, y + ty);
Setpix (x + tx, y-ty);
Setpix (X-TX, y-ty);
}
Context.putimagedata (data, 0, 0);
function Setpix (x, y) {