A Rubber Band Selection Highlight Box For The Web
I recently released a web presentation framework that includes a handy highlighting feature. Below is a video of the highlighting feature in action.
I also provided a ‘bookmarklet’ that you can save to enable this feature on any web page. Let’s examine how this effect was created using HTML, CSS, and magic. Okay not really magic, I have used jQuery but sometimes that is close enough.
Concept
To created the highlight effect we use four transparent overlays that cover the areas that surround the area we want to highlight.
The area to highlight is set using the mouse to click and drag a ‘rubber banding box’. The overlays are then dynamically positioned.
HTML
The HTML elements that are needed to create this effect are provided by the following markup.
<div id="topmask" class="highlight-mask"></div> <div id="leftmask" class="highlight-mask"></div> <div id="rightmask" class="highlight-mask"></div> <div id="bottommask" class="highlight-mask"></div> <div id="dragmask" class="highlight-drag"></div>
The top four elements in the above markup define the four masks (top, right, bottom, left) and the last element is used to create the ‘rubber banding box’.
CSS
The above markup is styled using the following:
.highlight-mask { background: transparent url('../images/theme/transBlack75.png') repeat 0 0; display: none; position: absolute; } .highlight-drag { background-color: transparent; border: dashed #ff3333 3px; position: absolute; display: none; }
All the elements are initially hidden and will be absolutely positioned using jQuery (see below). The mask areas use an image to create the transparent effect. The image is simply a 10×10 pixel square filled with black (#000000) with a 25% transparency (mostly opaque). The ‘rubber banding box’ has a transparent background and a 3 pixel wide dashed red (#ff3333) border.
JavaScript / jQuery
This effect is dynamically created using JavaScript. There are many times that a user may click and drag on a web page. We want to have a specific key combination to enable the highlighter. I have selected the SHIFT key as the enabler. So holding the SHIFT key while click and dragging is the mechanism of creating a highlight region. The highlight region is removed by pressing the ESC key. The following code enables enables the highlighter by monitoring the SHIFT key (keyCode = 16).
var isHighlightEnabled = false; $(document).keydown(function(event){ if(event.keyCode==16){ // enable the highlighter isHighlightEnabled = true; } }); $(document).keyup(function(event){ if(event.keyCode==16){ // disaable the highlighter isHighlightEnabled = false; } else if(event.keyCode==27){ // hide the highlighter divs $(".highlight-mask").hide(); $("#dragmask").hide(); } });
When the SHIFT key is pressed, the highlighter is enabled and when the SHIFT key is released the highlighter is disabled. The above code also monitors the ESC key (keyCode = 27) and hides the highlighter elements if the key is released.
The mouse events are used to define the highlighter region. The ‘mousedown’, ‘mousemove’, and ‘mouseup’ events are all used. The ‘mousedown’ event begins the highlight process.
var startX, startY; var isDragging = false; $(document).mousedown(function(event){ if(isHighlightEnabled){ startX = event.pageX; startY = event.pageY; isDragging = true; $("#dragmask").css( { 'left' : startX, 'top' : startY, 'width' : 0, 'height' : 0 } ).show(); // prevent default behavior of text selection return false; } });
If the SHIFT key is pressed a ‘mousedown’ saves the current mouse position (event.pageX and event.pageY), sets the ‘isDragging’ flag, shows the ‘rubber banding div’ and finally prevents the default behavior. The default behavior includes selecting text on the page and this degrades the highlighter experience.
$(document).mousemove(function(event){ if(isDragging){ var left, top, width, height; if(event.pageX>startX){ left = startX; width = event.pageX - startX; } else { left = event.pageX; width = startX - event.pageX; } if(event.pageY>startY){ top = startY; height = event.pageY - startY; } else { top = event.pageY; height = startY - event.pageY; } $("#dragmask").css( { 'left' : left, 'top' : top, 'width' : width, 'height' : height } ); } });
The ‘mousemove’ code updates the ‘rubber banding’ div position and size to track the current mouse position. The above code will keep one corner pinned at the position where the ‘mousedown’ event occurred, and dynamically position the opposite corner to the current position.
$(document).mouseup(function(event){ if(isDragging){ isDragging = false; $("#dragmask").hide(); var screenWidth = $(document).width(); var screenHeight = $(document).height(); var topOfHighlight, bottomOfHighlight; if(event.pageY>startY){ topOfHighlight = startY; bottomOfHighlight = event.pageY; } else{ topOfHighlight = event.pageY; bottomOfHighlight = startY; } var leftOfHighlight, rightOfHighlight; if(event.pageX>startX){ leftOfHighlight = startX; rightOfHighlight = event.pageX; } else { leftOfHighlight = event.pageX; rightOfHighlight = startX; } //position the top mask $("#topmask").css( { 'left' : 0, 'width' : screenWidth, 'top' : 0, 'height' : topOfHighlight } ).show(); // position the bottom mask $("#bottommask").css( { 'left' : 0, 'width' : screenWidth, 'top' : bottomOfHighlight, 'height' : screenHeight - bottomOfHighlight } ).show(); // position the left mask $("#leftmask").css( { 'left' : 0, 'width' : leftOfHighlight, 'top' : topOfHighlight, 'height' : bottomOfHighlight - topOfHighlight } ).show(); // position the right mask $("#rightmask").css( { 'left' : rightOfHighlight, 'width' : screenWidth - rightOfHighlight, 'top' : topOfHighlight, 'height' : bottomOfHighlight - topOfHighlight } ).show(); } });
When the mouse is released the ‘mouseup’ event hides the ‘rubber banding’ box and position/shows each of the transparent overlay masks.
Summary
The code above creates a nice web-based highlighter tool. However, the ability to display a ‘rubber banding selection box’ is useful in many scenarios. For instance, you could use this technique to select a region on an image that would define a zoom.