使用点击、鼠标移动和再次点击来绘制矩形

30

我试图通过用户的点击、鼠标移动和再次点击来绘制矩形,但我的代码存在两个问题。

首先,在绘制完一个矩形后,它会自动假定又要绘制下一个矩形。其次,第二个矩形的起点是创建第一个矩形的最后一次点击位置。

http://jsbin.com/uqonuw/3/edit


你能把那个演示精简到仅涉及绘图问题的部分吗?我并不认为我们需要包括“旋转”或“document.location”的分析部分。 - David Thomas
从我看来,您的两个问题是相同的。我认为您可以考虑使用一个简单的测试来确定这是“第一次”点击还是“第二次”点击。 - Laurent S.
5个回答

46

你离正确答案很近了。所以,这个问题实际上不是关于HTML5中的“canvas”元素,而是一个真正是div的画布。

http://jsfiddle.net/d9BPz/546/

为了看清楚您的代码的目的,我必须将其整理一下。需要发生的是矩形元素的跟踪。

每次单击画布时,我们要么创建矩形元素,要么完成矩形元素。因此,当我们完成时,将“element”(以前命名为“d”)设置为null是有意义的。创建元素时,我们必须将新DOM元素分配给“element”。

每次鼠标移动时,我们都想获取鼠标位置。如果元素正在创建过程中(或“不为空”),则需要调整元素大小。

然后将所有内容包装在一个函数中,就这样:

function initDraw(canvas) {
    var mouse = {
        x: 0,
        y: 0,
        startX: 0,
        startY: 0
    };
    function setMousePosition(e) {
        var ev = e || window.event; //Moz || IE
        if (ev.pageX) { //Moz
            mouse.x = ev.pageX + window.pageXOffset;
            mouse.y = ev.pageY + window.pageYOffset;
        } else if (ev.clientX) { //IE
            mouse.x = ev.clientX + document.body.scrollLeft;
            mouse.y = ev.clientY + document.body.scrollTop;
        }
    };

    var element = null;    
    canvas.onmousemove = function (e) {
        setMousePosition(e);
        if (element !== null) {
            element.style.width = Math.abs(mouse.x - mouse.startX) + 'px';
            element.style.height = Math.abs(mouse.y - mouse.startY) + 'px';
            element.style.left = (mouse.x - mouse.startX < 0) ? mouse.x + 'px' : mouse.startX + 'px';
            element.style.top = (mouse.y - mouse.startY < 0) ? mouse.y + 'px' : mouse.startY + 'px';
        }
    }

    canvas.onclick = function (e) {
        if (element !== null) {
            element = null;
            canvas.style.cursor = "default";
            console.log("finsihed.");
        } else {
            console.log("begun.");
            mouse.startX = mouse.x;
            mouse.startY = mouse.y;
            element = document.createElement('div');
            element.className = 'rectangle'
            element.style.left = mouse.x + 'px';
            element.style.top = mouse.y + 'px';
            canvas.appendChild(element)
            canvas.style.cursor = "crosshair";
        }
    }
}

用法:传递您想要变成矩形画布的块级元素。示例:

<!doctype html>
<html>
<head>
    <style>
    #canvas {
        width:2000px;
        height:2000px;
        border: 10px solid transparent;
    }
    .rectangle {
        border: 1px solid #FF0000;
        position: absolute;
    }
    </style>
</head>
<body>
    <div id="canvas"></div>
    <script src="js/initDraw.js"></script>
    <script>
        initDraw(document.getElementById('canvas'));
    </script>
</body>
</html>

3
当窗口滚动时,这个解决方案就会失效。那时,矩形将无法放置在正确的位置上。 - Max
@Max 在 Firefox 中已确认 - 尝试点击、滚动,然后移动鼠标。 - NonameSL
为什么画布是一个普通的<div>元素而不是<canvas>,是否有一种方法可以修改JS以使用后者? - Addison Klinke
@Spencer 如何只绘制一个矩形,如果再次单击之前需要清除,这是否可能? - Sathishkumar

12

