Como obter a posição do mouse sem eventos (sem mover o mouse)?

286

É possível obter a posição do mouse com JavaScript após o carregamento da página sem nenhum evento de movimento do mouse (sem mover o mouse)?

Norbert Tamas
fonte
61
Nada de errado com o evento mousemove. Apenas em alguns casos, os usuários não movem o mouse. Obrigado pela sua resposta.
Norbert Tamas
2
Norbert Tamas, a resposta da @ SuperNova (que não foi adicionada até este ano) mostra que o mouseenter funciona bem para isso porque é acionado no carregamento da página (se o mouse estiver na janela de exibição). Não funcionou dessa maneira em 2010, ou é que ninguém pensou em tentar?
31514 Peter
@CrescentFresh Em alguns casos (como scripts de usuário), você não deseja desacelerar o navegador adicionando muitos mousemoveeventos.
Tomáš Zato - Restabelece Monica
Possível no FF com o mouseover, mas não no IE e no Chrome.
Elad
Ou, em um jogo, sua câmera se move pelo mundo do jogo e o personagem está olhando para o mouse (estilo típico de atirador de cima para baixo), mas se o usuário não move um mouse, ele se centra no ponto errado à medida que você se move. você confia apenas no mouse. No entanto, não é grande coisa, apenas armazenamos as cordas "mundiais" do ponteiro e deixamos que as pessoas consultem isso.
Kamranicus

Respostas:

336

Resposta real: Não, não é possível.

OK, eu apenas pensei em uma maneira. Sobreponha sua página com uma div que cubra todo o documento. Dentro disso, crie (digamos) 2.000 x 2.000 <a>elementos (para que a :hoverpseudo-classe funcione no IE 6, veja), cada tamanho de 1 pixel. Crie uma :hoverregra CSS para os <a>elementos que alteram uma propriedade (digamos font-family). No seu manipulador de carga, percorra cada um dos 4 milhões de <a>elementos, verificando currentStyle/ getComputedStyle()até encontrar aquele com a fonte de foco. Faça uma extrapolação desse elemento para obter as coordenadas dentro do documento.

NB NÃO FAZER ISSO .

Tim Down
fonte
92
ha ha - em algum momento você deve google ao redor e veja se você pode descobrir quantas pessoas têm realmente implementado este
Pointy
6
Na verdade, é implementável sem ter que carregar muita CPU (eu acho. Não testei). No dom ready, construa os elementos <a> com javascript, pegue a posição do mouse e remova todos os elementos <a>. No mouse, você deve ter outra função para posicionar o mouse. Enfim, isso foi hilário.
precisa saber é o seguinte
21
Talvez isso possa ser tornado prático com a pesquisa binária? Loop fazendo um par de <a>elementos cobrindo determinados retângulos (usando posicionamento absoluto de <img>elementos dimensionados , suponho), encolhendo os retângulos a cada vez. Sim, é ridículo, mas não é possível obter essas informações antes da primeira troca de mouse.
Darius Bacon
29
stackoverflow.com/a/8543879/27024 diz que o foco não é acionado até o mouse se mover pela primeira vez. Isso frustra esse esquema.
Darius Bacon
4
@ DariusBacon: Essa resposta vinculada não parece estar correta: jsbin.com/utocax/3 . Então, sim, essa abordagem pode ser prática para algumas situações.
Tim Down
121

Edit 2020: Isso não funciona mais. Parece que os fornecedores de navegadores corrigiram isso. Como a maioria dos navegadores depende do cromo, ele pode estar em seu núcleo.

Resposta antiga: Você também pode conectar o mouse (esse evento é acionado após a recarga da página, quando o mouse está dentro da página). Estender o código de Corrupted deve fazer o truque:

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

Você também pode definir x e y como nulos no evento mouseleave-event. Assim, você pode verificar se o usuário está na sua página com o cursor.

Super Nova
fonte
11
Essa parece ser a única resposta realmente útil aqui, o que parece estranho. De fato (no Firefox, Chrome e IE11 mais recentes), o mouseenter é acionado no carregamento da página e fornece as coordenadas corretas. O comportamento do navegador nessa área simplesmente mudou nos últimos anos?
Peter Hansen
3
De fato, "mouseenter" não parece agregar nenhum valor. Eu testei com o seguinte jsFiddle no Chrome e IE, e eles não mostram os cordinates até colocar o mouse sobre o documento interno (painel de resultado): jsfiddle.net/xkpd784o/1
Mariano Desanze
1
@Proton: Mova o mouse para o painel de resultados e a área do painel de resultados ANTES da página estar totalmente carregada e não se mova. Após o carregamento, a página conhece imediatamente a posição do mouse. Nenhum movimento do mouse é necessário. Portanto, o mouseenter também é acionado quando a página é carregada e o mouse está dentro da área do documento. Ou seja, o que o OP originalmente queria. Ninguém mais fornece essa resposta.
SuperNova
1
Uma adição potencialmente útil é adicionar uma função para o mouseleaveevento que conjuntos xe yde volta para nullou'undefined'
rtpax
2
O chrome 68, usando o jsfiddel acima, alerta ocorre na primeira movimentação do mouse e não no carregamento, mesmo se o mouse for movido para a região renderizada antes que a página termine de carregar.
Junvar '04
84

