You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何绘制经过指定控制点的Canvas二次贝塞尔曲线

让Canvas二次贝塞尔曲线经过指定点的实现方法

你当前的代码是把目标点当作二次贝塞尔曲线的控制点来使用,但二次贝塞尔的控制点本身并不在曲线上,只是用于控制曲线的弯曲方向。要让曲线经过指定点,需要通过贝塞尔曲线的参数方程反推真正的控制点。

核心原理

二次贝塞尔曲线的参数方程为(t取值范围[0,1]):

B(t) = (1-t)²P₀ + 2t(1-t)P_c + t²P₁

其中:

  • P₀是曲线起点,P₁是曲线终点
  • P_c是贝塞尔控制点(不在曲线上)
  • 若要曲线经过目标点Q,只需代入Q=B(t),即可解出对应的P_c。

方法一:让目标点作为曲线中点(t=0.5)

当目标点是曲线的中点时,参数方程可以简化为:

P_c = 2Q - (P₀ + P₁)/2

对应代码实现:

const startPoints = [0, 0];
const targetPoint = [100, 40]; // 你希望曲线经过的点
const endPoints = [200, 200];

// 计算贝塞尔控制点
const getBezierControl = (p0, q, p1) => {
  return [
    2 * q[0] - (p0[0] + p1[0]) / 2,
    2 * q[1] - (p0[1] + p1[1]) / 2
  ];
};

const bezierControl = getBezierControl(startPoints, targetPoint, endPoints);

// 绘制曲线
ctx.moveTo(...startPoints);
ctx.quadraticCurveTo(...bezierControl, ...endPoints);
ctx.stroke();

代入你的坐标计算后,贝塞尔控制点为[100, -20],绘制出的曲线会准确经过(100, 40)。


方法二:指定目标点在曲线上的任意位置(自定义t值)

如果需要目标点在曲线的任意位置(比如t=0.3,即从起点到终点30%的位置),使用通用公式计算:

P_c = [Q - (1-t)²P₀ - t²P₁] / [2t(1-t)]

对应代码:

const startPoints = [0, 0];
const targetPoint = [100, 40];
const endPoints = [200, 200];
const t = 0.3; // 目标点对应的参数值

const getBezierControl = (p0, q, p1, t) => {
  const denominator = 2 * t * (1 - t);
  return [
    (q[0] - Math.pow(1 - t, 2) * p0[0] - Math.pow(t, 2) * p1[0]) / denominator,
    (q[1] - Math.pow(1 - t, 2) * p0[1] - Math.pow(t, 2) * p1[1]) / denominator
  ];
};

const bezierControl = getBezierControl(startPoints, targetPoint, endPoints, t);

// 绘制曲线
ctx.moveTo(...startPoints);
ctx.quadraticCurveTo(...bezierControl, ...endPoints);
ctx.stroke();

总结

二次贝塞尔曲线的控制点和“曲线上的点”是完全不同的概念,通过参数方程反推是实现需求的核心。你可以根据需要选择目标点在曲线上的位置,计算出对应的控制点后再绘制曲线。

内容的提问来源于stack exchange,提问作者mediumgoal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 23:40:40