イベントなしで(マウスを移動せずに)マウスの位置を取得する方法は?


286

マウス移動イベントなしで(マウスを移動せずに)ページのロード後にJavaScriptでマウス位置を取得することは可能ですか?


61
mousemoveイベントに問題はありません。場合によっては、ユーザーがマウスを動かさないこともあります。ご回答有難うございます。
Norbert Tamas、2010

2
Norbert Tamas、@ SuperNovaの回答(今年まで追加されなかった)は、ページの読み込み時に(マウスがビューポートにある場合)起動するため、mouseenterが正常に機能することを示しています。それは2010年にそのように機能しなかったのですか、それとも、誰もそれを試そうとは思わなかっただけですか?
Peter Hansen

@CrescentFresh場合によっては(ユーザースクリプトなど)、多くのmousemoveイベントを追加してブラウザーの速度を低下させたくない場合があります。
トマーシュZato -復活モニカ

マウスオーバーでFFで可能ですが、IEとChromeではできません。
Elad、2015年

または、ゲームでは、カメラはゲームの世界を動き回り、キャラクターはマウスを見ています(通常はトップダウンシューティングスタイル)。あなたはマウスムーブだけに依存しています。しかし、それは大したことではなく、ポインタの「世界」の座標を格納し、人々にそれをクエリさせるだけです。
kamranicus

回答:


336

本当の答え:いいえ、それは不可能です。

OK、私は方法を考えました。ドキュメント全体をカバーするdivでページをオーバーレイします。その中に(たとえば)2,000 x 2,000の<a>要素を作成します(:hover疑似クラスがIE 6で機能するようにするため)。各要素のサイズは1ピクセルです。プロパティを変更する要素のCSS :hoverルールを作成し<a>ます(たとえば、としますfont-family)。ロードハンドラーで、400万個の<a>要素のそれぞれを循環させ、ホバーフォントの要素が見つかるまでcurrentStyle/を確認しgetComputedStyle()ます。この要素から外挿して、ドキュメント内の座標を取得します。

これをしないでください


92
ハハ-ある時点でグーグルして、実際にこれを実装した人の数を把握できるかどうかを確認する必要があります
ポインティ

6
実際には、CPUにそれほど負荷をかけなくても実装できます(私はテストしていません)。dom readyでjavascriptを使用して<a>要素を作成し、マウスの位置を取得してから、すべての<a>要素を削除します。マウスマウスでは、マウスの位置を取得するための他の機能が必要です。とにかく、これは陽気でした。
machineaddict 2012

21
おそらく、これはバイナリ検索で実用的にできるでしょうか?<a>与えられた四角形をカバーする要素のペアを作成するループ(サイズ設定された<img>要素の絶対配置を使用すると思います)、四角形を毎回縮小します。はい、ばかげていますが、最初のマウス移動の前にこの情報を取得することはできません。
Darius Bacon 2013年

29
stackoverflow.com/a/8543879/27024は、マウスが初めて移動するまでホバーが作動しないことを示しています。これはこのスキームを失敗させます。
Darius Bacon

4
@DariusBacon:そのリンクされた答えは正しくないようです:jsbin.com/utocax/3。そのため、このアプローチは状況によっては実用的である場合があります。
Tim Down

121

編集2020:これは機能しなくなりました。ブラウザーベンダーがこれにパッチを適用したようです。ほとんどのブラウザはクロムに依存しているため、中核となる可能性があります。

以前の回答:mouseenterをフックすることもできます(このイベントは、ページのリロード後に、mousecursorがページ内にあるときに発生します)。Corruptedのコードを拡張することでうまくいくはずです。

var x = null;
var y = null;
    
document.addEventListener('mousemove', onMouseUpdate, false);
document.addEventListener('mouseenter', onMouseUpdate, false);
    
function onMouseUpdate(e) {
  x = e.pageX;
  y = e.pageY;
  console.log(x, y);
}

function getMouseX() {
  return x;
}

function getMouseY() {
  return y;
}

mouseleave-eventでxとyをnullに設定することもできます。したがって、ユーザーがカーソルを使用してページ上にいるかどうかを確認できます。


