Html5 Canvas painting tutorial (11)-use lineTo/arc/bezierCurveTo to draw an elliptical shape

Source: Internet
Author: User

Comments: There is no elliptical method in canvas. We need to simulate it using other methods. First, we need to specify the parameters required for an elliptic. The basic geometric knowledge tells us that the elliptic requires the coordinates of the center, width, height-or rotation angle. Next we will introduce how to use lineTo to draw an ellipse, use arc to draw a circle, and then scale it into an ellipse, using the bezie curve be in the canvas, you can easily draw a circle using the arc method. Originally, the circle can also be seen as an elliptic with equal width and height, but there is no elliptical method in the canvas, we need to simulate it using other methods.
First, we need to specify the parameters required to draw an elliptic. The basic geometric knowledge tells us that the elliptic requires the coordinates of the center, width, height, or rotation angle. However, this can be avoided for the time being, it is easier to rotate.
1. Use lineTo to draw an ellipse
You are not mistaken. A method like lineTo that is purely used to draw a straight line can actually be used to draw an elliptic !? But he does exist, but the writing method is incredible:

The Code is as follows:
Function DrawEllipse (Canvas, O, OA, OB ){
// Draw an ellipse. For example, var B = new Array (150,150); DrawEllipse (hb, B, 50, 30 );
With (Canvas ){
Var x = O [0] + OA;
Var y = O [1];
MoveTo (x, y );
For (var I = 0; I <= 360; I ++ ){
Var ii = I * Math. PI/180;
Var x = O [0] + OA * Math. cos (ii );
Var y = O [1]-OB * Math. sin (ii );
LineTo (x, y );
}
}
}

The principle of this method is that a circle has 360 degrees, so we use lineTo to cycle 360 times, draw a line segment of each degree, and finally form an elliptic. The sine cosine of the trigonometric function is used for calculation.
Note that the first parameter of this method is an array, that is, the coordinates of the center of the elliptical circle.

The idea is amazing, and the elliptic plot is also smooth. But it is not worth using-this method will take 360 cycles every time you draw an elliptic image. Only a little more than one elliptical image will be used to test the browser's performance.
We just need to understand his ideas.
2. Use arc to draw a circle and then scale it into an elliptic
The original text of this method is here, the core function is as follows:

The Code is as follows:
Var canvas = document. getElementById ('mycanvas ');
Var context = canvas. getContext ('2d ');
Var centerX = 0;
Var centerY = 0;
Var radius = 50;
// Save state
Context. save ();
// Translate context
Context. translate (canvas. width/2, canvas. height/2 );
// Scale context horizontally
Context. scale (2, 1 );
// Draw circle which will be stretched into an oval
Context. beginPath ();
Context. arc (centerX, centerY, radius, 0, 2 * Math. PI, false );
// Restore to original state
Context. restore ()

This method uses a canvas function that I have not mentioned before, that is, scale, which can scale the canvas. Zooming has two directions: horizontal and vertical. In the code, the horizontal direction of the canvas is enlarged, while the vertical direction is unchanged. so, the circle drawn by the original arc is changed to an ellipse.
This method is very good at the beginning, with few codes and easy-to-understand principles. But after analysis, we can find out his obvious weakness, that is, the inaccuracy! For example, if I need an elliptic with a width of 171 and a height of 56, if we set the arc Radius to 28, then we will be depressed by the yundun Number of 171/28/2.

However, there is a way to always set the arc Radius to 100, and then zoom in if it is not enough. However, it is still inaccurate.
3. Use the bezierCurveTo Curve
Since I think the scaling method above is not accurate, I really want to find a precise method for drawing an ellipse. Finally, I found it on stackoverflow:

The Code is as follows:
Function drawEllipse (ctx, x, y, w, h ){
Var kappa = 0.5522848;
Ox = (w/2) * kappa, // control point offset horizontal
Oy = (h/2) * kappa, // control point offset vertical
Xe = x + w, // x-end
Ye = y + h, // y-end
Xm = x + w/2, // x-middle
Ym = y + h/2; // y-middle
Ctx. beginPath ();
Ctx. moveTo (x, ym );
Ctx. bezierCurveTo (x, ym-oy, xm-ox, y, xm, y );
Ctx. bezierCurveTo (xm + ox, y, xe, ym-oy, xe, ym );
Ctx. bezierCurveTo (xe, ym + oy, xm + ox, ye, xm, ye );
Ctx. bezierCurveTo (xm-ox, ye, x, ym + oy, x, ym );
Ctx. closePath ();
Ctx. stroke ();
}

This method is perfect. He divided an elliptic into four besell curves and connected them into an elliptic. In the end, the width and height are also relatively accurate, and the overhead is also small.
However, this method still has shortcomings. We can see that the kappa parameter has a very strange value. I believe many people tell you why he wants to take this value before the geometric experts tell you, I still don't know why I have to take this value. And I have a strong urge to change him to see what the consequences are.

Of course, the impulse of a patient similar to obsessive-compulsive disorder cannot be said to be a weakness of this method. His real weakness is: why should we use four besels? In my opinion, an elliptic is obviously composed of two besell curves rather than four. This idea eventually gave me the perfect way to draw an elliptical image.
4, Draw an ellipse using two besell Curves
To learn whether the previous method can be simplified, I registered a stackoverflow account to ask questions. Because there are images in the problem, the points cannot be transferred due to insufficient points, I have to answer questions from foreigners to earn points. However, when I finally got lucky, I answered a question and solved my points.
The relation between the besell curve and the elliptic is raised here.
To be honest, I did not understand most of the answers below, but fortunately he provided a sample code page to help me understand the principles. I would like to express my gratitude to him again. Based on his answers, I found the following method to draw an ellipse:

The Code is as follows:
// Elliptic
CanvasRenderingContext2D. prototype. oval = function (x, y, width, height ){
Var k = (width/0.75)/2,
W = width/2,
H = height/2;
This. beginPath ();
This. moveTo (x, y-h );
This. bezierCurveTo (x + k, y-h, x + k, y + h, x, y + h );
This. bezierCurveTo (x-k, y + h, x-k, y-h, x, y-h );
This. closePath ();
Return this;
}

This method is both accurate and less code, and there is no strange and difficult to understand. You only need to remember this. The ratio of the width of the elliptic to the coordinates of the control points of the elliptic besell curve is as follows:
The shell control point x = (elliptical width/0.75)/2 has been reflected in the Code.

You can test the above four methods to draw an ellipse.
If you find a simpler method, share it with you.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.