在画布中获取鼠标位置

52
有没有一种方法可以获取在<canvas>标签内的鼠标位置?我想要相对于<canvas>的右上角的位置,而不是整个页面。
9个回答

50

通常情况下,接受的答案并不能始终有效。如果您不使用相对位置,则属性 offsetX 和 offsetY 可能会导致误解。

您应该使用来自 canvas API 的函数:canvas.getBoundingClientRect()

  function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
      x: evt.clientX - rect.left,
      y: evt.clientY - rect.top
    };
  }
  canvas.addEventListener('mousemove', function(evt) {
    var mousePos = getMousePos(canvas, evt);
    console.log('Mouse position: ' + mousePos.x + ',' + mousePos.y);
  }, false);

1
这应该是被接受的答案。 - Antonin Cezard

44

最简单的方法可能是在canvas元素上添加一个onmousemove事件监听器,然后你可以从事件本身获取相对于canvas的坐标。

如果您只需要支持特定的浏览器,则很容易实现此操作,但是不同的浏览器之间存在差异,例如Opera和Firefox。

类似以下代码应该适用于这两个浏览器:

function mouseMove(e)
{
    var mouseX, mouseY;

    if(e.offsetX) {
        mouseX = e.offsetX;
        mouseY = e.offsetY;
    }
    else if(e.layerX) {
        mouseX = e.layerX;
        mouseY = e.layerY;
    }

    /* do something with mouseX/mouseY */
}

5
我强烈建议使用JQuery或其他标准化偏移量的JavaScript框架。 - Soviut
4
只有当我按照Nat的建议将画布位置设置为相对位置时,这才对我起作用。 - Richard Garside
4
@Richard - 这是因为对于非定位元素,layerXlayerY是相对于整个文档的。请参阅我在此处给出的答案以获取更多信息:https://dev59.com/wW445IYBdhLWcg3wAFm0 - Wayne
6
如果 e.offsetX 被定义了,但等于 0,那么这段代码会执行错误的操作。 - prideout

23

请注意,您需要CSS:

将“position:relative;”设置为您的画布标签,以便在画布内获取相对鼠标位置。

如果存在边框,则偏移量会发生变化。


1
一直在搜索互联网以找出Firefox (7)为什么会报告layerY的奇怪值-这修复了它,非常感谢! - Mikey
谢谢!那就是我的问题。 - garg
谢谢,我之前一直得到不同的值。 - Neelam
+1 这解决了我在FF 11中遇到的5-10像素偏移问题。谢谢! - Mike Moore
这不是唯一必要的方法。这个答案应该解释的是,当画布是一个定位元素时,e.layerXe.layerY是相对于画布的,但当它不是时,它们是相对于整个文档的。请注意,这些属性不是任何标准的一部分。有更好的方法来做到这一点。 - Wayne

17

我将分享目前为止我创建的最可靠的鼠标代码。它适用于所有浏览器,包括所有类型的填充、边距、边框和添加组件(例如stumbleupon顶部栏)

// Creates an object with x and y defined,
// set to the mouse position relative to the state's canvas
// If you wanna be super-correct this can be tricky,
// we have to worry about padding and borders
// takes an event and a reference to the canvas
function getMouse = function(e, canvas) {
  var element = canvas, offsetX = 0, offsetY = 0, mx, my;

  // Compute the total offset. It's possible to cache this if you want
  if (element.offsetParent !== undefined) {
    do {
      offsetX += element.offsetLeft;
      offsetY += element.offsetTop;
    } while ((element = element.offsetParent));
  }

  // Add padding and border style widths to offset
  // Also add the <html> offsets in case there's a position:fixed bar (like the stumbleupon bar)
  // This part is not strictly necessary, it depends on your styling
  offsetX += stylePaddingLeft + styleBorderLeft + htmlLeft;
  offsetY += stylePaddingTop + styleBorderTop + htmlTop;

  mx = e.pageX - offsetX;
  my = e.pageY - offsetY;

  // We return a simple javascript object with x and y defined
  return {x: mx, y: my};
}

您会注意到我在函数中使用了一些(可选)未定义的变量。它们是:

  stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingLeft'], 10)      || 0;
  stylePaddingTop  = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingTop'], 10)       || 0;
  styleBorderLeft  = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderLeftWidth'], 10)  || 0;
  styleBorderTop   = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderTopWidth'], 10)   || 0;
  // Some pages have fixed-position bars (like the stumbleupon bar) at the top or left of the page
  // They will mess up mouse coordinates and this fixes that
  var html = document.body.parentNode;
  htmlTop = html.offsetTop;
  htmlLeft = html.offsetLeft;

