As requested in the comments, I have made a simpler example that focuses on the question. That being how to correctly calculate the two control points for a bezier curve that follows the pattern pictured below.
The solution I'm looking for needs calculate the variables control2 and control3 so that the curve draw has the same general form for any random pair of start/end points.
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)};
// The sign of lineRun and lineRise should tell direction, but
// it's not the correct direction because canvas points are
// numbered differently from standard graph. At least it is for y.
let lineRun = startPoint.x - endPoint.x; // delta along the X-axis
let lineRise = startPoint.y - endPoint.y; // delta along the Y-axis
// This math works only in the example case. I need better math,
// math that will work for any random start/end pair.
let cpX = (endPoint.x - lineRun) + (lineRise);
let cpY = (endPoint.y - lineRise) + (lineRun);
let control2 = {x:cpX, y:cpY};
//console.log(cpX, cpY, control2);
// Again, this math works only in the example case. I need better math,
// math that will work for any random start/end pair.
cpX = startPoint.x;
cpY = startPoint.y + lineRun + lineRun;
let control3 = {x:cpX, y:cpY};
//console.log(cpX, cpY, control3);
ctx.fillStyle = "#eee"; // lite grey
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.fillStyle = "#aaa"; // grey
ctx.fillRect(zoneTopLeftX, zoneTopLeftY, zoneWidth, zoneHeight);
ctx.beginPath();
// lable everything for demo
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); // point 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); // point 2
ctx.fillStyle = "#b1e22b"; // yellow-green
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); // point 3
ctx.fillStyle = "#8a2be2"; // purple-ish
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); // point 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();
#canvas {
position: absolute;
}
<canvas id="canvas" width="800" height="800"></canvas>
<div id="results"></div>
Any help is appreciated!
