如何获得鼠标单击画布元素的坐标?

时间:2022-10-27 12:42:59

What's the simplest way to add a click event handler to a canvas element that will return the x and y coordinates of the click (relative to the canvas element)?

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

No legacy browser compatibility required, Safari, Opera and Firefox will do.

不需要传统的浏览器兼容性,Safari、Opera和Firefox都可以。

19 个解决方案

#1


69  

As described here:

这里所描述的那样:

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;

Worked perfectly fine for me.

对我来说完全没问题。

#2


169  

Update (5/5/16): patriques' answer should be used instead, as it's both simpler and more reliable.

更新(5/5/16):应该使用patriques的答案,因为它既简单又可靠。


Since the canvas isn't always styled relative to the entire page, the canvas.offsetLeft/Top doesn't always return what you need. It will return the number of pixels it is offset relative to its offsetParent element, which can be something like a div element containing the canvas with a position: relative style applied. To account for this you need to loop through the chain of offsetParents, beginning with the canvas element itself. This code works perfectly for me, tested in Firefox and Safari but should work for all.

因为画布并不总是相对于整个页面的样式,画布。offsetLeft/Top并不总是返回你所需要的东西。它将返回相对于其offsetParent元素的像素的数量,它可以是一个包含有位置的画布的div元素:应用的相对样式。为了说明这一点,您需要遍历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;

The last line makes things convenient for getting the mouse coordinates relative to a canvas element. All that's needed to get the useful coordinates is

最后一行可以方便地将鼠标坐标与画布元素相关联。得到有用坐标所需要的一切。

coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;

#3


124  

If you like simplicity but still want cross-browser functionality I found this solution worked best for me. This is a simplification of @Aldekein´s solution but without jQuery.

如果您喜欢简单,但仍然需要跨浏览器的功能,我发现这个解决方案对我最有效。这是一个简化@Aldekein´s解决但没有jQuery。

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

#4


20  

Modern browser's now handle this for you. Chrome, IE9, and Firefox support the offsetX/Y like this, passing in the event from the click handler.

现代浏览器现在为你处理这个。Chrome、IE9和Firefox支持offsetX/Y,从单击处理程序中传递事件。

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

Most modern browsers also support layerX/Y, however Chrome and IE use layerX/Y for the absolute offset of the click on the page including margin, padding, etc. In Firefox, layerX/Y and offsetX/Y are equivalent, but offset didn't previously exist. So, for compatibility with slightly older browsers, you can use:

大多数现代浏览器也支持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 };
}

#5


17  

According to fresh Quirksmode the clientX and clientY methods are supported in all major browsers. So, here it goes - the good, working code that works in a scrolling div on a page with scrollbars:

根据新的Quirksmode,所有主流浏览器都支持clientX和clientY方法。所以,这里有一个很好的工作代码,它可以在滚动条的页面上使用滚动条:

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

This also requires jQuery for $(canvas).offset().

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

#6


13  

I made a full demostration that works in every browser with the full source code of the solution of this problem: Coordinates of a mouse click on Canvas in Javascript. To try the demo, copy the code and paste it into a text editor. Then save it as example.html and, finally, open the file with a browser.

我在每一个浏览器中都做了一个完整的演示,它使用完整的源代码来解决这个问题:鼠标在Javascript上单击画布的坐标。要尝试演示,复制代码并将其粘贴到一个文本编辑器中。然后将它作为示例保存。最后,用浏览器打开文件。

#7


10  

Here is a small modification to Ryan Artecona's answer for canvases with a variable (%) width:

这里是对Ryan Artecona的一个小修改,他的画布上有一个变量(%)宽度:

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

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

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

    // Fix for variable canvas width
    canvasX = Math.round( canvasX * (this.width / this.offsetWidth) );
    canvasY = Math.round( canvasY * (this.height / this.offsetHeight) );

    return {x:canvasX, y:canvasY}
}

#8


7  

Be wary while doing the coordinate conversion; there are multiple non-cross-browser values returned in a click event. Using clientX and clientY alone are not sufficient if the browser window is scrolled (verified in Firefox 3.5 and Chrome 3.0).

在进行坐标转换时要小心;在单击事件中返回多个非跨浏览器值。如果浏览器窗口被滚动(在Firefox 3.5和Chrome 3.0中验证),仅使用clientX和clientY是不够的。

This quirks mode article provides a more correct function that can use either pageX or pageY or a combination of clientX with document.body.scrollLeft and clientY with document.body.scrollTop to calculate the click coordinate relative to the document origin.

