当前位置:  开发笔记 > 编程语言 > 正文

如何在画布元素上获得鼠标点击的坐标?

如何解决《如何在画布元素上获得鼠标点击的坐标?》经验,为你挑选了10个好方法。

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

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



1> Ryan Artecon..:

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


由于画布并不总是相对于整个页面设置样式,因此canvas.offsetLeft/Top并不总是返回您需要的内容.它将返回相对于其offsetParent元素偏移的像素数,这可能类似于div包含position: relative应用了样式的画布的元素.为了解释这一点,你需要循环遍历offsetParents 链,从canvas元素本身开始.这段代码非常适合我,在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;

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

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


我的Chrome有`event.offsetX`和`event.offsetY`属性,所以我通过添加`if(event.offsetX!== undefined && event.offsetY!== undefined)修改你的解决方案{return {x:event.offsetX ,y:event.offsetY}; }`.看起来很有效.
不,它使用内置的javascript原型对象--- https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript#Prototype-based_programming
答案的最终版本对我不起作用.在Firefox上,如果滚动整个屏幕,我将取代的值作为输出.对我有用的是一个非常类似的解决方案,在http://stackoverflow.com/a/10816667/578749上给出,而不是event.pageX/Y,它从event.clientX/Y中减去计算的偏移量.有人可以复习并解释一下吗?
Baczek对于Chrome的`event.offsetX`和`event.offsetY`是正确的,它也适用于IE9.对于Firefox(经过测试w/v13),您可以使用`event.layerX`和`event.layerY`.
我另外添加了这个:`canvasX = event.pageX - totalOffsetX - document.body.scrollLeft; canvasY = event.pageY - totalOffsetY - document.body.scrollTop;`

2> patriques..:

如果您喜欢简单但仍想要跨浏览器功能,我发现这个解决方案最适合我.这是@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)
})


@ PeppeL-G边界客户端矩形为您计算.在发表评论之前,您可以在控制台中轻松测试它(这就是我所做的).
为像我这样的人添加用法:`var canvas = document.getElementById('canvasID'); canvas.addEventListener(“ mousedown”,函数(e){getCursorPosition(canvas,e);});`

3> N4ppeL..:

编辑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的答案适用于更一般的情况.
如果性能很重要,则不适合此解决方案,因为Dom访问是在每次点击/移动时完成的.并且getBoundingClientRect现在存在,并且更加优雅.
此帖子中的链接不再有效.

4> mafafu..:

现代浏览器现在可以为您处理.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 };
}



5> Aldekein..:

根据新鲜怪异模式将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的$(canvas).offset().



6> Manuel Ignac..:

我做了一个完整的演示,可以在每个浏览器中使用此问题的解决方案的完整源代码:鼠标在Javascript中单击Canvas的坐标.要尝试演示,请复制代码并将其粘贴到文本编辑器中.然后将其保存为example.html,最后,使用浏览器打开该文件.



7> Cryptovirus..:

以下是对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> fixermark..:

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

这个怪癖模式文章提供了一个更正确的函数,可以使用pageX或pageY或clientX与document.body.scrollLeft和clientY与document.body.scrollTop的组合来计算相对于文档原点的单击坐标.

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



9> Tomáš Zato -..:

我不确定所有这些答案的重点在于循环通过父元素并做各种奇怪的事情.

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

(来自MDN)在计算边界矩形时,会考虑视口区域(或 任何其他可滚动元素)的滚动量

正常图像

在非常简单的方法已经张贴在这里.只要涉及任何野生CSS规则,这是正确的.

处理拉伸的画布/图像

当图像像素宽度与其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];
}

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

处理CSS边框

如果画布边框很粗,那么事情就会变得复杂.你真的需要从边界矩形中减去边界.这可以使用.getComputedStyle完成.这个答案描述了这个过程.

然后功能增长了一点:

/* 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
  ...
}

我想不出任何会混淆这个最终功能的东西.在JsFiddle看到自己.

笔记

如果你不喜欢修改本机prototypes,只需更改函数并调用它(canvas, event)(并替换为thiswith canvas).



10> 小智..:

这是一个非常好的教程 -

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

 





















    
TXCWB_523
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有