11
これは、奇妙に思われる、ここで唯一の本当に役立つ答えのようです。確かに(最新のFirefox、Chrome、IE11では)mouseenterはページの読み込み時に起動し、正しい座標を提供します。この分野でのブラウザの動作は、過去数年間で単純に変化しましたか?
Peter Hansen、

3
実際、「mouseenter」は何の付加価値もないようです。私はChromeとIEで次jsfiddleでテストし、あなたが内部文書(結果パネル)の上にマウスを置くまで、彼らはcordinatesを表示しない:jsfiddle.net/xkpd784o/1
マリアーノDesanze

1
@Proton:ページが完全に読み込まれる前に結果パネルの領域にマウスを移動し、移動しないでください。ロード後、ページはすぐにマウスの位置を認識します。マウスを動かす必要はありません。したがって、ページが読み込まれ、マウスがドキュメント領域内にある場合、mouseenterも起動されます。つまり、OPが最初に望んでいたものです。他の誰もこの答えを提供しません。
SuperNova 2015年

1
潜在的に有用な添加はのための機能を追加することでmouseleave設定した場合xy裏面にnull又は'undefined'
rtpax

2
上記のjsfiddelを使用するChrome 68では、ページの読み込みが完了する前にレンダリングされた領域にマウスが移動された場合でも、読み込みではなく最初のマウスの移動時にアラートが発生します。
junvar 2018

84

できることは、カーソルの座標xy座標の変数を作成し、マウスが移動するたびに変数を更新し、間隔で関数を呼び出して、格納された位置で必要なことを行うことです。

もちろん、これの欠点は、マウスを機能させるために、マウスの最初の1回の動きが必要なことです。カーソルが少なくとも一度は位置を更新している限り、カーソルが再び移動するかどうかに関係なく、カーソルの位置を見つけることができます。

var cursorX;
var cursorY;
document.onmousemove = function(e){
    cursorX = e.pageX;
    cursorY = e.pageY;
}
setInterval(checkCursor, 1000);
function checkCursor(){
    alert("Cursor at: " + cursorX + ", " + cursorY);
}

上記のコードは、カーソルの位置を示すメッセージで1秒に1回更新されます。これがお役に立てば幸いです。


18
この投稿の件名を読みましたか?OPは、イベントを使用せずにマウス座標を取得する方法を尋ねます。しかし、あなたの投稿はonmousemoveイベントの使用を提案しています。
jake

53
@jake OPはイベント以外のメソッドを具体的に要求しましたが、この回答は、ここに来て回答とおそらく回避策を探している他の人にメリットをもたらします。また、私が知る限り、これはイベントを直接使用せずにいつでもカーソル位置を取得するための最良の方法であるため、この回答はトピック内で部分的に検討します。とは言っても、答えは、事実を述べ、コメントの乱用を回避する方法を提供するという線に沿って、より多くの言葉で表現されている可能性があります。
jpeltoniemi 2013

2
@Pichan cursorX/Yイベントが発生する前にこれらの変数を埋める方法を探していたので、メリットはありませんでした。
polkovnikov.ph 2016

マウスイベントを発生させないユーザーはごくわずか
SuperUberDuper 2016

1
注意してください。マウスムーブリスナーを維持することはコストがかかる場合があります。間隔内でリスナーを再作成し、座標を取得した後にリスナーを破棄することをお勧めします。
KRB

10

Tim Downが提案したものと同様のものを試すことができますが、画面上の各ピクセルに要素を持たせる代わりに、2〜4個の要素(ボックス)を作成し、それらの位置、幅、高さを動的に変更して、画面上のまだ可能な位置を分割します。 2-4再帰的に、したがって、マウスの実際の場所をすばやく見つけることができます。

たとえば、最初の要素は画面の右半分と左半分、その後は上半分と下半分になります。これで、マウスが配置されている画面の4分の1に繰り返しアクセスできるようになりました-このスペースの4分の1を発見してください...


9

2,000 x 2,000 <a>要素をレンダリングする場合、@ Tim Downの回答は効果的ではありません。