这个quirks模式文章提供了一个更正确的函数,它可以使用pageX或pageY,或者使用document.body的clientX组合。用document.body进行滚动。scrollTop计算单击坐标相对于文档原点。

UPDATE: Additionally, offsetLeft and offsetTop are relative to the padded size of the element, not the interior size. A canvas with the padding: style applied will not report the top-left of its content region as offsetLeft. There are various solutions to this problem; the simplest one may be to clear all border, padding, etc. styles on the canvas itself and instead apply them to a box containing the canvas.

更新:另外,offsetLeft和offsetTop相对于元素的padd大小,而不是内部大小。使用填充的画布:样式应用程序不会将其内容区域的左上角报告为offsetLeft。对于这个问题有各种各样的解决方案;最简单的方法可能是清除画布上的所有边框、填充等样式,并将它们应用到包含画布的框中。

#9


6  

Here is a very nice tutorial-

这是一个很好的教程。

http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/

http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/

 <canvas id="myCanvas" width="578" height="200"></canvas>
<script>
  function writeMessage(canvas, message) {
    var context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.font = '18pt Calibri';
    context.fillStyle = 'black';
    context.fillText(message, 10, 25);
  }
  function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
      x: evt.clientX - rect.left,
      y: evt.clientY - rect.top
    };
  }
  var canvas = document.getElementById('myCanvas');
  var context = canvas.getContext('2d');

  canvas.addEventListener('mousemove', function(evt) {
    var mousePos = getMousePos(canvas, evt);
    var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
    writeMessage(canvas, message);
  }, false);

hope this helps!

希望这可以帮助!

#10


4  

I'm not sure what's the point of all these answers that loop through parent elements and do all kinds of weird stuff.

我不知道所有这些答案的意义是什么,这些答案循环通过父元素,做各种奇怪的事情。

The HTMLElement.getBoundingClientRect method is designed to to handle actual screen position of any element. This includes scrolling, so stuff like scrollTop is not needed:

HTMLElement。getBoundingClientRect方法用于处理任何元素的实际屏幕位置。这包括滚动,所以不需要像scrollTop这样的东西:

(from MDN) The amount of scrolling that has been done of the viewport area (or any other scrollable element) is taken into account when computing the bounding rectangle

(从MDN)在计算边界矩形时考虑到viewport区域(或任何其他可滚动元素)的滚动量。

Normal image

The very simplest approach was already posted here. This is correct as long as no wild CSS rules are involved.

最简单的方法已经在这里发布了。只要没有涉及到野生CSS规则,这是正确的。

Handling stretched canvas/image

When image pixel width isn't matched by it's CSS width, you'll need to apply some ratio on pixel values:

当图像像素宽度与CSS宽度不匹配时,你需要对像素值应用一些比率:

/* Returns pixel coordinates according to the pixel that's under the mouse cursor**/
HTMLCanvasElement.prototype.relativeCoords = function(event) {
  var x,y;
  //This is the current screen rectangle of canvas
  var rect = this.getBoundingClientRect();
  var top = rect.top;
  var bottom = rect.bottom;
  var left = rect.left;
  var right = rect.right;
  //Recalculate mouse offsets to relative offsets
  x = event.clientX - left;
  y = event.clientY - top;
  //Also recalculate offsets of canvas is stretched
  var width = right - left;
  //I use this to reduce number of calculations for images that have normal size 
  if(this.width!=width) {
    var height = bottom - top;
    //changes coordinates by ratio
    x = x*(this.width/width);
    y = y*(this.height/height);
  } 
  //Return as an array
  return [x,y];
}

As long as the canvas has no border, it works for stretched images (jsFiddle).

只要画布没有边框,它就可以用于拉伸图像(jsFiddle)。

Handling CSS borders

If the canvas has thick border, the things get little complicated. You'll literally need to subtract the border from the bounding rectangle. This can be done using .getComputedStyle. This answer describes the process.

如果画布有厚厚的边框,事情就变得复杂了。你需要从边界矩形中减去边界。可以使用. getcomputedstyle来完成。这个答案描述了这个过程。

The function then grows up a little:

然后这个函数会增长一点:

/* Returns pixel coordinates according to the pixel that's under the mouse cursor**/
HTMLCanvasElement.prototype.relativeCoords = function(event) {
  var x,y;
  //This is the current screen rectangle of canvas
  var rect = this.getBoundingClientRect();
  var top = rect.top;
  var bottom = rect.bottom;
  var left = rect.left;
  var right = rect.right;
  //Subtract border size
  // Get computed style
  var styling=getComputedStyle(this,null);
  // Turn the border widths in integers
  var topBorder=parseInt(styling.getPropertyValue('border-top-width'),10);
  var rightBorder=parseInt(styling.getPropertyValue('border-right-width'),10);
  var bottomBorder=parseInt(styling.getPropertyValue('border-bottom-width'),10);
  var leftBorder=parseInt(styling.getPropertyValue('border-left-width'),10);
  //Subtract border from rectangle
  left+=leftBorder;
  right-=rightBorder;
  top+=topBorder;
  bottom-=bottomBorder;
  //Proceed as usual
  ...
}

