Canvas画贝塞尔曲线的关键在于明确起点和控制逻辑:quadraticCurveTo需一个控制点,bezierCurveTo需两个,二者均不定义起点,须由moveTo或前段终点提供;连续绘制时须确保路径衔接准确,避免断开或偏移。

Canvas 画贝塞尔曲线,关键不在函数本身,而在于你是否清楚每条曲线依赖的“起点”和“控制逻辑”。quadraticCurveTo 和 bezierCurveTo 都不定义起点,只负责从当前绘图位置画出一段平滑曲线——起点必须由 moveTo 或前一段路径的终点明确提供。
quadraticCurveTo:一个控制点,适合简单弧度
它生成的是二次贝塞尔曲线,由起点(当前点)、1个控制点、1个终点共三个点决定。控制点像一根“牵引杆”,离线段越远,曲线拱起越高;靠近中点,曲线越平缓。
- 调用前务必用 ctx.moveTo(x, y) 设好起点,否则默认从 (0, 0) 开始,容易画偏
- 参数顺序是 quadraticCurveTo(cpX, cpY, endX, endY),别把控制点和终点坐标填反
- 适合圆角矩形单边、下拉动画边框、简易抛物线弹道等场景
- 连续多段时,每段终点自动成为下一段起点,但要注意前一段是否真以你期望的位置结束
bezierCurveTo:两个控制点,支持S形与复杂拐弯
它生成三次贝塞尔曲线,起点(当前点)+ 2个控制点 + 终点,共四个点。两个控制点分别影响曲线起始段和结束段的切线方向,因此能做出带拐点、回旋或波浪状的形态。
- 参数严格为 bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, endX, endY)
- 若两个控制点几乎共线或重合,曲线会退化成近似直线,甚至“塌陷”
- 调试时建议临时画出控制点连线:ctx.lineTo(cp1X, cp1Y); ctx.moveTo(cp1X, cp1Y); ctx.lineTo(cp2X, cp2Y); ctx.moveTo(cp2X, cp2Y); ctx.lineTo(endX, endY)
- 在高 DPI 屏幕上,控制点坐标尽量取整,避免 ±1px 偏差引发视觉抖动
曲线接不上的常见原因和解法
不是方法错了,而是 Canvas 路径状态没管好。quadraticCurveTo 和 bezierCurveTo 都只追加曲线段,不会自动连接前一段的终点。
- “中间有白缝”“看起来断了一截”,大概率是前一段终点 ≠ 当前段期望起点
- 不要依赖非标准属性 ctx.currentPoint 获取当前位置,它不可靠
- 稳妥做法:绘制连续曲线时,用 ctx.lineTo(x, y) 显式衔接,或每次用 ctx.moveTo(x, y) 重置起点
- 调用 closePath() 前,确认当前点就是你想闭合到的位置,否则它会直线连回子路径起点,可能切穿曲线内部


















