Run canvas on background tab
Asked Answered
D

3

6

I have recently created a HTML5 canvas animation (also using Processing.js).

The problem is that when I switch the browser to a different tab the animation stops playing.

How can I allow the animation to keep playing while the user is on a different tab than the one containing the animation?

Example: http://jsfiddle.net/EyFTr/3/

If you switch tabs the clock stops, but if you open the link a new window and blur the window the clock will still move.

Dink answered 20/6, 2012 at 15:29 Comment(8)
You have an example or a jsfiddle?Nickelic
It works for me in Chrome. What browser are you looking at?Berserker
@Ibstr Look at what time the clock shows, go to a different tab, wait 10 seconds, go back. The clock is not 10 seconds more than it was before.Dink
@Cristy hmm, it is for me. I've got my wrist watch here to count with. I've been switching tabs right when the second hand is at 0 and then when I go back after 15 seconds, its at the 15 second mark.Berserker
Ok, sorry, actually the example is bad, I got it from processing.js examples the clock does not use incrementation, it gets the time at each step, let me update the exampleDink
There, I have created myself an example, you should be able to see the 'problem' now.Dink
@Cristy OK your new example is great. Also check out mine that I posted in the comments below Loktar's answer. It looks like yours stops completely, whereas mine seems to just run a little slower (I think setInterval is limited to 1000ms as Loktar suggested). I'm not sure why Processing.js stops completely.Berserker
@Berserker oh weird.. yeah I looked at the github and processing uses setTimeout to my knowledge. However if im wrong and they are using requestAnimationFrame instead it would make sense, since that stops completely when the tab is inactive.Dowd
D
4

The short answer is you can't.

https://developer.mozilla.org/en/DOM/window.setTimeout

In (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) and Chrome 11, timeouts are clamped to firing no more often than once per second (1000ms) in inactive tabs; see bug 633421 for more information about this in Mozilla or crbug.com/66078 for details about this in Chrome.

Browsers in question are a bit old in that quote but its still relevant. This is by design. Its to reduce processor load when the tab isn't active. (Processing.js uses setTimeout for animations)

Theres a few ways to "fix" this. They involve checking the time, and calculating where the object "should" be based on the time, once the tab becomes active. In your example however though it looks like your code will do that, since its a clock which is based the time anyway.

Dowd answered 20/6, 2012 at 15:37 Comment(6)
Right, but since the code is getting a new Date() every time, it should just update as soon as the tab comes back into focus. Right?Berserker
@Berserker yeah I just edited my answer. She may get that weird "catch up" animation where you see the hand jump after first switching to the tab, but other than that it should be right.Dowd
Here is a good illustration of the problem. When the tab is active, you get one new row per second. When you switch tabs, however, and come back, you will count fewer rows than you would expect.Berserker
@Berserker jsfiddle.net/loktar/TTnbg/3 made it a bit more relevant since processing uses setTimeout This would be a case though where you would check the time and make sure the correct amt of iterations ran.Dowd
Here is a potential solution. It uses timestamps to determine the number of iterations that were missed, and then tries to make up for them. It seems appropriate for some applications, but not for Processing.js since the intervals are done internally. Feedback?Berserker
@Berserker Id post a separate answer, thats what I meant with my last comment about checking the time. But you put a lot of effort into the fiddle you should at least get some points for it.Dowd
B
3

As Loktar suggested, this symptom could be alleviated by checking the time and figuring out where you should be. Here is a function that could do this:

function smartInterval(func, interval){
    var last = new Date() - interval,
        now,
        numMissed;

    (function iterate(){
        func();

        // compute the number of iterations you might have missed
        // if you tabbed away and the interval was restricted to 1000ms
        now = +new Date();
        numMissed = Math.round((now - last) / interval) - 1;

        // make up for those iterations that were lost
        while (numMissed--) { func(); }

        last = +new Date();
        setTimeout(iterate, interval);
    })();
}

Usage:

smartInterval(function(){console.log('hi');}, 100);

Here is a jsFiddle with an example. Try to comment out the while loop (while (numMissed--)) to see that by switching to a tab, you get less numbers. With the while loop there, however, it appears as if the interval has never changed.

Unfortunately, this might not be of any use to you since you are using Processing.js and the timeouts are set internally.

Berserker answered 20/6, 2012 at 17:21 Comment(3)
still a good answer for other people who come across this. +1Dowd
I'll try to solve the problem using the same algorithm (at each frame save the 'last' time and check if 'now'-'last' is larger [tab was switched] update the missing frames). One problem could be that when the user switches back to the curent tab the animation will be played in fast-forward :DDink
@Cristy I was wondering if that would happen! In my example, each step occurs fast enough that it seems to update instantly, but I could imagine a situation where you might see some lag while its catching up. Let me know how it goes!Berserker
M
1

See setInterval not working properly on Chrome . Essentially browsers will mess around with setInterval when backgrounded to improve performance, so you can't control exactly what happens.

Micrometeorology answered 20/6, 2012 at 15:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.