OK、私は方法を考えました。ドキュメント全体をカバーするdivでページをオーバーレイします。その中に(たとえば)2,000 x 2,000の要素(:hover疑似クラスがIE 6で機能するようにする)を作成します。各要素のサイズは1ピクセルです。プロパティを変更する要素(たとえばfont-family)のCSS:hoverルールを作成します。ロードハンドラーで、400万個の要素のそれぞれを循環させ、ホバーフォントの要素が見つかるまでcurrentStyle / getComputedStyle()を確認します。この要素から外挿して、ドキュメント内の座標を取得します。

これをしないでください。

ただし、一度に400万個の要素をレンダリングする必要はなく、代わりにバイナリ検索を使用します。<a>代わりに4つの要素を使用してください:

  • 手順1:画面全体を開始検索領域と見なします
  • ステップ2:検索領域を2 x 2 = 4つの長方形<a>要素に分割する
  • ステップ3:getComputedStyle()関数を使用して、どの長方形のマウスがホバーするかを決定する
  • ステップ4:検索領域をその長方形に縮小し、ステップ2から繰り返します。

この方法では、画面が2048pxより広くないことを考慮して、これらの手順を最大11回繰り返す必要があります。

したがって、最大11 x 4 = 44 <a>要素を生成します。

マウスの位置をピクセル単位で正確に決定する必要はないが、10pxの精度で問題ない場合。手順を最大8回繰り返すため、最大8 x 4 = 32 <a>要素を描画する必要があります。

また<a>、DOMは一般的に遅いため、要素を生成して破棄することはできません。代わりに、あなただけの最初の4つの再利用できる<a>要素を、ちょうど彼らの調整topleftwidthおよびheight手順をあなたのようにループを。

さて、4を作成<a>するのもやりすぎです。代わりに、各長方形で<a>テストするときに、同じ1つの要素を再利用できgetComputedStyle()ます。したがって、検索領域を2 x 2の<a>要素に分割する代わりに<a>topleftスタイルのプロパティを移動して、単一の要素を再利用します。

したがって、必要なのは、単一の<a>要素の最大値widthheight最大値を11回変更しtopleft最大値と最大値を44回変更するだけです。これにより、正確なマウスの位置がわかります。


3

最もシンプルなソリューションですが、100%正確ではありません

$(':hover').last().offset()

結果:{top: 148, left: 62.5}
結果は最も近い要素のサイズに依存し、undefinedユーザーがタブを切り替えたときに返されます


私にとって、それはundefined関係なく戻ります。これの使い方について詳しく教えていただけますか?
tresf 2018年

undefinedカーソルが要素の上に置かれていないとき(またはブラウザーがフォーカスを失ったとき)に戻ります。あなたのコンソールからしているテスト..場合は、時間間隔を設定する必要があるかもしれません
StefansArya

ありがとう。 setTimeout働いた。私はjsfiddleを使用していましたが、そうです。再生をクリックするたびにDOMを再描画するため、ホバーイベントにヒットすることはありません。他の人にこのヒントを追加することをお勧めします。
tresf 2018年

マウスの正確な位置は必要ありませんが、イベントオブジェクトなしでマウスが右または左に機能していることを知りたいので、ソリューションは私の場合に機能します。ありがとう
Swap-IOS-Android

2

タイマー付きの親ページがあり、一定時間またはタスクが完了した後、ユーザーを新しいページに転送するとします。ここで、カーソルの位置が必要になります。これらは待機しているため、必ずしもマウスに触れているわけではありません。したがって、標準イベントを使用して親ページでマウスを追跡し、最後の値をgetまたはpost変数で新しいページに渡します。

親ページでJHardingのコードを使用して、最新の位置が常にグローバル変数で利用できるようにすることができます。

var cursorX;
var cursorY;
document.onmousemove = function(e){
    cursorX = e.pageX;
    cursorY = e.pageY;
}

これは、親ページ以外の方法でこのページに移動するユーザーには役立ちません。


1

上記のTim Downのアイデアのように、水平/垂直検索を実装しました(最初にdivを水平に配置された垂直線リンクでいっぱいにし、次にdivを垂直に配置された水平線リンクでいっぱいにし、ホバー状態になっているものを確認します)。それはかなり速く動作します。残念ながら、KDE上のChrome 32では機能しません。

jsfiddle.net/5XzeE/4/