I can't think of anything that would confuse this final function. See yourself at JsFiddle.

我想不出什么东西会把这最后的函数搞混。在JsFiddle看到自己。

Notes

If you don't like modifying the native prototypes, just change the function and call it with (canvas, event) (and replace any this with canvas).

如果您不喜欢修改本机原型,只需更改该函数并调用它(canvas, event)(并用canvas替换任何该函数)。

#11


3  

Using jQuery in 2016, to get click coordinates relative to the canvas, I do:

在2016年使用jQuery,为了得到与画布相对的点击坐标,我这样做:

$(canvas).click(function(jqEvent) {
    var coords = {
        x: jqEvent.pageX - $(canvas).offset().left,
        y: jqEvent.pageY - $(canvas).offset().top
    };
});

This works since both canvas offset() and jqEvent.pageX/Y are relative to the document regardless of scroll position.

这在画布偏移()和jqEvent上都有效。pageX/Y相对于文档,而不考虑滚动位置。

Note that if your canvas is scaled then these coordinates are not the same as canvas logical coordinates. To get those, you would also do:

注意,如果您的画布被缩放,那么这些坐标与画布逻辑坐标不一样。为了得到这些,你也可以这样做:

var logicalCoords = {
    x: coords.x * (canvas.width / $(canvas).width()),
    y: coords.y * (canvas.height / $(canvas).height())
}

#12


2  

I recommend this link- http://miloq.blogspot.in/2011/05/coordinates-mouse-click-canvas.html

我推荐这个链接- http://miloq.blogspot.in/2011/05/coordinates-mouse-click .html。

<style type="text/css">

  #canvas{background-color: #000;}

</style>

<script type="text/javascript">

  document.addEventListener("DOMContentLoaded", init, false);

  function init()
  {
    var canvas = document.getElementById("canvas");
    canvas.addEventListener("mousedown", getPosition, false);
  }

  function getPosition(event)
  {
    var x = new Number();
    var y = new Number();
    var canvas = document.getElementById("canvas");

    if (event.x != undefined && event.y != undefined)
    {
      x = event.x;
      y = event.y;
    }
    else // Firefox method to get the position
    {
      x = event.clientX + document.body.scrollLeft +
          document.documentElement.scrollLeft;
      y = event.clientY + document.body.scrollTop +
          document.documentElement.scrollTop;
    }

    x -= canvas.offsetLeft;
    y -= canvas.offsetTop;

    alert("x: " + x + "  y: " + y);
  }

</script>

#13


1  

In Prototype, use cumulativeOffset() to do the recursive summation as mentioned by Ryan Artecona above.

在原型中,使用累积量抵消()来完成Ryan Artecona所提到的递归求和。

http://www.prototypejs.org/api/element/cumulativeoffset

http://www.prototypejs.org/api/element/cumulativeoffset

#14


1  

You could just do:

你可以做的:

var canvas = yourCanvasElement;
var mouseX = (event.clientX - (canvas.offsetLeft - canvas.scrollLeft)) - 2;
var mouseY = (event.clientY - (canvas.offsetTop - canvas.scrollTop)) - 2;

This will give you the exact position of the mouse pointer.

这将给出鼠标指针的确切位置。

#15


1  

See demo at http://jsbin.com/ApuJOSA/1/edit?html,output .

看到演示http://jsbin.com/ApuJOSA/1/edit?html输出。

  function mousePositionOnCanvas(e) {
      var el=e.target, c=el;
      var scaleX = c.width/c.offsetWidth || 1;
      var scaleY = c.height/c.offsetHeight || 1;

      if (!isNaN(e.offsetX)) 
          return { x:e.offsetX*scaleX, y:e.offsetY*scaleY };

      var x=e.pageX, y=e.pageY;
      do {
        x -= el.offsetLeft;
        y -= el.offsetTop;
        el = el.offsetParent;
      } while (el);
      return { x: x*scaleX, y: y*scaleY };
  }

#16


0  

Hey, this is in dojo, just cause it's what I had the code in already for a project.

这是在dojo中,因为我已经有了一个项目的代码。

