Jak uzyskać pozycję myszy bez zdarzeń (bez poruszania myszą)?

286

Czy możliwe jest uzyskanie pozycji myszy za pomocą JavaScript po wczytaniu strony bez żadnego zdarzenia ruchu myszy (bez poruszania myszą)?

Norbert Tamas
źródło
61
Nic złego ze zdarzeniem mousemove. W niektórych przypadkach użytkownicy nie poruszają myszą. Dziękuję za odpowiedź.
Norbert Tamas
2
Norbert Tamas, odpowiedź @ SuperNova (która nie została dodana do tego roku) pokazuje, że mouseenter działa dobrze, ponieważ uruchamia się przy ładowaniu strony (jeśli mysz znajduje się w oknie podglądu). Czy to nie zadziałało w 2010 roku, czy tylko nikt tego nie pomyślał?
Peter Hansen
@CrescentFresh W niektórych przypadkach (np. Skrypty użytkowników) nie chcesz spowalniać przeglądarki, dodając wiele mousemovezdarzeń.
Tomáš Zato - Przywróć Monikę
Możliwe w FF po najechaniu myszką, ale nie jest w IE i Chrome.
Elad
Lub, w grze, kamera porusza się po świecie gry, a postać patrzy na mysz (typowy styl strzelanki z góry na dół), ale jeśli użytkownik nie porusza myszą, centruje wokół niewłaściwego punktu, gdy się poruszasz, jeśli polegasz tylko na myszy. Jednak nie jest to wielka sprawa, po prostu przechowujemy „światowe” współrzędne wskaźnika i pozwalamy ludziom to zapytać.
kamranicus

Odpowiedzi:

336

Prawdziwa odpowiedź: nie, nie jest to możliwe.

OK, właśnie wymyśliłem sposób. Nałóż stronę na div, który obejmuje cały dokument. Wewnątrz tego utwórz (powiedzmy) 2000 x 2000 <a>elementów (aby :hoverpseudoklasa działała w IE 6, zobacz), każdy o rozmiarze 1 piksela. Utwórz :hoverregułę CSS dla tych <a>elementów, które zmieniają właściwość (powiedzmy font-family). W module obsługi ładunku przewijaj kolejno każdy z 4 milionów <a>elementów, sprawdzając currentStyle/, getComputedStyle()aż znajdziesz ten z czcionką aktywowaną. Ekstrapoluj z powrotem z tego elementu, aby uzyskać współrzędne w dokumencie.

NB NIE Rób tego .

Tim Down
źródło
92
ha ha - w pewnym momencie powinieneś poszukać w Google i sprawdzić, ile osób faktycznie to zaimplementowało
Pointy
6
W rzeczywistości można go wdrożyć bez dużego obciążenia procesora (chyba. Nie testowałem tego). W dom ready zbuduj elementy <a> z javascript, weź pozycję myszy, a następnie usuń wszystkie elementy <a>. Na mousemouse powinieneś mieć inną funkcję zajmującą pozycję myszy. W każdym razie to było przezabawne.
machineaddict
21
Być może byłoby to praktyczne w przypadku wyszukiwania binarnego? Pętla tworzy parę <a>elementów pokrywających dane prostokąty (jak <img>sądzę, stosując bezwzględne pozycjonowanie zwymiarowanych elementów), zmniejszając za każdym razem prostokąty. Tak, to śmieszne, ale nie jest w stanie uzyskać tych informacji przed pierwszym ruchem myszy.
Darius Bacon
29
stackoverflow.com/a/8543879/27024 mówi, że hover nie uruchamia się, dopóki mysz nie poruszy się po raz pierwszy. To udaremnia ten schemat.
Darius Bacon
4
@DariusBacon: Ta linkowana odpowiedź wydaje się nieprawidłowa: jsbin.com/utocax/3 . Tak, takie podejście może być praktyczne w niektórych sytuacjach.
Tim Down
121

Edycja 2020: To już nie działa. Wydaje się, że producenci przeglądarek załatali to. Ponieważ większość przeglądarek korzysta z chromu, może być w jego rdzeniu.

