¿Cómo obtener la posición del mouse sin eventos (sin mover el mouse)?

286

¿Es posible obtener la posición del mouse con JavaScript después de cargar la página sin ningún evento de movimiento del mouse (sin mover el mouse)?

Norbert Tamas
fuente
61
No hay nada malo con el evento mousemove. Solo en algunos casos los usuarios no mueven el mouse. Gracias por tu respuesta.
Norbert Tamas
2
Norbert Tamas, la respuesta de @ SuperNova (que no se agregó hasta este año) muestra que mouseenter funciona bien para esto porque se dispara en la carga de la página (si el mouse está en la ventana gráfica). ¿No funcionó así en 2010, o es que nadie pensó en probarlo?
Peter Hansen el
@CrescentFresh En algunos casos (como las secuencias de comandos de usuario) no desea ralentizar el navegador agregando muchos mousemoveeventos.
Tomáš Zato - Restablece a Mónica el
Posible en FF con mouseover, pero no en IE y Chrome.
Elad
O, en un juego, su cámara se mueve por el mundo del juego y el personaje está mirando el mouse (estilo típico de disparador de arriba hacia abajo) pero si el usuario no mueve un mouse, se centra en el punto incorrecto a medida que se mueve si solo confías en mousemove. Sin embargo, no es gran cosa, solo almacenamos las coordenadas "mundiales" del puntero y dejamos que las personas lo consulten.
kamranicus

Respuestas:

336

Respuesta real: No, no es posible.

OK, acabo de pensar en una manera. Superponga su página con un div que cubra todo el documento. Dentro de eso, cree (digamos) 2.000 x 2.000 <a>elementos (para que la :hoverpseudo-clase funcione en IE 6, vea), cada uno de 1 píxel de tamaño. Cree una :hoverregla CSS para aquellos <a>elementos que cambian una propiedad (digamos font-family). En su controlador de carga, recorra cada uno de los 4 millones de <a>elementos, verificando currentStyle/ getComputedStyle()hasta encontrar el que tiene la fuente de desplazamiento. Extrapolar hacia atrás desde este elemento para obtener las coordenadas dentro del documento.

NB NO HAGAS ESTO .

Tim Down
fuente
92
ja ja - en algún momento deberías buscar en Google y ver si puedes descubrir cuántas personas realmente han implementado esto
Pointy
66
En realidad, es implementable sin tener que cargar mucha CPU (creo. No lo he estado probando). En dom ready construya los elementos <a> con javascript, tome la posición del mouse y luego elimine todos los elementos <a>. En mousemouse debe tener otra función para tomar la posición del mouse. De todos modos, esto fue muy gracioso.
machineaddict
21
¿Quizás esto podría hacerse práctico con la búsqueda binaria? Bucle haciendo un par de <a>elementos que cubren los rectángulos dados ( <img>supongo que usando la posición absoluta de los elementos de tamaño ), reduciendo los rectángulos cada vez. Sí, es ridículo, pero no es posible obtener esta información antes del primer movimiento del mouse.
Darius Bacon
29
stackoverflow.com/a/8543879/27024 dice que el vuelo estacionario tampoco se dispara hasta que el mouse se mueve por primera vez. Esto frustra este esquema.
Darius Bacon
44
@DariusBacon: Esa respuesta vinculada no parece ser correcta: jsbin.com/utocax/3 . Entonces sí, este enfoque puede ser práctico para algunas situaciones.
Tim Down
121

Editar 2020: esto ya no funciona. Parece que los proveedores de navegadores lo resolvieron. Debido a que la mayoría de los navegadores dependen del cromo, podría estar en su núcleo.

Respuesta anterior: también puede conectar mouseenter (este evento se activa después de volver a cargar la página, cuando el mousecursor está dentro de la página). Extender el código de Corrupted debería hacer el truco:

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

También puede establecer x e y como nulo en mouseleave-event. Para que pueda verificar si el usuario está en su página con su cursor.

SuperNova
fuente
11
Esta parece ser la única respuesta realmente útil aquí, lo que parece extraño. De hecho (en los últimos Firefox, Chrome e IE11) el mouseenter se dispara al cargar la página y proporciona las coordenadas correctas. ¿Ha cambiado el comportamiento del navegador en esta área en los últimos años?
Peter Hansen el
3
De hecho, "mouseenter" no parece agregar ningún valor. Probé con el siguiente jsfiddle en Chrome e IE, y no muestran las cordinadas hasta que colocas
Mariano Desanze
1
@Proton: mueva el mouse al panel de resultados al área del panel de resultados ANTES de que la página se haya cargado completamente y no se mueva. Después de la carga, la página conoce inmediatamente la posición del mouse. No se necesita movimiento del mouse. Entonces mouseenter también se dispara cuando la página se ha cargado y el mouse está dentro del área del documento. Es decir, lo que originalmente quería el OP. Nadie más proporciona esta respuesta.
SuperNova
1
Una adición potencialmente útil es agregar una función para el mouseleaveevento que establece xy yvuelve a nullo'undefined'
rtpax
2
Chrome 68, utilizando el jsfiddel anterior, la alerta se produce en el primer movimiento del mouse y no en la carga, incluso si el mouse se mueve a la región renderizada antes de que la página termine de cargarse.
junvar
84

