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

286

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

Norbert Tamas
la source
61
Rien de mal à l'événement mousemove. Dans certains cas, les utilisateurs ne bougent pas la souris. Merci pour votre réponse.
Norbert Tamas
2
Norbert Tamas, la réponse de @ SuperNova (qui n'a pas été ajoutée avant cette année) montre que mouseenter fonctionne très bien pour cela car il se déclenche au chargement de la page (si la souris est dans la fenêtre). Cela n'a-t-il pas fonctionné ainsi en 2010, ou est-ce juste que personne n'a pensé à l'essayer?
Peter Hansen
@CrescentFresh Dans certains cas (comme les scripts utilisateur), vous ne voulez pas ralentir le navigateur en ajoutant de nombreux mousemoveévénements.
Tomáš Zato - Rétablir Monica
Possible dans FF avec survol, mais pas dans IE et Chrome.
Elad
Ou, dans un jeu, votre caméra se déplace dans le monde du jeu et le personnage regarde la souris (style de tir typique de haut en bas), mais si l'utilisateur ne déplace pas une souris, il se concentre sur le mauvais point lorsque vous vous déplacez si vous ne comptez que sur mousemove. Cependant, ce n'est pas un gros problème, nous stockons simplement les coordonnées "mondiales" du pointeur et laissons les gens l'interroger.
kamranicus

Réponses:

336

Vraie réponse: 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, créez (disons) 2 000 x 2 000 <a>éléments (pour que la :hoverpseudo-classe fonctionne dans IE 6, voir), chaque taille de 1 pixel. Créez une :hoverrègle CSS pour les <a>éléments qui modifient une propriété (disons font-family). Dans votre gestionnaire de charge, parcourez chacun des 4 millions d' <a>éléments, en vérifiant 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.

NB NE FAITES PAS CELA .

Tim Down
la source
92
ha ha - à un moment donné, vous devriez chercher sur Google et voir si vous pouvez comprendre combien de personnes ont réellement mis en œuvre cela
Pointy
6
En fait, il est implémentable sans trop de charge CPU (je pense. Je ne l'ai pas testé). Sur dom ready, créez les éléments <a> avec javascript, prenez la position de la souris puis supprimez tous les éléments <a>. Sur la souris, vous devriez avoir une autre fonction pour prendre la position de la souris. Quoi qu'il en soit, c'était hilarant.
machineaddict
21
Peut-être que cela pourrait être rendu pratique avec la recherche binaire? Boucle faisant une paire d' <a>éléments couvrant des rectangles donnés (en utilisant le positionnement absolu d' <img>éléments de taille , je suppose), rétrécissant les rectangles à chaque fois. Oui, c'est ridicule, mais il n'est pas possible d'obtenir ces informations avant le premier déplacement de la souris.
Darius Bacon
29
stackoverflow.com/a/8543879/27024 indique que le survol ne se déclenche pas non plus jusqu'à ce que la souris se déplace pour la première fois. Cela déjoue ce schéma.
Darius Bacon
4
@DariusBacon: Cette réponse liée ne semble pas être correcte: jsbin.com/utocax/3 . Alors oui, cette approche peut être pratique dans certaines situations.
Tim Down
121

Modifier 2020: Cela ne ne fonctionne plus. Il semble que les éditeurs de navigateurs aient corrigé cela. Parce que la plupart des navigateurs dépendent du chrome, il pourrait être dans son cœur.

Ancienne réponse: vous pouvez également accrocher mouseenter (cet événement est déclenché après le rechargement de la page, lorsque le curseur de la souris est à l'intérieur de 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 à null sur mouseleave-event. Ainsi, vous pouvez vérifier si l'utilisateur est sur votre page avec son curseur.

SuperNova
la source
11
Cela semble être la seule réponse vraiment utile ici, ce qui semble étrange. En effet (dans les derniers Firefox, Chrome et IE11), le mouseenter se déclenche au chargement de la page et fournit les coordonnées correctes. Le comportement du navigateur dans ce domaine a-t-il simplement changé au cours des dernières années?
Peter Hansen
3
En fait, "mouseenter" ne semble pas ajouter de valeur. J'ai testé avec le jsfiddle suivant dans Chrome et IE, et ils ne montrent pas les coordonnées tant que vous n'avez pas mis la souris sur le document interne (le panneau de résultat): jsfiddle.net/xkpd784o/1
Mariano Desanze
1
@Proton: Déplacez votre souris vers le panneau de résultats dans la zone du panneau de résultats AVANT que la page ne soit entièrement chargée et ne bouge pas. Après le chargement, la page connaît immédiatement la position de la souris. Aucun mouvement de souris n'est nécessaire. Ainsi, mouseenter est également déclenché lorsque la page est chargée et que la souris se trouve dans la zone du document. C'est-à-dire ce que le PO voulait à l'origine. Personne d'autre ne fournit cette réponse.
SuperNova
1
Un ajout potentiellement utile consiste à ajouter une fonction pour l' mouseleaveévénement qui se déclenche xet yrevenir à nullou'undefined'
rtpax
2
chrome 68, en utilisant le jsfiddel ci-dessus, l'alerte se produit au premier déplacement de la souris et non au chargement, même si la souris est déplacée vers la région rendue avant le chargement de la page.
junvar
84

Ce que vous pouvez faire est de créer des variables pour les xet les ycoordonnées de votre curseur, les mettre à jour chaque fois que la souris se déplace et appeler une fonction sur un intervalle de faire ce que vous avez besoin avec la position mémorisée.

L'inconvénient de cela est bien sûr qu'au moins un mouvement initial de la souris est nécessaire pour le faire fonctionner. Tant que le curseur met à jour sa position au moins une fois, nous pouvons retrouver sa position, qu'il se déplace à nouveau.

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 où se trouve votre curseur. J'espère que ça aide.

JHarding
la source
18
Avez-vous lu le sujet de cet article? L'OP demande comment obtenir les coordonnées de la souris sans utiliser d'événement. Pourtant, votre message suggère d'utiliser l'événement onmousemove.
jake
53
@jake Bien que l'OP ait spécifiquement demandé une méthode sans événement, cette réponse profite à ceux qui sont venus ici à la recherche d'une réponse et éventuellement d'une solution de contournement. En outre, je considérerais cette réponse partiellement dans le sujet car, pour autant que je sache, c'est la meilleure méthode pour obtenir la position du curseur à un moment donné sans avoir à utiliser directement les événements. Cela dit, la réponse aurait pu être formulée davantage dans le sens d'énoncer le fait et d'offrir un moyen de contourner les commentaires.
jpeltoniemi
2
@Pichan Cela ne m'a pas profité, car je cherchais un moyen de remplir ces cursorX/Yvariables avant qu'un événement ne se produise.
polkovnikov.ph
très peu d'utilisateurs ne déclenchent pas d'événements de souris
SuperUberDuper
1
Attention, il peut être coûteux de garder un auditeur de déplacement de souris autour. Je suggère de recréer l'auditeur dans l'intervalle et de le détruire après avoir obtenu les coordonnées.
KRB
10

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 (boîtes) et modifiez leur emplacement, largeur, hauteur dynamiquement pour diviser les emplacements encore possibles à l'écran par 2-4 récursivement, trouvant ainsi la position réelle de la souris rapidement.

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

AlexTR
la source
9

La réponse de @Tim Down n'est pas efficace si vous effectuez un rendu de 2 000 x 2 000 <a>éléments:

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 (pour que la pseudo-classe: hover fonctionne dans IE 6, voir), chaque taille de 1 pixel. Créez une règle CSS: hover pour les éléments qui modifient une propriété (disons police-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 la police hover. Extrapoler à partir de cet élément pour obtenir les coordonnées dans le document.

NB NE FAITES PAS CELA.

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

  • Étape 1: Considérez l'ensemble de l'écran comme zone de recherche de départ
  • Étape 2: diviser la zone de recherche en 2 x 2 = 4 <a>éléments rectangulaires
  • Étape 3: à l'aide de la getComputedStyle()fonction, déterminez dans quel rectangle la souris survole
  • Étape 4: Réduisez la zone de recherche à ce rectangle et répétez à partir de l'étape 2.

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

Vous générerez donc au maximum 11 x 4 = 44 <a>éléments.

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

De plus, la génération puis la destruction des <a>éléments ne sont pas performantes car le DOM est généralement lent. , Vous pouvez simplement réutiliser au lieu les 4 premiers <a>éléments et d' ajuster leur juste top, left, widthet heightque vous en boucle à travers les étapes.

Maintenant, créer 4 <a>est également exagéré. Au lieu de cela, vous pouvez réutiliser le même <a>élément pour les tests getComputedStyle()dans chaque rectangle. Ainsi, au lieu de diviser la zone de recherche en 2 x 2 <a>éléments réutiliser un seul <a>élément en le déplaçant avec topet leftpropriétés de style.

Donc, tout ce dont vous avez besoin est un seul <a>élément changer son widthet heightmax 11 fois, et changer son topet leftmax 44 fois et vous aurez la position exacte de la souris.

Alex Peterson
la source
3

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

$(':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 revient undefinedlorsque l'utilisateur a changé l'onglet

StefansArya
la source
Pour moi, ça revient undefinedquand même. Pouvez-vous nous expliquer comment l'utiliser?
tresf
Il reviendrait undefinedlorsque le curseur ne survolait aucun élément (ou lorsque le navigateur perdait le focus). Vous devrez peut-être définir un intervalle de temps si vous testez à partir de la console ..
StefansArya
Merci. setTimeouttravaillé. J'utilisais jsfiddle et vous avez raison, il n'a jamais frappé un événement de survol car il redessine le DOM à chaque fois que vous cliquez sur jouer. Je recommanderais d'ajouter cette astuce pour les autres.
tresf
Je ne veux pas la position précise de la souris, mais je veux juste savoir que la souris fonctionne à l'extrême droite ou à l'extrême gauche sans objet événement, donc votre solution fonctionne dans mon cas ... merci
Swap-IOS-Android
2

J'imagine que vous avez peut-être une page parent avec un minuteur et 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 parce qu'ils attendent, ils ne touchent pas nécessairement la souris. Suivez donc la souris sur la page parent en utilisant des événements standard et passez 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 d'autres moyens que votre page parent.


la source
1

J'ai implémenté une recherche horizontale / verticale, (faites d'abord une division pleine de liens de ligne verticale disposés horizontalement, puis faites une division pleine de liens de ligne horizontale disposés verticalement, et voyez simplement lequel a l'état de survol) comme l'idée de Tim Down ci-dessus, et ça marche assez vite. Malheureusement, ne fonctionne pas sur Chrome 32 sur KDE.

jsfiddle.net/5XzeE/4/

user2958613
la source
apparemment, ces astuces ne fonctionnent plus sauf s'il y a un déplacement explicite de la souris par l'utilisateur. :(
trusktr
1

Vous n'avez pas à déplacer la souris pour obtenir l'emplacement du curseur. L'emplacement est également signalé lors d'événements autres que le déplacement de la souris . Voici un événement de clic comme exemple:

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

S'appuyant sur la réponse de @ SuperNova , voici une approche utilisant des classes ES6 qui garde le contexte thiscorrect 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));

Patrick Berkeley
la source
1

Voici ma solution. Il exporte les propriétés window.currentMouseX et window.currentMouseY que vous pouvez utiliser n'importe où. Il utilise la position d'un élément survolé (le cas échéant) initialement et écoute ensuite les mouvements de la souris pour définir les valeurs correctes.

(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 Source: https://github.com/ocproducts/composr/commit/a851c19f925be20bc16bfe016be42924989f262e#diff-b162dc9c35a97618a96748639ff41251R1202

Salman von Abbas
la source
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;
}
Corrompu
la source
14
Cela ne nécessite-t-il pas encore que l'utilisateur déplace la souris?
Paul Hiemstra
0

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

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

Essentiellement, nous suivons un div factice à tout moment sans mouvement de 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);
}  
joshua
la source