Canvas绘制复杂图形的关键在于路径连接逻辑:先用beginPath()清空状态,再用moveTo()定位起点,连续lineTo()延展折线链,closePath()可选闭合,最后stroke()或fill()渲染。

Canvas绘制复杂图形,关键不在画多少线,而在于怎么“连”这些线。lineTo和moveTo不是独立动作,它们共同构成一条路径的节奏:moveTo定起点,lineTo画线并自动把终点变成下一个起点。漏掉beginPath或误用坐标,图形就容易错位、重叠甚至不显示。
moveTo是“抬笔再落”的定位动作
它本身不画任何东西,只把绘图“光标”移到指定位置,为后续lineTo提供起点。必须配合beginPath()使用,否则可能接着上一次路径继续画,导致意外连接。
- 每次开始新图形前,先调用ctx.beginPath(),再用ctx.moveTo(x, y)
- 如果跳过moveTo,直接lineTo,Canvas会从默认原点(0, 0)或上一个lineTo的终点开始连线——这常造成首段“飞线”
- 在绘制多边形或分段图形时,每个独立轮廓都应以自己的moveTo开头
lineTo是“拖笔画线+自动续位”的核心操作
它从当前光标位置(即上一步moveTo或lineTo的终点)画直线到新坐标,并立刻把光标移到该终点。这意味着连续多个lineTo,天然形成折线链。
- 第一个lineTo的起点 = moveTo设定的位置
- 第二个lineTo的起点 = 第一个lineTo的终点,无需再次moveTo
- 若两个lineTo参数完全相同,将生成零长度线段,stroke后不可见——这是线条“消失”的常见原因
组合路径的典型结构
绘制任意封闭或多段图形,基本骨架固定:
- ctx.beginPath()
- ctx.moveTo(x1, y1) —— 起始锚点
- ctx.lineTo(x2, y2)
- ctx.lineTo(x3, y3)
- ……(可重复多次)
- ctx.closePath() —— 可选,自动连回起点,对fill或stroke闭合区域很重要
- ctx.stroke() 或 ctx.fill()
比如画三角形:moveTo顶点A → lineTo顶点B → lineTo顶点C → closePath → fill,整个过程逻辑清晰、无歧义。
避免常见逻辑陷阱
初学者容易卡在几个“看似合理实则错误”的写法上:
- 重复调用moveTo却不接lineTo:光标反复跳转,但没留下任何路径
- 忘记beginPath()就连续绘图:多个图形路径被拼成一条,fill时颜色溢出、stroke时线条粘连
- 用lineTo代替moveTo来“跳转”:lineTo总会画线,想空移必须用moveTo
- 在循环中未重置起始点:比如画多个独立矩形,每个都需自己的beginPath + moveTo
本质上,Canvas路径是一条有方向、有状态的“笔迹流”。理解moveTo设起点、lineTo延路径、beginPath清状态这三者的关系,复杂图形就只是坐标的有序排列。











