arcTo方法用于绑制圆角和圆弧连接。它比arc更灵活,适合绑制圆角矩形等图形。
ctx.arcTo(x1, y1, x2, y2, radius)
| 参数 | 类型 | 说明 |
|---|---|---|
| x1, y1 | number | 第一个控制点坐标 |
| x2, y2 | number | 第二个控制点坐标 |
| radius | number | 圆弧半径 |
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()
当前位置: (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()