真正的鼠标位置在画布上

我试图用鼠标在一个 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 中创建一个简单的函数来获得正确的位置,但是我不知道该怎么做。

203470 次浏览

简单的1:1场景

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

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

只需从事件中调用它,并将事件和画布作为参数。它为鼠标位置返回一个具有 xy的对象。

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

代码中的集成示例:

// 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);
}

注意: 如果直接应用于画布元素, 边框和填充将影响位置,因此需要通过 getComputedStyle()考虑这些样式,或者将这些样式应用于父 div。

当 Element 和 Bitmap 的大小不同时

当元素的大小不同于位图本身时,例如,元素是使用 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 将返回一个 Array,而不是应该返回的 DOMMatrix。当 Chrome 通过实验标志启用时,不会返回 DOMMatrix而是 SVGMatrix

然而,在大多数情况下,您必须实现自己的自定义矩阵解决方案(如我自己的解决方案 给你-free/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) ,将所有这些步骤嵌入到一个简单易用的对象中,这个对象可以找到 给你,也可以处理其他一些大多数忽略的细节问题。

你需要得到鼠标位置 相对于画布

为此,您需要知道画布在页面上的 X/Y 位置。

这就是所谓的画布的“偏移”,这里是如何得到的偏移。(我使用 jQuery 是为了简化跨浏览器兼容性,但是如果你想使用原始的 javascript,一个快速的 Google 也能做到)。

    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>

参考这个问题: 我得到的 mouseEvent.offsetX 比实际的画布尺寸大得多 。我已经给出了一个功能,这将正好适合你的情况

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

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 评论 < a href = “ http://www.html5cabastutorials.com/Advanced/html5-Canvasutorials.com/”rel = “ norefrer”> http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/

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

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);
});

如果画布上有 向左填充衬垫上衣,通过以下方法减去 x 和 y:

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