48
<!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ベースのブラウザで完全に機能します。マウスを動かしながら、キャンバス上にポイントを描画します。残念ながら、そのイベントモデルはoffsetX / Yプロパティをサポートしていないため、Firefoxにはありません。(おそらく)event.clientX(Firefoxでもサポートされています)から、キャンバスの位置や変換などを考慮して、マウスの座標をキャンバスの相対座標に変換するにはどうすればよいですか?ありがとう、ルカ。

4

12 に答える 12

78

JQueryのバグトラッカーページから-素晴らしいポリフィルはこれです:

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

..ここで、eはjqueryイベントから返されたイベントです。明らかに、プロジェクトにすでにJqueryがある場合にのみ、それ以外の場合はoffset()手動で処理する必要があります。

于 2013-02-14T10:02:25.990 に答える
36

layerX、layerYを試してください

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

フィドル

于 2012-07-04T19:32:10.583 に答える
21

残念ながら、私には解決策がありませんでした。

私はここで良い実装を見つけました:

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;
于 2014-08-20T07:40:03.493 に答える
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;
}
于 2013-02-12T20:23:45.927 に答える
11

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;
于 2012-07-10T09:39:24.050 に答える
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;
    }
}
于 2013-05-06T16:43:11.523 に答える
3

さまざまな理由から、jquery以外のバージョンはどれも完全には機能しません。しかしあなたの助けを借りて、私はこれを機能させました:

if(!event.hasOwnProperty('offsetX')) {
    event.offsetX = event.layerX - event.currentTarget.offsetLeft;
    event.offsetY = event.layerY - event.currentTarget.offsetTop;
}
于 2013-05-13T11:47:42.517 に答える
3

EnotionZとlazbranniganによる最後の2つの回答(以前はそれぞれ0票)を除いて、ここに投稿されたすべての回答が、div内に複数の要素が含まれている場合に間違っていることがわかりました。私の場合、1つの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などのマージンでも機能しますが、私はそれを試していません。

于 2014-02-14T13:36:09.777 に答える
2

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;
  }
于 2013-09-21T13:57:04.543 に答える
1

この質問には更新された回答が必要です。


layerXまず、コメントで述べたように、とを使用した古い回答のすべてについてlayerY

「この機能は非標準であり、標準の軌道に乗っていません。Webに面している本番サイトでは使用しないでください。すべてのユーザーに対して機能するわけではありません。また、実装間に大きな非互換性があり、動作が将来変更される可能性があります。 。」

(ソース:developer.mozilla.org/en-US/docs/Web/API/UIEvent/layerX


次に、console.log(event)Firefoxで0offsetXoffsetY表示しているときにconsole.log(event.offsetX)、0ではないことを発見しました。嘘をついている可能性があるので注意してください。

この動作はここで説明されています:

ロギングオブジェクト

使用しないでくださいconsole.log(obj)、使用してくださいconsole.log(JSON.parse(JSON.stringify(obj)))

このようにして、ログに記録した時点でobjの値が表示されていることを確認できます。それ以外の場合、多くのブラウザは、値の変更に応じて常に更新されるライブビューを提供します。これはあなたが望むものではないかもしれません。

JSON.stringify()(また、ここで必要なことを実行しないことに注意してください...イベントオブジェクト全体を文字列化するわけではありません。)

于 2020-08-07T19:47:31.990 に答える
1

OffsetX / Yの動作は、FireFox、Chrome/Edgeで異なります。コードスニペットを追加して値を計算する必要がある場合があります。

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

myRefは、最も近い親要素のrefです。したがって、オフセットは、この要素(clientX)からその親の要素を引いた距離になります。

于 2020-11-28T13:26:48.837 に答える
0

それでも解決策が必要な場合は、Firefoxでこれが完璧に機能します。

var x = e.offsetX || e.originalEvent.layerX;
var y = e.offsetY || e.originalEvent.layerY;
于 2015-04-30T23:22:11.247 に答える