JavaScript - śledź pozycję myszy

161

Mam nadzieję, że prześledzę pozycję kursora myszy, okresowo co t msekund. Więc zasadniczo, kiedy strona się ładuje - ten tracker powinien się uruchamiać i przez (powiedzmy) co 100 ms powinienem pobrać nową wartość posX i posY i wydrukować ją w formularzu.

Wypróbowałem następujący kod - ale wartości nie są odświeżane - tylko początkowe wartości posX i posY pojawiają się w polach formularza. Jakieś pomysły, jak mogę to uruchomić i uruchomić?

<html>
<head>
<title> Track Mouse </title>
<script type="text/javascript">
function mouse_position()
{
    var e = window.event;

    var posX = e.clientX;
    var posY = e.clientY;

    document.Form1.posx.value = posX;
    document.Form1.posy.value = posY;

    var t = setTimeout(mouse_position,100);

}
</script>

</head>

<body onload="mouse_position()">
<form name="Form1">
POSX: <input type="text" name="posx"><br>
POSY: <input type="text" name="posy"><br>
</form>
</body>
</html>
Hari
źródło
Problem w tym, że eventgdy funkcja zostanie wywołana po raz drugi , nie będzie żadnego obiektu. Prawdopodobnie powinieneś posłuchać jakiegoś zdarzenia niż użyć setTimeout.
Felix Kling
Tak, ale funkcja mouse_position () nie powinna wywoływać siebie co 100 milisekund. Czy nie powinien faktycznie zachowywać się jak nieskończona funkcja rekurencyjna?
Hari
2
możliwy duplikat przechwytywania pozycji myszy w setInterval () w Javascript
Shadow Wizard is Ear For You
@Titan: Tak, ale podejrzewam, że wystąpi błąd, ponieważ window.eventbędzie undefinedlub null. Jeśli nie ma zdarzenia, nie ma eventobiektu.
Felix Kling
1
z interesu, jakie jest tego zastosowanie?
SuperUberDuper

Odpowiedzi:

178

Pozycja myszy jest raportowana na eventobiekcie odebranym przez moduł obsługi mousemovezdarzenia, który można dołączyć do okna (bąbelki zdarzenia):