Stara odpowiedź: możesz także zaczepić mouseenter (to zdarzenie jest uruchamiane po przeładowaniu strony, gdy kursor myszy znajduje się na stronie). Rozszerzenie kodu Corrupt powinno załatwić sprawę:

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

Możesz także ustawić x i y na wartość null dla zdarzenia mouseleave-event. Możesz więc sprawdzić, czy użytkownik jest na Twojej stronie za pomocą kursora.

SuperNova
źródło
11
To wydaje się być jedyną naprawdę przydatną odpowiedzią tutaj, co wydaje się dziwne. Rzeczywiście (w najnowszym Firefoksie, Chrome i IE11) centrum myszy uruchamia się przy ładowaniu strony i podaje prawidłowe współrzędne. Czy zachowanie przeglądarki w tym obszarze po prostu zmieniło się w ciągu ostatnich kilku lat?
Peter Hansen
3
W rzeczywistości „mouseenter” nie wydaje się dodawać żadnej wartości. Testowałem za pomocą następującego jsfiddle w Chrome i IE, i nie wyświetlają cordinates, dopóki nie umieścisz myszy na wewnętrznym dokumencie (panelu wyników): jsfiddle.net/xkpd784o/1
Mariano Desanze
1
@Proton: Przesuń mysz do panelu wyników do obszaru panelu wyników PRZED załadowaniem strony i nie ruszaj się. Po załadowaniu strona natychmiast rozpoznaje pozycję myszy. Nie jest wymagany ruch myszy. Tak więc mouseenter jest również uruchamiany, gdy strona się załaduje, a mysz znajdzie się w obszarze dokumentu. To jest, czego pierwotnie chciał PO. Nikt inny nie udziela tej odpowiedzi.
SuperNova
1
Potencjalnie użyteczne dodawania w celu dodawania funkcji w mouseleaveprzypadku, który wyznacza xi ytylnej do nulllub'undefined'
rtpax
2
chrome 68, używając powyższego jsfiddel, alert pojawia się przy pierwszym ruchu myszy, a nie przy ładowaniu, nawet jeśli mysz zostanie przeniesiona do renderowanego regionu przed zakończeniem ładowania strony.
Junvar
84

Możesz tworzyć zmienne dla xi ywspółrzędne kursora, aktualizować je za każdym razem, gdy mysz się porusza, i wywoływać funkcję w określonym przedziale czasu, aby zrobić to, czego potrzebujesz z zapisaną pozycją.

Wadą tego jest oczywiście to, że wymagany jest co najmniej jeden początkowy ruch myszy. Tak długo, jak kursor aktualizuje swoją pozycję co najmniej raz, jesteśmy w stanie znaleźć jego pozycję, niezależnie od tego, czy porusza się ponownie.

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

Poprzedni kod aktualizuje się co sekundę komunikatem o tym, gdzie znajduje się kursor. Mam nadzieję, że to pomoże.

JHarding
źródło
18
Czy czytałeś temat tego postu? OP pyta, jak uzyskać współrzędne myszy bez użycia zdarzenia. Jednak Twój post sugeruje użycie zdarzenia onmousemove.
jake
53
@jake Chociaż PO poprosił konkretnie o metodę nie-zdarzenia, ta odpowiedź jest korzystna dla innych, którzy przybyli tutaj, szukając odpowiedzi i być może obejścia. Rozważę również tę odpowiedź częściowo w ramach tematu, ponieważ o ile wiem, jest to najlepsza metoda na uzyskanie pozycji kursora w danym momencie bez konieczności bezpośredniego używania zdarzeń. To powiedziawszy, odpowiedź mogłaby zostać sformułowana bardziej podobnie do stwierdzenia faktu i oferowania sposobu na uniknięcie niepotrzebnego komentowania.
jpeltoniemi
2
@Pichan Nie przyniosło mi to korzyści, ponieważ szukałem sposobu na wypełnienie tych cursorX/Yzmiennych przed jakimkolwiek zdarzeniem.
polkovnikov.ph
bardzo niewielu użytkowników nie uruchamia zdarzeń myszy
SuperUberDuper
1
Ostrożnie, utrzymywanie nasłuchu myszy w ruchu może być kosztowne. Sugerowałbym odtworzenie detektora w interwale i zniszczenie detektora po uzyskaniu współrzędnych.
KRB
10