It should be fairly Obvious how to convert it back to non dojo vanilla JavaScript.

如何将其转换为非dojo香草JavaScript应该是相当明显的。

  function onMouseClick(e) {
      var x = e.clientX;
      var y = e.clientY;
  }
  var canvas = dojo.byId(canvasId);
  dojo.connect(canvas,"click",onMouseClick);

Hope that helps.

希望有帮助。

#17


0  

Here is some modifications of the above Ryan Artecona's solution.

下面是对Ryan Artecona解决方案的一些修改。

function myGetPxStyle(e,p)
{
    var r=window.getComputedStyle?window.getComputedStyle(e,null)[p]:"";
    return parseFloat(r);
}

function myGetClick=function(ev)
{
    // {x:ev.layerX,y:ev.layerY} doesn't work when zooming with mac chrome 27
    // {x:ev.clientX,y:ev.clientY} not supported by mac firefox 21
    // document.body.scrollLeft and document.body.scrollTop seem required when scrolling on iPad
    // html is not an offsetParent of body but can have non null offsetX or offsetY (case of wordpress 3.5.1 admin pages for instance)
    // html.offsetX and html.offsetY don't work with mac firefox 21

    var offsetX=0,offsetY=0,e=this,x,y;
    var htmls=document.getElementsByTagName("html"),html=(htmls?htmls[0]:0);

    do
    {
        offsetX+=e.offsetLeft-e.scrollLeft;
        offsetY+=e.offsetTop-e.scrollTop;
    } while (e=e.offsetParent);

    if (html)
    {
        offsetX+=myGetPxStyle(html,"marginLeft");
        offsetY+=myGetPxStyle(html,"marginTop");
    }

    x=ev.pageX-offsetX-document.body.scrollLeft;
    y=ev.pageY-offsetY-document.body.scrollTop;
    return {x:x,y:y};
}

#18


0  

First, as others have said, you need a function to get the position of the canvas element. Here's a method that's a little more elegant than some of the others on this page (IMHO). You can pass it any element and get its position in the document:

首先,正如其他人所说,您需要一个函数来获得画布元素的位置。这里有一种方法比这个页面上的其他方法更优雅一些(IMHO)。您可以通过任何元素并在文档中获得它的位置:

function findPos(obj) {
    var curleft = 0, curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
        return { x: curleft, y: curtop };
    }
    return undefined;
}

Now calculate the current position of the cursor relative to that:

现在计算光标相对于此的当前位置:

$('#canvas').mousemove(function(e) {
    var pos = findPos(this);
    var x = e.pageX - pos.x;
    var y = e.pageY - pos.y;
    var coordinateDisplay = "x=" + x + ", y=" + y;
    writeCoordinateDisplay(coordinateDisplay);
});

Notice that I've separated the generic findPos function from the event handling code. (As it should be. We should try to keep our functions to one task each.)

