Implementing Event Latency in JavaScript
Handling browser events in JavaScript is probably the most time-consuming, frustrating, and misunderstood aspects of client-side programming. Libraries such as jQuery make it easier, but it’s still useful to have a little knowledge of what’s going on beneath the surface.
In this article, we will implement event latency, i.e. the response to an event will occur a little time after it fired. This is often useful in situations such as creating drop-down menus. So let’s start with a little HTML and CSS code (it’s kept brief for the purpose of this example, hence no DOCTYPE)…
<html>
<head>
<title>Latency test</title>
<style type="text/css">
#element1
{
width: 20em;
margin: 20px;
background-color: #dff;
border: 2px solid #00d;
}
#para1
{
text-align: center;
padding: 10px;
margin: 30px;
background-color: #ccc;
border: 1px solid #000;
}
</style>
</head>
<body>
<div id="element1">
<p id="para1">Hover over me...</p>
</div>
</body>
</html>
This just produces a box similar to the following…
Now we’ll add a little JavaScript just before the closing body
tag…
<script type="text/javascript">
window.onload = function() {
// get nodes
var element1 = document.getElementById("element1");
var para1 = document.getElementById("para1");
// define events
if (element1 && para1) {
element1.onmouseover = Handler;
element1.onmouseout = Handler;
}
// event handler
function Handler(e) {
e = (e ? e : window.event);
var on = (e.type == "mouseover");
Highlight(on);
return false;
}
// highlight or dim element (pass true|false)
function Highlight(on) {
para1.firstChild.nodeValue = (on ? "over" : "out");
element1.style.backgroundColor = (on ? "#ffd" : "#dff");
if (!on) alert("moved out");
}
};
</script>
This adds a couple of (DOM0) events that fire when the cursor moves over or out of the light-blue element1 div
. An event Handler function is called to sort out IE inconsistencies and discover whether a mouse over or out event was fired. The Highlight function is passed true (mouse over) or false (mouse out) and it changes the paragraph text and background color accordingly. Finally, if the mouse is moved out, an alert box is shown.
The script works, however, when we move the mouse into the grey paragraph box the “moved out” alert appears. This occurs because the browser fires two events – a mouseout for element1 and a mouseover for para1. Although we did not delegate an event handler for para1, browsers implement a technique known as bubbling and events will propagate through all element1’s descendants.
In this example, we only care if the last event fired was a mouseout that was not immediately followed by a mouseover. We can therefore fix the problem in our Handler() function with a little event latency:
var timer;
function Handler(e) {
e = (e ? e : window.event);
var on = (e.type == "mouseover");
if (timer) clearTimeout(timer);
timer = setTimeout( function() { Highlight(on); }, 300);
return false;
}
When an event occurs, we clear any existing timeout. A new timeout is then created which calls the Highlight function after 300 milliseconds (Highlight(on) is contained in a function so the value of ‘on’ is retained by the closure). This process makes it impossible for Highlight() to be executed any more frequently than every 300 milliseconds. When it is called, only the most recent value of ‘on’ is available.
Reload the page and you will notice that there is a short delay before any event animation occurs. In addition, the alert will only appear when you move outside of the blue #element1 box.
I hope you find the technique useful in other JavaScript projects.