使用 mousedown 在 canvas 上拖动一个圆圈

Dragging a circle on a canvas using mousedown

现在,我有 2 个圆圈和中间的一条线。我希望能够拖动其中一个仍然连接着线的圆圈,并且在我移动它时它会保持与圆圈的连接。 node1 和 node2 是圆形维度。 line/muscle 连接到node1 和node2 的x 和y 位置。

function draw() {
    //draw in the container
    c.fillStyle = "#000000";
    c.fillRect(container.y, container.x, container.width, container.height);

    //draw first node
    c.arc(node1.x, node1.y, node1.r, 0, 2*Math.PI);
    c.fillStyle = node1.color;
    c.fill();

    //draw second node
    c.arc(node2.x, node2.y, node2.r, 0, 2*Math.PI);
    c.strokeStyle = node2.color;
    c.fillStyle = node2.color;
    c.fill();

    //draw muscle
    c.beginPath();
    c.moveTo(muscle.node1x, muscle.node1y);
    c.lineTo(muscle.node2x, muscle.node2y);
    c.strokeStyle = muscle.color;
    c.lineWidth = muscle.width;
    c.stroke();
}

项目到目前为止的情况

下面的代码是基于你的draw功能,实现了拖动功能。

function draw(container, c, node1, node2, muscle) {
  //draw in the container
  c.fillStyle = "#000000";
  c.fillRect(container.y, container.x, container.width, container.height);

  //draw first node
  c.arc(node1.x, node1.y, node1.r, 0, 2 * Math.PI);
  c.fillStyle = node1.color;
  c.closePath();
  c.fill();

  //draw second node
  c.arc(node2.x, node2.y, node2.r, 0, 2 * Math.PI);
  c.strokeStyle = node2.color;
  c.fillStyle = node2.color;
  c.closePath();
  c.fill();

  //draw muscle
  c.beginPath();
  c.moveTo(muscle.node1x, muscle.node1y);
  c.lineTo(muscle.node2x, muscle.node2y);
  c.strokeStyle = muscle.color;
  c.lineWidth = muscle.width;
  c.closePath();
  c.stroke();
}

function Node(x, y, r, color) {
  this.x = x;
  this.y = y;
  this.r = r || 20;
  this.color = color || "#ff0";
}

function Muscle(node1, node2, width, color) {
  this.node1 = node1;
  this.node2 = node2;
  this.width = width || 5;
  this.color = color || "#f00";
  Object.defineProperties(this, {
    node1x: {
      "get": () => this.node1.x,
      "set": x => { this.node1.x = x }
    },
    node1y: {
      "get": () => this.node1.y,
      "set": y => { this.node1.y = y }
    },
    node2x: {
      "get": () => this.node2.x,
      "set": x => { this.node2.x = x }
    },
    node2y: {
      "get": () => this.node2.y,
      "set": y => { this.node2.y = y }
    }
  })
}


function handleMouseDrag(canvas, nodes) {
  var isDrag = false;
  var offset = { x: 0, y: 0, x0: 0, y0: 0 };
  var dragNode = undefined;
  canvas.addEventListener("mousedown", function (e) {
    var x = e.offsetX, y = e.offsetY;
    for (var i in nodes) {
      if (Math.pow(x - nodes[i].x, 2) + Math.pow(y - nodes[i].y, 2) < Math.pow(nodes[i].r, 2)) {
        isDrag = true;
        dragNode = nodes[i];
        offset = { x: dragNode.x, y: dragNode.y, x0: x, y0: y };
        return;
      }
    }
  });
  canvas.addEventListener("mousemove", function (e) {
    if (isDrag) {
      dragNode.x = e.offsetX - offset.x0 + offset.x;
      dragNode.y = e.offsetY - offset.y0 + offset.y;
    }
  });
  canvas.addEventListener("mouseup", function (e) {
    isDrag = false;
  });
  canvas.addEventListener("mouseleave", function (e) {
    isDrag = false;
  });
}

function main() {
  var node1 = new Node(40, 40);
  var node2 = new Node(120, 120);
  var muscle = new Muscle(node1, node2);

  var canvas = document.getElementById("canvas");
  var container = { x: 0, y: 0, get width() { return canvas.width }, get height() { return canvas.height } }
  var ctx = canvas.getContext("2d");

  handleMouseDrag(canvas, [node1, node2]);

  function updateFrame() {
    ctx.save();
    draw(container, ctx, node1, node2, muscle);
    ctx.restore();
    requestAnimationFrame(updateFrame)
  };
  updateFrame();
}

main();
<canvas width="400" height="400" id="canvas"></canvas>