以下是如何点击移动并点击以创建矩形的方法

创建这些变量:

var isDrawing=false;
var startX;
var startY;

在你的mousedown事件处理程序中:

  • 如果这是开始点击,设置isDrawing标志并设置startX / Y。
  • 如果这是结束点击,清除isDrawing标志并绘制矩形。

您可能还想更改鼠标光标,以便用户知道他们正在绘制。

if(isDrawing){
    isDrawing=false;
    ctx.beginPath();
    ctx.rect(startX,startY,mouseX-startX,mouseY-startY);
    ctx.fill();
    canvas.style.cursor="default";
}else{
    isDrawing=true;
    startX=mouseX;
    startY=mouseY;
    canvas.style.cursor="crosshair";
}

这里有一个Fiddle:http://jsfiddle.net/m1erickson/7uNfW/

不要使用点击移动点击的方式,试试使用拖拽来创建一个矩形吧!

创建以下变量:

var mouseIsDown=false;
var startX;
var startY;
在你的mousedown事件处理程序中,设置mouseIsDown标志并设置startX/Y。可选地,更改光标以使用户知道他们正在拖动一个矩形。
      mouseIsDown=true;
      startX=mouseX;
      startY=mouseY;
      canvas.style.cursor="crosshair";

在鼠标松开事件处理程序中,清除mouseIsDown标志并绘制矩形。

如果更改了光标,请将其改回。

      mouseIsDown=false;
      ctx.beginPath();
      ctx.rect(startX,startY,mouseX-startX,mouseY-startY);
      ctx.fill();
      canvas.style.cursor="default";

3

对于那些遇到滚动问题的人,我找到了一个解决方法。
你需要获取偏移量(使用window.pageYOffset),并从任何给定的推荐片段中减去鼠标位置。你也应该从高度上减去它。


2

我也在做一个项目,这是我的代码,希望你喜欢。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Selection</title>
    <script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
    <style>
        body {
            margin: 0px;
            background-color: #f1f1f1;
        }
        canvas {
            border: none;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="800" height="500"></canvas>
    <div id="output"></div>
    <script>
        //Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var canvasx = $(canvas).offset().left;
var canvasy = $(canvas).offset().top;
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;

//Mousedown
$(canvas).on('mousedown', function(e) {
    last_mousex = parseInt(e.clientX-canvasx);
    last_mousey = parseInt(e.clientY-canvasy);
    mousedown = true;
});

//Mouseup
$(canvas).on('mouseup', function(e) {
    mousedown = false;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
});

//Mousemove
$(canvas).on('mousemove', function(e) {
    mousex = parseInt(e.clientX-canvasx);
    mousey = parseInt(e.clientY-canvasy);
    if(mousedown) {
        ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
        ctx.beginPath();
        var width = mousex-last_mousex;
        var height = mousey-last_mousey;
        ctx.rect(last_mousex,last_mousey,width,height);
        //ctx.fillStyle = "#8ED6FF";
        ctx.fillStyle = 'rgba(164, 221, 249, 0.3)'
        ctx.fill();
        ctx.strokeStyle = '#1B9AFF';
        ctx.lineWidth = 1;
        ctx.fillRect(last_mousex, last_mousey, width, height)
        ctx.stroke();
    }
    //Output
    $('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});
    </script>
</body>
</html>

0
下面是我在React中创建的解决方案。可能存在一些边缘情况,但根据我的知识它是有效的。
解决方案方法。
  1. 您必须具有起始(x,y位置)和结束(x,y)位置
  2. 一旦用户单击单元格捕获单元格号和列号起始点(x,y),这将在mouseDown事件上发生
  3. 然后用户开始移动鼠标,在这种情况下分别捕获单元格编号和行编号结束(x,y)。
  4. 现在出现了div绘制逻辑,其中条件将在以下条件为真时突出显示单元格。
  5. i = cellNumber
  6. i >= Math.min(start,end) && i <= Math.max(start,end) && i%4 <= Math.max(startY, endY)

enter image description here

https://codesandbox.io/s/still-field-0q760y?file=/src/App.js


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接