There is another method called ctx.arcTo(x1, y1, x2, y2, radius), which is a bit complex to use, but very practical for drawing rounded rectangles.
In fact, the arcTo(...) method draws an arc of a circle depending on some tangents. Let's look at these pictures for a better understanding:
ctx.moveTo(x0, y0);
ctx.arcTo(x1, y1, x2, y2, radius);
While this method may seem complex, it can save us from some even more complex trigonometry. It was defined mainly for drawing rounded shapes like rounded rectangles. We used an excerpt here from the excellent tutorial on the arcTo(...) method.
It works like this:
Draw an imaginary line through (x0,y0) and (x1,y1), draw another imaginary line through (x1,y1) and (x2,y2),
Take an imaginary circle of radius r, and slide it between the two lines towards the mid-point. The two points at which the circle touches the lines are called the tangent points.
arcTo(x1, y1, x2, y2, r) will draw a line from the current point (x0,y0) to the first tangent point on the line from (x0,y0) to (x1,y1),
It will also draw an arc from that tangent point to the other tangent point on the line from (x1,y1) to (x2,y2) along the circumference of the circle.
The resulting new current point on the path will be the tangent point where the arc ends up in the above step.
Source code extract:
context.beginPath();
context.moveTo(0, 20);
context.arcTo(100, 100, 200, 20, 50);
context.lineWidth = 5;
context.strokeStyle = "#0000ff";
context.stroke();
Try this:
Source code:
var roundedRect=function(ctx,x,y,width,height,radius,fill,stroke) {
ctx.beginPath();
// draw top and top right corner
ctx.moveTo(x+radius,y);
ctx.arcTo(x+width,y,x+width,y+radius,radius);
// draw right side and bottom right corner
ctx.arcTo(x+width,y+height,x+width-radius,y+height,radius);
// draw bottom and bottom left corner
ctx.arcTo(x,y+height,x,y+height-radius,radius);
// draw left and top left corner
ctx.arcTo(x,y,x+radius,y,radius);
if(fill) {
ctx.fill();
}
if(stroke){
ctx.stroke();
}
}
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.strokeStyle = 'rgb(150,0,0)';
ctx.fillStyle = 'rgb(0,150,0)';
ctx.lineWidth = 7;
roundedRect(ctx, 15, 15, 160, 120, 20, true, true);
In this example, each call to ctx.arcTo(...) draws a side plus a corner. The arcTo() method enables us to draw rounded rectangle in a code-efficient way.
This example at JS Bin is the same as the previous one, except that we added at the end of the roundedRect function the same lines of code that draw the rounded rectangle, but using lineTo instead of arcTo. Just take a look!
Red = arcTo and Pink = lineTo
For drawing a rounded square, this code also works:
ctx.moveTo(x+radius, y);
ctx.arcTo(x+width, y,x+width, y+height, radius);
ctx.arcTo(x+width, y+height, x, y+height, radius);
ctx.arcTo(x, y+height, x, y,radius);
ctx.arcTo(x, y, x+width, y,radius);
which might be easier than trying to figure out where the arc will end like this:
ctx.moveTo(x+radius, y);
ctx.arcTo(x+width, y, x+width, y+radius, radius);
ctx.arcTo(x+width, y+height, x+width-radius, y+height,radius);
ctx.arcTo(x, y+height, x, y+height-radius, radius);
ctx.arcTo(x, y, x+radius, y,radius);
This could be particularly helpful if you are dealing with something other than a rectangle, like this rounded triangle: