canvas绘制平滑曲线需用多段三次贝塞尔曲线拼接,确保经过所有给定点;关键在于按四点滑动窗口(p0-p1-p2-p3)计算控制点,缩放系数取0.25,首尾点特殊处理,并启用round线帽/线连接提升视觉效果。

Canvas 绘制平滑曲线,核心不是“画一条线”,而是用多段贝塞尔曲线拼接出视觉连续、无尖角的路径,同时确保曲线经过所有给定点(而非仅逼近)。直接用 lineTo 或简单 quadraticCurveTo 串连,容易出现拐点生硬或不经过中间点的问题。关键在于合理计算控制点。
控制点决定平滑度和过点精度
Canvas 本身不提供“插值拟合”API,必须手动算控制点。三次贝塞尔曲线(bezierCurveTo)最常用,因它有两个控制点,能更好调节曲率。要让曲线穿过点列 P₀, P₁, P₂, ..., Pₙ,通常把每相邻三或四个点作为一段的锚点,并为每段生成合适的控制点。
常见可靠做法是:
- 起始点
P₀为路径起点 - 对每个
i从1到n−2,以Pᵢ为当前段终点,用Pᵢ₋₁,Pᵢ,Pᵢ₊₁,Pᵢ₊₂计算两控制点 - 控制点偏移量一般取相邻向量的固定比例(如 1/4 或 1/5),太大会翘起,太小则趋近直线
例如这段典型计算:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
const cp1x = p1.x + (p2.x - p0.x) / 4; const cp1y = p1.y + (p2.y - p0.y) / 4; const cp2x = p2.x - (p3.x - p1.x) / 4; const cp2y = p2.y - (p3.y - p1.y) / 4; ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, p2.x, p2.y);
其中 p0→p1→p2→p3 是滑动四元组,p2 是本段真正经过的点。
两端点需要特殊处理
首尾两个点无法套用四点公式(缺前驱或后继),常见稳妥方案:
- 起点
P₀直接moveTo - 终点
Pₙ作为最后一段的终点,不额外延伸 - 首段控制点可用
P₀→P₁→P₂估算,末段用Pₙ₋₂→Pₙ₋₁→Pₙ估算 - 或者加虚拟点(如镜像延拓),避免端点处曲率突变
二次贝塞尔也可行,但适用场景更窄
若点较稀疏、对精度要求不高,可用 quadraticCurveTo,逻辑更简:
- 每三个点
A→B→C构成一段,B是曲线必经点 - 控制点
Q按公式:Q.x = 2*B.x - (A.x + C.x)/2,同理算 y - 然后
moveTo(A)→quadraticCurveTo(Q, C) - 缺点是整条曲线由若干独立二次段拼成,连接处一阶导数未必连续(可能微小折角)
实际建议:优先用三次贝塞尔 + 均匀步进
- 点数 ≥ 4 时,三次贝塞尔拼接效果更稳
- 控制点缩放系数
a = b = 0.25是经验起点,可微调(0.2 更柔和,0.3 更贴点) - 绘制前务必
beginPath(),避免残留路径干扰 - 可选开启抗锯齿:
ctx.lineCap = 'round'; ctx.lineJoin = 'round'; - 若需动画或交互重绘,把点坐标和控制点缓存,避免每帧重复计算
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