注意,我已经将通用的findPos函数与事件处理代码分开了。(它应该。我们应该尽量把我们的功能保持在一个任务上。

The values of offsetLeft and offsetTop are relative to offsetParent, which could be some wrapper div node (or anything else, for that matter). When there is no element wrapping the canvas they're relative to the body, so there is no offset to subtract. This is why we need to determine the position of the canvas before we can do anything else.

offsetLeft和offsetTop的值相对于offsetParent,它可以是一些包装器div节点(或其他任何东西)。当没有元素包装画布时,它们是相对于身体的,所以没有抵消。这就是为什么我们需要在做其他事情之前确定画布的位置。

Similary, e.pageX and e.pageY give the position of the cursor relative to the document. That's why we subtract the canvas's offset from those values to arrive at the true position.

同样,e。pageX和e。pageY给出了相对于文档的游标位置。这就是为什么我们要把画布的偏移量从这些值中减去到真正的位置。

An alternative for positioned elements is to directly use the values of e.layerX and e.layerY. This is less reliable than the method above for two reasons:

定位元素的另一种选择是直接使用e的值。layerX e.layerY。这比上面的方法更不可靠,有两个原因:

  1. These values are also relative to the entire document when the event does not take place inside a positioned element
  2. 当事件不发生在定位元素中时,这些值也相对于整个文档。
  3. They are not part of any standard
  4. 它们不是任何标准的一部分。

#19


0  

ThreeJS r77

ThreeJS r77

var x = event.offsetX == undefined ? event.layerX : event.offsetX;
var y = event.offsetY == undefined ? event.layerY : event.offsetY;

mouse2D.x = ( x / renderer.domElement.width ) * 2 - 1;
mouse2D.y = - ( y / renderer.domElement.height ) * 2 + 1;

After trying many solutions. This worked for me. Might help someone else hence posting. Got it from here

在许多的解决方案。这为我工作。可能会帮助其他人发布。从这里得到它

#1


69  

As described here:

这里所描述的那样:

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;

Worked perfectly fine for me.

对我来说完全没问题。

#2


169  

Update (5/5/16): patriques' answer should be used instead, as it's both simpler and more reliable.

更新(5/5/16):应该使用patriques的答案,因为它既简单又可靠。


Since the canvas isn't always styled relative to the entire page, the canvas.offsetLeft/Top doesn't always return what you need. It will return the number of pixels it is offset relative to its offsetParent element, which can be something like a div element containing the canvas with a position: relative style applied. To account for this you need to loop through the chain of offsetParents, beginning with the canvas element itself. This code works perfectly for me, tested in Firefox and Safari but should work for all.

因为画布并不总是相对于整个页面的样式,画布。offsetLeft/Top并不总是返回你所需要的东西。它将返回相对于其offsetParent元素的像素的数量,它可以是一个包含有位置的画布的div元素:应用的相对样式。为了说明这一点,您需要遍历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;

The last line makes things convenient for getting the mouse coordinates relative to a canvas element. All that's needed to get the useful coordinates is

最后一行可以方便地将鼠标坐标与画布元素相关联。得到有用坐标所需要的一切。

coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;

#3


124  

If you like simplicity but still want cross-browser functionality I found this solution worked best for me. This is a simplification of @Aldekein´s solution but without jQuery.

如果您喜欢简单,但仍然需要跨浏览器的功能,我发现这个解决方案对我最有效。这是一个简化@Aldekein´s解决但没有jQuery。

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

#4


20  

Modern browser's now handle this for you. Chrome, IE9, and Firefox support the offsetX/Y like this, passing in the event from the click handler.

现代浏览器现在为你处理这个。Chrome、IE9和Firefox支持offsetX/Y,从单击处理程序中传递事件。

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

Most modern browsers also support layerX/Y, however Chrome and IE use layerX/Y for the absolute offset of the click on the page including margin, padding, etc. In Firefox, layerX/Y and offsetX/Y are equivalent, but offset didn't previously exist. So, for compatibility with slightly older browsers, you can use:

大多数现代浏览器也支持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 };
}

#5


17  

According to fresh Quirksmode the clientX and clientY methods are supported in all major browsers. So, here it goes - the good, working code that works in a scrolling div on a page with scrollbars:

根据新的Quirksmode,所有主流浏览器都支持clientX和clientY方法。所以,这里有一个很好的工作代码,它可以在滚动条的页面上使用滚动条:

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

This also requires jQuery for $(canvas).offset().

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

#6


13  

I made a full demostration that works in every browser with the full source code of the solution of this problem: Coordinates of a mouse click on Canvas in Javascript. To try the demo, copy the code and paste it into a text editor. Then save it as example.html and, finally, open the file with a browser.

我在每一个浏览器中都做了一个完整的演示,它使用完整的源代码来解决这个问题:鼠标在Javascript上单击画布的坐标。要尝试演示,复制代码并将其粘贴到一个文本编辑器中。然后将它作为示例保存。最后,用浏览器打开文件。

#7


10  

Here is a small modification to Ryan Artecona's answer for canvases with a variable (%) width:

这里是对Ryan Artecona的一个小修改,他的画布上有一个变量(%)宽度:

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

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

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

    // Fix for variable canvas width
    canvasX = Math.round( canvasX * (this.width / this.offsetWidth) );
    canvasY = Math.round( canvasY * (this.height / this.offsetHeight) );

    return {x:canvasX, y:canvasY}
}

#8


7  

Be wary while doing the coordinate conversion; there are multiple non-cross-browser values returned in a click event. Using clientX and clientY alone are not sufficient if the browser window is scrolled (verified in Firefox 3.5 and Chrome 3.0).

在进行坐标转换时要小心;在单击事件中返回多个非跨浏览器值。如果浏览器窗口被滚动(在Firefox 3.5和Chrome 3.0中验证),仅使用clientX和clientY是不够的。

This quirks mode article provides a more correct function that can use either pageX or pageY or a combination of clientX with document.body.scrollLeft and clientY with document.body.scrollTop to calculate the click coordinate relative to the document origin.

这个quirks模式文章提供了一个更正确的函数,它可以使用pageX或pageY,或者使用document.body的clientX组合。用document.body进行滚动。scrollTop计算单击坐标相对于文档原点。