Lo que puede hacer es crear variables para las coordenadas xy yde su cursor, actualizarlas cada vez que se mueve el mouse y llamar a una función en un intervalo para hacer lo que necesita con la posición almacenada.

La desventaja de esto, por supuesto, es que se requiere al menos un movimiento inicial del mouse para que funcione. Mientras el cursor actualice su posición al menos una vez, podremos encontrar su posición independientemente de si se mueve de nuevo.

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

El código anterior se actualiza una vez por segundo con un mensaje de dónde está el cursor. Espero que esto ayude.

JHarding
fuente
18
¿Leíste el tema de esta publicación? El OP pregunta cómo obtener las coordenadas del mouse sin usar un evento. Sin embargo, su publicación sugiere usar el evento onmousemove.
Jake
53
@jake Aunque el OP solicitó específicamente un método sin eventos, esta respuesta beneficia a otros que vinieron aquí buscando una respuesta y posiblemente una solución alternativa. Además, consideraría esta respuesta parcialmente dentro del tema, ya que hasta donde sé, este es el mejor método para obtener la posición del cursor en un momento dado sin tener que usar eventos directamente. Dicho esto, la respuesta podría haberse redactado más en la línea de afirmar el hecho y ofrecer una forma de evitar las dudas en los comentarios.
jpeltoniemi 01 de
2
@ Pichan No me benefició, porque he estado buscando una manera de llenar esas cursorX/Yvariables antes de que ocurra cualquier evento.
polkovnikov.ph
muy pocos usuarios Wont eventos de ratón fuego
SuperUberDuper
1
Cuidado, puede ser costoso mantener un oyente moviendo el mouse. Sugeriría recrear al oyente en el intervalo y destruir al oyente después de obtener las coordenadas.
KRB
10

Podría intentar algo similar a lo que sugirió Tim Down, pero en lugar de tener elementos para cada píxel en la pantalla, cree solo 2-4 elementos (cuadros) y cambie su ubicación, ancho y altura dinámicamente para dividir las ubicaciones posibles en la pantalla por 2-4 recursivamente, encontrando así la ubicación real del mouse rápidamente.

Por ejemplo, los primeros elementos toman la mitad derecha e izquierda de la pantalla, luego la mitad superior e inferior. Por ahora ya sabemos en qué cuarto de la pantalla se encuentra el mouse, podemos repetir: descubra qué cuarto de este espacio ...

AlexTR
fuente
9

La respuesta de @Tim Down no es eficaz si representa 2.000 x 2.000 <a>elementos:

OK, acabo de pensar en una manera. Superponga su página con un div que cubra todo el documento. Dentro de eso, cree (digamos) 2.000 x 2.000 elementos (para que la pseudoclase: hover funcione en IE 6, vea), cada uno de 1 píxel de tamaño. Cree un CSS: regla de desplazamiento para aquellos elementos que cambian una propiedad (digamos font-family). En su controlador de carga, recorra cada uno de los 4 millones de elementos, verifique currentStyle / getComputedStyle () hasta que encuentre el que tiene la fuente de desplazamiento. Extrapolar hacia atrás desde este elemento para obtener las coordenadas dentro del documento.

NB NO HAGAS ESTO.

Pero no tiene que representar 4 millones de elementos a la vez, en su lugar use la búsqueda binaria. Solo use 4 <a>elementos en su lugar:

  • Paso 1: considere la pantalla completa como el área de búsqueda inicial
  • Paso 2: divide el área de búsqueda en 2 x 2 = 4 <a>elementos rectangulares
  • Paso 3: utilizando la getComputedStyle()función, determine en qué rectángulo se desplaza el mouse
  • Paso 4: reduzca el área de búsqueda a ese rectángulo y repita desde el paso 2.

De esta manera, deberá repetir estos pasos un máximo de 11 veces, teniendo en cuenta que su pantalla no es más ancha que 2048px.

Entonces generarás un máximo de 11 x 4 = 44 <a>elementos.

