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

如何在JavaScript中基于固定形态生成贝塞尔曲线控制点?

通用三阶贝塞尔曲线控制点计算需求

我需要一个通用计算方法来确定三阶贝塞尔曲线的两个控制点(对应代码中的control2和control3),确保无论使用任意随机起止点对,绘制出的曲线都能保持下图所示的基本形态。

目标贝塞尔曲线形态

当前代码中的控制点计算仅适用于示例场景,无法适配任意起止点;同时因为Canvas坐标系Y轴方向与标准坐标系相反,现有的方向增量计算(lineRun和lineRise)存在错误。以下是当前的演示代码:

JavaScript 代码

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

let canvasWidth = canvas.width;
let canvasHeight = canvas.height;
let zoneWidth = canvas.width*0.2;
let zoneHeight = canvas.height*0.2;
let zoneTopLeftX = (canvas.width/2) - (zoneWidth/2);
let zoneTopLeftY = (canvas.height/2) - (zoneHeight/2);

let startPoint = {x:zoneTopLeftX+30, y:zoneTopLeftY+(zoneHeight/2)};
let endPoint = {x:zoneTopLeftX+zoneWidth-30, y:zoneTopLeftY+(zoneHeight/2)};

// lineRun和lineRise的符号应表示方向,但由于Canvas坐标系与标准坐标系不同(至少Y轴如此),当前方向不正确。
let lineRun = startPoint.x - endPoint.x; // X轴增量
let lineRise = startPoint.y - endPoint.y; // Y轴增量

// 此计算仅适用于示例场景,我需要适用于任意随机起止点对的通用计算方法。
let cpX = (endPoint.x - lineRun) + (lineRise);
let cpY = (endPoint.y - lineRise) + (lineRun);
let control2 = {x:cpX, y:cpY};
//console.log(cpX, cpY, control2);

// 同样,此计算仅适用于示例场景,我需要适用于任意随机起止点对的通用计算方法。
cpX = startPoint.x;
cpY = startPoint.y + lineRun + lineRun;
let control3 = {x:cpX, y:cpY};
//console.log(cpX, cpY, control3);

ctx.fillStyle = "#eee"; // 浅灰色
ctx.fillRect(0, 0, canvasWidth, canvasHeight);

ctx.fillStyle = "#aaa"; // 灰色
ctx.fillRect(zoneTopLeftX, zoneTopLeftY, zoneWidth, zoneHeight);

ctx.beginPath();
// 为演示标注所有元素
ctx.font = "bold 12px Courier";
ctx.strokeText("canvas width: "+canvasWidth, 15, 15);
ctx.strokeText("canvas height: "+canvasHeight, 15, 30);

ctx.beginPath();
ctx.arc(startPoint.x, startPoint.y, 5, 0, 2 * Math.PI); // 点1
ctx.fillStyle = "red";
ctx.fill();
ctx.strokeText("1 (" + (startPoint.x + "").substring(0,5) + "," + (startPoint.y + "").substring(0,5) + ")", startPoint.x+5, startPoint.y+15);

ctx.beginPath();
ctx.arc(control2.x, control2.y, 5, 0, 2 * Math.PI);     // 点2
ctx.fillStyle = "#b1e22b"; // 黄绿色
ctx.fill();
ctx.strokeText("2 (" + (control2.x + "").substring(0,5) + "," + (control2.y + "").substring(0,5) + ")", control2.x+5, control2.y+15);

ctx.beginPath();
ctx.arc(control3.x, control3.y, 5, 0, 2 * Math.PI);     // 点3
ctx.fillStyle = "#8a2be2"; // 紫灰色
ctx.fill();
ctx.strokeText("3 (" + (control3.x + "").substring(0,5) + "," + (control3.y + "").substring(0,5) + ")", control3.x+5, control3.y+15);

ctx.beginPath();
ctx.arc(endPoint.x, endPoint.y, 5, 0, 2 * Math.PI);     // 点4
ctx.fillStyle = "blue";
ctx.fill();
ctx.strokeText("4 (" + (endPoint.x + "").substring(0,5) + "," + (endPoint.y + "").substring(0,5) + ")", endPoint.x+5, endPoint.y+15);

ctx.moveTo(startPoint.x, startPoint.y);
ctx.bezierCurveTo(control2.x, control2.y, control3.x, control3.y, endPoint.x, endPoint.y);
ctx.stroke();

CSS 代码

#canvas {
  position: absolute;
}

HTML 代码

<canvas id="canvas" width="800" height="800"></canvas>
<div id="results"></div>

感谢任何帮助!


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:13:15