I have a div displaying some horizontally scrollable images with white-space:nowrap; overflow-x:scroll and i'm trying to make the function below work:
var mouseIsInDiv = false;
function autoScroll() {
var i = 1;
while (mouseIsInDiv = false) {
setTimeout(function(){
document.getElementById("theDiv").scrollLeft = i;
i++;
},50);
}
}
It is supposed to loop through (while the mouse is not within this scrollable div) incrementing the scroll position by 1px every 50 miliseconds. In other words it's supposed to scroll through the images automatically when this function is called. I'm not getting any syntactic errors but whenever i press a button that calls this function on a webpage, the browser crashes completely - I'm using the latest versions of Chrome, Safari and Firefox. Any ideas would be really helpful, I've been tearing my hair out over this!
Your loop creates many timeouts that happens in the same time (after 50 milisecs) you need to set the timeout recursivly, inside the set timeout function, and ask if mouseISInDiv inside the set timeout function as well.
The current code state, the loop will run many many times in a small amount of time, and page will crush(it's liek infinite) and after 50 millisecs there will be many set timeouts that ran.
I had a fun time working on this one, so I'll post my response despite the correct answer already having been accepted.
Basically, you need to restructure everything so that the whole scheme is asynchronous. That means event listeners respond to mouse movement, and there are no while loops.
Thus, I present this fiddle. Here is the javascript:
var mouseIsInDiv = false;
var theDiv = document.getElementById("theDiv");
theDiv.onmouseover = function() { mouseIsInDiv = true; };
theDiv.onmouseout = function() {
mouseIsInDiv = false;
scrollLeft1();
};
function scrollLeft1() {
if (mouseIsInDiv == false && theDiv.scrollLeft < theDiv.clientWidth) {
theDiv.scrollLeft += 1;
setTimeout(scrollLeft1, 50);
}
}
scrollLeft1();
As you can see, the function calls itself recursively and asynchronously, and the whole thing can be restarted after manually resetting the scroll. You could also add an event listener for the scroll completion.
Related
I have a block of code that executes when a button is clicked. The code uses a loop that sometimes takes a while to complete. When the user clicks the button, I want the cursor to change a "wait" cursor before the loop begins. Once the loop is finished, the cursor should return to normal.
What is actually happening (in Chrome for Windows at least) is that the style doesn't get updated until after the loop. It seems to be a quirk of how buttons work. I really don't know. I'm out of guesses!
A sample fiddle: http://jsfiddle.net/ra51npjr/1/ (it just uses console.log to execute "something"... you might need to change how many times the loop runs depending on how zippy or slow your machine is).
Sample HTML:
<div class="fakebody">
<button id="foo">Foo</button>
</div>
Sample CSS:
.fakeBody {
height: 1000px;
width: 100%;
}
.wait {
cursor: wait !important;
}
Sample JavaScript:
$('#foo').on('click', function (e) {
$('.fakebody').addClass('wait');
for (i = 0; i < 10000; i++) {
console.log(i);
}
$('.fakebody').removeClass('wait');
});
--
Here are my ASSUMPTIONS on how the script should work:
The click happens, which fires up the code. Indeed, if I log "started!" inside the code block, it will correctly log that it has started
The cursor should be a wait cursor so long as it is hovering anywhere over "fakebody".
The for loop is just a simple way to kill a few seconds to see the effect. Feel free to substitute any other loop that takes a while to complete
At the end of the loop, the cursor is no longer a wait cursor
What is actually happening:
The loop executes
At the end of the loop, the cursor turns to a "wait" cursor and then instantly back to a regular cursor. The change doesn't happen until the loop is complete
Does anybody know a technique or workaround to get the cursor to change before the loop starts instead of only after it is finished? Is this known behaviour that I need to educate myself about (and if so, do you know where I should start looking?)
This is a common issue in JavaScript. This question may provide some deeper insight, but essentially the point is that synchronous JavaScript execution must finish before the browser can perform other actions (like updating the view).
Because .addClass, the for loop, and .removeClass all occur synchronously, the browser doesn't get a chance to redraw anything. A technique that is often used in these cases is to setTimeout with a timeout of 0, which essentially just "yields" control back to the browser.
$('.fakebody').addClass('wait');
setTimeout(function() {
for (i = 0; i < 10000; i++) {
console.log(i);
}
$('.fakebody').removeClass('wait');
}, 0);
If this is a common pattern, you could potentially extract it out to a function (which would also help improve readability) that wraps the async setTimeout. Here's a simple example:
/**
* Wraps a long-running JavaScript process in a setTimeout
* which yields to allow the browser to process events, e.g. redraw
*/
function yieldLongRunning(preFn, fn, postFn, ctx) {
if (arguments.length <= 2) {
ctx = fn; fn = preFn;
preFn = postFn = function() {};
}
preFn.call(ctx);
setTimeout(function() {
fn.call(ctx);
postFn.call(ctx);
}, 0);
}
And use it like so:
yieldLongRunning(function() {
$('.fakebody').addClass('wait');
},
function() {
for (i = 0; i < 10000; i++) {
console.log(i);
}
},
function() {
$('.fakebody').removeClass('wait');
});
As a side point, note that setTimeout(..., 0) simply queues the function in the browser's event loop, alongside other queued JavaScript functions, as well as other types of events (like redraws). Thus, no setTimeout call is guaranteed to run precisely at the given time - the timeout argument is simply a lower-bound (and, in fact, there is a minimum timeout of 4ms specified by HTML5 spec, which browsers use to prevent infinite timeout loops; you can still use 0, though, and the browser will add it to the event queue after the minimum delay).
I think you should try to force a redraw by hiding + showing the parent element.
Try this:
document.getElementById('fakebody').style.display = 'none';
document.getElementById('fakebody').style.display = 'block';
Before and after the loop (i.e. when you want the child element "foo" to refresh.
EDIT: Since you're using jquery you could do this:
$('#fakebody').hide().show(0);
Demo - Use queue & dequeue to construct an order of what should happen when in jQuery.
$('#foo').on('click', function (e) {
$('.fakebody').addClass('wait').queue(function(n) {
for (i = 0; i < 10000; i++) { console.log(i); }
}).removeClass('wait').dequeue();
});
Context
I've got about 10 complex graphs which take 5sec each to refresh. If I do a loop on these 10 graphs, it takes about 50 seconds to refresh. During these 50 seconds, the user can move a scrollbar. If the scrollbar is moved, the refresh must stop and when the scrollbar stops to move, the refresh occurs again.
I'm using the setTimeout function inside the loop to let the interface refresh.
the algorithm is :
render the first graph
setTimeout(render the second graph, 200)
when the second graph is rendered, render the third one in 200ms, and so on
The setTimeout allows us to catch the scrollbar event and to clearTimeout the next refresh to avoid to wait 50sec before moving the scrollbar...
The problem is that it does not run anytime.
Take the simple following code (you can try it in this fiddle : http://jsfiddle.net/BwNca/5/) :
HTML :
<div id="test" style="width: 300px;height:300px; background-color: red;">
</div>
<input type="text" id="value" />
<input type="text" id="value2" />
Javascript :
var i = 0;
var j = 0;
var timeout;
var clicked = false;
// simulate the scrollbar update : each time mouse move is equivalent to a scrollbar move
document.getElementById("test").onmousemove = function() {
// ignore first move (because onclick send a mousemove event)
if (clicked) {
clicked = false;
return;
}
document.getElementById("value").value = i++;
clearTimeout(timeout);
}
// a click simulates the drawing of the graphs
document.getElementById("test").onclick = function() {
// ignore multiple click
if (clicked) return;
complexAlgorithm(1000);
clicked = true;
}
// simulate a complexe algorithm which takes some time to execute (the graph drawing)
function complexAlgorithm(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
document.getElementById("value2").value = j++;
// launch the next graph drawing
timeout = setTimeout(function() {complexAlgorithm(1000);}, 1);
}
The code does :
when you move your mouse into the red div, it updates a counter
when you click on the red div, it simulates a big processing of 1sec (so it freezes the interface due to javascript mono thread)
after the freezing, wait 1ms, and resimulate the processing and so on until the mouse move again
when the mouse move again, it breaks the timeout to avoid infinite loop.
The problem
When you click one time and move the mouse during the freeze, I was thinking that the next code that will be executed when a setTimeout will occurs is the code of the mousemove event (and so it will cancel the timeout and the freeze) BUT sometimes the counter of click gains 2 or more points instead of gaining only 1 point due to the mouvemove event...
Conclusion of this test : the setTimeout function does not always release resource to execute a code during a mousemove event but sometimes kept the thread and execute the code inside the settimeout callback before executing another code.
The impact of this is that in our real example, the user can wait 10 sec (2 graphs are rendered) instead of waiting 5 seconds before using the scrollbar. This is very annoying and we need to avoid this and to be sure that only one graph is rendered (and other canceled) when the scrollbar is moved during a render phase.
How to be sure to break the timeout when the mouse move ?
PS: in the simple example below, if you update the timeout with 200ms, all runs perfectly but it is not an acceptable solution (the real problem is more complex and the problem occurs with a 200ms timer and a complex interface). Please do not provide a solution as "optimize the render of the graphs", this is not the problem here.
EDIT : cernunnos has a better explanation of the problem :
Also, by "blocking" the process on your loop you are ensuring no event can be handled until that loop has finished, so any event will only be handled (and the timeout cleared) inbetween the execution of each loop (hence why you sometimes have to wait for 2 or more full executions before interrupting).
The problem is exactly contains in bold words : I want to be sure to interrupt the execution when I want and not to wait 2 or more full executions before interrupting
Second EDIT :
In summary : takes this jsfiddle : http://jsfiddle.net/BwNca/5/ (the code above).
Update this jsfiddle and provide a solution to :
Mouse move on the red div. Then click and continue moving : the right counter must raise only once. But sometimes it raises 2 or 3 times before the first counter can run again... this is the problem, it must raise only once !
The BIG problem here is setTimeout is unpredictable once it started, and especially when it is doing some heavy lifiting.
You can see the demo here:
http://jsfiddle.net/wao20/C9WBg/
var secTmr = setTimeout(function(){
$('#display').append('Timeout Cleared > ');
clearTimeout(secTmr);
// this will always shown
$('#display').append('I\'m still here! ');
}, 100);
There are two things you can do to minimize the impact on the browser performance.
Store all the intances of the setTimeoutID, and loop through it when you want to stop
var timers = []
// When start the worker thread
timers.push( setTimeout(function () { sleep(1000);}, 1) );
// When you try to clear
while (timers.length > 0) {
clearTimeout(timers.pop());
}
Set a flag when you try to stop process and check that flag inside your worker thread just in case clearTimeout failed to stop the timer
// Your flag
var STOPForTheLoveOfGod = false;
// When you try to stop
STOPForTheLoveOfGod = true;
while (timers.length > 0) {
clearTimeout(timers.pop());
}
// Inside the for loop in the sleep function
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if (STOPForTheLoveOfGod) {
break;
}
// ...
}
}
You can try out this new script.
http://jsfiddle.net/wao20/7PPpS/4/
I may have understood the problem but assuming you are trying to block the interface after a click for a minimum of 1 second and unblocking it by moving the mouse (after that 1 second minimum):
This is not a good implementation of sleep, as you are keeping the process running the whole time (doing nothing != sleeping), this results in a waste of resources.
Why not create an overlay (a semi/fully transparent div), put it on top of the rest of the interface (position fixed, full width and full height) and use it to prevent any interaction with the underlying interface. Then destroy it when the conditions are right (a second has passed and the user moved the mouse).
This behaves more like a sleep (has some initial processing time but then releases the processor for a given amount of time) and should help you achieve the behavior you need (assuming i understood it right).
It has the added bonus of allowing you to give the user some visual cue that some processing is being done.
Edit:
Also, by "blocking" the process on your loop you are ensuring no event can be handled until that loop has finished, so any event will only be handled (and the timeout cleared) inbetween the execution of each loop (hence why you sometimes have to wait for 2 or more full executions before interrupting).
Surprising enough you have not figured out that, when you setTimeout(); you can input a check after that. A variable is true then trash the wait, or trash it. Now there is a method that you can check to scroll with a scroll bar. After you have checked it true inside a variabled using the means, then you will find this will repeat inifite times as they scroll the bar, making many executing times of 5 seconds. To fix this add a 1 second wait to make sure it doesn't over repeat. Your welcome :)
Any long-running function is going to tie up your browser window. Consider moving your complexAlgorithm() outside of your main javascript code using WebWorkers.
The answer is in your question
...the refresh must stop and when the scrollbar stops to move, the
refresh occurs again.
You should write complexAlgorithm in such way that you can almost instantly brake it in a middle (just when you know you will have to re run)
so main code should look something like
stopAllRefresh; //should instantly(or after completing small chunk) stop refresh
setTimeout(startRefresh, 100);
and render graph in small chunks (each runs < 1sec) in setTimeout
like
var curentGraph = 0;
var curentChunk = 0;
function renderGraphChunk(){
if (needToBreak) //check if break rendering
{exit};
// Render chunk here
render(curentGraph, curentChunk);
curentChunk +=1;
setTimeout(renderGraphChunk, 1);
}
this is just a idea sketch, real implementation can be completely different
What you want to do can not be done without web worker, that is only implemented in some latest browser specially Chrome.
Otherwise, you have to break your algorithm in queue. Just like jQuery UI puts every next animation calculation in queue. http://api.jquery.com/jQuery.queue/
It is a simple queue and next instruction set is queued with help of setTimeout.
for (i=0; i <1000; i++)
{
process (i) ;
}
Can be translated to
function queue(s,n, f)
{
this.i=s;
this.n=n;
this.f=f;
this.step = function(){
if ( this.i <this.n)
{
this.f(this.i);
this.i = this.i +1;
var t = this;
setTimeout( function ( ) { t.step(); } , 5);
}
}
this.step();
}
queue ( O, 1000, function(i){
process(i);
}) ;
This is just an example of how Synchronous for loop can be written to execute same logic asynchronously using smaller independent iteration.
Try and check out web workers. I think it will be useful in this situation.
http://en.wikipedia.org/wiki/Web_worker
http://www.html5rocks.com/en/tutorials/workers/basics/
I am trying to make a simple hidden object game using javascript. When the user finds and clicks an image, I want 3 things to happen in the following order; a sound plays, the image size increases, and the image goes invisible. The problem I am running into is getting the 3 events to happen sequentially, not concurrent. Right now, seems that all three events happen all at the same time.
I've tried using setTimeout(), and while that does create a delay, it still runs all functions at the same time, even if each function is nested in setTimeout.
Example: (all this does is waits 1.5 sec then plays the sound and makes the image invisible):
function FindIt(image, id){
var t = setTimeout('sound()',10);
var b = setTimeout('bigger(' + image + ')',30);
var h = setTimeout('hide(' + image + ')',1500);
}
Below are the functions I am currently using and the actual results are: click the image, nothing happens for 2 seconds, then the sound plays and the image goes invisible.
function FindIt(image, id){
sound();
bigger(image);
hide(image);
}
function sound(){
document.getElementById("sound_element").innerHTML= "<embed src='chime.wav' hidden=true autostart=true loop=false>";
}
function bigger(image){
var img = document.getElementById(image);
img.style.width = 112;
img.style.height = 112;
}
function hide(id){
var ms = 2000;
ms += new Date().getTime();
while (new Date() < ms){} //Create a 2 second delay
var img = document.getElementById(id);
img.style.visibility='hidden';
}
Any guidance would be greatly appreciated!
To trigger things sequentially, you need to execute the second item some amount of time after the first one completes, execute the third item some amount of time after the second one completes, etc...
Only your sound() function actually takes some time, so I'd suggest the following:
function FindIt(image, id){
sound();
// set timer to start next action a certain time after the sound starts
setTimeout(function() {
bigger(image);
// set timer to start next action a certain time after making the image bigger
setTimeout (function() {
hide(image);
}, 1000); // set this time for how long you want to wait after bigger, before hide
}, 1000); // set the time here for how long you want to wait after starting the sound before making it bigger
}
FYI, the animation capabilities in libraries like jQuery or YUI make this sort of thing a lot easier.
Also, please don't use this kind of construct in your JS:
while (new Date() < ms){}
That locks up the browser for that delay and is very unfriendly to the viewer. Use setTimeout to create a delay.
For reference, using the animation libraries in jQuery, the jQuery code to handle a click on the object and then animate it over a 2 second period to a larger size, delay for 1 second, then slideup to disappear is as follows:
$("#rect").click(function() {
$(this).animate({height: 200, width: 400}, 2000).delay(1000).slideUp();
});
jQuery manages an animation queue and handles setting all the timers and doing all the sequencing and animation for you. It's a lot, lot easier to program and gives a very nice result.
You can see it work and play with it here: http://jsfiddle.net/kC4Mz/.
why don't use "event" approach. like onTaskDone();
function task1(arg, onTask1Done){
console.log(arg);
if(onTask1Done)onTask1Done();
}
task1("working", function(){console.log("task2");});
The Frame.js library is designed to elegantly handle situations like this:
function FindIt(image, id){
Frame(10, function(next) { sound(); next(); });
Frame(30, function(next) { bigger(image); next(); });
Frame(1500, function(next) { hide(image); next(); });
Frame.start();
}
Frame.js offers many advantages over using standard timeouts, especially if you are doing a lot of this kind of thing, which for a game, you likely are.
https://github.com/bishopZ/Frame.js
I have a jQuery slider on my site and the code going to the next slide is in a function called nextImage. I used setInterval to run my function on a timer, and it does exactly what I want: it runs my slides on a timer. BUT, if I go to the site in Chrome, switch to another tab and return, the slider runs through the slides continuously until it 'catches up'. Does anyone know of a way to fix this. The following is my code.
setInterval(function() {
nextImage();
}, 8000);
How to detect when a tab is focused or not in Chrome with Javascript?
window.addEventListener('focus', function() {
document.title = 'focused';
},false);
window.addEventListener('blur', function() {
document.title = 'not focused';
},false);
To apply to your situation:
var autopager;
function startAutopager() {
autopager = window.setInterval(nextImage, 8000);
}
function stopAutopager() {
window.clearInterval(autopager);
}
window.addEventListener('focus', startAutopager);
window.addEventListener('blur', stopAutopager);
Note that in the latest version of Chromium, there is either a bug or a 'feature' which is making this less reliable, requiring that the user has clicked at least once anywhere in the window. See linked question above for details.
I post an answer here: How can I make setInterval also work when a tab is inactive in Chrome?
Just do this:
setInterval(function() {
$("#your-image-container").stop(true,true);
nextImage();
}, 1000);
inactive browser tabs buffer some of the setInterval or setTimeout functions.
stop(true,true) - will stop all buffered events and execute immadietly only last animation.
The window.setTimeout() method now clamps to send no more than one timeout per second in inactive tabs. In addition, it now clamps nested timeouts to the smallest value allowed by the HTML5 specification: 4 ms (instead of the 10 ms it used to clamp to).
A few ideas comes to mind:
Idea #1
You can make it so that a short burst is idempotent. For example, you could say:
function now() {
return (new Date()).getTime();
}
var autopagerInterval = 8000;
function startAutopager() {
var startImage = getCurrentImageNumber();
var startTime = now();
var autopager = setInterval(
function() {
var timeSinceStart = now() - startTime();
var targetImage = getCurrentImageNumber + Math.ceil(timeSinceStart/autopagerInterval);
if (getCurrentImageNumber() != targetImage)
setImageNumber(targetImage); // trigger animation, etc.
},
autopagerInterval
);
return autopager;
}
This way even if the function runs 1000 times, it will still run in only a few milliseconds and animate only once.
note: If the user leaves the page and comes back, it will have scrolled. This is probably not what the original poster wants, but I leave this solution up since it is sometimes what you want.
Idea #2
Another way to add idempotence (while still keeping your nextImage() function and not having it scroll to the bottom of the page) would be to have the function set a mutex lock which disappears after a second (cleared by another timeout). Thus even if the setInterval function was called 1000 times, only the first instance would run and the others would do nothing.
var locked = false;
var autopager = window.setInterval(function(){
if (!locked) {
locked = true;
window.setTimeout(function(){
locked=false;
}, 1000);
nextImage();
}
}, 8000);
edit: this may not work, see below
Idea #3
I tried the following test:
function f() {
console.log((new Date()) + window.focus());
window.setTimeout(f, 1000);
}
f();
It seems to indicate that the function is being called every second. This is odd... but I think this means that the callbacks are being called, but that the page renderer refuses to update the page in any graphical way while the tab is unfocused, delaying all operations until the user returns, but operations keep piling up.
Also the window.focus() function doesn't say if the window has focus; it GIVES focus to the window, and is thus irrelevant.
What we want is probably this: How to detect when a tab is focused or not in Chrome with Javascript? -- you can unset your interval when the window loses focus (blur), and reset it when it gains focus.
I don't know exactly what is going on in your function nextImage(), but I had a similar issue. I was using animate() with setInterval() on a jQuery image slider that I created, and I was experiencing the same thing as you when I switched to a different tab and back again. In my case the animate() function was being queued, so once the window regained focus the slider would go crazy. To fix this I just stopped the animate() function from queuing.
There are a couple ways you can do this. the easiest is with .stop(), but this issue and ways to fix it are documented in the jQuery docs. Check this page near the bottom under the heading additional notes: http://api.jquery.com/animate/
I had faced similar issue, somehow this code below works fine for me.
var t1= window.setInterval('autoScroll()', 8000);
window.addEventListener('focus', function() {
focused = true;
window.clearInterval(t1);
t1 = window.setInterval('autoScroll()', 8000);
},false);
window.addEventListener('blur', function() {
focused = false;
window.clearInterval(t1);
},false)
function autoScroll()
{
if ( running == true){
if ( focused = true){
forwardSlide();
}
}
else {
running = true;
}
}
If you are using Soh Tanaka's image slider then just add this...to solve your Google Chrome issue:
$(".image_reel").stop(true, true).fadeOut(300).animate({ left: -image_reelPosition}, 500 ).fadeIn(300);
Take note of the .stop() function. Ignore the fading in and out stuff, that's what I used on my version
Thanks
Seconding the comment by jgerstle to use page visibility events instead, see https://www.w3.org/TR/page-visibility/#example-1-visibility-aware-video-playback for more around subscribing to 'visibilitychange' for hidden/visible states.
This seems to be more useful than focus/blur these days as it covers visible-but-not-selected windows if concerned also about multi-window operating systems.
In my web app, I use the onkeydown event to capture key strokes.
For example, I capture the 'j' key to animate a scroll down the page (and do some other stuff meanwhile).
My problem is the user might keep the 'j' key down to scroll further down the page (this is equivalent to fast multiple key strokes).
In my app, this result in a series of animations that doesn't look that good.
How can I know when the key has been released, and know the amount of key stokes I should have captured? This way I could run one long animation instead of multiple short ones.
Building on #JMD:
var animate = false;
function startanimation()
{
animate = true;
runanimation();
}
function stopanimation()
{
animate = false;
}
function runanimation()
{
if ( animation_over )
{
if ( !animate )
{
return;
}
return startanimation();
}
// animation code
var timeout = 25;
setTimeout(function(){runanimation();},timeout);
}
document.onkeydown = startanimation;
document.onkeyup = stopanimation;
You'll need to add some checks for starting/ending animations, however.
Edit: added a return to the JS; would've recursed endlessly.
Rather than trying to stack up the animations, you could start an animation on keyDown, and if at the end of the animation you haven't yet received keyUp then start another animation. As soon as you reach the end of an animation and you do have keyUp then you're done.
setTimeout returns a timer ID. So what I would do is after you receive a keyDown event, I would start a timer with a very short wait period, like so:
var globalTimerId = -1;
var keyDownCount = 0;
function handleKeyDown(e) {
if (globalTimerId != -1) {
clearTimeout(globalTimerId);
keyDownCount++;
}
/* 500 means 1/2 a second, adjust for your needs */
globalTimerId = setTimeout(handleKeyDownAfterWait, 500);
keyDownCount = 1;
}
function handleKeyDownAfterWait() {
globalTimerId = -1;
/* keyDownCount will have the number of times handleKeyDown was called */
}
So the idea is that each time a keyDown event is received, the timer is cleared (assuming it hasn't elapsed yet) and restarted. If the timer expires, the user has let go of the key and you can handle that in handleKeyDownAfterWait.
There may be other more elegant solutions with jQuery or another JS library however. This is just something quick and dirty (and possibly buggy ;))
you can try using my repsonsiveness plugin see:
http://notetodogself.blogspot.com/2008/12/jquery-responsiveness-plugin-for-fast.html
see the demo here:
http://doesthatevencompile.com/current-projects/jquery.responsiveness/
the one where you type stuff fast. you can adapt that to your needs. like so:
the animation event will be bound with the plugin, and execute when the user stops doing something fast. you can count how many times he does the fast thing by normal binding of the event.