O que você pode fazer é criar variáveis ​​para as coordenadas xe ydo seu cursor, atualizá-las sempre que o mouse se mover e chamar uma função em um intervalo para fazer o que você precisa com a posição armazenada.

A desvantagem disso é que, pelo menos, um movimento inicial do mouse é necessário para que ele funcione. Desde que o cursor atualize sua posição pelo menos uma vez, podemos encontrar sua posição, independentemente de ele se mover novamente.

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

O código anterior é atualizado uma vez por segundo com uma mensagem de onde está o cursor. Eu espero que isso ajude.

JHarding
fonte
18
Você leu o assunto deste post? O OP pergunta como obter as coordenadas do mouse sem usar um evento. No entanto, sua postagem sugere o uso do evento onmousemove.
Jake
53
@jake Embora o OP tenha solicitado especificamente um método que não seja de evento, esta resposta beneficia outras pessoas que vieram aqui procurando uma resposta e possivelmente uma solução alternativa. Além disso, eu consideraria essa resposta parcialmente dentro do tópico, pois, até onde eu sei, esse é o melhor método para obter a posição do cursor a qualquer momento, sem precisar usar eventos diretamente. Dito isto, a resposta poderia ter sido formulada mais ao longo das linhas de afirmação do fato e oferecendo uma maneira de evitar os comentários nos comentários.
Jspeltoniemi
2
@ Pichan Não me beneficiou, porque eu estava procurando uma maneira de preencher essas cursorX/Yvariáveis ​​antes que qualquer evento acontecesse.
913616165_04_03_03_03-
muito poucos usuários não
acionam
1
Cuidado, pode ser dispendioso manter um ouvinte em movimento. Eu sugeriria recriar o ouvinte no intervalo e destruir o ouvinte depois de obter as coordenadas.
KRB
10

Você pode tentar algo semelhante ao que Tim Down sugeriu - mas em vez de ter elementos para cada pixel na tela, crie apenas 2 a 4 elementos (caixas) e altere sua localização, largura e altura dinamicamente para dividir os locais ainda possíveis na tela por 2-4 recursivamente, encontrando assim a localização real do mouse rapidamente.

Por exemplo - os primeiros elementos ficam com a metade direita e esquerda da tela, depois a metade superior e inferior. Até agora já sabemos em que quarto da tela o mouse está localizado, somos capazes de repetir - descubra qual quarto desse espaço ...

AlexTR
fonte
9

A resposta de @Tim Down não tem desempenho se você renderizar 2.000 x 2.000 <a>elementos:

OK, acabei de pensar em uma maneira. Sobreponha sua página com uma div que cubra todo o documento. Dentro disso, crie (digamos) 2.000 x 2.000 elementos (para que a pseudo classe: hover funcione no IE 6, veja), cada tamanho de 1 pixel. Crie uma regra CSS: hover para os elementos que alteram uma propriedade (digamos família de fontes). No seu manipulador de carga, percorra cada um dos 4 milhões de elementos, verificando currentStyle / getComputedStyle () até encontrar aquele com a fonte hover. Faça uma extrapolação desse elemento para obter as coordenadas dentro do documento.

NB NÃO FAZER ISSO.

Mas você não precisa renderizar 4 milhões de elementos de uma só vez; em vez disso, use a pesquisa binária. Basta usar 4 <a>elementos:

  • Etapa 1: considere a tela inteira como a área de pesquisa inicial
  • Etapa 2: divida a área de pesquisa em 2 x 2 = 4 <a>elementos retangulares
  • Etapa 3: Usando a getComputedStyle()função, determine em qual mouse retângulo passa o mouse
  • Etapa 4: reduza a área de pesquisa para esse retângulo e repita a partir da etapa 2.

Dessa forma, você precisará repetir essas etapas no máximo 11 vezes, considerando que sua tela não excede 2048px.

Então você irá gerar no máximo 11 x 4 = 44 <a>elementos.

