--- title: CanvasRenderingContext2D.arcTo() slug: Web/API/CanvasRenderingContext2D/arcTo translation_of: Web/API/CanvasRenderingContext2D/arcTo ---
Canvas 2D APIの CanvasRenderingContext2D.arcTo() メソッドは、2つの制御点と半径を指定して現在のサブパスに円弧を追加します。円弧は現在のパスの最後の点と自動的に直線で連結されます。
このメソッドは主に角丸の図形を描画するのに使用されます。
Note: 相対的に大きな半径を指定した場合、得られる角丸の描線が期待するものとは異なる可能性があります: 円弧と連結する直線は円弧の半径に合うように描線されます。
void ctx.arcTo(x1, y1, x2, y2, radius);
x1y1x2y2radiusarcTo() の仕組みを解釈するには、始点と1つ目の制御点を結ぶ直線と、そこから2つ目の制御点を結ぶ直線の2つの線をイメージする方法があります。arcTo()を使用しない場合、これら2つの線分は鋭角を形成しますが、arcTo() はこの鋭角部分に接する円弧を描くことで滑らかに接続します。すなわち、2直線に接する円弧を作成するということになります。
<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();
この例では、arcTo() によって描かれる線を黒い太線、接線を灰色、制御点を赤、始点となる現在のパスの最後の点を青で描画しています。
{{ EmbedLiveSample('How_arcTo_works', 315, 165) }}
この例では arcTo()を用いて丸い角をもつ線を描画しています。これが最も一般的な使われ方です。
<canvas id="canvas"></canvas>
描線は直前のmoveTo()により座標 (230, 20)から開始し、2つの制御点(90, 130) と (20, 20) を結ぶ直線に接するように形成された半径50の円弧に接続されます。円弧の終端からは lineTo() メソッドにより (20, 20) の点まで直線が描画されます。2つ目の制御点の座標と同じ座標を lineTo() で指定することで、滑らかな描線を得ることができます。
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();
{{ EmbedLiveSample('Creating_a_rounded_corner', 315, 165) }}
相対的に大きな半径を指定した場合には、前述の方法では期待されるような滑らかな描線は得られません。この例では、moveTo()後の地点から円弧に接続される線は下方ではなく上方に向かってしまっています。これは、2つの直線に接する円の半径が大き過ぎるために、始点よりも上方に円弧との接点があるために発生しています。
<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();
{{ EmbedLiveSample('Result_of_a_large_radius', 315, 165) }}
以下はより洗練されたデモです。半径の変化幅を調節し、どのように描線が変化するかを試すことができます。
<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);
| Specification | Status | Comment |
|---|---|---|
| {{SpecName('HTML WHATWG', "scripting.html#dom-context-2d-arcto", "CanvasRenderingContext2D.arcTo")}} | {{Spec2('HTML WHATWG')}} |
{{Compat("api.CanvasRenderingContext2D.arcTo")}}