UPDATE: Additionally, offsetLeft and offsetTop are relative to the padded size of the element, not the interior size. A canvas with the padding: style applied will not report the top-left of its content region as offsetLeft. There are various solutions to this problem; the simplest one may be to clear all border, padding, etc. styles on the canvas itself and instead apply them to a box containing the canvas.

更新:另外,offsetLeft和offsetTop相对于元素的padd大小,而不是内部大小。使用填充的画布:样式应用程序不会将其内容区域的左上角报告为offsetLeft。对于这个问题有各种各样的解决方案;最简单的方法可能是清除画布上的所有边框、填充等样式,并将它们应用到包含画布的框中。

#9


6  

Here is a very nice tutorial-

这是一个很好的教程。

http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/

http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/

 <canvas id="myCanvas" width="578" height="200"></canvas>
<script>
  function writeMessage(canvas, message) {
    var context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.font = '18pt Calibri';
    context.fillStyle = 'black';
    context.fillText(message, 10, 25);
  }
  function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
      x: evt.clientX - rect.left,
      y: evt.clientY - rect.top
    };
  }
  var canvas = document.getElementById('myCanvas');
  var context = canvas.getContext('2d');

  canvas.addEventListener('mousemove', function(evt) {
    var mousePos = getMousePos(canvas, evt);
    var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
    writeMessage(canvas, message);
  }, false);

hope this helps!

希望这可以帮助!

#10


4  

I'm not sure what's the point of all these answers that loop through parent elements and do all kinds of weird stuff.

我不知道所有这些答案的意义是什么,这些答案循环通过父元素,做各种奇怪的事情。

The HTMLElement.getBoundingClientRect method is designed to to handle actual screen position of any element. This includes scrolling, so stuff like scrollTop is not needed:

HTMLElement。getBoundingClientRect方法用于处理任何元素的实际屏幕位置。这包括滚动,所以不需要像scrollTop这样的东西:

(from MDN) The amount of scrolling that has been done of the viewport area (or any other scrollable element) is taken into account when computing the bounding rectangle

(从MDN)在计算边界矩形时考虑到viewport区域(或任何其他可滚动元素)的滚动量。

Normal image

The very simplest approach was already posted here. This is correct as long as no wild CSS rules are involved.

最简单的方法已经在这里发布了。只要没有涉及到野生CSS规则,这是正确的。

Handling stretched canvas/image

When image pixel width isn't matched by it's CSS width, you'll need to apply some ratio on pixel values:

当图像像素宽度与CSS宽度不匹配时,你需要对像素值应用一些比率:

/* Returns pixel coordinates according to the pixel that's under the mouse cursor**/
HTMLCanvasElement.prototype.relativeCoords = function(event) {
  var x,y;
  //This is the current screen rectangle of canvas
  var rect = this.getBoundingClientRect();
  var top = rect.top;
  var bottom = rect.bottom;
  var left = rect.left;
  var right = rect.right;
  //Recalculate mouse offsets to relative offsets
  x = event.clientX - left;
  y = event.clientY - top;
  //Also recalculate offsets of canvas is stretched
  var width = right - left;
  //I use this to reduce number of calculations for images that have normal size 
  if(this.width!=width) {
    var height = bottom - top;
    //changes coordinates by ratio
    x = x*(this.width/width);
    y = y*(this.height/height);
  } 
  //Return as an array
  return [x,y];
}

As long as the canvas has no border, it works for stretched images (jsFiddle).

只要画布没有边框,它就可以用于拉伸图像(jsFiddle)。

Handling CSS borders

If the canvas has thick border, the things get little complicated. You'll literally need to subtract the border from the bounding rectangle. This can be done using .getComputedStyle. This answer describes the process.

如果画布有厚厚的边框,事情就变得复杂了。你需要从边界矩形中减去边界。可以使用. getcomputedstyle来完成。这个答案描述了这个过程。

The function then grows up a little:

然后这个函数会增长一点:

/* Returns pixel coordinates according to the pixel that's under the mouse cursor**/
HTMLCanvasElement.prototype.relativeCoords = function(event) {
  var x,y;
  //This is the current screen rectangle of canvas
  var rect = this.getBoundingClientRect();
  var top = rect.top;
  var bottom = rect.bottom;
  var left = rect.left;
  var right = rect.right;
  //Subtract border size
  // Get computed style
  var styling=getComputedStyle(this,null);
  // Turn the border widths in integers
  var topBorder=parseInt(styling.getPropertyValue('border-top-width'),10);
  var rightBorder=parseInt(styling.getPropertyValue('border-right-width'),10);
  var bottomBorder=parseInt(styling.getPropertyValue('border-bottom-width'),10);
  var leftBorder=parseInt(styling.getPropertyValue('border-left-width'),10);
  //Subtract border from rectangle
  left+=leftBorder;
  right-=rightBorder;
  top+=topBorder;
  bottom-=bottomBorder;
  //Proceed as usual
  ...
}

