Is there any way to measure the number of milliseconds between mouse press and release?
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.
Date.now()
would be better than instantiating a date object. Not all browsers do though. –
Keratitis new Date()
is usually a bad practice. Read the event's .timeStamp
property instead, so that (at least in some browsers) your timing won't be at risk of being skewed if one or both of your event handlers end up being queued because other JavaScript is executing when the event occurs. See my answer (https://mcmap.net/q/468920/-how-to-measure-the-milliseconds-between-mousedown-and-mouseup) for a much lengthier take on this, complete with examples. –
Budding (function() {...})();
instead of just running the code? –
Jockey element
, start
, and end
names don't leak into the global scope. –
Gerenuk 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 callingDate.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- Some computationally expensive JavaScript starts executing that will take 1 second to execute.
- The first event occurs (i.e. the user mouses down on the target element)
- 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- 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.
- 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
You can use two global variables to record the time of mousedown and mouseup, and have a substract
I think this is the most elegant way:
function onMouseDown(e) {
window.onmouseup = function(e2) {
var diff = e2.timeStamp - e.originalEvent.timeStamp;
console.log(diff);
window.onmouseup = null;
};
}
© 2022 - 2024 — McMap. All rights reserved.
+
beforenew Date()
do? – Centesimal