# CanvasRenderingContext2D.arcTo()

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 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();
``````

### Live demo

More sophisticated demo of the method. You can play around with range input to see how arc changes.

#### HTML

``````<div>
</div>
<canvas id="canvas"></canvas>
``````

#### JavaScript

``````const canvas = document.getElementById('canvas');
const ctx    = canvas.getContext('2d');

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);
``````

## Specifications

Specification
HTML Standard (HTML)
# dom-context-2d-arcto-dev

## Browser compatibility

BCD tables only load in the browser