1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
| class Bezier { constructor(ctx) { this.ctx = ctx; }
draw(controlPoints, t = 1) { if (!controlPoints.length) return; const curvePoints = []; let i = 0; while (i <= t) { this.drawLines(controlPoints, i, curvePoints, false, null, "blue"); i += 0.01; } this.drawLines(controlPoints, t, curvePoints, false, null, "blue"); return curvePoints; }
drawAnimation(controlPoints, t = 1) { if (!controlPoints.length) return Promise.resolve([]); return new Promise((resolve) => { const curvePoints = []; let i = 0; const p2d = new Path2D(); const draw = () => { ctx.clearRect(0, 0, canvas.width, canvas.height); if (i > t) { this.drawLines(controlPoints, t, curvePoints, true, p2d, "blue"); resolve(curvePoints); return; } ctx.fillText(`t = (${i.toFixed(2)})`, 10, 20); this.drawLines(controlPoints, i, curvePoints, true, p2d, "blue"); i += 0.01; requestAnimationFrame(draw); }; draw(); }); }
drawLines(points, t, curvePoints, isAnimation, p2d, color) { if (points.length < 2) { curvePoints.push({ ...points[0] }); this.drawCurve(curvePoints, isAnimation, p2d); return; } if (isAnimation) { this.ctx.save(); for (let i = 0; i < points.length; i++) { this.ctx.beginPath(); this.ctx.strokeStyle = color ?? "red"; this.ctx.lineWidth = 2; i > 0 && this.ctx.moveTo(points[i - 1].x, points[i - 1].y); this.ctx.lineTo(points[i].x, points[i].y); this.ctx.stroke(); this.ctx.beginPath(); this.ctx.strokeStyle = "black"; this.ctx.lineWidth = 1; this.ctx.arc(points[i].x, points[i].y, 5, 0, 2 * Math.PI); this.ctx.stroke(); } this.ctx.restore(); } const newPoints = []; for (let i = 0; i < points.length - 1; i++) { newPoints.push(this.calcMotionPoint(points[i], points[i + 1], t)); } this.drawLines(newPoints, t, curvePoints, isAnimation, p2d, null); }
drawCurve(curvePoints, isAnimation, p2d) { const len = curvePoints.length; if (isAnimation) { const x = curvePoints[len - 1].x; const y = curvePoints[len - 1].y; p2d.lineTo(x, y); this.ctx.stroke(p2d); this.ctx.save(); this.ctx.beginPath(); this.ctx.strokeStyle = "blue"; this.ctx.lineWidth = 1; this.ctx.arc(x, y, 5, 0, 2 * Math.PI); this.ctx.stroke(); this.ctx.restore(); } else { if (len < 3) return; this.ctx.beginPath(); this.ctx.moveTo(curvePoints[len - 3].x, curvePoints[len - 3].y); this.ctx.lineTo(curvePoints[len - 2].x, curvePoints[len - 2].y); this.ctx.lineTo(curvePoints[len - 1].x, curvePoints[len - 1].y); this.ctx.stroke(); } }
calcMotionPoint(p1, p2, t) { return { x: (1 - t) * p1.x + t * p2.x, y: (1 - t) * p1.y + t * p2.y, }; } }
|