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.
注意: 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.
void ctx.arcTo(x1, y1, x2, y2, radius);
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.
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.
<canvas id="canvas"></canvas>
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();
In this example, the path created by
arcTo()
is
thick and black
.
Tangent lines are gray
,
control points are red
,和
start point is blue
.
This example creates a rounded corner using
arcTo()
. This is one of the method's most common uses.
<canvas id="canvas"></canvas>
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();
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.
<canvas id="canvas"></canvas>
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();
More sophisticated demo of the method. You can play around with range input to see how arc changes.
<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>
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);
| 规范 | 状态 | 注释 |
|---|---|---|
|
HTML 实时标准
The definition of 'CanvasRenderingContext2D.arcTo' in that specification. |
实时标准 |
| 桌面 | 移动 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
arcTo
|
Chrome 1 | Edge 12 | Firefox 1.5 | IE 9 | Opera 11.6 | Safari 2 | WebView Android 1 | Chrome Android 18 | Firefox Android 4 | Opera Android 12 | Safari iOS 1 | Samsung Internet Android 1.0 |
完整支持
CanvasRenderingContext2D
CanvasRenderingContext2D
addHitRegion()
arc()
arcTo()
beginPath()
bezierCurveTo()
clearHitRegions()
clearRect()
clip()
closePath()
createImageData()
createLinearGradient()
createPattern()
createRadialGradient()
drawFocusIfNeeded()
drawImage()
drawWidgetAsOnScreen()
drawWindow()
ellipse()
fill()
fillRect()
fillText()
getImageData()
getLineDash()
getTransform()
isPointInPath()
isPointInStroke()
lineTo()
measureText()
moveTo()
putImageData()
quadraticCurveTo()
rect()
removeHitRegion()
resetTransform()
restore()
rotate()
save()
scale()
scrollPathIntoView()
setLineDash()
setTransform()
stroke()
strokeRect()
strokeText()
transform()
translate()