The CanvasRenderingContext2D
.arcTo()
method of the Canvas 2D API adds a circular arc to the current sub-path, using the given control points and radius. The arc is automatically connected to the path's latest point with a straight line, if necessary for the specified parameters.
This method is commonly used for making rounded corners.
Note: Be aware that you may get unexpected results when using a relatively large radius: the arc's connecting line will go in whatever direction it must to meet the specified radius.
Syntax
void ctx.arcTo(x1, y1, x2, y2, radius);
Parameters
x1
- The x-axis coordinate of the first control point.
y1
- The y-axis coordinate of the first control point.
x2
- The x-axis coordinate of the second control point.
y2
- The y-axis coordinate of the second control point.
radius
- The arc's radius. Must be non-negative.
Examples
How arcTo works
One way to think about arcTo()
is to imagine two straight segments: one from the starting point to a first control point, and another from there to a second control point. Without arcTo()
, these two segments would form a sharp corner: arcTo()
creates a circular arc that fits this corner and smooths is out. In other words, the arc is tangential to both segments.
HTML
<canvas id="canvas"></canvas>
JavaScript
const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); // Tangential lines ctx.beginPath(); ctx.strokeStyle = 'gray'; ctx.moveTo(200, 20); ctx.lineTo(200, 130); ctx.lineTo(50, 20); ctx.stroke(); // Arc ctx.beginPath(); ctx.strokeStyle = 'black'; ctx.lineWidth = 5; ctx.moveTo(200, 20); ctx.arcTo(200,130, 50,20, 40); ctx.stroke(); // Start point ctx.beginPath(); ctx.fillStyle = 'blue'; ctx.arc(200, 20, 5, 0, 2 * Math.PI); ctx.fill(); // Control points ctx.beginPath(); ctx.fillStyle = 'red'; ctx.arc(200, 130, 5, 0, 2 * Math.PI); // Control point one ctx.arc(50, 20, 5, 0, 2 * Math.PI); // Control point two ctx.fill();
Result
In this example, the path created by arcTo()
is thick and black. Tangent lines are gray, control points are red, and the start point is blue.
Creating a rounded corner
This example creates a rounded corner using arcTo()
. This is one of the method's most common uses.
HTML
<canvas id="canvas"></canvas>
JavaScript
The arc begins at the point specified by moveTo()
: (230, 20). It is shaped to fit control points at (90, 130) and (20, 20), and has a radius of 50. The lineTo()
method connects the arc to (20, 20) with a straight line. Note that the arc's second control point and the point specified by lineTo()
are the same, which produces a totally smooth corner.
const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const p0 = { x: 230, y: 20 } const p1 = { x: 90, y: 130 } const p2 = { x: 20, y: 20 } const labelPoint = function (p) { const offset = 15; ctx.fillText('(' + p.x + ',' + p.y + ')', p.x + offset, p.y + offset); } ctx.beginPath(); ctx.moveTo(p0.x, p0.y); ctx.arcTo(p1.x, p1.y, p2.x, p2.y, 50); ctx.lineTo(p2.x, p2.y); labelPoint(p0); labelPoint(p1); labelPoint(p2); ctx.stroke();
Result
Result of a large radius
If you use a relatively large radius, the arc may appear in a place you didn't expect. In this example, the arc's connecting line goes above, instead of below, the coordinate specified by moveTo()
. This happens because the radius is too large for the arc to fit entirely below the starting point.
HTML
<canvas id="canvas"></canvas>
JavaScript
const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); ctx.beginPath(); ctx.moveTo(180, 90); ctx.arcTo(180,130, 110,130, 130); ctx.lineTo(110, 130); ctx.stroke();
Result
Live demo
More sophisticated demo of the method. You can play around with range input to see how arc changes.
HTML
<div>
<label for="radius">Radius: </label>
<input name="radius" type="range" id="radius" min=0 max=100 value=50>
<label for="radius" id="radius-output">50</label>
</div>
<canvas id="canvas"></canvas>
JavaScript
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const controlOut = document.getElementById('radius-output');
const control = document.getElementById('radius');
control.oninput = () => {
controlOut.textContent = r = control.value;
};
const mouse = { x: 0, y: 0 };
let r = 100; // Radius
const p0 = { x: 0, y: 50 };
const p1 = { x: 100, y: 100 };
const p2 = { x: 150, y: 50 };
const p3 = { x: 200, y: 100 };
const labelPoint = function (p, offset, i = 0){
const {x, y} = offset;
ctx.beginPath();
ctx.arc(p.x, p.y, 2, 0, Math.PI * 2);
ctx.fill();
ctx.fillText(`${i}:(${p.x}, ${p.y})`, p.x + x, p.y + y);
}
const drawPoints = function (points){
for (let i = 0; i < points.length; i++) {
var p = points[i];
labelPoint(p, { x: 0, y: -20 } , i)
}
}
// Draw arc
const drawArc = function ([p0, p1, p2], r) {
ctx.beginPath();
ctx.moveTo(p0.x, p0.y);
ctx.arcTo(p1.x, p1.y, p2.x, p2.y, r);
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
let t0 = 0;
let rr = 0; // the radius that changes over time
let a = 0; // angle
let PI2 = Math.PI * 2;
const loop = function (t) {
t0 = t / 1000;
a = t0 % PI2;
rr = Math.abs(Math.cos(a) * r);
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawArc([p1, p2, p3], rr);
drawPoints([p1, p2, p3]);
requestAnimationFrame(loop);
}
loop(0);
Result
Specifications
Specification | Status | Comment |
HTML Living StandardThe definition of 'CanvasRenderingContext2D.arcTo' in that specification. | Living Standard |
Browser compatibility
The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out https://github.com/mdn/browser-compat-data and send us a pull request.
Update compatibility data on GitHub
Desktop | Mobile | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
arcTo
|
Chrome
Full support 1 |
Edge
Full support 12 |
Firefox
Full support 1.5 |
IE
Full support 9 |
Opera
Full support 11.6 |
Safari
Full support 2 |
WebView Android
Full support 1 |
Chrome Android
Full support 18 |
Firefox Android
Full support 4 |
Opera Android
Full support 12 |
Safari iOS
Full support 1 |
Samsung Internet Android
Full support 1.0 |
Legend
- Full support
- Full support
See also
- The interface defining this method:
CanvasRenderingContext2D
CanvasRenderingContext2D.arcTo() by Mozilla Contributors is licensed under CC-BY-SA 2.5.