ユーザーによる明示的なマウスの移動がない限り、これらのトリックはもはや機能しません。:(
trusktr

1

カーソルの位置を取得するためにマウスを動かす必要はありません。場所は、mousemove以外のイベントでも報告されます。ここですクリックイベントの例としては:

document.body.addEventListener('click',function(e)
{
    console.log("cursor-location: " + e.clientX + ',' + e.clientY);
});

1

@SuperNova の答えをリフィングしthisて、コールバックでコンテキストを正しく保持するES6クラスを使用するアプローチを次に示します。

class Mouse {
  constructor() {
    this.x = 0;
    this.y = 0;
    this.callbacks = {
      mouseenter: [],
      mousemove: [],
    };
  }

  get xPos() {
    return this.x;
  }

  get yPos() {
    return this.y;
  }

  get position() {
    return `${this.x},${this.y}`;
  }

  addListener(type, callback) {
    document.addEventListener(type, this); // Pass `this` as the second arg to keep the context correct
    this.callbacks[type].push(callback);
  }

  // `handleEvent` is part of the browser's `EventListener` API.
  // https://developer.mozilla.org/en-US/docs/Web/API/EventListener/handleEvent
  handleEvent(event) {
    const isMousemove = event.type === 'mousemove';
    const isMouseenter = event.type === 'mouseenter';

    if (isMousemove || isMouseenter) {
      this.x = event.pageX;
      this.y = event.pageY;
    }

    this.callbacks[event.type].forEach((callback) => {
      callback();
    });
  }
}

const mouse = new Mouse();

mouse.addListener('mouseenter', () => console.log('mouseenter', mouse.position));
mouse.addListener('mousemove', () => console.log('mousemove A', mouse.position));
mouse.addListener('mousemove', () => console.log('mousemove B', mouse.position));


1

これが私の解決策です。これは、エクスポートwindow.currentMouseXwindow.currentMouseYあなたはどこでも使用できるプロパティを。最初にホバーされた要素(存在する場合)の位置を使用し、その後マウスの動きをリッスンして正しい値を設定します。

(function () {
    window.currentMouseX = 0;
    window.currentMouseY = 0;

    // Guess the initial mouse position approximately if possible:
    var hoveredElement = document.querySelectorAll(':hover');
    hoveredElement = hoveredElement[hoveredElement.length - 1]; // Get the most specific hovered element

    if (hoveredElement != null) {
        var rect = hoveredElement.getBoundingClientRect();
        // Set the values from hovered element's position
        window.currentMouseX = window.scrollX + rect.x;
        window.currentMouseY = window.scrollY + rect.y;
    }

    // Listen for mouse movements to set the correct values
    document.addEventListener('mousemove', function (e) {
        window.currentMouseX = e.pageX;
        window.currentMouseY = e.pageY;
    });
}())

Composr CMSソース: https : //github.com/ocproducts/composr/commit/a851c19f925be20bc16bfe016be42924989f262e#diff-b162dc9c35a97618a96748639ff41251R1202


0
var x = 0;
var y = 0;

document.addEventListener('mousemove', onMouseMove, false)

function onMouseMove(e){
    x = e.clientX;
    y = e.clientY;
}

function getMouseX() {
    return x;
}

function getMouseY() {
    return y;
}

14
これでもユーザーがマウスを動かす必要はありませんか?
Paul Hiemstra

0

私はdivとピクセルを数えることなく合理的な解決策があるかもしれないと思います。

単にアニメーションフレームまたは関数の時間間隔を使用します。開始するだけの場合でも、マウスイベントは1回必要ですが、技術的には、好きな場所に配置できます。

基本的に、マウスを動かさずに常にダミーdivを追跡しています。

// create a div(#mydiv) 1px by 1px set opacity to 0 & position:absolute;

以下はロジックです。

var x,y;


$('body').mousemove(function( e ) {

    var x = e.clientX - (window.innerWidth / 2);
    var y = e.clientY - (window.innerHeight / 2);
 }


function looping (){

   /* track my div position 60 x 60 seconds!
      with out the mouse after initiation you can still track the dummy div.x & y
      mouse doesn't need to move.*/

   $('#mydiv').x = x;    // css transform x and y to follow 
   $('#mydiv)'.y = y;

   console.log(#mydiv.x etc)

   requestAnimationFrame( looping , frame speed here);
}  
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.