JavaScript
Article

Writing a Mousestop Event Plugin Using jQuery

By Sam Deering

I recently published a jQuery tooltip plugin of my own that was pretty simple, it basically popped up when you hovered over an element, nothing fancy. However I noticed the default browser had a bit of a delay before it actually shows up. It also won’t show up until you stop moving your mouse around on the element. Lastly there was only a certain amount of time you had to stop moving your mouse before the tooltip didn’t appear at all.

I wanted to rebuild this functionality and ended up writing my own little mousestop event plugin in jQuery which I thought I would share. It’s a pretty simple little piece of code that basically triggers when a mouse stops over a certain element with a few options for the timers.

You can check out documentation on it here: jQuery mousestop plugin
Also check it out in action with my tooltip plugin here: jQuery tooltip plugin

1. The mouse stop event

First we just want to know how to detect a mouse stop, this is actually pretty easy and only requires a single timer to constantly loop until enough delay has occurred.

var movementTimer = null;

    $("#element").mousemove(function(e)
    {
    	clearTimeout(movementTimer);
    	movementTimer = setTimeout(function()
    	{
    		//do something here
    	}, 300);
    })

2. Stopping the Timer on Mouseout

We have our mousestop working, but now what happens when we mouseout of the element? We wouldn’t want mousestop event to trigger, since we are technically not stopping on the element. All we need to do here is add a mouseout event that clears our timer to make sure it doesn’t get executed.

var movementTimer = null;

    $("#element").mouseout(function(e)
    {
    	clearTimeout(movementTimer);
    })

3. Setting the Grace Period

Here is where it starts getting tricker. If we want to set an amount of time that the mousestop event has to trigger before it’s completely turned off, we will need to introduce a second timer.

var counter = 0;
    var counterMax = 20;
    var movement = false;

    elem
    .mouseover(function(e)
    {
    	movement = true;
    	
    	//check if movement has stopped to a maximum time of 100*counterMax, after that event will not run at all unless you re-mouseover
    	displayTimer = setInterval(function()
    	{
    		counter++;
    		
    		if(counter < counterMax)
    		{
    			if(!movement)
    			{
    				//run some code
    			}
    			//else do nothing, just iterate
    		}
    	}, 100)
    })
[/js]

This starts a timer that checks to see if movement has stopped, which would be set by our previous timer. The max here is 20 intervals for 100 milliseconds each giving us a two second grace period. Since this timer now controls our function, if it does not execute within the grace period, we are done.

4. Getting Proper Coordinates There is one more crucial piece here that we need to add. Since we are running this from the mouseover event, our event.pageX and event.pageY coordinates will be from where they entered the element, however we will probably want the mouse position of where it is now while the mouse is moving around. [js] var x = null; var y = null; var movementTimer = null; $("#element").mousemove(function(e) { x = e.pageX; y = e.pageY; })

5. Putting It All Together

We can now put this all together into a plugin like below. This little jQuery plugin has less than 100 lines of code, and is less than 1KB in size when minified.

(function($)
{
var defaultSettings =
{
timeToStop : null, // the amount of time the stop even thas to run before it will not run at all anymore
delayToStop : ‘300’, // the delay for what is considered a “stop”
onMouseout : null, // function to run when we mouseout of our element
onStopMove : null // function to run when we start moving again after the stop
};

$.fn.mousestop = function(func, settings)
{
settings = $.extend({}, defaultSettings, settings || {});

return this.each(function()
{
var elem = $(this);

var movement = false;

var displayTimer = null
var movementTimer = null;

//only need this piece if there is a time limit on when the mouse stop can occur.
if(settings.timeToStop != null)
{
var x = null;
var y = null;

var counter = 0;
var counterMax = Math.ceil(settings.timeToStop / 100);

elem
.mouseover(function(e)
{
movement = true;

//check if movement has stopped to a maximum time of 100*counterMax, after that event will not run at all unless you re-mouseover
displayTimer = setInterval(function()
{
counter++;

if(counter < counterMax) { if(!movement) { clearTimeout(displayTimer);//clear the timeout to avoid any funkiness //set the coordinates for the event to the ones from the document event e.pageX = x; e.pageY = y; func(e); } //else do nothing, just iterate }else movement = false;//we can turn this off to avoid using the timeout in the mousemove }, 100) }) } elem .mouseout(function(e) { //kill this timers incase it's still running clearTimeout(displayTimer); clearTimeout(movementTimer); counter = 0;//reset counter for when we mouseover again movement = false;//set movement back to false settings.onMouseout(e);//call our mouseout }) .mousemove(function(e) { x = e.pageX; y = e.pageY; if(movement)//if we have moused over this will be on { //clear timer and set again, this will determine our "stop" which will occur if mouse is in same position for the delayToStop time or more milliseconds clearTimeout(movementTimer); movementTimer = setTimeout(function() { movement = false; if(settings.timeToStop == null) func(e); }, settings.delayToStop); } else { settings.onStopMove(e);//call our mousemove - this is after the stop movement = true; } }); }); } })(jQuery); [/js] We really end up providing three types of functionality for our plugin that we can use now. The first is the mousestop that triggers anytime we stop the mouse for a given period of time. The second functionality lets us set the mousestop event only once, which we can do by just setting the timeout really high. The third is the grace period for the mousestop event to be able to trigger at all. This plugin really didn't take that long to develop especially using jQuery, it really was just a matter of setting some flags on off in the correct order for the timers to function properly. All in all a nice little plugin that gives us an extra event to play with in our code.

About the Author
websanova
Robert Nova is a web developer with a particular interest in jQuery plugins and finding ways to help developers build their projects as quickly as possible. He is founder of www.websanova.com, a site dedicated to jQuery plugins and other entrepreneurial resources.

Free Guide:

7 Habits of Successful CTOs

"What makes a great CTO?" Engineering skills? Business savvy? An innate tendency to channel a mythical creature (ahem, unicorn)? All of the above? Discover the top traits of the most successful CTOs in this free guide.

  • Sim

    Hi , this plugin don’t work for dynamic element like this :

    $(“.myClass”).live(‘mousestop’ ,function (event) {
    //do some function
    });

    also , this plagin has problem with popover bootstrap.

    thanks

Recommended
Sponsors
Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in JavaScript, once a week, for free.