Si no necesita determinar la posición del mouse exactamente en un píxel, pero digamos que la precisión de 10px está bien. Debería repetir los pasos como máximo 8 veces, por lo que necesitaría dibujar un máximo de 8 x 4 = 32 <a>elementos.

Tampoco se genera y luego se destruyen los <a>elementos, ya que DOM es generalmente lento. En su lugar, sólo puede volver a utilizar los 4 primeros <a>elementos y simplemente ajustar su top, left, widthy heightcomo se bucle a través de los pasos.

Ahora, crear 4 también <a>es una exageración. En cambio, puede reutilizar el mismo <a>elemento para cuando realice la prueba getComputedStyle()en cada rectángulo. Así, en lugar de dividir el área de búsqueda en 2 x 2 <a>elementos que acabamos de volver a utilizar un solo <a>elemento moviéndolo con topy leftpropiedades de estilo.

Por lo tanto, todo lo que necesita es que un solo <a>elemento cambie su widthy heightmáximo 11 veces, y cambie su topy leftmáximo 44 veces y tendrá la posición exacta del mouse.

Alex Peterson
fuente
3

La solución más simple pero no 100% precisa

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

Resultado: {top: 148, left: 62.5}
el resultado depende del tamaño del elemento más cercano y se devuelve undefinedcuando el usuario cambia la pestaña

StefansArya
fuente
Para mí, vuelve undefinedindependientemente. ¿Puedes explicar cómo usar esto?
Tresf
Volvería undefinedcuando el cursor no estuviera flotando sobre ningún elemento (o cuando el navegador perdiera el foco). Puede que necesite establecer un intervalo de tiempo si está probando desde la consola ..
StefansArya
Gracias. setTimeouttrabajó. Estaba usando jsfiddle y tienes razón, nunca llegó a un evento flotante porque redibuja el DOM cada vez que haces clic en reproducir. Recomendaría agregar esta pista para otros.
Tresf
No quiero una posición precisa del mouse, pero solo quiero saber que el mouse está en el extremo derecho o extremo izquierdo en funcionamiento sin objeto de evento, por lo que su solución funciona en mi caso ... gracias
Swap-IOS-Android
2

Imagino que tal vez tenga una página principal con un temporizador y después de un cierto tiempo o una tarea completada, reenvíe al usuario a una nueva página. Ahora desea la posición del cursor y, como están esperando, no necesariamente tocan el mouse. Por lo tanto, siga el mouse en la página principal utilizando eventos estándar y pase el último valor a la nueva página en una variable get o post.

Puede usar el código de JHarding en su página principal para que la última posición siempre esté disponible en una variable global:

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

Esto no ayudará a los usuarios que naveguen a esta página por otros medios que no sean su página principal.


fuente
1

Implementé una búsqueda horizontal / vertical (primero haga un div lleno de enlaces de línea vertical dispuestos horizontalmente, luego haga un div lleno de enlaces de línea horizontal dispuestos verticalmente, y simplemente vea cuál tiene el estado de desplazamiento) como la idea de Tim Down anterior, y Funciona bastante rápido. Lamentablemente, no funciona en Chrome 32 en KDE.

jsfiddle.net/5XzeE/4/

usuario2958613
fuente
aparentemente estos trucos ya no funcionan a menos que el usuario mueva explícitamente el mouse. :(
trusktr
1

No tiene que mover el mouse para obtener la ubicación del cursor. La ubicación también se informa en eventos que no sean mousemove . Aquí hay un evento de clic como ejemplo:

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

Refiriéndose a la respuesta de @ SuperNova , aquí hay un enfoque que usa clases ES6 que mantiene el contexto thiscorrecto en su devolución de llamada:

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
fuente
1

Aquí está mi solución. Exporta window.currentMouseX y window.currentMouseY propiedades que puede utilizar en cualquier lugar. Utiliza la posición de un elemento suspendido (si lo hay) inicialmente y luego escucha los movimientos del mouse para establecer los valores correctos.

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

Compositor CMS Fuente: https://github.com/ocproducts/composr/commit/a851c19f925be20bc16bfe016be42924989f262e#diff-b162dc9c35a97618a96748639ff41251R1202

Salman von Abbas
fuente
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;
}
Corrupto
fuente
14
¿Esto todavía no requiere que el usuario mueva el mouse?
Paul Hiemstra
0

Creo que puedo tener una solución razonable sin contar divs y píxeles ... jajaja

Simplemente use el marco de animación o el intervalo de tiempo de una función. aún necesitará un evento de mouse una vez, aunque solo sea para iniciar, pero técnicamente lo posiciona donde quiera.

Esencialmente, estamos rastreando un div dummy en todo momento sin movimiento del mouse.

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

Debajo está la lógica ...

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
fuente