我建议只计算一次,这就是它们不在getMouse函数中的原因。


1
很棒的小工具方法。我认为在大多数情况下,您不需要每次计算画布偏移量。 - uchamp

7

对于鼠标位置,我通常使用jQuery,因为它规范化了一些事件属性。

function getPosition(e) {

    //this section is from http://www.quirksmode.org/js/events_properties.html
    var targ;
    if (!e)
        e = window.event;
    if (e.target)
        targ = e.target;
    else if (e.srcElement)
        targ = e.srcElement;
    if (targ.nodeType == 3) // defeat Safari bug
        targ = targ.parentNode;

    // jQuery normalizes the pageX and pageY
    // pageX,Y are the mouse positions relative to the document
    // offset() returns the position of the element relative to the document
    var x = e.pageX - $(targ).offset().left;
    var y = e.pageY - $(targ).offset().top;

    return {"x": x, "y": y};
};

// now just make sure you use this with jQuery
// obviously you can use other events other than click
$(elm).click(function(event) {
    // jQuery would normalize the event
    position = getPosition(event);
    //now you can use the x and y positions
    alert("X: " + position.x + " Y: " + position.y);
});

这在所有浏览器中都适用。

编辑:

我从我正在使用的一个类中复制了代码,因此调用this.canvas的jQuery代码是错误的。更新后的函数找出导致事件的DOM元素(targ),然后使用该元素的偏移量来确定正确的位置。


6

GEE是一个非常有用的库,可以解决与画布相关的问题,包括鼠标位置。


这个库太棒了,谢谢提供链接。 - justanotherhobbyist
3
GEE不再得到维护,开发者称其为“完全废弃”。 - arkon

2

使用鼠标事件和画布属性的简单方法:

功能的JSFiddle演示http://jsfiddle.net/Dwqy7/5/
(注意:未考虑边框,导致偏移一位):

  1. 在画布中添加鼠标事件
    canvas.addEventListener("mousemove", mouseMoved);

  2. 根据以下内容调整event.clientXevent.clientY
    canvas.offsetLeft
    window.pageXOffset
    window.pageYOffset
    canvas.offsetTop
    因此:

    canvasMouseX = event.clientX - (canvas.offsetLeft - window.pageXOffset); canvasMouseY = event.clientY - (canvas.offsetTop - window.pageYOffset);

原始问题要求从右上角获取坐标(第二个函数)。 这些函数需要在可以访问画布元素的范围内。

左上角为0,0:

function mouseMoved(event){
    var canvasMouseX = event.clientX - (canvas.offsetLeft - window.pageXOffset);
    var canvasMouseY = event.clientY - (canvas.offsetTop - window.pageYOffset);
}

0,0 在右上角:

function mouseMoved(event){
    var canvasMouseX =  canvas.width - (event.clientX - canvas.offsetLeft)- window.pageXOffset;
    var canvasMouseY = event.clientY - (canvas.offsetTop - window.pageYOffset);
}

off-by-1-pixel 是指你的 1px 边框(边框和内边距也要算在内)。你还应该考虑到滚动条...干杯! :-) - markE
@markE 感谢您的提醒;我已经调整了上面的代码和 JSFiddle 以适应滚动。我找不到一种方法来调整画布边框。 - Keving

1

我会使用jQuery。

$(document).ready(function() {

    $("#canvas_id").bind( "mousedown", function(e){ canvasClick(e); } );

}

function canvasClick( e ){

    var x = e.offsetX;
    var y = e.offsetY;

}

这样,您的画布可以在页面上的任何位置,相对或绝对。

-1
从鼠标位置减去画布DOM元素的X和Y偏移量,以获得画布内的局部位置。

3
如何在所有浏览器中获取画布(canvas)DOM元素的X和Y坐标? - Richard Garside
1
看到一个拥有18k声望的人发表错误的建议,总是让人感到不爽... - arkon
1
能告诉我为什么我的建议是“胡说八道”吗?您认为它不正确,不够详细等等?那样会更有帮助。此外,我的声望并不一定意味着我的答案会完美无缺,这就是为什么有投票系统的原因。不同意?那就投反对票。 - Soviut
我已经投了反对票。这只是看起来像答案,但实际上并不是。 - GameAlchemist
1
请问您能否解释一下我应该在答案中添加什么来使其更好?我同意它相当笼统,可能需要一个代码示例等等。但是到目前为止,人们只是说“不是很好的答案”。 - Soviut
1
你可以添加如何从 DOM 元素获取 (x,y) 位置的内容。 - Ramy Al Zuhouri

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