web-dev-qa-db-ja.com

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

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

244
Norbert Tamas

本当の答え:いいえ、できません。

さて、私は方法を考えました。文書全体をカバーするdivでページを重ねます。その中に、(<a>擬似クラスがIE 6で動作するように、2、000 x 2,000の:hover要素を作成してください)。プロパティを変更するそれらの:hover要素に対してCSS <a>ルールを作成します(font-familyと言いましょう)。ロードハンドラで、ホバーフォントの要素が見つかるまでcurrentStyle/getComputedStyle()をチェックして、400万個の<a>要素のそれぞれを順に調べます。この要素から外挿して、文書内の座標を取得します。

N.B. しないでください

303
Tim Down

Mouseenterをフックすることもできます(このイベントは、マウスカーソルがページ内にあるときに、ページのリロード後に発生します)。 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に設定することもできます。それで、あなたはそれがカーソルであなたがあなたのページにいるかどうか確認することができます。

109
SuperNova

あなたができることはあなたのカーソルのxy座標のために変数を作成して、マウスが動くたびにそれらを更新して、あなたが保存された位置で必要なことをするためにある間隔で関数を呼ぶことです。

もちろん、これに対するマイナス面は、マウスを動かすには少なくとも1回の初期動作が必要なことです。カーソルが少なくとも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回更新され、カーソルの位置を示すメッセージが表示されます。これが役に立つことを願っています。

79
JHarding

Tim Downが提案したのと同じようなことを試すことができます - しかし、画面上の各ピクセルの要素を持つ代わりに、たった2〜4個の要素(ボックス)を作成してください。これにより、マウスの実際の位置を素早く見つけることができます。

たとえば、最初の要素は画面の左右半分、その後は上下半分になります。これまでに、マウスが画面のどの四分の一にあるかをすでに知っていて、繰り返すことができます - このスペースのどの四分の一を見つけることができます...

9
AlexTR

@Tim Downの答えは、2,000 x 2,000の<a>要素をレンダリングした場合はパフォーマンスが良くありません。

さて、私は方法を考えました。文書全体をカバーするdivでページをオーバーレイします。その中に、(1つにつき)2,000 x 2,000の要素を作成します(つまり、:hover擬似クラスがIE 6で動作するようにします)。サイズはそれぞれ1ピクセルです。プロパティを変更する要素に対してCSS:hoverルールを作成します(例えばfont-familyとしましょう)。ロードハンドラで、ホバーフォントの要素が見つかるまでcurrentStyle/getComputedStyle()をチェックして、400万個の各要素を順に調べます。この要素から外挿して、文書内の座標を取得します。

N.B.これをしないでください。

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

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

この方法では、画面の幅が2048ピクセル以下であることを考慮して、これらの手順を最大11回繰り返す必要があります。

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

あなたが正確に1ピクセルにマウス位置を決定する必要はないが、10px精度が良いと言うならば。あなたはせいぜい8回ステップを繰り返すでしょう、それであなたは最大8 x 4 = 32 <a>要素を描く必要があるでしょう。

DOMは一般に遅いので、<a>要素を生成してから破棄することもできません。代わりに、最初の4つの<a>エレメントを再利用して、ステップをループするときにそれらのtopleftwidth、およびheightを調整するだけで済みます。

さて、4 <a>を作成することはやり過ぎです。代わりに、それぞれの長方形でgetComputedStyle()をテストするときに同じ<a>要素を再利用できます。そのため、検索領域を2 x 2の<a>要素に分割する代わりに、topおよびleftスタイルのプロパティで移動して、単一の<a>要素を再利用するだけです。

したがって、必要なのは単一の<a>要素で、そのwidthheightの最大11回の変更、およびtopleftの最大44回の変更で、正確なマウス位置が得られます。

4
Alex Peterson

最も単純な解決策だが100%正確ではない

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

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

2
StefansArya

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

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

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

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

2
user2892032

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

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

上記のTim Downのアイデアのように、水平/垂直検索を実行しました(最初に水平に配置された垂直線リンクでdivを作成し、次に垂直に配置された水平線リンクでdivを作成します)。それはかなり速く動きます。残念ながら、KDE上のChrome 32では動作しません。

jsfiddle.net/5XzeE/4/

1
user2958613

これが私の解決策です。 window.currentMouseXおよびwindow.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-b162dc9c35a9144201ffffff

1
Salman Abbas

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

単にアニメーションフレームまたは関数の時間間隔を使用してください。あなたはまだ開始するためにマウスのイベントを一度だけ必要とするでしょう、しかし技術的にあなたはこれまでにあなたが好きなところにこれを位置づけます。

基本的に、マウスを動かさずに常にダミーの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);
}  
0
joshua

リフティング @ SuperNova's answer では、コールバックで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));
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;
}
0
Corrupted