如何获取鼠标在画布元素上单击的坐标?

IT技术 javascript canvas
2021-02-01 10:00:54

将单击事件处理程序添加到将返回单击的 x 和 y 坐标(相对于画布元素)的画布元素的最简单方法是什么?

不需要旧版浏览器兼容性,Safari、Opera 和 Firefox 都可以。

6个回答

如果你喜欢简单但仍然想要跨浏览器功能,我发现这个解决方案最适合我。这是@Aldekein 解决方案的简化,但没有 jQuery

function getCursorPosition(canvas, event) {
    const rect = canvas.getBoundingClientRect()
    const x = event.clientX - rect.left
    const y = event.clientY - rect.top
    console.log("x: " + x + " y: " + y)
}

const canvas = document.querySelector('canvas')
canvas.addEventListener('mousedown', function(e) {
    getCursorPosition(canvas, e)
})
如果画布被缩放,这不起作用。不确定这是否是浏览器错误。
2021-03-14 10:00:54
@TomášZato,哦,getBoundingClientRect返回相对于视口的位置?然后我的猜测是错误的。我从来没有测试过它,因为这对我来说从来都不是问题,我想警告其他读者我看到的一个潜在问题,但感谢您的澄清。
2021-03-19 10:00:54
@PeppeL-G 边界客户端矩形为您计算。您可以在发表评论之前轻松地在控制台中对其进行测试(这就是我所做的)。
2021-03-20 10:00:54
如果页面向下滚动,我想还应该考虑文档的滚动偏移量。
2021-03-30 10:00:54
为像我这样的人添加用法: var canvas = document.getElementById('canvasID'); canvas.addEventListener("mousedown", function (e) { getCursorPosition(canvas, e);});
2021-03-30 10:00:54

更新(2016 年 5 月 5 日):应该改用 patriques 的回答,因为它既简单又可靠。


由于画布的样式并不总是相对于整个页面,因此canvas.offsetLeft/Top并不总是返回您需要的内容。它将返回相对于其 offsetParent 元素偏移的像素数,该元素可以类似于div包含position: relative应用样式的画布元素为了解决这个问题,您需要遍历offsetParents,从画布元素本身开始。这段代码非常适合我,在 Firefox 和 Safari 中测试过,但应该适用于所有人。

function relMouseCoords(event){
    var totalOffsetX = 0;
    var totalOffsetY = 0;
    var canvasX = 0;
    var canvasY = 0;
    var currentElement = this;

    do{
        totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
        totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
    }
    while(currentElement = currentElement.offsetParent)

    canvasX = event.pageX - totalOffsetX;
    canvasY = event.pageY - totalOffsetY;

    return {x:canvasX, y:canvasY}
}
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;

最后一行使获取相对于画布元素的鼠标坐标变得方便。获得有用坐标所需要的只是

coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;
不,它使用内置的 javascript 原型对象 --- developer.mozilla.org/en/...
2021-03-13 10:00:54
这个答案的最终版本对我不起作用。在 Firefox 上,如果滚动整个屏幕,我会得到位移值作为输出。对我有用的是一个非常相似的解决方案,在stackoverflow.com/a/10816667/578749给出,它不是 event.pageX/Y,而是从 event.clientX/Y 中减去计算出的偏移量。有人可以回顾一下并解释一下吗?
2021-03-17 10:00:54
Baczek 关于 Chrome 是正确的event.offsetXevent.offsetY它也适用于 IE9。对于 Firefox(使用 v13 测试),您可以使用event.layerXevent.layerY
2021-03-21 10:00:54
我另外添加了这个: canvasX = event.pageX - totalOffsetX - document.body.scrollLeft; canvasY = event.pageY - totalOffsetY - document.body.scrollTop;
2021-03-22 10:00:54
我的 Chrome 具有event.offsetXevent.offsetY属性,因此我通过添加if (event.offsetX !== undefined && event.offsetY !== undefined) { return {x:event.offsetX, y:event.offsetY}; }. 看起来它有效。
2021-04-06 10:00:54

编辑 2018:这个答案很旧,它使用检查不再需要的旧浏览器,因为clientXclientY属性在所有当前浏览器中都有效。您可能想查看Patriques Answer以获得更简单、更新的解决方案。

原始答案:
如我当时发现的一篇文章所述,但不再存在:

var x;
var y;
if (e.pageX || e.pageY) { 
  x = e.pageX;
  y = e.pageY;
}
else { 
  x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; 
  y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; 
} 
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;

对我来说非常好。

这个解决方案并不总是有效 - 当画布不一定相对于整个页面定位时,Ryan Artecona 的答案适用于更一般的情况。
2021-03-31 10:00:54
如果性能很重要,则不适合此解决方案,因为每次单击/移动时都会完成 Dom 访问。并且 getBoundingClientRect 现在存在,并且更加优雅。
2021-04-08 10:00:54

现代浏览器现在可以为您处理这个问题。Chrome、IE9 和 Firefox 支持这样的 offsetX/Y,从点击处理程序传入事件。

function getRelativeCoords(event) {
    return { x: event.offsetX, y: event.offsetY };
}

大多数现代浏览器也支持 layerX/Y,但是 Chrome 和 IE 使用 layerX/Y 作为页面上点击的绝对偏移量,包括边距、填充等。在 Firefox 中,layerX/Y 和 offsetX/Y 是等效的,但偏移量没有'以前不存在。因此,为了与稍旧的浏览器兼容,您可以使用:

function getRelativeCoords(event) {
    return { x: event.offsetX || event.layerX, y: event.offsetY || event.layerY };
}
@JulianMann 感谢您提供信息。我已经根据更多当前的支持更新了这个答案。看起来您现在几乎可以普遍使用 offsetX/Y。
2021-03-27 10:00:54
有趣的是 layerX, layerY 在 Chrome 和 Firefox 上是如何定义的,但在 Chrome 上它是不准确的(或意味着其他)。
2021-04-04 10:00:54

根据新鲜怪异模式clientXclientY方法,在所有主要的浏览器都支持。所以,这里是 - 在带有滚动条的页面上的滚动 div 中工作的良好的工作代码:

function getCursorPosition(canvas, event) {
var x, y;

canoffset = $(canvas).offset();
x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft - Math.floor(canoffset.left);
y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop - Math.floor(canoffset.top) + 1;

return [x,y];
}

这也需要jQuery for $(canvas).offset().

相当于@N4ppeL 答案。
2021-03-19 10:00:54