用 3 个给定点画布绘制抛物线

问题描述

我需要在 html5 画布中绘制一条完美的曲线/抛物线。给出了点的 3 {x;y} 坐标。我尝试使用 bezierCurveto 或 quadraticCurveto,但曲线不会到达中间点。

我想要的结果(蓝色虚线和蓝色曲线):Wanted result

我得到的结果:Current result

代码

      ctx.strokeStyle = '#00478a';
      ctx.linewidth = 1.5;

      ctx.beginPath();
      ctx.moveto(x1AtRatio,30);
      ctx.quadraticCurveto(criticalSectionAtRatio,100,x2AtRatio,30);

      ctx.stroke();

其中 x1AtRatio - x2AtRatio - criticalSectionAtRatio 是用户输入的给定 x,30 - 100 - 30 是 y

解决方法

控制点定义斜率

您需要使用两个贝塞尔曲线,因为曲线不会通过控制点。

控制点设置曲线从最后一个点到下一个点的斜率。

示例(如下)使用两条曲线绘制抛物线。函数drawCurve()

  • 我画了两次,一次缩放一次,一次正常。
  • 控制点为蓝色。
  • 曲线上的三个点是红色的
  • 斜坡是绿色的。

例如

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

// drawScaled
ctx.setTransform(2,2,-50,-55);
drawAll();

// without scale
ctx.setTransform(1,1,0);
drawAll();

function drawCurve() {
    ctx.beginPath();
    ctx.strokeStyle = "#000";
    ctx.moveTo(100 - 30,30);  // start left side
    ctx.quadraticCurveTo(
        100 - 30 / 2,100,// controls point sets slope out from start and into center
        100,100               // center point
    );
    ctx.quadraticCurveTo(
        100 + 30 / 2,// control point sets slope out from center and into last point
        100 + 30,30           // last point
    );
    ctx.stroke();
}

function drawAll() {
    // points on curve
    drawPoint(100-30,30);
    drawPoint(100,100);
    drawPoint(100+30,30);

    // Control points
    drawPoint(100 - 30 / 2,"#00F");
    drawPoint(100 + 30 / 2,"#00F");

    // Draw line through all points to show slopes
    drawLine(100-30,30,100 - 30 / 2,100);
    drawLine(100 - 30 / 2,100);
    drawLine(100,100 + 30 / 2,100);
    drawLine(100 + 30 / 2,100 + 30,30);

    // Draw curve
    drawCurve();
}




function drawPoint(x,y,col = "red") {
    ctx.fillStyle = col;
    ctx.beginPath();
    ctx.arc(x,Math.PI * 2);
    ctx.fill();
}
function drawLine(x,x1,y1,col = "#0A08") {
    ctx.strokeStyle = col;
    ctx.beginPath();
    ctx.lineTo(x,y);
    ctx.lineTo(x1,y1);
    ctx.stroke();
}
canvas {
    border: 1px solid black;
}
<canvas id="canvas"></canvas>