web-dev-qa-db-fra.com

Comment obtenir la position de la souris sans événement (sans déplacer la souris)?

Est-il possible d'obtenir la position de la souris avec JavaScript après le chargement d'une page sans événement de déplacement de la souris (sans déplacer la souris)?

241
Norbert Tamas

Réponse réelle: non, ce n'est pas possible.

OK, je viens de penser à un moyen. Superposez votre page avec un div qui couvre tout le document. À l'intérieur de cela, créez (disons) 2 000 x 2 000 éléments <a> (de sorte que la pseudo-classe :hover fonctionne dans IE 6, voir), d'une taille d'un pixel chacun. Créez une règle CSS :hover pour les éléments <a> qui modifient une propriété (disons font-family). Dans votre gestionnaire de charge, parcourez chacun des 4 millions d'éléments <a> en cochant currentStyle/getComputedStyle() jusqu'à ce que vous trouviez celui avec la police de survol. Extrapoler à partir de cet élément pour obtenir les coordonnées dans le document.

N.B. NE FAITES PAS CELA .

298
Tim Down

Vous pouvez également relier mouseenter (cet événement est déclenché après le rechargement de la page, lorsque le curseur de la souris est dans la page). L'extension du code de Corrupted devrait faire l'affaire:

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

Vous pouvez également définir x et y sur null sur mouseleave-event. Donc, vous pouvez vérifier si l'utilisateur est sur votre page avec son curseur.

105
SuperNova

Ce que vous pouvez faire, c'est créer des variables pour les coordonnées x et y de votre curseur, les mettre à jour chaque fois que la souris se déplace et appeler une fonction sur un intervalle pour faire ce dont vous avez besoin avec la position enregistrée.

L’inconvénient de ceci est bien sûr qu’au moins un mouvement initial de la souris est nécessaire pour que cela fonctionne. Tant que le curseur met à jour sa position au moins une fois, nous sommes en mesure de trouver sa position, qu’il se déplace à nouveau ou non. 

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

Le code précédent est mis à jour une fois par seconde avec un message indiquant l'emplacement de votre curseur. J'espère que ça aide.

80
JHarding

Vous pouvez essayer quelque chose de similaire à ce que Tim Down a suggéré - mais au lieu d’avoir des éléments pour chaque pixel sur l’écran, créez seulement 2 à 4 éléments (cases) et modifiez leur emplacement, largeur et hauteur de manière dynamique pour diviser les emplacements encore possibles par 2-4 récursivement, trouvant ainsi rapidement l'emplacement réel de la souris.

Par exemple, les premiers éléments occupent les moitiés droite et gauche de l'écran, puis les moitiés supérieure et inférieure. A présent, nous savons déjà dans quel quart d’écran se trouve la souris, nous pouvons le répéter - découvrez quel quart de cet espace ...

9
AlexTR

La réponse de @Tim Down n'est pas performante si vous restituez 2 000 x 2 000 éléments <a>:

OK, je viens de penser à un moyen. Superposez votre page avec un div que couvre tout le document. À l'intérieur, créez (disons) 2 000 x 2 000 éléments (pour que la pseudo-classe: hover fonctionne dans IE 6, voir), chaque taille de 1 pixel. Créez une règle CSS: hover pour ces éléments cela change une propriété (disons font-famille). Dans votre gestionnaire de charge, Parcourez chacun des 4 millions d’éléments en vérifiant currentStyle/getComputedStyle () jusqu'à ce que vous trouviez celui avec le police de survol. Extrapoler en arrière de cet élément pour obtenir les coordonnées dans le document.

N.B. NE FAITES PAS CELA.

Mais vous ne devez pas générer 4 millions d'éléments à la fois, utilisez plutôt la recherche binaire. Utilisez simplement 4 éléments <a> à la place:

  • Étape 1: Considérez l’ensemble de l’écran comme zone de recherche initiale
  • Étape 2: divisez la zone de recherche en 2 x 2 = 4 éléments rectangulaires <a>
  • Étape 3: À l'aide de la fonction getComputedStyle(), déterminez dans quelle souris rectangulaire survole
  • Étape 4: réduisez la zone de recherche à ce rectangle et recommencez à partir de l'étape 2.

De cette façon, vous devrez répéter ces étapes au maximum 11 fois, sachant que votre écran n’est pas plus large que 2048px.

Ainsi, vous générerez un maximum de 11 x 4 = 44 <a> éléments.

Si vous n'avez pas besoin de déterminer exactement la position de la souris au pixel près, dites que la précision de 10px est correcte. Vous devez répéter les étapes au maximum 8 fois. Vous devez donc dessiner au maximum 8 x 4 = 32 <a> éléments.

La génération et la destruction des éléments <a> ne sont pas non plus exécutées, car DOM est généralement lent. Au lieu de cela, vous pouvez simplement réutiliser les 4 éléments <a> initiaux et simplement ajuster leurs top, left, width et height lorsque vous parcourez des étapes.

Maintenant, créer 4 <a> est également une overkill. Au lieu de cela, vous pouvez réutiliser le même élément <a> lors du test de getComputedStyle() dans chaque rectangle. Ainsi, au lieu de scinder la zone de recherche en 2 x 2 éléments <a>, réutilisez simplement un seul élément <a> en le déplaçant avec les propriétés de style top et left.

Donc, tout ce dont vous avez besoin est d’un seul élément <a>, changez sa width et height max 11 fois, et changez sa top et left max 44 fois et vous obtiendrez la position exacte de la souris.

4
Alex Peterson

J'imagine que vous avez peut-être une page parent avec un minuteur et qu'après un certain temps ou une tâche terminée, vous transférez l'utilisateur vers une nouvelle page. Maintenant, vous voulez la position du curseur, et comme ils attendent, ils ne touchent pas nécessairement la souris. Suivez donc la souris sur la page parente à l'aide d'événements standard et transmettez la dernière valeur à la nouvelle page dans une variable get ou post.

Vous pouvez utiliser le code de JHarding sur votre page parent afin que la dernière position soit toujours disponible dans une variable globale:

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

Cela n’aidera pas les utilisateurs qui accèdent à cette page par un moyen autre que votre page parent.

2
user2892032

La solution la plus simple mais pas précise à 100%

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

Résultat: {top: 148, left: 62.5}
Le résultat dépend de la taille de l'élément le plus proche et renvoie undefined lorsque l'utilisateur a basculé l'onglet

1
StefansArya

Vous n'avez pas besoin de déplacer la souris pour obtenir l'emplacement du curseur. L'emplacement est également signalé pour des événements autres que mousemove . Voici un click-event à titre d'exemple:

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

J'ai implémenté une recherche horizontale/verticale (créez d'abord une division complète avec des liens de lignes verticales disposés horizontalement, puis créez une division complète avec des liens de lignes horizontales disposés verticalement et voyez simplement lequel est en état de survol), comme dans Tim Tim ça marche assez vite. Malheureusement, cela ne fonctionne pas sur Chrome 32 sur KDE.

jsfiddle.net/5XzeE/4/

1
user2958613

Je pense que je peux avoir une solution raisonnable sans compter les divs et les pixels..lol 

Utilisez simplement une image d'animation ou un intervalle de temps d'une fonction. vous aurez toujours besoin d'un événement de souris une fois, mais juste pour l'initier, mais techniquement, vous le positionnez où vous voulez.

Essentiellement, nous suivons un div fictif à tout moment sans déplacer la souris.

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

Voici la logique ..

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

Riffing on @ SuperNova's answer , voici une approche utilisant les classes ES6 qui maintient le contexte de this correct dans votre rappel:

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
Patrick Berkeley
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