Event.offsetX в Firefox

<!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) в относительные координаты холста с учетом положения холста, преобразования и т.д.? Спасибо, Лука.

Ответ 1

Попробуйте layerX, layerY

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

FIDDLE

Ответ 2

Из страницы отслеживания ошибок JQuery - это хороший polyfill:

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

.. где e - событие, возвращаемое из события jquery. Очевидно, только если у вас есть Jquery уже в вашем проекте, в противном случае вам придется вручную делать вещи offset().

Ответ 3

К сожалению, для меня не было никакого решения.

Я нашел хорошую реализацию здесь:

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;

Ответ 4

К сожалению, 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;
}

Ответ 5

В решении Musa есть ошибка: подумайте, что произойдет, если e.offsetX === 0 и e.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;

Или, потому что мы можем предположить, что если offsetX определено, offsetY тоже будет:

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

Ответ 6

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

Ответ 7

Ни одна из не-jquery версий не работает полностью по разным причинам. С вашей помощью, однако, я получил это для работы:

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

Ответ 8

Я обнаружил, что все ответы размещены здесь, кроме двух последних ответов EnotionZ и laz brannigan (ранее с нулевым количеством голосов каждый), где неправильно в тех случаях, когда несколько элементов содержались в div. В моем случае у меня есть несколько элементов холста внутри одного div, и я слушаю каждый холст отдельно.

После значительных проб и ошибок окончательный правильный ответ, к которому я пришел, который отлично работает и идентичен для меня в 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, указанных в его сообщении, но я этого не пробовал.

Ответ 9

Но что вы будете делать, если нет полей layerX, layerY?

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

Ответ 10

Если некоторые из них по-прежнему нуждаются в решениях, это прекрасно работает в Firefox:

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