I can't think of anything that would confuse this final function. See yourself at JsFiddle.

我想不出什么东西会把这最后的函数搞混。在JsFiddle看到自己。

Notes

If you don't like modifying the native prototypes, just change the function and call it with (canvas, event) (and replace any this with canvas).

如果您不喜欢修改本机原型,只需更改该函数并调用它(canvas, event)(并用canvas替换任何该函数)。

#11


3  

Using jQuery in 2016, to get click coordinates relative to the canvas, I do:

在2016年使用jQuery,为了得到与画布相对的点击坐标,我这样做:

$(canvas).click(function(jqEvent) {
    var coords = {
        x: jqEvent.pageX - $(canvas).offset().left,
        y: jqEvent.pageY - $(canvas).offset().top
    };
});

This works since both canvas offset() and jqEvent.pageX/Y are relative to the document regardless of scroll position.

这在画布偏移()和jqEvent上都有效。pageX/Y相对于文档,而不考虑滚动位置。

Note that if your canvas is scaled then these coordinates are not the same as canvas logical coordinates. To get those, you would also do:

注意,如果您的画布被缩放,那么这些坐标与画布逻辑坐标不一样。为了得到这些,你也可以这样做:

var logicalCoords = {
    x: coords.x * (canvas.width / $(canvas).width()),
    y: coords.y * (canvas.height / $(canvas).height())
}

#12


2  

I recommend this link- http://miloq.blogspot.in/2011/05/coordinates-mouse-click-canvas.html

我推荐这个链接- http://miloq.blogspot.in/2011/05/coordinates-mouse-click .html。

<style type="text/css">

  #canvas{background-color: #000;}

</style>

<script type="text/javascript">

  document.addEventListener("DOMContentLoaded", init, false);

  function init()
  {
    var canvas = document.getElementById("canvas");
    canvas.addEventListener("mousedown", getPosition, false);
  }

  function getPosition(event)
  {
    var x = new Number();
    var y = new Number();
    var canvas = document.getElementById("canvas");

    if (event.x != undefined && event.y != undefined)
    {
      x = event.x;
      y = event.y;
    }
    else // Firefox method to get the position
    {
      x = event.clientX + document.body.scrollLeft +
          document.documentElement.scrollLeft;
      y = event.clientY + document.body.scrollTop +
          document.documentElement.scrollTop;
    }

    x -= canvas.offsetLeft;
    y -= canvas.offsetTop;

    alert("x: " + x + "  y: " + y);
  }

</script>

#13


1  

In Prototype, use cumulativeOffset() to do the recursive summation as mentioned by Ryan Artecona above.

在原型中,使用累积量抵消()来完成Ryan Artecona所提到的递归求和。

http://www.prototypejs.org/api/element/cumulativeoffset

http://www.prototypejs.org/api/element/cumulativeoffset

#14


1  

You could just do:

你可以做的:

var canvas = yourCanvasElement;
var mouseX = (event.clientX - (canvas.offsetLeft - canvas.scrollLeft)) - 2;
var mouseY = (event.clientY - (canvas.offsetTop - canvas.scrollTop)) - 2;

This will give you the exact position of the mouse pointer.

这将给出鼠标指针的确切位置。

#15


1  

See demo at http://jsbin.com/ApuJOSA/1/edit?html,output .

看到演示http://jsbin.com/ApuJOSA/1/edit?html输出。

  function mousePositionOnCanvas(e) {
      var el=e.target, c=el;
      var scaleX = c.width/c.offsetWidth || 1;
      var scaleY = c.height/c.offsetHeight || 1;

      if (!isNaN(e.offsetX)) 
          return { x:e.offsetX*scaleX, y:e.offsetY*scaleY };

      var x=e.pageX, y=e.pageY;
      do {
        x -= el.offsetLeft;
        y -= el.offsetTop;
        el = el.offsetParent;
      } while (el);
      return { x: x*scaleX, y: y*scaleY };
  }

#16


0  

Hey, this is in dojo, just cause it's what I had the code in already for a project.

这是在dojo中,因为我已经有了一个项目的代码。

It should be fairly Obvious how to convert it back to non dojo vanilla JavaScript.

