画布中真实的鼠标位置

Real mouse position in canvas

本文关键字:鼠标 位置 真实 布中      更新时间:2023-09-26

我试图用鼠标在HTML5画布上画画,但它似乎工作得很好的唯一方法是,如果画布在0,0(左上角)的位置,如果我改变画布的位置,由于某种原因,它不像它应该画。这是我的代码。

 function createImageOnCanvas(imageId){
    document.getElementById("imgCanvas").style.display = "block";
    document.getElementById("images").style.overflowY= "hidden";
    var canvas = document.getElementById("imgCanvas");
    var context = canvas.getContext("2d");
    var img = new Image(300,300);
    img.src = document.getElementById(imageId).src;
    context.drawImage(img, (0),(0));
}
function draw(e){
    var canvas = document.getElementById("imgCanvas");
    var context = canvas.getContext("2d");
    posx = e.clientX;
    posy = e.clientY;
    context.fillStyle = "#000000";
    context.fillRect (posx, posy, 4, 4);
}

HTML部分

 <body>
 <div id="images">
 </div>
 <canvas onmousemove="draw(event)" style="margin:0;padding:0;" id="imgCanvas"
          class="canvasView" width="250" height="250"></canvas> 

我读过有一种方法可以在JavaScript中创建一个简单的函数来获得正确的位置,但我不知道如何做到这一点。

简单的1:1场景

对于画布元素与位图大小的比例为1:1的情况,您可以使用以下代码片段获取鼠标位置:

function getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect();
  return {
    x: evt.clientX - rect.left,
    y: evt.clientY - rect.top
  };
}

用event和canvas作为参数从你的事件中调用它。它返回一个对象,其中鼠标位置为xy

由于您获得的鼠标位置是相对于客户端窗口的,因此您必须减去canvas元素的位置以将其相对于元素本身进行转换。

代码中的集成示例:

// put this outside the event loop..
var canvas = document.getElementById("imgCanvas");
var context = canvas.getContext("2d");
function draw(evt) {
  var pos = getMousePos(canvas, evt);
  context.fillStyle = "#000000";
  context.fillRect (pos.x, pos.y, 4, 4);
}

注意:如果直接应用到canvas元素上,边框和填充会影响位置,所以这些需要通过getComputedStyle()来考虑-或者将这些样式应用到父div上。

当元素和位图大小不同时

当元素的大小与位图本身不同时,例如,元素使用CSS缩放或存在像素纵横比等,您必须解决这个问题。

例子:

function  getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect(), // abs. size of element
    scaleX = canvas.width / rect.width,    // relationship bitmap vs. element for x
    scaleY = canvas.height / rect.height;  // relationship bitmap vs. element for y
  return {
    x: (evt.clientX - rect.left) * scaleX,   // scale mouse coordinates after they have
    y: (evt.clientY - rect.top) * scaleY     // been adjusted to be relative to element
  }
}

与转换应用于上下文(缩放,旋转等)

然后是更复杂的情况下,你已经应用转换到上下文,如旋转,倾斜/剪切,缩放,翻译等。为了解决这个问题,你可以计算当前矩阵的逆矩阵。

较新的浏览器允许您通过currentTransform属性读取当前矩阵,Firefox(当前alpha版本)甚至通过mozCurrentTransformInverted提供反向矩阵。然而,通过mozCurrentTransform, Firefox将返回一个数组,而不是DOMMatrix。Chrome,当通过实验标志启用时,将返回DOMMatrix,但SVGMatrix

在大多数情况下,你将不得不实现你自己的自定义矩阵解决方案(如我自己的解决方案在这里-免费/MIT项目),直到它得到全面支持。

当你最终获得矩阵时,无论你采取什么路径来获得矩阵,你都需要将其反转并将其应用于鼠标坐标。然后将坐标传递给画布,画布将使用其矩阵将其转换回当前的任何位置。

这样点将处于相对于鼠标的正确位置。这里还需要调整坐标(在对其应用逆矩阵之前),使其相对于元素。

