Reputation: 3148
I can't find the right values to draw a simple equilateral triangle with rounded corners with a given radius. Thanks for your help.
var canvas = document.getElementById('arch');
var context = canvas.getContext('2d');
// Vertices of the equilateral triangle :
// (0,0) (200,0) (100, h*100)
const radius = 15
const h = Math.sqrt(3) / 2
context.beginPath();
context.moveTo(radius, 0);
context.lineTo(200 - radius, 0);
context.quadraticCurveTo(200, 0, 200, radius*h);
context.lineTo(100+radius, (h*200)-radius);
context.quadraticCurveTo(100, h*200, 100-radius, h*200);
context.lineTo(radius, radius);
context.quadraticCurveTo(0, 0, 0, 0);
context.lineWidth = 2
context.strokeStyle = 'black';
context.stroke();
<canvas id="arch" width=500px height=500px>
</canvas>
Upvotes: 1
Views: 211
Reputation: 54026
Though the existing answer works well it requires the calculation of the start and end angles of each arc (which is not mentioned?). There is also an additional check per corner, and that is to make sure that the arc direction is clockwise or anticlockwise.
The 2D canvas API has arcTo that eliminates the need to calculate any angles or winding directions.
There is a need to calculate line segment centers however the math is a lot simpler.
The example below uses the function pathRounded
to draw rounded corners on a given set of points. The path can be concave or convex, must have at least 3 or more points, and the radius must fit the corners.
If you want corners to fit any set of lines then you need to get the min length of either line entering a corner and ensure that the radius is not greater than half that length.
const ctx = canvas.getContext('2d');
const P2 = (x, y) => ({x,y});
const path = [P2(140, 0), P2(280, 140), P2(0, 140)];
pathRounded(ctx, path, 20);
function pathRounded(ctx, points, radius) {
const len = points.length;
ctx.lineWidth = 8;
ctx.beginPath();
var i = 0, p1 = points[i++], p2 = points[i++];
ctx.moveTo((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5);
while (i <= points.length + 1) {
p1 = p2;
p2 = points[i++ % len];
const x = (p1.x + p2.x) * 0.5;
const y = (p1.y + p2.y) * 0.5;
ctx.arcTo(p1.x, p1.y, x, y, radius);
}
ctx.closePath();
ctx.stroke();
}
<canvas id="canvas" height="150" width="300"></canvas>
Upvotes: 1
Reputation: 17584
I don't think that quadraticCurveTo will get your expected result, try using arc instead:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc
Here is a quick example:
var canvas = document.getElementById('arch');
var context = canvas.getContext('2d');
const radius = 18
context.lineWidth = 8
context.strokeStyle = 'black';
context.beginPath();
context.arc(30, 30, radius, 2.2, -1.4);
context.arc(90, 30, radius, 4.6, 1.0);
context.arc(60, 60, radius, 0.6, 2.6);
context.arc(30, 30, radius, 2.2, -1.4);
context.stroke();
<canvas id="arch"></canvas>
Upvotes: 1