Javascript & canvas、图像旋转坐标问题

问题描述 投票:0回答:1

我遇到旋转图像坐标的问题。当我在图像上按鼠标右键时,单击鼠标的位置应出现一个黄色圆圈。它在启动图像、调整大小的图像(鼠标滚轮)和拖动的图像(鼠标左键单击并拖动)上工作得很好。问题是,用滑块旋转图像后,我无法正确计算鼠标的正确坐标 - 例如,当我将图像旋转 180 度时,圆圈出现在对角线上,但它应该出现在我单击的位置。有趣的是,当我在旋转之前放置圆圈,然后旋转图像时,圆圈会以正确的坐标旋转。我的代码中缺少一些转换,但我只是看不到将其放入哪个转换以及何处。我将不胜感激。预先感谢;)

这是我的代码:

window.onload = () => {
  const canvas = document.getElementById("canvas");
  const context = canvas.getContext("2d");
  context.imageSmoothingEnabled = false;
  const mousePos = document.getElementById("mouse-pos");
  const transformedMousePos = document.getElementById("transformed-mouse-pos");

  const image = new Image();
  image.src =
    "https://e7.pngegg.com/pngimages/584/916/png-clipart-bright-blue-sky-aqua-blue-button-rounded-blank-download-free-download-png-download-vector-download-svg-download-transparent-thumbnail.png";
  image.onload = drawImageToCanvas;

  let isDragging = false;
  let dragStartPosition = { x: 0, y: 0 };
  let currentTransformedCursor;

  class Obraz {
    constructor(x, y) {
      this.x = x;
      this.y = y;
    }
  }

  let points = [];

  function markPoint(x, y) {
    let obraz = new Obraz(x, y);
    points.push(obraz);
  }

  function drawPoints() {
    const centerX = canvas.width / 2;
    const centerY = canvas.height / 2;

    context.save();
    context.translate(centerX, centerY);
    context.rotate((rotationAngle * Math.PI) / 180);
    const radius = 10;
    context.lineWidth = 3;
    context.strokeStyle = "#FFFF00";
    context.filter = "none";
    points.forEach((item) => {
      context.beginPath();
      context.arc(
        item.x - centerX,
        item.y - centerY,
        radius,
        0,
        2 * Math.PI,
        false
      );
      context.stroke();
    });
    context.restore();
  }

  function drawImageToCanvas() {
    context.save();
    context.setTransform(1, 0, 0, 1, 0, 0);
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.restore();

    context.save();
    context.translate(canvas.width / 2, canvas.height / 2);
    context.rotate((rotationAngle * Math.PI) / 180);

    context.drawImage(image, -100, -100, 200, 200);
    context.restore();

    drawPoints();
  }

  let rotateSlider = document.getElementById("rotateSlider");
  let rotationAngle = 0;

  rotateSlider.addEventListener("input", function () {
    rotationAngle = this.value;
    drawImageToCanvas(rotationAngle);
  });

  function getTransformedPoint(x, y) {
    const originalPoint = new DOMPoint(x, y);
    return context.getTransform().invertSelf().transformPoint(originalPoint);
  }

  function onMouseDown(event) {
    isDragging = true;
    dragStartPosition = getTransformedPoint(event.offsetX, event.offsetY);

    if (event.button === 2) {
      currentTransformedCursor = getTransformedPoint(
        event.offsetX,
        event.offsetY
      );
      markPoint(currentTransformedCursor.x, currentTransformedCursor.y);

      drawImageToCanvas();
    }
  }

  function onMouseMove(event) {
    currentTransformedCursor = getTransformedPoint(
      event.offsetX,
      event.offsetY
    );
    mousePos.innerText = `Original X: ${event.offsetX}, Y: ${event.offsetY}`;
    transformedMousePos.innerText = `Transformed X: ${currentTransformedCursor.x}, Y: ${currentTransformedCursor.y}`;

    if (isDragging) {
      context.translate(
        currentTransformedCursor.x - dragStartPosition.x,
        currentTransformedCursor.y - dragStartPosition.y
      );
      drawImageToCanvas();
    }
  }

  function onMouseUp() {
    isDragging = false;
  }

  function onWheel(event) {
    const zoom = event.deltaY < 0 ? 1.1 : 0.9;

    context.translate(currentTransformedCursor.x, currentTransformedCursor.y);
    context.scale(zoom, zoom);
    context.translate(-currentTransformedCursor.x, -currentTransformedCursor.y);

    drawImageToCanvas();
    event.preventDefault();
  }

  let buttonReset = document.getElementById("reset");

  buttonReset.addEventListener("click", function (event) {
    rotateSlider.value = 0;
    rotationAngle = 0;
    drawImageToCanvas();
  });

  let buttonClear = document.getElementById("clear");

  buttonClear.addEventListener("click", function (event) {
    points = [];
    drawImageToCanvas();
  });

  canvas.addEventListener("mousedown", onMouseDown);
  canvas.addEventListener("mousemove", onMouseMove);
  canvas.addEventListener("mouseup", onMouseUp);
  canvas.addEventListener("wheel", onWheel);

  canvas.addEventListener("contextmenu", function (ev) {
    ev.preventDefault();
  });
};
.nav-header {
    font-size: 1.5rem;
}
 
.row {
    margin-bottom: 0;
}
 
#sourceImage,
.image-controls,
.image-save,
.preset-filters {
    display: none;
}
 
.image-preview {
    display: flex;
    justify-content: center;
    margin-top: 20px;
}
 
#canvas {
    max-height: 420px;
    object-fit: contain;
}

.container-image {
    overflow: auto;
    justify-content: center;
    align-items: center;

    width: 90%;
    height: 90%;

    position: absolute;
}

.image {
    object-fit: cover;
    transform: translate(20%, 20%);
}
<canvas id="canvas" width="350" height="350"></canvas>

<div class="col s6">
  <span class="range-field">
    <input id="rotateSlider" type="range" value="0" min="-180" max="180">
  </span>
  <button class="btn btn-flat red white-text" id="reset">
    Reset
  </button>
  <button class="btn btn-flat red white-text" id="clear">
    Clear
  </button>
</div>

<div id="mouse-pos"></div>
<div id="transformed-mouse-pos"></div>

javascript html image canvas
1个回答
0
投票

我找到了问题的解决方案,需要在单击方法下“稍微”修改变换。我将离开这个主题,以防有人会考虑类似的解决方案。

function onMouseDown(event) {
    isDragging = true;
    dragStartPosition = getTransformedPoint(event.offsetX, event.offsetY);
    
    if (event.button === 2) {
        currentTransformedCursor = getTransformedPoint(event.offsetX, event.offsetY);
        const transformedX = currentTransformedCursor.x - canvas.width / 2;
        const transformedY = currentTransformedCursor.y - canvas.height / 2;
        const unrotatedX = Math.cos(-rotationAngle * Math.PI / 180) * transformedX - Math.sin(-rotationAngle * Math.PI / 180) * transformedY + canvas.width / 2;
        const unrotatedY = Math.sin(-rotationAngle * Math.PI / 180) * transformedX + Math.cos(-rotationAngle * Math.PI / 180) * transformedY + canvas.height / 2;
        markPoint(unrotatedX, unrotatedY);
        drawImageToCanvas();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.