Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to measure the milliseconds between mousedown and mouseup?

People also ask

What is Mousedown and mouseup?

MouseDown occurs when the user presses the mouse button; MouseUp occurs when the user releases the mouse button.

What is the difference between Mousedown and click?

Note: This differs from the click event in that click is fired after a full click action occurs; that is, the mouse button is pressed and released while the pointer remains inside the same element. mousedown is fired the moment the button is initially pressed.

Does mouseup fire before click?

Mouseup is always firing before click, despite this order.

What is on Mousedown?

The onmousedown event occurs when a user presses a mouse button over an element. Tip: The order of events related to the onmousedown event (for the left/middle mouse button): onmousedown. onmouseup.


You could create a closure to share two variables, one to store the start time and other for the end time, then in the mouseup event, get the difference:

(function () {
    var element = document.getElementById('element'),
        start, end;

    element.onmousedown = function () {
      start = +new Date(); // get unix-timestamp in milliseconds
    };


    element.onmouseup = function () {
      end = +new Date();

      var diff = end - start; // time difference in milliseconds
    };

})();

Check this working example.


tl;dr answer and example

  • Get the time between two events by subtracting the .timeStamp property of the first event from the .timeStamp property of the second event.
  • Don't ever try to get the time an event occurred by creating a new Date() or calling Date.now() inside its handler.
  • Be aware that even if you follow this advice, in old versions of some browsers you'll get the wrong result if execution of your event handlers is delayed by slow execution of some unrelated JavaScript.

const button = document.getElementById("button");
let mousedownTime;

button.addEventListener('mousedown', () => {
  mousedownTime = new Date().getTime();
});

button.addEventListener('mouseup', function () {
  const mouseupTime = new Date().getTime(),
        timeDifference = mouseupTime - mousedownTime;
  alert(`Button held down for ${timeDifference}ms`);
});
<button id="button">Click Me</button>

Longer answer and explanation

This is a much more subtle problem than other answers here give it credit for being.

The approach proposed by CMS's answer - of getting the time inside each handler by creating a new Date() and then subtracting these times from each other - has the potential to be grossly inaccurate. The problem with this approach is that you're not comparing the times at which the events occurred, you're comparing the times at which their handlers fired.

The article linked to by the question asker - John Resig's How JavaScript Timers Work - is relevant to understanding the problem here. JavaScript execution is single threaded, and whenever something outside of JavaScript triggers some JavaScript execution - whether it's a timeout firing, an event occurring, or a script loading - that JavaScript gets added to a queue of callbacks waiting to fire, which get executed sequentially.

This leads to a couple of ways that our attempt to calculate the time between events can get horribly screwed up if we try to calculate it based upon the times that the handlers run. Consider the following two scenarios:

First scenario
  1. Some computationally expensive JavaScript starts executing that will take 1 second to execute.
  2. The first event occurs (i.e. the user mouses down on the target element)
  3. 200 milliseconds later, the second event occurs (i.e. the user mouses up on the target element).

What happens next? The computationally expensive JavaScript finishes running, and then both event handlers fire in rapid succession. Consequently, if you are timing the events by getting the current time when the handler fires, you will wrongly calculate the time between the events to be close to 0 milliseconds.

Second scenario
  1. The first event occurs and its handler fires. It stores the current time in a variable for later reference, and then starts doing some computation that will take 1 second to complete.
  2. 200 milliseconds after the first event is triggered, the second event is triggered.

What happens next? This time, of course, we will wrongly calculate the time between events as being approximately 1 second, because the second handler's execution gets delayed.

You can see this in action here:

const button = document.getElementById("button");
let mousedownTime;

button.addEventListener('mousedown', function () {
  mousedownTime = new Date().getTime();
  document.getElementById("mousedown-time").innerHTML = mousedownTime;
  document.getElementById("time-difference").innerHTML = '';
  hotSleep();
});

button.addEventListener('mouseup', function () {
  const mouseupTime = new Date().getTime(),
        timeDifference = mouseupTime - mousedownTime;
  document.getElementById("mouseup-time").innerHTML = mouseupTime;
  document.getElementById("time-difference").innerHTML = timeDifference;
});

/**
 * Hot-sleeps for 1 second when called.
 * 
 * In a real life scenario, this might be some expensive numerical
 * computation, or some DOM manipulation code.
 */
function hotSleep () {
  const startTime = new Date().getTime();
  while (new Date().getTime() < startTime+1000) {}
}
<button id="button">Click Me</button>
<div>
  Time of last mousedown: <span id="mousedown-time"></span>
</div>
<div>
  Time of last mouseup: <span id="mouseup-time"></span>
</div>
<div>
  Time between events: <span id="time-difference"></span>
</div>

Just click the button and observe that the calculated time difference between mousedown and mouseup is always roughly 1000ms.

What can we do to stop this? Well, ideally, we want a way of getting the actual time an event occurred, not merely the time its handler fired. Does the DOM API offer us such a thing?

In modern browsers, yes. Events have a .timeStamp property, which, nowadays, should provide the time the event occurred rather than the time the handler fired. (This wasn't true in the past; when I first wrote this answer, only Firefox implemented this properly and other browsers would return the time the handler fired. Thankfully, everyone now implements this correctly.)

Below, then, is a modified version of the example with the hot-sleep from above. The only change is that the time that events occurred is determined using the events' .timestamp property - which is enough to mean that we now compute the duration of the click correctly.

const button = document.getElementById("button");
let mousedownTime;

button.addEventListener('mousedown', e => {
  mousedownTime = e.timeStamp;
  document.getElementById("mousedown-time").innerHTML = mousedownTime;
  document.getElementById("time-difference").innerHTML = '';
  hotSleep();
});

button.addEventListener('mouseup', e => {
  const mouseupTime = e.timeStamp,
        timeDifference = mouseupTime - mousedownTime;
  document.getElementById("mouseup-time").innerHTML = mouseupTime;
  document.getElementById("time-difference").innerHTML = timeDifference;
});

/**
 * Hot-sleeps for 1 second when called.
 * 
 * In a real life scenario, this might be some expensive numerical
 * computation, or some DOM manipulation code.
 */
function hotSleep () {
  const startTime = new Date().getTime();
  while (new Date().getTime() < startTime+1000) {}
}
<button id="button">Click Me</button>
<div>
  Time of last mousedown: <span id="mousedown-time"></span>
</div>
<div>
  Time of last mouseup: <span id="mouseup-time"></span>
</div>
<div>
  Time between events: <span id="time-difference"></span>
</div>

Since the other links seem to be broken now, at least on chrome, here's a simple working demo:

var startTime;

window.startTimer = function() {
    startTime = new Date();
}
window.reportTime = function() {
	alert(new Date() - startTime)
}
<button onmousedown="startTimer()" onmouseup="reportTime()">Measure click time</button>

When onmousedown is fired you can hang an onmouseup event on window. This will allow to avoid unnecessary closures.

el.onmousedown = function () {
  var time = new Date(); //time in milliseconds
  window.onmouseup=function(){
    var diff=new Date()-time;
    window.onmouseup=null;
  }
};

check result here: http://jsbin.com/uneqo