Se você não precisar determinar a posição do mouse exatamente em um pixel, mas diga que a precisão de 10px está correta. Você repetiria as etapas no máximo 8 vezes, portanto, seria necessário desenhar no máximo 8 x 4 = 32 <a>elementos.

Também gerar e destruir os <a>elementos não é performatizado, pois o DOM geralmente é lento. Em vez disso, você pode simplesmente reutilizar os 4 primeiros <a>elementos e apenas ajustar o seu top, left, widthe heightcomo você percorrer as etapas.

Agora, criar 4 também <a>é um exagero. Em vez disso, você pode reutilizar o mesmo <a>elemento para testar getComputedStyle()em cada retângulo. Portanto, em vez de dividir a área de pesquisa em <a>elementos 2 x 2 , apenas reutilize um único <a>elemento movendo-o com as propriedades tope leftstyle.

Portanto, tudo o que você precisa é de um único <a>elemento, altere seu widthe heightmáximo 11 vezes, e altere seu tope leftmáximo 44 vezes, e você terá a posição exata do mouse.

Alex Peterson
fonte
3

A solução mais simples, mas não 100% precisa

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

Resultado: {top: 148, left: 62.5}
o resultado depende do tamanho do elemento mais próximo e retorna undefinedquando o usuário alterna a guia

StefansArya
fonte
Para mim, ele retorna undefinedindependentemente. Você pode elaborar como usar isso?
tresf
Ele retornaria undefinedquando o cursor não estivesse pairando nenhum elemento (ou quando o navegador perdesse o foco). Pode ser necessário definir um intervalo de tempo, se você está testando a partir do console ..
StefansArya
Obrigado. setTimeouttrabalhou. Eu estava usando jsfiddle e você está certo, ele nunca atinge um evento de foco, porque redesenha o DOM toda vez que você clica em reproduzir. Eu recomendaria adicionar essa dica para outras pessoas.
tresf
Eu não quero a posição exata do mouse, mas eu só quero saber que o mouse é extremo direito ou extremo esquerdo em função sem objeto de evento para que sua solução funcione no meu caso .. obrigado
Swap-IOS-Android
2

Eu imagino que talvez você tenha uma página pai com um cronômetro e, após um certo período de tempo ou uma tarefa ser concluída, encaminhe o usuário para uma nova página. Agora você quer a posição do cursor e, como eles estão esperando, não estão necessariamente tocando o mouse. Portanto, acompanhe o mouse na página pai usando eventos padrão e passe o último valor para a nova página em uma variável get ou post.

Você pode usar o código do JHarding na página pai para que a posição mais recente esteja sempre disponível em uma variável global:

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

Isso não ajudará os usuários que navegam para esta página por outros meios que não a sua página pai.


fonte
1

Eu implementei uma pesquisa horizontal / vertical (primeiro faça uma div cheia de links de linhas verticais organizados horizontalmente, depois faça uma div cheia de links de linhas horizontais organizadas verticalmente e simplesmente veja qual deles tem o estado de foco), como a idéia de Tim Down acima, e funciona muito rápido. Infelizmente, não funciona no Chrome 32 no KDE.

jsfiddle.net/5XzeE/4/

user2958613
fonte
aparentemente esses truques não funcionam mais, a menos que haja um movimento explícito do mouse pelo usuário. :(
trusktr
1

Você não precisa mover o mouse para obter a localização do cursor. O local também é relatado em outros eventos que não o mouse remoto . Aqui está um evento de clique como exemplo:

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

Examinando a resposta da @ SuperNova , aqui está uma abordagem usando as classes ES6 que mantém o contexto thiscorreto no retorno de chamada:

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

Aqui está a minha solução. Ela exporta window.currentMouseX e window.currentMouseY propriedades que você pode usar em qualquer lugar. Ele usa a posição de um elemento pairado (se houver) inicialmente e depois escuta os movimentos do mouse para definir os valores corretos.

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

Fonte do CMS do Composr : https://github.com/ocproducts/composr/commit/a851c19f925be20bc16bfe016be42924989f262e#diff-b162dc9c35a97618a96748639ff41251R1202

Salman von Abbas
fonte
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;
}
Corrompido
fonte
14
Isso ainda não exige que o usuário mova o mouse?
Paul Hiemstra
0

Acho que posso ter uma solução razoável sem contar divs e pixels .. lol

Basta usar o quadro de animação ou um intervalo de tempo de uma função. você ainda precisará de um evento de mouse uma vez, apenas para iniciar, mas tecnicamente você o posiciona onde quiser.

Essencialmente, estamos rastreando uma div falsa o tempo todo, sem o movimento do mouse.

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

Abaixo está a 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
fonte