有没有办法使用 HTML canvas 围绕这两个圆圈绘制路径/形状?

Not*_*ota 4 html javascript css canvas

我想在两个圆圈周围添加一个形状/路径。 我想要的图片

这是我当前的代码。

var length = 200
var size = 50
// circles
ctx.beginPath();
ctx.arc(123,120,100,0,2*Math.PI);
ctx.stroke();
ctx.fill()
ctx.beginPath();
ctx.arc(length,length,size,0,2*Math.PI);
ctx.stroke();
ctx.fill()
// line between the 2 circles
ctx.beginPath();
ctx.moveTo(123,120);
ctx.lineTo(length,length);
ctx.stroke();
Run Code Online (Sandbox Code Playgroud)

use*_*291 7

如果找到两个圆的外切线,就可以在它们之间画两条线。然后您可以使用 .arc 绘制剩余的圆形部分:

// Setup
const cvs = document.createElement("canvas");
cvs.width = cvs.height = 400;
const ctx = cvs.getContext("2d");
const inputs = Array.from(document.querySelectorAll("input"));
inputs.forEach(el => el.addEventListener("input", onChange));
document.body.appendChild(cvs);
onChange();


// Drawing utils
function drawCircle({ x, y, r }, color = "black", width = 1) {
  ctx.strokeStyle = color;
  ctx.lineWidth = width;
  ctx.beginPath();
  ctx.arc(x, y, r, 0, 2*Math.PI);
  ctx.stroke();
}

function drawLine(x1, y1, x2, y2, color = "black", width = 1) {
  ctx.strokeStyle = color;
  ctx.lineWidth = width;
  
  ctx.beginPath();
  ctx.moveTo(x1, y1);
  ctx.lineTo(x2, y2);
  ctx.stroke();
}

function drawArc(x, y, r, a1, a2, color = "black", width = 1) {
  ctx.strokeStyle = color;
  ctx.lineWidth = width;
  
  ctx.beginPath();
  ctx.arc(x, y, r, a1, a2);
  ctx.stroke();
}



function render(c1, c2) {
  ctx.clearRect(0, 0, cvs.width, cvs.height);
  
  // circles
  drawCircle(c1);
  drawCircle(c2);

  // line between the 2 circles
  drawLine(c1.x, c1.y, c2.x, c2.y);

  // tangents
  const tangents = outerTangents(c1, c2);
  tangents.lines.forEach(
    ([[x1, y1], [x2, y2]]) => drawLine(x1, y1, x2, y2, "rgba(255, 0, 0, 0.5)", 5)
  );

  // Arcs
  const [ a1, a2 ] = tangents.angles;
  const from = a2 + a1;
  const to = a1 - a2;
  drawArc(c1.x, c1.y, c1.r, from, to, "rgba(0, 255, 255, 0.5)", 5);
  drawArc(c2.x, c2.y, c2.r, to, from, "rgba(255, 0, 255, 0.5)", 5);
}

function onChange() {
  const [ x1, y1, r1, x2, y2, r2 ] = inputs.map(el => el.valueAsNumber);
  render({ x: x1, y: y1, r: r1 }, { x: x2, y: y2, r: r2 });
}

// https://en.wikipedia.org/wiki/Tangent_lines_to_circles#Outer_tangent
function outerTangents({ x: x1, y: y1, r: r1 }, { x: x2, y: y2, r: r2 }) {
  const dx = x2 - x1;
  const dy = y2 - y1;
  const dxy = Math.sqrt(dx ** 2 + dy ** 2);

  if (dxy <= Math.abs(r2 - r1)) {
    return { lines: [], angles: [] };
  }

  const a1 = Math.atan2(dy, dx);
  const a2 = Math.acos((r1 - r2) / dxy);

  return {
    lines: [
      [
        [x1 + r1 * Math.cos(a1 + a2), y1 + r1 * Math.sin(a1 + a2)],
        [x2 + r2 * Math.cos(a1 + a2), y2 + r2 * Math.sin(a1 + a2)]
      ],
      [
        [x1 + r1 * Math.cos(a1 - a2), y1 + r1 * Math.sin(a1 - a2)],
        [x2 + r2 * Math.cos(a1 - a2), y2 + r2 * Math.sin(a1 - a2)]
      ]
    ],
    angles: [ a1, a2 ]
  };
}
Run Code Online (Sandbox Code Playgroud)
X1 <input type="range" min="10" max="150" step="1" value="123">
Y1 <input type="range" min="10" max="150" step="1" value="120">
R1 <input type="range" min="10" max="150" step="1" value="100">

X2 <input type="range" min="10" max="250" step="1" value="200">
Y2 <input type="range" min="10" max="250" step="1" value="140">
R2 <input type="range" min="10" max="150" step="1" value="50">
Run Code Online (Sandbox Code Playgroud)