Firefox中的event.offsetX

时间:2012-07-04 19:20:51

标签: javascript html5 events firefox html5-canvas

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script language="javascript">
function main(){
    var canvas = document.getElementById("canvas");
    canvas.addEventListener("mousemove", function(e){
        if (!e) e = window.event;
        var ctx = canvas.getContext("2d");

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

        ctx.fillRect(x, y, 1, 1);
    });
}
</script>
</head>
<body onload="main();">
<div style="width: 800px; height: 600px; -webkit-transform: scale(0.75,0.75); -moz-transform: scale(0.75,0.75)">
    <canvas id="canvas" width="400px" height="400px" style="background-color: #cccccc;"></canvas>
</div>
</body>
</html>

请考虑以上快速而肮脏的例子。 请注意我的画布包含一个应用了比例变换的div。 以上代码适用于任何基于webkit的浏览器。移动鼠标时,它会在画布上绘制点。 不幸的是,它不在Firefox中,因为它的事件模型不支持offsetX / Y属性。 如何将(也许)event.clientX(在firefox中也支持)中的鼠标坐标转换为画布相对坐标,同时考虑画布位置,变换等? 谢谢,卢卡。

12 个答案:

答案 0 :(得分:77)

来自JQuery bug tracker page - 这是一个很好的polyfill:

var offX  = (e.offsetX || e.pageX - $(e.target).offset().left);

..其中e是从jquery事件返回的事件。显然,只有你的项目中已经有Jquery,否则必须手动执行offset()

答案 1 :(得分:35)

尝试layerX,layerY

var x = (e.offsetX === undefined) ? e.layerX : e.offsetX;
var y = (e.offsetY === undefined) ? e.layerY : e.offsetY;

FIDDLE

答案 2 :(得分:20)

不幸的是没有解决方案适合我。

我找到了一个很好的实现here

var target  = e.target || e.srcElement,
              rect    = target.getBoundingClientRect(),
              offsetX = e.clientX - rect.left,
              offsetY  = e.clientY - rect.top;

e.offsetX   = offsetX;
e.offsetY   = offsetY;

答案 3 :(得分:15)

不幸的是,offsetX和layerX并不完全相同,offsetX是当前元素中的偏移量,但是layerX是页面的偏移量。以下是我目前正在使用的修复:

function fixEvent(e) {
    if (! e.hasOwnProperty('offsetX')) {
        var curleft = curtop = 0;
        if (e.offsetParent) {
           var obj=e;
           do {
              curleft += obj.offsetLeft;
              curtop += obj.offsetTop;
           } while (obj = obj.offsetParent);
        }
        e.offsetX=e.layerX-curleft;
        e.offsetY=e.layerY-curtop;
    }
    return e;
}

答案 4 :(得分:11)

Musa解决方案中存在一个错误:想想e.offsetX === 0e.layerX === undefined ...

会发生什么
var x = e.offsetX || e.layerX; // x is now undefined!

更强大的版本如下:

var x = e.hasOwnProperty('offsetX') ? e.offsetX : e.layerX;
var y = e.hasOwnProperty('offsetY') ? e.offsetY : e.layerY;

或者,因为我们可以假设如果定义offsetXoffsetY也是如此:

var hasOffset = e.hasOwnProperty('offsetX'),
    x         = hasOffset ? e.offsetX : e.layerX,
    y         = hasOffset ? e.offsetY : e.layerY;

答案 5 :(得分:4)

offset实际上并未直接转换为layer; offset属性不考虑元素的边距。下面的代码应该考虑到这一点。

function(e) {
    var x = e.offsetX, y = e.offsetY;
    if(e.hasOwnProperty('layerX')) {
      x = e.layerX - e.currentTarget.offsetLeft;
      y = e.layerY - e.currentTarget.offsetTop;
    }
}

答案 6 :(得分:3)

由于各种原因,所有非jquery版本都不能完全运行。在你的帮助下,我得到了这个工作:

if(!event.hasOwnProperty('offsetX')) {
    event.offsetX = event.layerX - event.currentTarget.offsetLeft;
    event.offsetY = event.layerY - event.currentTarget.offsetTop;
}

答案 7 :(得分:3)

我发现所有答案都在这里发布除了 EnotionZ和laz brannigan的最后两个答案(之前每个票数为零),在div中包含多个元素的情况下出错。在我的情况下,我在一个div中有几个canvas元素,我正在分别听每个画布。

经过大量的反复试验后我得到了最终的正确答案,对我来说,FireFox和Chrome的完美和完全相同,如下所示:

//inside my mouse events handler:
var anOffsetX = (inEvent.offsetX !== undefined) ? inEvent.offsetX : (inEvent.layerX - inEvent.target.offsetLeft);
var anOffsetY = (inEvent.offsetY !== undefined) ? inEvent.offsetY : (inEvent.layerY - inEvent.target.offsetTop);

据推测,这也适用于边距,例如EnotionZ在他的帖子中指出,但我没有尝试过。

答案 8 :(得分:2)

但是,如果没有layerXlayerY字段,您会怎么做?

 var xe=e.offsetX,ye=e.offsetY;
  if(!xe){
     xe=e.clientX - $(e.target).offset().left;
  }
  if(!ye){
    ye= e.clientY - $(e.target).offset().top;
  }

答案 9 :(得分:0)

如果有些人仍然需要解决方案,那么这个解决方案在Firefox中非常完美:

var x = e.offsetX || e.originalEvent.layerX;
var y = e.offsetY || e.originalEvent.layerY;

答案 10 :(得分:0)

此问题需要更新的答案。


首先,正如我在评论中提到的,有关使用layerXlayerY的所有较早答案:

“此功能是非标准的,不是标准的功能。请勿在面向Web的生产站点上使用它:不适用于每个用户。实现之间还可能存在很大的不兼容性,并且行为可能会更改将来。”

(来源:developer.mozilla.org/en-US/docs/Web/API/UIEvent/layerX


第二,我发现当您在Firefox中console.log(event)时,offsetXoffsetY显示0,但是当您console.log(event.offsetX)时,它不是0。小心,因为您可能被骗了。

here对此行为进行了解释:

记录对象

不要使用console.log(obj),请使用console.log(JSON.parse(JSON.stringify(obj)))

这样,您可以确定在登录时会看到obj的值。否则,许多浏览器会提供实时视图,该实时视图会随着值的变化而不断更新。这可能不是您想要的。

(还请注意,JSON.stringify()不会在这里执行您想要的操作……它不会对整个事件对象进行字符串化。)

答案 11 :(得分:0)

OffsetX / Y行为在FireFox,Chrome / Edge中不同。您可能需要通过添加代码段来计算值:

const offsetX = evt.clientX - this.myRef.current.getBoundingClientRect().left;
const offsetY = evt.clientY - this.myRef.current.getBoundingClientRect().top;

myRef 是其最接近的父元素的引用。因此,偏移量就是该元素(clientX)之间的距离减去其父元素之间的距离。