Track mouse speed with JS
Asked Answered
T

8

23

What's the best way to track the mouse speed with plain JS/JQuery? I'd like to track how fast a user moves the mouse in all directions (up/down/left/right).

Tunicle answered 20/6, 2011 at 20:25 Comment(0)
S
18

Sparklines has a nifty example of tracking mouse movement and graphing it. Their code is available in the source of their site starting at line 315.

Simple and effective.

Here is the code:

 var mrefreshinterval = 500; // update display every 500ms
 var lastmousex=-1; 
 var lastmousey=-1;
 var lastmousetime;
 var mousetravel = 0;
 $('html').mousemove(function(e) {
     var mousex = e.pageX;
     var mousey = e.pageY;
     if (lastmousex > -1)
         mousetravel += Math.max( Math.abs(mousex-lastmousex), Math.abs(mousey-lastmousey) );
     lastmousex = mousex;
     lastmousey = mousey;
 });
Sandrocottus answered 20/6, 2011 at 20:30 Comment(4)
Does this solution track mouse distance only? Why is the distance the max of difference of x and y coordinates and not the sum of the squares of the differences? And is mrefreshinterval a "predefined" attribute? I don't see how you use it. Thanks.Primo
"lastmousetime" is not even used here , and time is a key component of speed. This looks like an approxmation of general distance travelledBarb
mrefreshinterval is not used. What is $?Doublestop
Answer is totally wrong! It measures distance, not speed.Doublestop
E
18
var timestamp = null;
var lastMouseX = null;
var lastMouseY = null;

document.body.addEventListener("mousemove", function(e) {
    if (timestamp === null) {
        timestamp = Date.now();
        lastMouseX = e.screenX;
        lastMouseY = e.screenY;
        return;
    }

    var now = Date.now();
    var dt =  now - timestamp;
    var dx = e.screenX - lastMouseX;
    var dy = e.screenY - lastMouseY;
    var speedX = Math.round(dx / dt * 100);
    var speedY = Math.round(dy / dt * 100);

    timestamp = now;
    lastMouseX = e.screenX;
    lastMouseY = e.screenY;
});
Expellee answered 7/11, 2013 at 9:53 Comment(4)
Please add some description to your code. Why you think it is an answer? Are the previous answers incorrect or inefficient? Or maybe you want to show different approach to the problem? Posting just a block of code is not an answer.Danell
This is more correctly instead of using intervals. In every iteration (except first) we'll know speed. When we using intervals we have average speed (in this interval).Shaum
By far the best answerSnaggy
It should be e.timeStamp to get the nearest real time when the position is measured. Event is measured before it is created and put on event loop. To measure time after event is popped from event loop makes deviations because there are various things happening.Doublestop
P
12

With current modern browser we can now use movementX or movementY to detect mouse's movement speed. Before you want to use it you should see the compatibility table because older browser will have a prefix like webkitMovementX.

document.addEventListener("mousemove", function(ev){
    console.log(`Movement X: ${ev.movementX}, Y: ${ev.movementY}`);
}, false);

The result above is not an average speed like pixel/second but it's total movement between triggered mousemove event. If you need px/s then you can do it like below:

var totalX = 0;
var totalY = 0;
var moveX = 0;
var moveY = 0;

document.addEventListener("mousemove", function(ev){
    totalX += Math.abs(ev.movementX);
    totalY += Math.abs(ev.movementY);
    moveX += ev.movementX;
    moveY += ev.movementY;
}, false);

setInterval(function(){
    console.log(`Speed X: ${totalX}px/s, Y: ${totalY}px/s`);
    console.log(`Movement X: ${moveX}px/s, Y: ${moveY}px/s`);
    moveX = moveY = totalX = totalY = 0;
}, 1000);

Negative number represent movement to the left or top, while positive represent movement to the bottom or right direction.

Presidency answered 14/4, 2020 at 7:33 Comment(0)
S
7

Same way you get speed for anything else:

speed = distance / time

acceleration = speed / time 

And use:

 $(document).mousemove(function(e){
     var xcoord = e.pageX;
     var ycoord = e.pageY;
 }); 

To get the mouse coordinates whenever the mouse moves.

Seline answered 20/6, 2011 at 20:30 Comment(2)
Yes, but you need at least two mouse moves to have the correct time. Suppose you moved mouse to [5, 5] and then froze for 10 seconds. Then you move quickly to [10, 5] in a split second, the output would be 10 pixels in 10 seconds, because when you got to [5, 5] was the last time you recorded the timestamp. I know for mouse movement the first actual move doesn't often matter because you're triggering more, but I'm trying this for touch as well, where you might have just one move to work with if you swipe very fast.Brawley
I agree with @treznik, it's not clear at all from your code how you get the value from the variable "time".Briquette
P
3