显示矩阵步骤的示例:

function draw(evt) {
  var pos = getMousePos(canvas, evt);        // get adjusted coordinates as above
  var imatrix = matrix.inverse();            // get inverted matrix somehow
  pos = imatrix.applyToPoint(pos.x, pos.y);  // apply to adjusted coordinate
    
  context.fillStyle = "#000000";
  context.fillRect(pos.x-1, pos.y-1, 2, 2);
}

使用currentTransform的一个例子是:

  var pos = getMousePos(canvas, e);          // get adjusted coordinates as above
  var matrix = ctx.currentTransform;         // W3C (future)
  var imatrix = matrix.invertSelf();         // invert
  // apply to point:
  var x = pos.x * imatrix.a + pos.y * imatrix.c + imatrix.e;
  var y = pos.x * imatrix.b + pos.y * imatrix.d + imatrix.f;

更新:我做了一个免费的解决方案(MIT),将所有这些步骤嵌入到一个易于使用的对象中,该对象可以在这里找到,并且还处理了其他一些通常被忽略的细节。

您可以使用下面的代码片段获取鼠标位置:

function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
        x: (evt.clientX - rect.left) / (rect.right - rect.left) * canvas.width,
        y: (evt.clientY - rect.top) / (rect.bottom - rect.top) * canvas.height
    };
}

这段代码考虑了改变坐标到画布空间(evt.clientX - rect.left)和缩放画布逻辑大小不同于它的样式大小(/ (rect.right - rect.left) * canvas.width见:HTML5中的画布宽度和高度)。

示例:http://jsfiddle.net/sierawski/4xezb7nL/

来源:Jerryj评论http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/

您需要获得鼠标位置相对于画布

要做到这一点,你需要知道画布在页面上的X/Y位置。

这被称为画布的"偏移量",下面是如何获得偏移量。(我使用jQuery是为了简化跨浏览器兼容性,但如果你想使用原始javascript,快速谷歌也会得到)。

    var canvasOffset=$("#canvas").offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;

然后在鼠标处理程序中,您可以像这样获得鼠标X/Y:

  function handleMouseDown(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
}

下面是演示如何成功跟踪画布上的鼠标事件的示例代码:

http://jsfiddle.net/m1erickson/WB7Zu/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>
<script>
$(function(){
    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var canvasOffset=$("#canvas").offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    function handleMouseDown(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
      $("#downlog").html("Down: "+ mouseX + " / " + mouseY);
      // Put your mousedown stuff here
    }
    function handleMouseUp(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
      $("#uplog").html("Up: "+ mouseX + " / " + mouseY);
      // Put your mouseup stuff here
    }
    function handleMouseOut(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
      $("#outlog").html("Out: "+ mouseX + " / " + mouseY);
      // Put your mouseOut stuff here
    }
    function handleMouseMove(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
      $("#movelog").html("Move: "+ mouseX + " / " + mouseY);
      // Put your mousemove stuff here
    }
    $("#canvas").mousedown(function(e){handleMouseDown(e);});
    $("#canvas").mousemove(function(e){handleMouseMove(e);});
    $("#canvas").mouseup(function(e){handleMouseUp(e);});
    $("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
    <p>Move, press and release the mouse</p>
    <p id="downlog">Down</p>
    <p id="movelog">Move</p>
    <p id="uplog">Up</p>
    <p id="outlog">Out</p>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

计算画布事件中鼠标点击或鼠标移动的正确位置的最简单方法是使用这个小公式:

canvas.addEventListener('click', event =>
{
    let bound = canvas.getBoundingClientRect();
    let x = event.clientX - bound.left - canvas.clientLeft;
    let y = event.clientY - bound.top - canvas.clientTop;
    context.fillRect(x, y, 16, 16);
});

如果画布有padding-leftpadding-top,通过:

减去x和y

x -= parseFloat(style['padding-left'].replace('px'));
y -= parseFloat(style['padding-top'].replace('px'));

参考这个问题:mouseEvent。我得到的offsetX比实际画布尺寸大得多