CanvasRenderingContext2D:arcTo() 方法

基线 广泛可用

此功能已得到良好确立,并且可在许多设备和浏览器版本中使用。它自以下时间起在各个浏览器中可用: 2015 年 7 月.

Canvas 2D API 的CanvasRenderingContext2D.arcTo()方法使用给定的控制点和半径向当前子路径添加一个圆弧。如果必要,例如起始点和控制点在一条线上,则会自动使用直线将圆弧连接到路径的最新点。

此方法通常用于创建圆角。

注意:使用相对较大的半径时,可能会得到意想不到的结果:圆弧的连接线将朝任何必须满足指定半径的方向延伸。

语法

js
arcTo(x1, y1, x2, y2, radius)

参数

x1

第一个控制点的 x 轴坐标。

y1

第一个控制点的 y 轴坐标。

x2

第二个控制点的 x 轴坐标。

y2

第二个控制点的 y 轴坐标。

radius

圆弧的半径。必须是非负数。

使用说明

假设P0是调用arcTo()时路径上的点,P1 = (x1, y1) 和P2 = (x2, y2) 分别是第一个和第二个控制点,r是调用中指定的radius

  • 如果r为负数,则会引发IndexSizeError 异常
  • 如果r为 0,则arcTo()的行为就像P0P1P2共线(在一条线上)一样。
  • 如果所有点都共线,则会从P0绘制到P1的线,除非点P0P1重合(具有相同的坐标),在这种情况下不会绘制任何内容。

可以在下面的构造 arcTo() 路径示例中创建这些条件以查看结果。

返回值

无(undefined)。

异常

IndexSizeError DOMException

如果radius为负值,则抛出此异常。

示例

arcTo()的工作原理

关于arcTo()的一种思考方式是想象两条直线段:一条从起始点到第一个控制点,另一条从那里到第二个控制点。如果没有arcTo(),这两条线段将形成一个尖角:arcTo()在此角处创建圆弧并将其平滑化。换句话说,圆弧与这两条线段相切。

HTML

html
<canvas id="canvas"></canvas>

JavaScript

js
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()创建的路径为粗黑色。切线为灰色,控制点为红色,起始点为蓝色。

创建圆角

此示例使用arcTo()创建圆角。这是该方法最常用的用途之一。

HTML

html
<canvas id="canvas"></canvas>

JavaScript

圆弧从moveTo()指定的点开始:(230, 20)。它的形状适合 (90, 130) 和 (20, 20) 处的控制点,半径为 50。lineTo()方法使用直线将圆弧连接到 (20, 20)。请注意,圆弧的第二个控制点和lineTo()指定的点相同,这会产生一个完全平滑的角。

js
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 = (p) => {
  const offset = 10;
  ctx.fillText(`(${p.x},${p.y})`, p.x + offset, p.y + offset);
};

ctx.beginPath();
ctx.lineWidth = 4;
ctx.font = "1em sans-serif";
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();

结果

大半径的结果

如果使用相对较大的半径,圆弧可能会出现在您意想不到的地方。在此示例中,圆弧的连接线位于moveTo()指定的坐标上方,而不是下方。发生这种情况是因为半径太大,以至于圆弧无法完全位于起始点下方。

HTML

html
<canvas id="canvas"></canvas>

JavaScript

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

结果

构造 arcTo() 路径

演示显示了半无限线和圆,其中心为C,与T1T2处的线相切,用于确定arcTo()渲染的路径。

请注意,当所有点都在一条线上时,arcTo将从P0P1创建一条直线。此外,如果P0P1具有相同的坐标,则arcTo不会绘制任何内容。

除了能够使用滑块设置圆弧半径外,还可以通过使用鼠标左键按下拖动来移动初始点P0和控制点P1P2。还可以编辑数值,并且可以使用箭头键更改获得焦点的带下划线的元素。

动画化 arcTo() 绘制

对于此示例,您可以随意更改圆弧半径以查看路径如何变化。路径从起始点p0开始绘制,使用arcTo(),控制点为p1p2,半径从 0 变化到使用滑块选择的最大半径。然后,lineTo()调用将路径完成到p2

HTML

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

js
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 = radius = control.value;
};

const p1 = { x: 100, y: 100 };
const p2 = { x: 150, y: 50 };
const p3 = { x: 200, y: 100 };
let radius = control.value; // match with init control value

function labelPoint(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);
}

function drawPoints(points) {
  points.forEach((p, i) => {
    labelPoint(p, { x: 0, y: -20 }, `p${i}`);
  });
}

// Draw arc
function drawArc([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();
}

function loop(t) {
  const angle = (t / 1000) % (2 * Math.PI);
  const rr = Math.abs(Math.cos(angle) * radius);

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  drawArc([p1, p2, p3], rr);
  drawPoints([p1, p2, p3]);
  requestAnimationFrame(loop);
}

loop(0);

结果

规范

规范
HTML 标准
# dom-context-2d-arcto-dev

浏览器兼容性

BCD 表格仅在启用 JavaScript 的浏览器中加载。

另请参阅