Drawing Curves in HTML Canvas
HTML Canvas 2D Context – Part 3
Foreword: In this part of the series, I explain how to draw curves with little mathematical skills; the little math skills you need is taught to you.
By: Chrysanthus Date Published: 16 Apr 2016
Introduction
Drawing an Arc
An arc is part of a circle. Drawing an arc is similar to drawing a line, but this time, you do not really need the moveTo(x,y) method.
Consider a circle. Imagine a line from the center that goes horizontally to the right edge of the circle. Such a line is called the radius of the circle. If you rotate this line (in your mind) clockwise, by an angle, the angle at the center of the circle between the new and initial placement of the line, will be increasing. It can increase to 90 degrees, 180 degrees, 270 degrees and 360 degrees (complete cycle).
In simple terms the syntax to draw an arc is:
context.arc(x, y, radius, startAngle, endAngle)
where (x,y) is the center of the circle, radius is the distance from the center of the circle to the edge of the circle, in pixels (without the units). startAngle is the arc start angle measured clockwise at the center of the circle and endAngle is the end arc angle measured clockwise at the center of the circle.
The angles are typed in radians, without the units. Zero degrees is zero radians. 90 degrees is approximately 1.57 radians; 180 degrees is approximately 3.14 radians; 270 degrees is approximately 4.71 radians; 360 degrees is approximately 6.28 radians. With these you should be able to estimate your angles in radians.
Read and try the following code and note that the moveTo(x,y) method has not been used:
<!DOCTYPE HTML>
<html>
<head>
<title>Illustration</title>
</head>
<body>
<canvas id="C1" width="400" height="300" style="float:right;border:2px solid red">
Your browser does not support the canvas element! So you cannot see the chart. Please upgrade your browser.
</canvas>
<script type="text/ECMAScript">
cv = document.getElementById('C1');
if (cv.getContext)
{
cntxt = cv.getContext('2d');
cntxt.beginPath();
cntxt.lineWidth = 5;
cntxt.strokeStyle = "blue";
cntxt.arc(200,50,40,0.79,2.36);
cntxt.stroke();
}
</script>
</body>
</html>
For the above arc, the center is above the arc. In order to appreciate what is really going on, you will need to do some practice on your own as follows: Go to the above code; keep values of the center and pair of angles fixed, then change the value of the radius several times to see the effect on the screen. Next keep the values of the radius and center fixed, then change the values of the pair of angles several times to see the effect on the screen. Finally, keep the values of the radius and pair of angles fixed and then change the value of the center coordinates several times to see the effect on the screen.
The arc method of the context object is useful for drawing an independent arc. The example above is a whole path on its own. Imagine that you have a straight-line path and you want to continue the path with an arc. In this case, you would use the arcTo method of the context object.
Example: In order to illustrate the use of the arcTo method, consider a straight line moving downward and to the left. Where this line ends, consider an arc that continues smoothly (aligning) from the end of the straight subpath, going downward and to the left and then upward, and ends just a bit higher up than its bottom. In order to explain how to draw such an arc I will first of all draw a V letter. The following code sample draws a V from right to left. Read and try it.
<!DOCTYPE HTML>
<html>
<head>
<title>Illustration</title>
</head>
<body>
<canvas id="C1" width="400" height="300" style="float:right;border:2px solid red">
Your browser does not support the canvas element! So you cannot see the chart. Please upgrade your browser.
</canvas>
<script type="text/ECMAScript">
cv = document.getElementById('C1');
if (cv.getContext)
{
cntxt = cv.getContext('2d');
cntxt.beginPath();
cntxt.lineWidth = 5;
cntxt.strokeStyle = "blue";
cntxt.moveTo(260,20);
cntxt.lineTo(180,120);
cntxt.lineTo(100,20);
cntxt.stroke();
}
</script>
</body>
</html>
In this code the V is drawn in the opposite direction, from right to left; it still stands upright, as it should. The right-top corner of the V has coordinates, (260,20). The bottommost point of the V has coordinates, (180,120). The left-top corner of the V has coordinates, (100,20).
<!DOCTYPE HTML>
<html>
<head>
<title>Illustration</title>
</head>
<body>
<canvas id="C1" width="400" height="300" style="float:right;border:2px solid red">
</canvas>
<script type="text/ECMAScript">
cv = document.getElementById('C1');
if (cv.getContext)
{
//the V
cntxt = cv.getContext('2d');
cntxt.beginPath();
cntxt.lineWidth = 5;
cntxt.strokeStyle = "blue";
cntxt.moveTo(260,20);
cntxt.lineTo(180,120);
cntxt.lineTo(100,20);
cntxt.stroke();
// the arc from a stright line
cntx = cv.getContext('2d');
cntx.beginPath();
cntx.lineWidth = 5;
cntx.strokeStyle = "red";
cntx.moveTo(260,20);
cntx.lineTo(220,70);
cntx.arcTo(180,120,100,20,40);
cntx.stroke();
}
</script>
</body>
</html>
You can clearly see in the display, how the arc sits comfortably (and aligned) in the V. In this code, the center of the circle, is above the bottommost point of the V.
Our task is to have a straight-line and have an arc continue smoothly from the end of the straight-line path. Try the following code, which better demonstrates this. The explanation is given after.
<!DOCTYPE HTML>
<html>
<head>
<title>Illustration</title>
</head>
<body>
<canvas id="C1" width="400" height="300" style="float:right;border:2px solid red">
</canvas>
<script type="text/ECMAScript">
cv = document.getElementById('C1');
if (cv.getContext)
{
cntxt = cv.getContext('2d');
cntxt.beginPath();
cntxt.lineWidth = 5;
cntxt.strokeStyle = "blue";
cntxt.moveTo(260,20);
cntxt.lineTo(220,70);
cntxt.arcTo(180,120,100,20,40);
cntxt.stroke();
}
</script>
</body>
</html>
Now, if the straight line (first subpath) is short, the arc will be connected from it by extending the straight line. On the other hand, if the straight line is long (longer than where the arc should start), there will be no arc. The syntax to draw an arc from a straight line is:
context.arcTo(x1, y1, x2, y2, radius)
(x1,y1) are the coordinates of the bottommost point of the V. (x2,y2) are the coordinates of the right-top or left-top of the V, depending on which direction (moving) you are imagining (drawing) the V. In the above case, it is the left-top. radius is the radius of the circle, whose circumference the arc is a part. The arc is sitting comfortably (smoothly) in the V; and with that fact, you should be able to make a good estimate of the radius.
Now, what about the coordinates for the end of the straight-line subpath? You do not need these coordinates as I explain now: The arcTo method will always elongate or even start the straight line before drawing the arc. So all you need is to know the direction of the line and estimate the length (value) of the line; then choose suitable coordinates for the three corners of the v. So you do not need a lineTo(x,y) method for the straight line. Read and try the following code which draws the above line and arc exactly, without the lineTo(x,y) method:
<!DOCTYPE HTML>
<html>
<head>
<title>Illustration</title>
</head>
<body>
<canvas id="C1" width="400" height="300" style="float:right;border:2px solid red">
</canvas>
<script type="text/ECMAScript">
cv = document.getElementById('C1');
if (cv.getContext)
{
cntxt = cv.getContext('2d');
cntxt.beginPath();
cntxt.lineWidth = 5;
cntxt.strokeStyle = "blue";
cntxt.moveTo(260,20);
cntxt.arcTo(180,120,100,20,40);
cntxt.stroke();
}
</script>
</body>
</html>
The result is OK.
Always remember: The arcTo method will always elongate or even start the straight line before drawing the arc.
Two Opening Straight Lines with an arc Bottom
In the above code, the arc can continue upward with a smooth connecting straight line. To achieve this, just add a lineTo(x,y) method that will end at the left-top corner of the V after the arcTo method in the code. Read and try the following code that illustrates this:
<!DOCTYPE HTML>
<html>
<head>
<title>Illustration</title>
</head>
<body>
<canvas id="C1" width="400" height="300" style="float:right;border:2px solid red">
</canvas>
<script type="text/ECMAScript">
cv = document.getElementById('C1');
if (cv.getContext)
{
cntxt = cv.getContext('2d');
cntxt.beginPath();
cntxt.lineWidth = 5;
cntxt.strokeStyle = "blue";
cntxt.moveTo(260,20);
cntxt.arcTo(180,120,100,20,40);
cntxt.lineTo(100,20);
cntxt.stroke();
}
</script>
</body>
</html>
Always remember: The arcTo method will always elongate or even start the straight line before drawing the arc. The greater the radius of the circle, the higher up the arc is; the smaller the radius, the lower down the arc is.
Quadratic Curve
The arc is one kind of curve. Another kind of curve is known as the quadratic curve. The quadratic curve looks like the complete drawing of the above code. However, the bottom part is not an arc; it is of a different curvature. Also, there are no straight lines for the quadratic curve. It is a curve all through, which curves, less at the top. Try the following code, which draws a quadratic curve on a V.
<!DOCTYPE HTML>
<html>
<head>
<title>Illustration</title>
</head>
<body>
<canvas id="C1" width="400" height="300" style="float:right;border:2px solid red">
</canvas>
<script type="text/ECMAScript">
cv = document.getElementById('C1');
if (cv.getContext)
{
//the V
cntx = cv.getContext('2d');
cntx.beginPath();
cntx.lineWidth = 5;
cntx.strokeStyle = "pink";
cntx.moveTo(260,20);
cntx.lineTo(180,250);
cntx.lineTo(100,50);
cntx.stroke();
//the complete quadratic curve
cntxt = cv.getContext('2d');
cntxt.beginPath();
cntxt.lineWidth = 5;
cntxt.strokeStyle = "orange";
cntxt.moveTo(260,20);
cntxt.quadraticCurveTo(180,250,100,50);
cntxt.stroke();
}
</script>
</body>
</html>
context.quadraticCurveTo(cpx, cpy, x, y)
where (cpx, cpy) is the control point and (x,y) is the end of the quadratic curve. The quadratic curve (complete) forms a subpath. The beginning of the quadratic curve is the end of the previous subpath. Read and try the following code:
<!DOCTYPE HTML>
<html>
<head>
<title>Illustration</title>
</head>
<body>
<canvas id="C1" width="400" height="300" style="float:right;border:2px solid red">
</canvas>
<script type="text/ECMAScript">
cv = document.getElementById('C1');
if (cv.getContext)
{
//quadratic curve
cntxt = cv.getContext('2d');
cntxt.beginPath();
cntxt.lineWidth = 5;
cntxt.strokeStyle = "orange";
cntxt.moveTo(260,20);
cntxt.quadraticCurveTo(180,250,100,50);
cntxt.stroke();
}
</script>
</body>
</html>
The quadratic curve (and its V) does not have to be standing upright. It can point in any direction. Read and try the following code that illustrates this:
<!DOCTYPE HTML>
<html>
<head>
<title>Illustration</title>
</head>
<body>
<canvas id="C1" width="400" height="300" style="float:right;border:2px solid red">
</canvas>
<script type="text/ECMAScript">
cv = document.getElementById('C1');
if (cv.getContext)
{
//quadratic curve
cntxt = cv.getContext('2d');
cntxt.beginPath();
cntxt.lineWidth = 5;
cntxt.strokeStyle = "orange";
cntxt.moveTo(370,210);
cntxt.quadraticCurveTo(20,250,200,30);
cntxt.stroke();
}
</script>
</body>
</html>
The quadratic curve does not have to be symmetrical; the arms do not also have to be of the same length.
The Bezier Curve
Another kind of curve is called the Bezier curve. The following code shows two Vs and the Bezier Curve drawn on them. Two arms of the two Vs are the same. The first V is upright and the other is inverted. The drawing here as well as the drawing for all the curves in this tutorial are from right to left. Try the code - explanation is given later.
<!DOCTYPE HTML>
<html>
<head>
<title>Illustration</title>
</head>
<body>
<canvas id="C1" width="400" height="300" style="float:right;border:2px solid red">
</canvas>
<script type="text/ECMAScript">
cv = document.getElementById('C1');
if (cv.getContext)
{
//the Vs
cntx = cv.getContext('2d');
cntx.beginPath();
cntx.lineWidth = 5;
cntx.strokeStyle = "pink";
cntx.moveTo(250,20);
cntx.lineTo(180,250);
cntx.lineTo(120,20);
cntx.lineTo(50,250);
cntx.stroke();
//bezier complete curve
cntxt = cv.getContext('2d');
cntxt.beginPath();
cntxt.lineWidth = 5;
cntxt.strokeStyle = "orange";
cntxt.moveTo(250,20);
cntxt.bezierCurveTo(180,250,120,20,50,250);
cntxt.stroke();
}
</script>
</body>
</html>
The Vs are in pink and the Bezier curve is in orange. In the diagram of the above code, the bottommost point of the first V is the first control point of the complete curve. The topmost point of the second V is the second control point of the complete curve. The context syntax for the Bezier curve is
context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
where (cp1x, cp1y) is the first control point; (cp2x, cp2y) is the second control point and (xy) is the end of the curve. The curve is a subpath. The beginning of the curve is where the previous subpath ended. Read and try the following code:
<!DOCTYPE HTML>
<html>
<head>
<title>Illustration</title>
</head>
<body>
<canvas id="C1" width="400" height="300" style="float:right;border:2px solid red">
</canvas>
<script type="text/ECMAScript">
cv = document.getElementById('C1');
if (cv.getContext)
{
//bezier complete curve
cntxt = cv.getContext('2d');
cntxt.beginPath();
cntxt.lineWidth = 5;
cntxt.strokeStyle = "orange";
cntxt.moveTo(250,20);
cntxt.bezierCurveTo(180,250,120,20,50,250);
cntxt.stroke();
}
</script>
</body>
</html>
Important
The new drawing teaching technique you find in this tutorial, is my innovation. Precisely, the use of the V to draw curves is my innovation. The canvas element is a new thing and I have come up with the use of the V to explain how to draw curves in the canvas.
Time to take a break. We stop here and continue in the next part.
Chrys
Related Links
DOM Basics for HTMLDOM Event Basics for HTML
HTML Text and Other Elements in DOM
HTML Grouping and Sectioning Content Elements in DOM
DOM and HTML Embedded Content
HTML Canvas 2D Context
More Related Links
PurePerl MySQL API
Major in Website Design
Web Development Course
Producing a Pure Perl Library
BACK NEXT