如何进行多选矩形?

How to make multiple selection rects?

我正在用 EJS 制作一个网站(服务器用 Express),它会做一些图像处理。我想做一个功能,用户可以 select 他们上传的图像的一部分,当按下保存按钮时, selected 区域的坐标被保存。他们可以根据需要多次这样做。但是,如果他们在再次 select 一个区域时不单击保存按钮,则旧区域将被覆盖。我在 select 时遇到问题 - 矩形坐标不正确并且通常无法正常工作。我目前正在使用 HTML canvas 来执行此操作,但欢迎提出任何建议。 相关代码如下:

表格(注意是EJS不是HTML):

<form id="edit-form" action="/process" method="POST">
    <input
        type="text"
        id="comment-input"
        placeholder="Write a comment: "
        spellcheck="true"
    />

    <button onclick="addComment();" type="button">Add comment</button><br />

    <p id="feedback"></p>

    <ol id="comments-list"></ol>
    <br />

    <canvas id="edit-canvas"></canvas>
    <br />

    <input type="text" name="comments" style="display: none" />
    <input type="text" name="image" style="display: none" />

    <button type="submit">Submit</button>
</form>

<script src="./js/edit.js"></script>
<script>
    imageExport.value = "<%- image %>";

    const backgroundImage = new Image();

    backgroundImage.src = "/downloads/<%- image %>";

    backgroundImage.onload = () => {
        editCanvas.width = backgroundImage.width;
        editCanvas.height = backgroundImage.height;

        ctx.drawImage(backgroundImage, 0, 0);
    };
</script>

JavaScript代码:

const editCanvas = document.querySelector("#edit-canvas");

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

editCanvas.addEventListener("mousedown", (event) => {
    const startCoords = { x: event.offsetX, y: event.offsetY };

    // draw rect to mouse x and y
    ctx.fillRect(startCoords.x, startCoords.y, event.clientX, event.clientY);

    editCanvas.addEventListener("mouseup", (event2) => {
        ctx.clearRect(startCoords.x, startCoords.y, event.clientX, event.clientY);

        const endCoords = { x: event2.offsetX, y: event2.offsetY };

        ctx.fillRect(
            startCoords.x,
            startCoords.y,
            endCoords.x - startCoords.x,
            endCoords.y - startCoords.y
        );
    });
});

您的代码中有几个错误。

(1)

您正在 mousedown 侦听器中添加一个 mouseup 侦听器。这意味着每次有人点击 canvas 它都会创建一个新的监听器,导致 mouseup 监听器被多次触发。

(2)

您只是在 pressing/releasing canvas 上绘制矩形,而不是在用户实际移动鼠标时绘制。

(3)

在回调函数中,您使用事件的 .offsetX.offsetY 属性来访问位置。错了,你需要分别使用 .clientX.clientY。此外,代码没有考虑 canvas 元素本身在屏幕上的位置,需要从鼠标位置中减去。

如果我们遍历以上所有要点,我们将得出以下结论:

const editCanvas = document.querySelector("#edit-canvas");
const ctx = editCanvas.getContext("2d");
const backgroundImage = new Image();
let painting = false;

backgroundImage.onload = () => {
  editCanvas.width = backgroundImage.width;
  editCanvas.height = backgroundImage.height;

  ctx.drawImage(backgroundImage, 0, 0);
}

backgroundImage.src = "https://picsum.photos/id/237/200/300";
let startCoords, canvasPosition;

editCanvas.addEventListener("mousedown", (event) => {
  painting = true;
  canvasPosition = editCanvas.getBoundingClientRect();
  startCoords = {
    x: event.clientX - canvasPosition.left,
    y: event.clientY - canvasPosition.top
  };
});

editCanvas.addEventListener("mousemove", (event) => {
  if (painting) {
  canvasPosition = editCanvas.getBoundingClientRect();
    let endCoords = {
      x: event.clientX - canvasPosition.left,
      y: event.clientY - canvasPosition.top
    };
    ctx.drawImage(backgroundImage, 0, 0);
    ctx.fillStyle = 'rgba(255,0,0,0.4)';
    ctx.fillRect(
      startCoords.x,
      startCoords.y,
      endCoords.x - startCoords.x,
      endCoords.y - startCoords.y
    );
  }
});

editCanvas.addEventListener("mouseup", () => {
  painting = false;
});
<form id="edit-form" action="/process" method="POST">
  <input type="text" id="comment-input" placeholder="Write a comment: " spellcheck="true" />

  <button onclick="addComment();" type="button">Add comment</button><br />

  <p id="feedback"></p>

  <ol id="comments-list"></ol>
  <br />

  <canvas id="edit-canvas"></canvas>
  <br />

  <input type="text" name="comments" style="display: none" />
  <input type="text" name="image" style="display: none" />

  <button type="submit">Submit</button>
</form>