Możesz spróbować czegoś podobnego do tego, co sugerował Tim Down - ale zamiast mieć elementy dla każdego piksela na ekranie, utwórz tylko 2-4 elementy (pola) i dynamicznie zmieniaj ich położenie, szerokość i wysokość, aby podzielić możliwe lokalizacje na ekranie rekursywnie przez 2-4, dzięki czemu szybko znajdujemy rzeczywistą lokalizację myszy.

Na przykład - pierwsze elementy zajmują prawą i lewą połowę ekranu, następnie górną i dolną połowę. Do tej pory wiemy już, w której części ekranu znajduje się mysz, jesteśmy w stanie powtarzać - odkryć, która ćwiartka tego miejsca ...

AlexTR
źródło
9

Odpowiedź @Tim Down nie jest skuteczna, jeśli renderujesz 2000 x 2000 <a>elementów:

OK, właśnie wymyśliłem sposób. Nałóż stronę na div, który obejmuje cały dokument. Wewnątrz tego utwórz (powiedzmy) 2000 x 2000 elementów (aby pseudo-klasa: hover działała w IE 6, zobacz), każdy o rozmiarze 1 piksela. Utwórz regułę CSS: najedź dla tych elementów, które zmieniają właściwość (powiedzmy rodzinę czcionek). W module obsługi ładunku przewijaj kolejno każdy z 4 milionów elementów, sprawdzając currentStyle / getComputedStyle (), aż znajdziesz ten z czcionką aktywowaną. Ekstrapoluj z powrotem z tego elementu, aby uzyskać współrzędne w dokumencie.

NB NIE Rób tego.

Ale nie musisz renderować 4 milionów elementów jednocześnie, zamiast tego użyj wyszukiwania binarnego. <a>Zamiast tego użyj 4 elementów:

  • Krok 1: Rozważ cały ekran jako początkowy obszar wyszukiwania
  • Krok 2: Podziel obszar wyszukiwania na 2 x 2 = 4 <a>elementy prostokątne
  • Krok 3: Za pomocą tej getComputedStyle()funkcji określ, w której myszy ma się poruszać prostokąt
  • Krok 4: Zmniejsz obszar wyszukiwania do tego prostokąta i powtórz od kroku 2.

W ten sposób musisz powtórzyć te kroki maksymalnie 11 razy, biorąc pod uwagę, że ekran nie jest szerszy niż 2048 pikseli.

Wygenerujesz więc maksymalnie 11 x 4 = 44 <a>elementy.

Jeśli nie musisz określać położenia myszy dokładnie do piksela, ale powiedz, że precyzja 10px jest OK. Powtórzyłbyś kroki co najwyżej 8 razy, więc musisz narysować maksymalnie 8 x 4 = 32 <a>elementy.

Również generowanie, a następnie niszczenie <a>elementów nie jest wykonywane, ponieważ DOM jest na ogół powolny. Zamiast tego, można po prostu ponowne początkowe 4 <a>elementów i po prostu dostosować swoje top, left, widtha heightjak ty pętlę przez kroki.

Teraz tworzenie 4 <a>to także przesada. Zamiast tego możesz użyć tego samego <a>elementu do testowania getComputedStyle()w każdym prostokącie. Zamiast dzielić obszar wyszukiwania na 2 x 2 <a>elementy, wystarczy ponownie użyć jednego <a>elementu, przenosząc go za pomocą właściwości topi leftstylu.

Wszystko czego potrzebujesz to jeden <a>element, zmień jego widthi heightmaks. 11 razy, zmień jego topi leftmaks. 44 razy, a będziesz miał dokładnie pozycję myszy.

Alex Peterson
źródło
3

Najprostsze rozwiązanie, ale nie w 100% dokładne

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

