javascript 画布中的真实鼠标位置
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17130395/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Real mouse position in canvas
提问by Solar Confinement
I'm trying to draw with the mouse over a HTML5 canvas, but the only way that it seems to work well is if the canvas is in the position 0,0 (upper left corner) if I change the canvas position, for some reason it doesn't draw like it should. Here is my code.
我正在尝试用鼠标在 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);
}
The HTML part
HTML 部分
<body>
<div id="images">
</div>
<canvas onmousemove="draw(event)" style="margin:0;padding:0;" id="imgCanvas"
class="canvasView" width="250" height="250"></canvas>
I have read there's a way of creating a simple function in JavaScript to get the right position, but I have no idea about how to do it.
我读过有一种方法可以在 JavaScript 中创建一个简单的函数来获得正确的位置,但我不知道如何去做。
回答by
The Simple 1:1 Scenario
简单的 1:1 场景
For situations where the canvas element is 1:1 compared to the bitmap size, you can get the mouse positions by using this snippet:
对于画布元素与位图大小为 1:1 的情况,您可以使用以下代码段获取鼠标位置:
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
Just call it from your event with the event and canvas as arguments. It returns an object with x and y for the mouse positions.
只需使用事件和画布作为参数从您的事件中调用它。它返回一个带有 x 和 y 的对象作为鼠标位置。
As the mouse position you are getting is relative to the client window you'll have to subtract the position of the canvas element to convert it relative to the element itself.
由于您获得的鼠标位置是相对于客户端窗口的,因此您必须减去画布元素的位置才能将其相对于元素本身进行转换。
Example of integration in your code:
代码中的集成示例:
//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);
}
Note: borders and padding will affect position if applied directly to the canvas element so these needs to be considered via getComputedStyle()
- or apply those styles to a parent div instead.
注意:如果直接应用于画布元素,边框和填充会影响位置,因此需要通过getComputedStyle()
- 或将这些样式应用于父 div 来考虑这些。
When Element and Bitmap are of different sizes
当 Element 和 Bitmap 大小不同时
When there is the situation of having the element at a different size than the bitmap itself, for example, the element is scaled using CSS or there is pixel-aspect ratio etc. you will have to address this.
当元素的大小与位图本身的大小不同时,例如,元素使用 CSS 缩放或存在像素长宽比等,您将不得不解决这个问题。
Example:
例子:
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
}
}
With transformations applied to context (scale, rotation etc.)
将变换应用于上下文(缩放、旋转等)
Then there is the more complicated case where you have applied transformation to the context such as rotation, skew/shear, scale, translate etc. To deal with this you can calculate the inverse matrix of the current matrix.
然后是更复杂的情况,您已将变换应用于上下文,例如旋转、倾斜/剪切、缩放、平移等。要处理此问题,您可以计算当前矩阵的逆矩阵。
Newer browsers let you read the current matrix via the currentTransform
property and Firefox (current alpha) even provide a inverted matrix through the mozCurrentTransformInverted
. Firefox however, via mozCurrentTransform
, will return an Array and not DOMMatrix
as it should. Neither Chrome, when enabled via experimental flags, will return a DOMMatrix
but a SVGMatrix
.
较新的浏览器允许您通过currentTransform
属性读取当前矩阵,而 Firefox(当前 alpha)甚至通过mozCurrentTransformInverted
. 然而,Firefox 通过mozCurrentTransform
,将返回一个数组而不是DOMMatrix
它应该的样子。通过实验性标志启用时,Chrome 都不会返回 a DOMMatrix
but a SVGMatrix
。
In most cases however you will have to implement a custom matrix solution of your own (such as my own solution here- free/MIT project) until this get full support.
然而,在你将不得不实现自己的定制基质溶液大多数情况下(比如我自己的解决方案在这里-免费/ MIT项目),直至该得到充分的支持。
When you eventually have obtained the matrix regardless of path you take to obtain one, you'll need to invert it and apply it to your mouse coordinates. The coordinates are then passed to the canvas which will use its matrix to convert it to back wherever it is at the moment.
当您最终获得矩阵时,无论您采用何种路径获得矩阵,您都需要反转它并将其应用于鼠标坐标。然后将坐标传递给画布,画布将使用其矩阵将其转换回当前所在的任何位置。
This way the point will be in the correct position relative to the mouse. Also here you need to adjust the coordinates (before applying the inverse matrix to them) to be relative to the element.
这样,该点将处于相对于鼠标的正确位置。同样在这里,您需要调整坐标(在对它们应用逆矩阵之前)以相对于元素。
An example just showing the matrix steps
仅显示矩阵步骤的示例
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);
}
An example of using currentTransform
when implemented would be:
使用currentTransform
when 实现的一个例子是:
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;
UpdateI made a free solution (MIT) to embed all these steps into a single easy-to-use object that can be found hereand also takes care of a few other nitty-gritty things most ignore.
更新我制作了一个免费的解决方案 (MIT),将所有这些步骤嵌入到一个易于使用的对象中,该对象可以在这里找到,并且还处理了其他一些最容易被忽视的细节。
回答by Rafa? S
You can get the mouse positions by using this snippet:
您可以使用以下代码段获取鼠标位置:
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
};
}
This code takes into account both changing coordinates to canvas space (evt.clientX - rect.left
) and scaling when canvas logical size differs from its style size (/ (rect.right - rect.left) * canvas.width
see: Canvas width and height in HTML5).
此代码考虑了将坐标更改为画布空间 ( evt.clientX - rect.left
) 和画布逻辑大小与其样式大小不同时的缩放(/ (rect.right - rect.left) * canvas.width
请参阅:HTML5 中的画布宽度和高度)。
Example: http://jsfiddle.net/sierawski/4xezb7nL/
示例:http: //jsfiddle.net/sierawski/4xezb7nL/
Source: jerryj comment on http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
来源:jerryj 评论http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
回答by Martin Wantke
The easiest way to compute the correct mouse click or mouse move position on a canvas event is to use this little equation:
在画布事件上计算正确的鼠标单击或鼠标移动位置的最简单方法是使用这个小等式:
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);
});
If the canvas has padding-leftor padding-top, subtract x and y via:
如果画布有padding-left或padding-top,请通过以下方式减去 x 和 y :
x -= parseFloat(style['padding-left'].replace('px'));
y -= parseFloat(style['padding-top'].replace('px'));
x -= parseFloat(style['padding-left'].replace('px'));
y -= parseFloat(style['padding-top'].replace('px'));
回答by markE
You need to get the mouse position relative to the canvas
您需要获取相对于画布的鼠标位置
To do that you need to know the X/Y position of the canvas on the page.
为此,您需要知道画布在页面上的 X/Y 位置。
This is called the canvas's “offset”, and here's how to get the offset. (I'm using jQuery in order to simplify cross-browser compatibility, but if you want to use raw javascript a quick Google will get that too).
这称为画布的“偏移量”,这里是如何获得偏移量。(我使用 jQuery 是为了简化跨浏览器的兼容性,但如果你想使用原始 javascript,一个快速的谷歌也会得到它)。
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
Then in your mouse handler, you can get the mouse X/Y like this:
然后在您的鼠标处理程序中,您可以像这样获得鼠标 X/Y:
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
}
Here is an illustrating code and fiddle that shows how to successfully track mouse events on the canvas:
这是一个说明代码和小提琴,展示了如何在画布上成功跟踪鼠标事件:
http://jsfiddle.net/m1erickson/WB7Zu/
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>
回答by sumitb.mdi
Refer this question: The mouseEvent.offsetX I am getting is much larger than actual canvas size.I have given a function there which will exactly suit in your situation
参考这个问题:我得到的 mouseEvent.offsetX 比实际画布尺寸大得多。我在那里给出了一个完全适合你情况的函数