如何将其转换为非dojo香草JavaScript应该是相当明显的。

  function onMouseClick(e) {
      var x = e.clientX;
      var y = e.clientY;
  }
  var canvas = dojo.byId(canvasId);
  dojo.connect(canvas,"click",onMouseClick);

Hope that helps.

希望有帮助。

#17


0  

Here is some modifications of the above Ryan Artecona's solution.

下面是对Ryan Artecona解决方案的一些修改。

function myGetPxStyle(e,p)
{
    var r=window.getComputedStyle?window.getComputedStyle(e,null)[p]:"";
    return parseFloat(r);
}

function myGetClick=function(ev)
{
    // {x:ev.layerX,y:ev.layerY} doesn't work when zooming with mac chrome 27
    // {x:ev.clientX,y:ev.clientY} not supported by mac firefox 21
    // document.body.scrollLeft and document.body.scrollTop seem required when scrolling on iPad
    // html is not an offsetParent of body but can have non null offsetX or offsetY (case of wordpress 3.5.1 admin pages for instance)
    // html.offsetX and html.offsetY don't work with mac firefox 21

    var offsetX=0,offsetY=0,e=this,x,y;
    var htmls=document.getElementsByTagName("html"),html=(htmls?htmls[0]:0);

    do
    {
        offsetX+=e.offsetLeft-e.scrollLeft;
        offsetY+=e.offsetTop-e.scrollTop;
    } while (e=e.offsetParent);

    if (html)
    {
        offsetX+=myGetPxStyle(html,"marginLeft");
        offsetY+=myGetPxStyle(html,"marginTop");
    }

    x=ev.pageX-offsetX-document.body.scrollLeft;
    y=ev.pageY-offsetY-document.body.scrollTop;
    return {x:x,y:y};
}

#18


0  

First, as others have said, you need a function to get the position of the canvas element. Here's a method that's a little more elegant than some of the others on this page (IMHO). You can pass it any element and get its position in the document:

首先,正如其他人所说,您需要一个函数来获得画布元素的位置。这里有一种方法比这个页面上的其他方法更优雅一些(IMHO)。您可以通过任何元素并在文档中获得它的位置:

function findPos(obj) {
    var curleft = 0, curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
        return { x: curleft, y: curtop };
    }
    return undefined;
}

Now calculate the current position of the cursor relative to that:

现在计算光标相对于此的当前位置:

$('#canvas').mousemove(function(e) {
    var pos = findPos(this);
    var x = e.pageX - pos.x;
    var y = e.pageY - pos.y;
    var coordinateDisplay = "x=" + x + ", y=" + y;
    writeCoordinateDisplay(coordinateDisplay);
});

Notice that I've separated the generic findPos function from the event handling code. (As it should be. We should try to keep our functions to one task each.)

注意,我已经将通用的findPos函数与事件处理代码分开了。(它应该。我们应该尽量把我们的功能保持在一个任务上。

The values of offsetLeft and offsetTop are relative to offsetParent, which could be some wrapper div node (or anything else, for that matter). When there is no element wrapping the canvas they're relative to the body, so there is no offset to subtract. This is why we need to determine the position of the canvas before we can do anything else.

offsetLeft和offsetTop的值相对于offsetParent,它可以是一些包装器div节点(或其他任何东西)。当没有元素包装画布时,它们是相对于身体的,所以没有抵消。这就是为什么我们需要在做其他事情之前确定画布的位置。

Similary, e.pageX and e.pageY give the position of the cursor relative to the document. That's why we subtract the canvas's offset from those values to arrive at the true position.

同样,e。pageX和e。pageY给出了相对于文档的游标位置。这就是为什么我们要把画布的偏移量从这些值中减去到真正的位置。

An alternative for positioned elements is to directly use the values of e.layerX and e.layerY. This is less reliable than the method above for two reasons:

定位元素的另一种选择是直接使用e的值。layerX e.layerY。这比上面的方法更不可靠,有两个原因:

  1. These values are also relative to the entire document when the event does not take place inside a positioned element
  2. 当事件不发生在定位元素中时,这些值也相对于整个文档。
  3. They are not part of any standard
  4. 它们不是任何标准的一部分。

#19


0  

ThreeJS r77

ThreeJS r77

var x = event.offsetX == undefined ? event.layerX : event.offsetX;
var y = event.offsetY == undefined ? event.layerY : event.offsetY;

mouse2D.x = ( x / renderer.domElement.width ) * 2 - 1;
mouse2D.y = - ( y / renderer.domElement.height ) * 2 + 1;

After trying many solutions. This worked for me. Might help someone else hence posting. Got it from here

在许多的解决方案。这为我工作。可能会帮助其他人发布。从这里得到它