在调整大小的画布上绘图时鼠标位置错误

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

我正在为我的 ML 模型构建一个 Web 应用程序,在其中我需要用鼠标指针标记图像中存在遮挡的区域。然后,ML 模型获取标记的图像并重建缺失的区域。

为了在图像上绘制,首先我制作了一个画布,然后我们需要将所选图像上传到该画布上。然后我制作了画布以获取调整后的图像的大小。

这里的问题是:鼠标指向一个位置,但在另一个位置上绘图。

我进一步发现,当我改变网页窗口大小时,在某些窗口形状下,鼠标指针精确地绘制在我想要的位置。

我不明白发生了什么?是因为窗口大小调整错误还是什么原因?

调整画布大小

function overlayImage() {
    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    var rect = canvas.getBoundingClientRect();
   
    var img = this; 

    var scaleX = canvas.width / img.width;
    var scaleY = canvas.height / img.height;
    var scale = Math.min(scaleX, scaleY); 
    
    var newWidth = img.width * scale;
    var newHeight = img.height * scale;

    ctx.clearRect(0, 0, canvas.width, canvas.height);

    canvas.width = newWidth;
    canvas.height = newHeight;
    
    ctx.drawImage(img, 0,0, newWidth, newHeight); 
}

现在是鼠标事件

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
var rect = canvas.getBoundingClientRect();
let coord = { 
  x: 0,
  y: 0 
};

document.addEventListener("mousedown", start);
document.addEventListener("mouseup", stop);
window.addEventListener("resize", resize);

function resize() {
  ctx.canvas.width = window.innerWidth;
  ctx.canvas.height = window.innerHeight;
}
resize();

function reposition(event) {
  coord.x = (event.clientX  - rect.left) / (rect.right - rect.left) * canvas.width;
  coord.y = (event.clientY  - rect.top) / (rect.bottom - rect.top) * canvas.height;
}
function start(event) {
  document.addEventListener("mousemove", draw);
  console.log("To check if mouse event is occurring")
  reposition(event);
}
function stop() {
  document.removeEventListener("mousemove", draw);
}
function draw(event) {
  ctx.beginPath();
  ctx.lineWidth = 5;
  ctx.lineCap = "round";
  ctx.strokeStyle = "black";
  ctx.moveTo(coord.x, coord.y);
  reposition(event);
  ctx.lineTo(coord.x, coord.y);
  ctx.stroke();
}

我尝试纠正 x,y 的偏移值,但仍然不起作用。

然后我检查了如果我不调整画布大小,那么可能会有所帮助,但仍然不起作用。

堆栈溢出中存在静态画布大小的解决方案,但我的画布大小根据图像尺寸而变化,并且纵横比平衡。这就是为什么我可以在一些图像上正确绘制,而绘图的起点远离我所指的位置。

javascript canvas html5-canvas
1个回答
0
投票

在使用

x
y
之前,您需要更新
moveTo()
lineTo()
坐标(通过获取画布本身的比例因子来获取正确的位置)。查看下面示例中的
DrawingBoard
类的
startDrawing
addPoint
scale
函数。

drawing.js

class DrawingBoard {
    
    constructor(canvas) {
        this.canvas = canvas;
        this.ctx = canvas.getContext('2d');
        this.isDrawing = false;
    }

    scale(x, y) {
        const pageWidth = document.body.clientWidth;
        const scale = Math.min(pageWidth / this.canvas.width, 1);
        return [x/scale, y/scale];
    }

    startDrawing(x, y, color) {
        this.isDrawing = true;
        this.ctx.strokeStyle = color;
        this.ctx.beginPath();
        this.ctx.moveTo(... this.scale(x, y));
    }

    addPoint(x, y) {
        if (this.isDrawing) {
            this.ctx.lineTo(... this.scale(x, y));
            this.ctx.stroke();
        }
    }

    stopDrawing() {
        this.isDrawing = false;
        this.ctx.closePath();
    }

}
const imageCanvas = document.getElementById('imageCanvas');
const overlayCanvas = document.getElementById('overlayCanvas');

const board = new DrawingBoard(overlayCanvas);
overlayCanvas.addEventListener('mousedown', event => {
    board.startDrawing(event.offsetX, event.offsetY, '#ff7b06');
});

overlayCanvas.addEventListener('mousemove', event => {
    board.addPoint(event.offsetX, event.offsetY);
});

overlayCanvas.addEventListener('mouseup', () => board.stopDrawing());
overlayCanvas.addEventListener('mouseout', () => board.stopDrawing());

以下代码与回答问题并不真正相关,但是,它提供了一个完整的工作示例。

drawing.js
继续

document
    .getElementById('imageInput')
    .addEventListener('change', ({target: {files}}) => {

        const [file] = files;

        imageCanvas.hidden = false;
        overlayCanvas.hidden = false;

        if (file && file.type.match('image/jpeg')) {

            const reader = new FileReader();

            reader.onload = ({target: {result}}) => {

                const image = new Image();

                image.onload = () => {

                    const ctx = imageCanvas.getContext('2d');

                    const maxWidth = document.body.clientWidth;

                    let { width, height } = image;

                    imageCanvas.width = width;
                    imageCanvas.height = height;

                    copyProperties(overlayCanvas, imageCanvas, 'width', 'height');

                    ctx.clearRect(0, 0, width, height);
                    ctx.drawImage(image, 0, 0, width, height);

                }

                image.src = result;

            }

            reader.readAsDataURL(file);

        }

    });
function copyProperties(target, source, ...properties) {
    for (const property of properties) {
        target[property] = source[property];
    }
}

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Draw on Image</title>

    <link rel="stylesheet" href="drawing.css">
</head>

<body>

    <header>
        <label for="imageInput">Select an JPEG Image</label>
        <input type="file" id="imageInput" accept=".jpg,.jpeg">
    </header>

    <main>
        <div class="canvas-container">
            <canvas id="imageCanvas" hidden></canvas>
            <canvas id="overlayCanvas" hidden></canvas>
        </div>
    </main>

    <script src="drawing.js"></script>

</body>

</html>

drawing.css

body {
    margin: 0;
    padding: 0;
}
header {
    padding: 1rem;
    border-bottom: 1px solid black;
}
.canvas-container {
    position: relative;
}
canvas {
    max-width: 100%;
    height: auto;
}
#overlayCanvas {
    position: absolute;
    top: 0;
    left: 0;
    pointer-events: auto;
    cursor: crosshair;
}
© www.soinside.com 2019 - 2024. All rights reserved.