(function() {
    document.onmousemove = handleMouseMove;
    function handleMouseMove(event) {
        var eventDoc, doc, body;

        event = event || window.event; // IE-ism

        // If pageX/Y aren't available and clientX/Y are,
        // calculate pageX/Y - logic taken from jQuery.
        // (This is to support old IE)
        if (event.pageX == null && event.clientX != null) {
            eventDoc = (event.target && event.target.ownerDocument) || document;
            doc = eventDoc.documentElement;
            body = eventDoc.body;

            event.pageX = event.clientX +
              (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
              (doc && doc.clientLeft || body && body.clientLeft || 0);
            event.pageY = event.clientY +
              (doc && doc.scrollTop  || body && body.scrollTop  || 0) -
              (doc && doc.clientTop  || body && body.clientTop  || 0 );
        }

        // Use event.pageX / event.pageY here
    }
})();

(Zauważ, że jego treść ifbędzie działać tylko w starym IE).

Przykład powyższego w akcji - rysuje kropki podczas przeciągania myszą po stronie. (Testowane na IE8, IE11, Firefox 30, Chrome 38).

Jeśli naprawdę potrzebujesz rozwiązania opartego na zegarze, możesz połączyć to z kilkoma zmiennymi stanu:

(function() {
    var mousePos;

    document.onmousemove = handleMouseMove;
    setInterval(getMousePosition, 100); // setInterval repeats every X ms

    function handleMouseMove(event) {
        var dot, eventDoc, doc, body, pageX, pageY;

        event = event || window.event; // IE-ism

        // If pageX/Y aren't available and clientX/Y are,
        // calculate pageX/Y - logic taken from jQuery.
        // (This is to support old IE)
        if (event.pageX == null && event.clientX != null) {
            eventDoc = (event.target && event.target.ownerDocument) || document;
            doc = eventDoc.documentElement;
            body = eventDoc.body;

            event.pageX = event.clientX +
              (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
              (doc && doc.clientLeft || body && body.clientLeft || 0);
            event.pageY = event.clientY +
              (doc && doc.scrollTop  || body && body.scrollTop  || 0) -
              (doc && doc.clientTop  || body && body.clientTop  || 0 );
        }

        mousePos = {
            x: event.pageX,
            y: event.pageY
        };
    }
    function getMousePosition() {
        var pos = mousePos;
        if (!pos) {
            // We haven't seen any movement yet
        }
        else {
            // Use pos.x and pos.y
        }
    }
})();

O ile mi wiadomo, nie można uzyskać pozycji myszy bez obejrzenia zdarzenia, co wydaje się potwierdzać ta odpowiedź na inne pytanie dotyczące przepełnienia stosu .

Uwaga dodatkowa : jeśli zamierzasz robić coś co 100 ms (10 razy na sekundę), staraj się, aby rzeczywiste przetwarzanie, które wykonujesz w tej funkcji, było bardzo, bardzo ograniczone . To dużo pracy dla przeglądarki, szczególnie starszych Microsoft. Tak, na nowoczesnych komputerach nie wydaje się to dużo, ale w przeglądarkach dużo się dzieje ... Na przykład możesz śledzić ostatnią przetworzoną pozycję i natychmiast zwolnić sprzedawcę, jeśli pozycja nie została t zmienił się.

TJ Crowder
źródło
66

Oto rozwiązanie oparte na jQuery i nasłuchiwaniu zdarzeń myszy (które jest znacznie lepsze niż zwykłe odpytywanie) w treści:

$("body").mousemove(function(e) {
    document.Form1.posx.value = e.pageX;
    document.Form1.posy.value = e.pageY;
})
solendil
źródło
Jak wspomniałem, regularne głosowanie jest dokładnie tym, co chcę robić. Nie śledzę zmian w zdarzeniach myszy, szukam tylko przechwytywania pozycji myszy co x milisekund (niezależnie od tego, czy mysz się poruszyła, czy nie).
Hari
3
Dlaczego śledzenie wartości, o której wiesz na pewno, nie uległo zmianie? Nie rozumiem, chyba że jest to problem z pracą domową. Za pomocą metody zdarzenia możesz śledzić każdą zmianę tych wartości, a następnie przeprowadzić 100 ms sondowanie w innym miejscu, jeśli chcesz obsłużyć te wartości w jakimkolwiek celu.
solendil
1
Nie ma żadnej korzyści z używania jQuery tutaj, z wyjątkiem niepotrzebnego używania 5mb biblioteki JS
Pattycake Jr
@PattycakeJr Ostatni raz oglądałem, że w wersji zminimalizowanej było poniżej 90kB
Kris
1
@PattycakeJr także jeśli jesteś bardzo mało prawdopodobne, pobierając ją w ogóle, jeśli wskazują na CDN ponieważ prawie co drugi łączy lokacji do niego
Brian Leishman
53
onmousemove = function(e){console.log("mouse location:", e.clientX, e.clientY)}

Otwórz konsolę ( Ctrl+ Shift+ J), skopiuj i wklej powyższy kod i przesuń mysz w oknie przeglądarki.

RegarBoy
źródło
1
Imo najlepsza odpowiedź
HereHere
10

Uważam, że zbytnio się nad tym zastanawiamy,

function mouse_position(e)
{
//do stuff
}
<body onmousemove="mouse_position(event)"></body>

DGRAMOP
źródło
1
Jestem nowy na tym forum, więc tylko po to, żeby wiedzieć, proszę wyjaśnić, dlaczego - i mój awnser - to jest tak, żebym nie popełniał ponownie tego samego błędu. Dzięki! ThePROgrammer
dGRAMOP
10
Mnie też irytują głosy przeciwne bez wyjaśnienia. Aby dać ci możliwe wyjaśnienie, ta odpowiedź nie dotyczy problemu odpytywania OP co 100 ms. Z jego odpowiedzi na inne odpowiedzi jasno wynika, że ​​jest to konieczność.
aaaaaa
1
uważam, że również ten rodzaj obsługi zdarzeń w tekście jest przestarzały. document.body.addEventListener("mousemove", function (e) {})jest sposób na zrobienie tego w kodzie javascript, a nie w html
Ryan
10

Myślę, że on chce tylko znać pozycje X / Y kursora, niż dlaczego odpowiedź jest tak skomplikowana.

// Getting 'Info' div in js hands
var info = document.getElementById('info');

// Creating function that will tell the position of cursor
// PageX and PageY will getting position values and show them in P
function tellPos(p){
  info.innerHTML = 'Position X : ' + p.pageX + '<br />Position Y : ' + p.pageY;
}
addEventListener('mousemove', tellPos, false);
* {
  padding: 0:
  margin: 0;
  /*transition: 0.2s all ease;*/
  }
#info {
  position: absolute;
  top: 10px;
  right: 10px;
  background-color: black;
  color: white;
  padding: 25px 50px;
}
<!DOCTYPE html>
<html>
  
  <body>
    <div id='info'></div>
        </body>
  </html>

Murtaza
źródło
5

Kod oparty na ES6:

let handleMousemove = (event) => {
  console.log(`mouse position: ${event.x}:${event.y}`);
};

document.addEventListener('mousemove', handleMousemove);

Jeśli potrzebujesz dławienia do przenoszenia myszy, użyj tego:

let handleMousemove = (event) => {
  console.warn(`${event.x}:${event.y}\n`);
};

let throttle = (func, delay) => {
  let prev = Date.now() - delay;
  return (...args) => {
    let current = Date.now();
    if (current - prev >= delay) {
      prev = current;
      func.apply(null, args);
    }
  }
};

// let's handle mousemoving every 500ms only
document.addEventListener('mousemove', throttle(handleMousemove, 500));

oto przykład

oboshto
źródło
2

Niezależnie od przeglądarki poniższe wiersze działały za mnie, aby pobrać poprawną pozycję myszy.

event.clientX - event.currentTarget.getBoundingClientRect().left event.clientY - event.currentTarget.getBoundingClientRect().top

Sai Ganesh Pittala
źródło
2

Jeśli chcesz tylko wizualnie śledzić ruch myszy:

<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<style type="text/css">
* { margin: 0; padding: 0; }
html, body { width: 100%; height: 100%; overflow: hidden; }
</style>
<body>
<canvas></canvas>

<script type="text/javascript">
var
canvas    = document.querySelector('canvas'),
ctx       = canvas.getContext('2d'),
beginPath = false;

canvas.width  = window.innerWidth;
canvas.height = window.innerHeight;

document.body.addEventListener('mousemove', function (event) {
	var x = event.clientX, y = event.clientY;

	if (beginPath) {
		ctx.lineTo(x, y);
		ctx.stroke();
	} else {
		ctx.beginPath();
		ctx.moveTo(x, y);
		beginPath = true;
	}
}, false);
</script>
</body>
</html>

luistar15
źródło
2

Nie mam wystarczającej reputacji, aby opublikować odpowiedź na komentarz, ale przyjąłem doskonałą odpowiedź TJ Crowdera i w pełni zdefiniowałem kod na zegarze 100 ms . (Kilka szczegółów pozostawił wyobraźni.)

Dzięki OP za pytanie i TJ za odpowiedź! Oboje jesteście wielką pomocą. Kod jest osadzony poniżej jako lustro isbin.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Example</title>
  <style>
    body {
      height: 3000px;
    }
    .dot {
      width: 2px;
      height: 2px;
      background-color: black;
      position: absolute;
    }
  </style>
</head>
<body>
<script>
(function() {
    "use strict";
    var mousePos;

    document.onmousemove = handleMouseMove;
    setInterval(getMousePosition, 100); // setInterval repeats every X ms

    function handleMouseMove(event) {
        var eventDoc, doc, body;

        event = event || window.event; // IE-ism

        // If pageX/Y aren't available and clientX/Y are,
        // calculate pageX/Y - logic taken from jQuery.
        // (This is to support old IE)
        if (event.pageX == null && event.clientX != null) {
            eventDoc = (event.target && event.target.ownerDocument) || document;
            doc = eventDoc.documentElement;
            body = eventDoc.body;

            event.pageX = event.clientX +
              (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
              (doc && doc.clientLeft || body && body.clientLeft || 0);
            event.pageY = event.clientY +
              (doc && doc.scrollTop  || body && body.scrollTop  || 0) -
              (doc && doc.clientTop  || body && body.clientTop  || 0 );
        }

        mousePos = {
            x: event.pageX,
            y: event.pageY
        };
    }
    function getMousePosition() {
        var pos = mousePos;
		
        if (!pos) {
            // We haven't seen any movement yet, so don't add a duplicate dot 
        }
        else {
            // Use pos.x and pos.y
            // Add a dot to follow the cursor
            var dot;
            dot = document.createElement('div');
            dot.className = "dot";
            dot.style.left = pos.x + "px";
            dot.style.top = pos.y + "px";
            document.body.appendChild(dot);
        }
    }
})();
</script>
</body>
</html>

Kris z K
źródło
0

Oto połączenie tych dwóch wymagań: śledzenie pozycji myszy co 100 milisekund:

var period = 100,
    tracking;

window.addEventListener("mousemove", function(e) {
    if (!tracking) {
        return;
    }

    console.log("mouse location:", e.clientX, e.clientY)
    schedule();
});

schedule();

function schedule() {
    tracking = false;

    setTimeout(function() {
        tracking = true;
    }, period);
}

To śledzi i działa na pozycji myszy, ale tylko co milisekundy okresu .

Bobby Jack
źródło
0

Tylko uproszczona wersja odpowiedzi @TJ Crowder i @RegarBoy .

Moim zdaniem mniej znaczy więcej.

Sprawdź wydarzenie onmousemove, aby uzyskać więcej informacji o wydarzeniu.

Śledzenie myszy obrazu

Jest nowa wartość posXi za posYkażdym razem, gdy mysz porusza się zgodnie ze współrzędnymi poziomymi i pionowymi.

<!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>Example Mouse Tracker</title>
      <style>    
        body {height: 3000px;}
        .dot {width: 2px;height: 2px;background-color: black;position: absolute;}
      </style>
    </head>
    <body>
    <p>Mouse tracker</p>
    <script>
    onmousemove = function(e){
        //Logging purposes
        console.log("mouse location:", e.clientX, e.clientY);

        //meat and potatoes of the snippet
        var pos = e;
        var dot;
        dot = document.createElement('div');
        dot.className = "dot";
        dot.style.left = pos.x + "px";
        dot.style.top = pos.y + "px";
        document.body.appendChild(dot);
    }      
    </script>
    </body>
    </html>
Jonas
źródło