拖放事件时在画布上绘制的形状移动太远

Posted

技术标签:

【中文标题】拖放事件时在画布上绘制的形状移动太远【英文标题】:Shapes drawn on canvas moves too far when drag and drop event 【发布时间】:2022-01-09 09:51:23 【问题描述】:

我在拖动一个矩形时遇到了一个问题,如果我将它移动了一点点,它将重新绘制到离当前新鼠标位置太远的位置。 如何修正距离计算?

<!DOCTYPE html>
<html>
    <meta charset="utf-8">
    <head>

    </head>
    <body>
        <canvas id="face-canvas" style="border:1px solid #000000;"></canvas>

        <script type="module">
            (() => 
                let canvas = document.getElementById("face-canvas");
                canvas.height = 300;
                canvas.width = 300;
                let cnt = canvas.getContext("2d");

                let isDragging = false;
                let offsetX = canvas.getBoundingClientRect().left;
                let offsetY = canvas.getBoundingClientRect().top;
                let startX = 0, startY = 0;
                let selectedObjIndex = 0;
                let drawn_obj = [];
                drawn_obj.push(...drawBox(20, 15, 50, 50, "#1df"), index: 1)
                drawn_obj.push(...drawBox(80, 40, 50, 50, "#a33"), index: 2)




                document.addEventListener("mousedown", (event) => onMouseDown(event));
                document.addEventListener("mousemove", (event) => onMouseMove(event));
                document.addEventListener("mouseup", (event) => onMouseUp(event));


                function onMouseDown(event) 
                    event.preventDefault();
                    event.stopPropagation();
                    startX = Math.abs(parseInt(event.clientX - offsetX));
                    startY = Math.abs(parseInt(event.clientY - offsetY));
                    selectedObjIndex = selectedObj(startX, startY);
                    if(selectedObjIndex > 0) 
                        isDragging = true;
                        console.log("ffffffff")
                    
                

                function onMouseMove(event) 
                    if(isDragging && selectedObjIndex > 0) 
                        let moveX = parseInt(event.clientX - offsetX);
                        let moveY = parseInt(event.clientY - offsetY);
                        let newX = parseInt(moveX - startX);
                        let newY = parseInt(moveY - startY);
                        drawn_obj[selectedObjIndex - 1].x += newX; 
                        drawn_obj[selectedObjIndex - 1].y += newY;
                        console.log("newX, newY", newX, newY)

                        redrawAll();
                    
                
                
                function onMouseUp() 
                    event.preventDefault();
                    event.stopPropagation();
                    isDragging = false;
                

                function selectedObj(x, y) 
                    for(let i = 0; i < drawn_obj.length; ++i) 
                        if(x >= drawn_obj[i].x && x <= (drawn_obj[i].x + drawn_obj[i].w) && 
                            y >= drawn_obj[i].y && y <= (drawn_obj[i].y + drawn_obj[i].h)) 
                            return drawn_obj[i].index;
                        
                    

                    return 0;
                

                function redrawAll() 
                    cnt.clearRect(0, 0, canvas.width, canvas.height);
                    for(let i = 0; i < drawn_obj.length; ++i) 
                        drawBox(drawn_obj[i].x, drawn_obj[i].y, drawn_obj[i].w, drawn_obj[i].h, drawn_obj[i].color);
                    
                

                function drawBox(x, y, w, h, color) 
                    cnt.fillStyle = color;
                    cnt.fillRect(x, y, w, h);
                    return x: x, y: y, w: w, h: h, color: color
                
            )();
        </script>
    </body>
</html>

【问题讨论】:

明显的问题是使用+=,每次移动都会不断增加坐标。这就是为什么它如此迅速地从画布上加速。您只需使用= 并将鼠标坐标更正为最初单击的对象内的点的偏移量。 @tromgy 它现在正在工作,但是现在当我从任何位置拖动形状时,在拖动过程中光标将设置到它的角落,我怎样才能将光标保持在使用点击它? 【参考方案1】:

您可以这样做:

    在顶层函数中为对象内部的偏移量添加两个变量:
let objectOffsetX = 0;
let objectOffsetY = 0;
    在收到点击事件时计算它们:
function onMouseDown(event) 
    event.preventDefault();
    event.stopPropagation();
    startX = event.clientX - offsetX;
    startY = event.clientY - offsetY;

    selectedObjIndex = selectedObj(startX, startY);

    objectOffsetX = startX - drawn_obj[selectedObjIndex - 1].x;
    objectOffsetY = startY - drawn_obj[selectedObjIndex - 1].y;

    if(selectedObjIndex > 0) 
        isDragging = true;
        console.log("ffffffff")
    

    当鼠标移动时,使用画布偏移和对象偏移计算新的对象位置:
function onMouseMove(event) 
    if(isDragging && selectedObjIndex > 0) 
        let newX = event.clientX - offsetX - objectOffsetX;
        let newY = event.layerY - offsetY - objectOffsetY;
        drawn_obj[selectedObjIndex - 1].x = newX;
        drawn_obj[selectedObjIndex - 1].y = newY;
        console.log("newX, newY", newX, newY)

        redrawAll();
    

您可能会注意到我简化了一些代码,您实际上不需要使用parseInt,您已经将所有内容都作为(整数)数字,而不是字符串。

你可以看到codepen的整个过程

【讨论】:

所以基本上我有两个问题:01)+=,每一步都在增加。 02)我必须计算形状偏移,以便在移动时保持鼠标光标。

以上是关于拖放事件时在画布上绘制的形状移动太远的主要内容,如果未能解决你的问题,请参考以下文章

如何在鼠标移动时在画布上绘制CIRCLE

使在画布上绘制的形状不可移动(fabric.js)

如何在 PyQt5 中通过拖放来绘制矩形并调整其形状

在画布上拖放形状

Android在画布上操纵图像 - 使用触摸,移动,放大/缩小,缩放

Android使用ontouch在画布上绘制矩形