Reputation: 11
Why can't modern browsers keep up with the mouse? Firefox 3.6, Chrome 8.xx, Opera 10.xx, all fail to fire mouse events like mouseover, mouseout and mousemove at anything like a high enough rate to keep up with a fast moving mouse.
How does the browser decide when to generate a mouseover or mouseout event under these conditions? In practice it bears no resemblance to the accepted definition of "This mouseout event is sent to an element when the user moves the mouse outside the element. This event is the reverse of mouseover." [MDC]
The code below is the simplest case I can find to demonstrate this behaviour. Event listeners are attached to the document object.
<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" lang="en" >
<head>
<title>Mouse event tracking</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<style type="text/css">
div {
position: absolute;
border: 1px solid black;
width: 40px;
height: 100px;
}
</style>
</head>
<body>
<h1 style="position: absolute; top: 10px; left: 10px; font-size: 14px">Start on green, move mouse to yellow</h1>
<div id="ladder_start" style="top: 50px; left: 10px; background-color: #44ff44;"></div>
<div id="ladder" style="top: 50px; left: 50px;"></div>
<div id="ladder_end" style="top: 50px; left: 850px; background-color: #ffff44;"></div>
<div id="ladder_p_over" style="top: 50px; left: 900px; width: 100px; height: 50px"></div>
<div id="ladder_p_out" style="top: 100px; left: 900px; width: 100px; height: 50px"></div>
<canvas id="ladder_trace" style="position: absolute; border: 1px solid black; top: 155px; left: 50px; height: 20px"></canvas>
<script type="text/javascript">
window.addEventListener("load", function (event) {
if (window.event_tests_loaded === true) {
return;
}
var ladder = document.getElementById("ladder");
var ladder_trace = document.getElementById("ladder_trace");
var ladder_start = document.getElementById("ladder_start");
var ladder_end = document.getElementById("ladder_end");
var ladder_p_over = document.getElementById("ladder_p_over");
var ladder_p_out = document.getElementById("ladder_p_out");
var mouse_over_count = 0;
var mouse_out_count = 0;
var steps = [];
var trace = ladder_trace.getContext('2d');
var step_over = function (event) {
event.preventDefault();
event.stopPropagation();
if (typeof event.target.parentNode === "object") {
if (event.target.parentNode === ladder) {
event.target.style.backgroundColor = event.target.highlight_color;
mouse_over_count++;
ladder_p_over.textContent = mouse_over_count;
}
}
};
var step_out = function (event) {
event.preventDefault();
event.stopPropagation();
if (typeof event.target.parentNode === "object") {
if (event.target.parentNode === ladder) {
mouse_out_count++;
ladder_p_out.textContent = mouse_out_count;
}
}
};
var move = function (event) {
event.preventDefault();
event.stopPropagation();
if ((event.clientX >= 50) && (event.clientX < 850)) {
trace.fillStyle = "black";
trace.strokeStyle = "black";
trace.lineWidth = 1;
trace.beginPath();
trace.moveTo(event.clientX - 50 + 0.5, 0);
trace.lineTo(event.clientX - 50 + 0.5, 20);
trace.stroke();
}
};
ladder_start.addEventListener("mouseover", function (event) {
event.preventDefault();
event.stopPropagation();
mouse_over_count = 0;
mouse_out_count = 0;
ladder_p_over.textContent = mouse_over_count;
ladder_p_out.textContent = mouse_out_count;
var i;
for (i = 0; i < 40; i++) {
steps[i].style.backgroundColor = steps[i].original_color;
}
trace.clearRect(0, 0, 800, 20);
document.addEventListener("mouseover", step_over, false);
document.addEventListener("mouseout", step_out, false);
document.addEventListener("mousemove", move, false);
}, false);
ladder_end.addEventListener("mouseover", function (event) {
document.removeEventListener("mouseover", step_over, false);
document.removeEventListener("mouseout", step_out, false);
document.removeEventListener("mousemove", move, false);
}, false);
(function () {
var i;
for (i = 0; i < 40; i++) {
steps[i] = document.createElement("div");
steps[i].style.width = "20px";
steps[i].style.border = "0";
steps[i].style.top = "0px";
steps[i].style.left = (i * 20) + "px";
steps[i].original_color = "rgb(" + (i * 4) + ",0,0)";
steps[i].highlight_color = "rgb(255," + (i * 4) + ",255)";
steps[i].style.backgroundColor = steps[i].original_color;
ladder.appendChild(steps[i]);
}
ladder.style.width = (i * 20) + "px";
ladder_trace.style.width = (i * 20) + "px";
ladder_trace.width = (i * 20);
ladder_trace.height = 20;
}());
ladder_p_over.textContent = mouse_over_count;
ladder_p_out.textContent = mouse_out_count;
}, false);
</script>
</body>
</html>
Upvotes: 1
Views: 894
Reputation: 9141
That would be because they render first, and then check for input.
I've been frustrated about this for a while too, but a few tests confirmed this.
They render and then check for input.
Edit: If you have a good computer and use a good recording software, try recording your mouse in your monitor's full FPS. Now play it in slow motion, like 1/10 speed.
You'll notice that the mouse cursor doesn't pass through every pixel on the screen. If it did, it could either...
To fix this, every OS makes the mouse jump/skip to the required pixel every frame.
... and thus, your problem.
Upvotes: 2