arcTo 绘制圆弧

arcTo方法用于绑制圆角和圆弧连接。它比arc更灵活,适合绑制圆角矩形等图形。

arcTo方法语法

ctx.arcTo(x1, y1, x2, y2, radius)
参数类型说明
x1, y1number第一个控制点坐标
x2, y2number第二个控制点坐标
radiusnumber圆弧半径

工作原理

arcTo根据当前位置和两个控制点确定圆弧:

当前位置 ────┐
            │
            │ 圆弧
            │
        控制点1 ──── 控制点2

圆弧与两条线相切:当前位置到控制点1的线,控制点1到控制点2的线。

基本用法

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

ctx.beginPath()
ctx.moveTo(50, 50)
ctx.arcTo(200, 50, 200, 200, 30)
ctx.lineTo(200, 200)
ctx.stroke()

arcTo原理演示

arcTo工作原理

当前位置: (50, 100)

控制点1: (200, 100)

控制点2: (200, 220)

半径: 50

绘制圆角矩形

arcTo最适合绑制圆角矩形:

function roundRect(ctx, x, y, width, height, radius) {
  ctx.beginPath()
  ctx.moveTo(x + radius, y)
  ctx.arcTo(x + width, y, x + width, y + height, radius)
  ctx.arcTo(x + width, y + height, x, y + height, radius)
  ctx.arcTo(x, y + height, x, y, radius)
  ctx.arcTo(x, y, x + width, y, radius)
  ctx.closePath()
}

roundRect(ctx, 50, 50, 200, 100, 20)
ctx.fillStyle = '#3498db'
ctx.fill()

圆角矩形演示

圆角矩形

不等圆角

四个角可以有不同的圆角半径:

function roundRectUnequal(ctx, x, y, width, height, radii) {
  const [tl, tr, br, bl] = radii
  
  ctx.beginPath()
  ctx.moveTo(x + tl, y)
  ctx.arcTo(x + width, y, x + width, y + height, tr)
  ctx.arcTo(x + width, y + height, x, y + height, br)
  ctx.arcTo(x, y + height, x, y, bl)
  ctx.arcTo(x, y, x + width, y, tl)
  ctx.closePath()
}

// 左上20, 右上40, 右下10, 左下30
roundRectUnequal(ctx, 50, 50, 200, 100, [20, 40, 10, 30])
ctx.fillStyle = '#e74c3c'
ctx.fill()

不等圆角演示

不等圆角矩形

左上20, 右上40, 右下10, 左下30

绘制气泡框

function drawBubble(ctx, x, y, width, height, radius, pointerSize) {
  ctx.beginPath()
  
  // 左上角
  ctx.moveTo(x + radius, y)
  
  // 上边
  ctx.lineTo(x + width - radius, y)
  ctx.arcTo(x + width, y, x + width, y + radius, radius)
  
  // 右边
  ctx.lineTo(x + width, y + height - radius)
  ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius)
  
  // 下边(带尖角)
  ctx.lineTo(x + width / 2 + pointerSize, y + height)
  ctx.lineTo(x + width / 2, y + height + pointerSize)
  ctx.lineTo(x + width / 2 - pointerSize, y + height)
  
  // 左下角
  ctx.lineTo(x + radius, y + height)
  ctx.arcTo(x, y + height, x, y + height - radius, radius)
  
  // 左边
  ctx.lineTo(x, y + radius)
  ctx.arcTo(x, y, x + radius, y, radius)
  
  ctx.closePath()
}

drawBubble(ctx, 50, 30, 200, 80, 15, 15)
ctx.fillStyle = '#f39c12'
ctx.fill()

气泡框演示

气泡框示例

注意事项

半径过大时

ctx.beginPath()
ctx.moveTo(50, 100)
ctx.arcTo(100, 100, 100, 200, 100)  // 半径过大
ctx.stroke()

当半径超过两条线段交点到起点的距离时,圆弧会自动调整。

需要先moveTo

// 错误:没有起点
ctx.beginPath()
ctx.arcTo(100, 50, 100, 150, 20)  // 从(0,0)开始

// 正确
ctx.beginPath()
ctx.moveTo(50, 50)
ctx.arcTo(100, 50, 100, 150, 20)

arcTo不会自动lineTo

ctx.beginPath()
ctx.moveTo(50, 50)
ctx.arcTo(200, 50, 200, 200, 30)
// 当前位置在圆弧终点,不是(200, 200)
ctx.lineTo(200, 200)  // 需要手动连接
ctx.stroke()

arcTo与arc对比

arcTo:适合圆角连接

arc:适合独立圆弧