This is a method to counter the fact you could start tracking, pause and then move your finger or mouse very quickly (suppose a sudden flick on a touch screen).

var time = 200
var tracker = setInterval(function(){
    historicTouchX = touchX;
}, time);

document.addEventListener("touchmove", function(){
    speed = (historicTouchX - touchX) / time;
    console.log(Math.abs(speed));
}, false);

I have done this with only the touchX in this example. The idea is to take a snapshot of the x position every 200 milliseconds, and then take that from the current position then divide by the 200 (speed = distance / time). This would keep a fresh update on the speed. The time is milliseconds and the output would be the number of pixels traveled per 200 milliseconds.

Prophetic answered 19/3, 2014 at 16:29 Comment(0)
T
1

I also had a requirement to find the acceleration, speed, movement of the mouse. Below is the code which is implemented for the react application. Through this we were able to find the movement, speed, max speed, acceleration, maximum acceleration of the mouse.

    let previousEvent, currentEvent;        
    let maxSpeed = 0, previousSpeed = 0, speed = 0, maxPositiveAcc = 0, maxNegativeAcc = 0;
    componentDidMount() {
              
                document.addEventListener('mousemove', (event) => {
                    currentEvent = event
                });
        
                setInterval(function () {
                    if (currentEvent && previousEvent) {
                        let movementX = Math.abs(currentEvent.pageX - previousEvent.pageX);
                        let movementY = Math.abs(currentEvent.pageY - previousEvent.pageY);
                        let movement = Math.sqrt(movementX * movementX + movementY * movementY);
         //Dividing by 100 since the setInterval function is called every 100ms
                        speed = 10 * movement; 
                        maxSpeed = Math.round(speed > maxSpeed ? (maxSpeed = speed) : maxSpeed);
        
                        let acceleration = 10 * (speed - previousSpeed);
        
                        if (acceleration > 0) {
                            maxPositiveAcceleration = Math.round(acceleration > maxPositiveAcc ? (maxPositiveAcc = acceleration) : maxPositiveAcc);
                        } else {
                            maxNegativeAcceleration = Math.round(acceleration < maxNegativeAcc ? (maxNegativeAcc = acceleration) : maxNegativeAcc);
                        }
                    }
                    previousEvent = currentEvent
                    previousSpeed = speed;
                }, 100);
            }
Tomkin answered 14/2, 2021 at 8:38 Comment(1)
Very clever to have addEventListener for mousemove at minimal by moving code to setInterval and doing code every 100ms instead of each 10ms mousemove, that would slow down some browsers.Doublestop
M
0

I'm looking for a way to track mouse speed as well. I found this video on Youtube https://www.youtube.com/watch?v=Lrfmu9V_foE. You can see how to track mouse speed with mousemove event once has defined previous mouse event and current mouse event.

Anyways, I want to store the speed as a value to use elsewhere but don't know how to.

Manifestation answered 21/10, 2021 at 13:26 Comment(2)
Please don't use Post Answer to ask a question. Use the Ask Question button and include these details. You can also add a link to this question if the context would be useful. - From ReviewRomansh
If you have a new question, please ask it by clicking the Ask Question button. Include a link to this question if it helps provide context. - From ReviewParadise
D
0

This uses e.movementX instead of e.screenX - lastMouseX. The speed is for any direction, not only speedX or speedY. speedMax is useful to trig something at a turn fast enough (a throw). The direction can define a turn.

var timestamp = 0, speedMax = 0;

document.body.addEventListener("mousemove", function(e) {

    var now = Date.now();

    var dt = now - timestamp;
    var dx = e.movementX;
    var dy = e.movementY;

    var distance = Math.sqrt(dx*dx + dy*dy);
    var direction = Math.atan2(dy, dx);

    //speed is zero when mouse was still (dt hold a long pause)
    var speed = parseInt(distance / dt * 100);
    var speedX = Math.round(dx / dt * 100);
    var speedY = Math.round(dy / dt * 100);

    //reset if speed is zero, otherwise set max of any speed
    speedMax = !speed? 0: speed > speedMax? speed: speedMax;

    timestamp = now;
});

The first speed is zero because dt is a big number.

Doublestop answered 4/11, 2023 at 1:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.