使用 Catmull-Rom 曲线实现Canvas手写轨迹平滑曲线
drawSmoothPath(points) {
let canvasDom = this.$refs["canvas"];
let ctx = canvasDom.getContext("2d");
ctx.strokeStyle = "#ff0000";
ctx.lineWidth = 1;
// 遍历所有点,绘制光滑路径
for (let i = 0; i < points.length - 1; i++) {
const p0 = points[i > 0 ? i - 1 : i]; // 获取前一个控制点
const p1 = points[i]; // 当前控制点
const p2 = points[i + 1]; // 下一个控制点
const p3 = points[i + 2 < points.length ? i + 2 : points.length - 1]; // 下下一个控制点,确保不会超出范围
ctx.beginPath(); // 开始一条新路径
ctx.moveTo(p1.x, p1.y); // 移动到当前控制点的位置
// 以 t 从 0 到 1 的步骤绘制曲线
for (let t = 0; t <= 1; t += 0.1) {
const x = // 计算插值点的 x 坐标
0.5 *
(2 * p1.x +
(-p0.x + p2.x) * t +
(2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * t * t +
(-p0.x + 3 * p1.x - 3 * p2.x + p3.x) * t * t * t);
const y = // 计算插值点的 y 坐标
0.5 *
(2 * p1.y +
(-p0.y + p2.y) * t +
(2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * t * t +
(-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * t * t * t);
ctx.lineTo(x, y); // 连接到计算出的点
}
ctx.stroke(); // 绘制路径
}
},
let arr = [{x:10,y:11},{x:11,y:12},{x:14,y:15},{x:115,y:17}]; //入参结构
drawSmoothPath(arr);
解析
基于 Catmull-Rom 曲线的数学推导,该曲线是由一组控制点定义的。p0, p1, p2, p3: 这些是控制点,分别是我们正在插值的点的前一个、当前、下一个和下下一个点。