Wynik: {top: 148, left: 62.5}
wynik zależy od najbliższego rozmiaru elementu i zwraca, undefinedgdy użytkownik zmieni kartę

StefansArya
źródło
Dla mnie wraca undefinedniezależnie. Czy potrafisz wyjaśnić, jak z tego korzystać?
tresf
Wróci, undefinedgdy kursor nie będzie unosił się nad jakimkolwiek elementem (lub gdy przeglądarka straci fokus). Może być konieczne ustawienie interwału czasowego, jeśli
testujesz
Dzięki. setTimeoutpracował Używałem jsfiddle i masz rację, nigdy nie uderzył w zdarzenie najechania myszą, ponieważ przerysowuje DOM za każdym razem, gdy grasz. Polecam dodanie tej wskazówki innym.
tresf
Nie chcę dokładnej pozycji myszy, ale chcę tylko wiedzieć, że mysz jest skrajnie prawa lub skrajnie lewa do funkcji bez obiektu zdarzenia, więc twoje rozwiązanie działa w moim przypadku .. dziękuję
Zamień-IOS-Android
2

Wyobrażam sobie, że może masz stronę nadrzędną z zegarem i po pewnym czasie lub wykonaniu zadania przekierowujesz użytkownika na nową stronę. Teraz chcesz pozycję kursora, a ponieważ czekają, niekoniecznie dotykają myszy. Śledź więc mysz na stronie nadrzędnej za pomocą standardowych zdarzeń i przekaż ostatnią wartość do nowej strony w zmiennej get lub post.

Możesz użyć kodu JHarding na swojej stronie nadrzędnej, aby najnowsza pozycja była zawsze dostępna w zmiennej globalnej:

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

To nie pomoże użytkownikom, którzy przechodzą na tę stronę w sposób inny niż strona nadrzędna.


źródło
1

Zaimplementowałem wyszukiwanie poziome / pionowe (najpierw wykonuję div pełen pionowe łącza liniowe ułożone poziomo, a następnie robię div pełen poziome łącza liniowe ułożone pionowo i po prostu sprawdzam, który z nich jest w stanie najechania), podobnie jak pomysł Tima Down powyżej, i działa dość szybko. Niestety nie działa w Chrome 32 na KDE.

jsfiddle.net/5XzeE/4/

użytkownik2958613
źródło
najwyraźniej te sztuczki już nie działają, chyba że użytkownik wyraźnie poruszy myszą. :(
trusktr
1

Nie musisz poruszać myszą, aby uzyskać lokalizację kursora. Lokalizacja jest również zgłaszana w przypadku zdarzeń innych niż ruch myszy . Oto przykład zdarzenia kliknięcia :

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

Wracając do odpowiedzi @ SuperNova , oto podejście wykorzystujące klasy ES6, które zachowuje kontekst dla thispoprawnego oddzwaniania:

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
źródło
1

Oto moje rozwiązanie. Eksportuje właściwości window.currentMouseX i window.currentMouseY , których można używać w dowolnym miejscu. Wykorzystuje pozycję elementu ukrytego (jeśli istnieje) początkowo, a następnie nasłuchuje ruchów myszy, aby ustawić prawidłowe wartości.

(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 Źródło: https://github.com/ocproducts/composr/commit/a851c19f925be20bc16bfe016be42924989f262e#diff-b162dc9c35a97618a96748639ff41251R1202

Salman von Abbas
źródło
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;
}
Zepsuty
źródło
14
Czy to nie wymaga od użytkownika poruszania myszą?
Paul Hiemstra
0

Myślę, że mogę mieć rozsądne rozwiązanie bez liczenia div i pikseli..lol

Po prostu użyj ramki animacji lub przedziału czasowego funkcji. Nadal będziesz potrzebować zdarzenia myszy, aby zainicjować, ale technicznie ustawiasz to tam, gdzie chcesz.

Zasadniczo śledzimy atrapę div przez cały czas bez ruchu myszy.

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

Poniżej znajduje się logika ..

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);
}  
Jozuego
źródło