路径基础

路径是Canvas绑制图形的核心机制。理解路径的工作原理,是掌握Canvas绑制的关键。

路径的概念

可以把路径想象成画笔的运动轨迹。在纸上画画时:

  1. 画笔有抬起和落下两种状态
  2. 抬起时移动画笔不留下痕迹
  3. 落下时移动画笔留下线条

Canvas的路径系统与此类似。

路径的组成

一个完整的路径包含以下元素:

元素方法说明
起点moveTo()设置路径起始位置
线段lineTo()从当前位置画直线到目标位置
弧线arc()绑制圆弧
曲线bezierCurveTo()绑制贝塞尔曲线
闭合closePath()连接终点和起点

路径的生命周期

// 1. 开始新路径
ctx.beginPath()

// 2. 定义路径形状
ctx.moveTo(50, 50)
ctx.lineTo(150, 50)
ctx.lineTo(150, 150)

// 3. 闭合路径(可选)
ctx.closePath()

// 4. 渲染路径
ctx.stroke()  // 描边
ctx.fill()    // 填充

路径生命周期演示

步骤1:beginPath

步骤2:定义形状

步骤3:closePath

步骤4:stroke/fill

子路径

一个路径可以包含多个子路径:

ctx.beginPath()

// 第一个子路径
ctx.moveTo(50, 50)
ctx.lineTo(100, 50)
ctx.lineTo(100, 100)
ctx.closePath()

// 第二个子路径(新的moveTo创建)
ctx.moveTo(150, 50)
ctx.lineTo(200, 50)
ctx.lineTo(200, 100)
ctx.closePath()

// 一起渲染
ctx.stroke()

子路径演示

多个子路径示例

两个三角形共享同一个路径,一起渲染

路径与状态

路径和绑制状态是分开的:

// 设置样式
ctx.strokeStyle = '#e74c3c'
ctx.lineWidth = 3

// 创建路径
ctx.beginPath()
ctx.moveTo(50, 50)
ctx.lineTo(150, 50)
ctx.stroke()

// 改变样式不影响已渲染的路径
ctx.strokeStyle = '#3498db'

// 新路径使用新样式
ctx.beginPath()
ctx.moveTo(50, 100)
ctx.lineTo(150, 100)
ctx.stroke()

路径检测

使用isPointInPath检测点是否在路径内:

ctx.beginPath()
ctx.rect(50, 50, 100, 80)

if (ctx.isPointInPath(80, 70)) {
  console.log('点在矩形内')
}

if (ctx.isPointInStroke(80, 50)) {
  console.log('点在边框上')
}

常见错误

忘记beginPath

// 错误:路径累积
ctx.moveTo(50, 50)
ctx.lineTo(100, 100)
ctx.stroke()

ctx.lineTo(200, 100)  // 会连接到上一个终点
ctx.stroke()

// 正确:每次新路径都beginPath
ctx.beginPath()
ctx.moveTo(50, 50)
ctx.lineTo(100, 100)
ctx.stroke()

ctx.beginPath()
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.stroke()

beginPath错误演示

❌ 错误:忘记beginPath

✓ 正确:使用beginPath