Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Countdown timer 'delays' when tab is inactive?

Trying to build a very simple Javascript countdown. However, whenever the tab is inactive, the countdown begins to lag and holds an incorrect count.

See jsfiddle here for example: https://jsfiddle.net/gbx4ftcn/

function initTimer(t) {

  var self = this,
    timerEl = document.querySelector('.timer'),
    minutesGroupEl = timerEl.querySelector('.minutes-group'),
    secondsGroupEl = timerEl.querySelector('.seconds-group'),

    minutesGroup = {
      firstNum: minutesGroupEl.querySelector('.first'),
      secondNum: minutesGroupEl.querySelector('.second')
    },

    secondsGroup = {
      firstNum: secondsGroupEl.querySelector('.first'),
      secondNum: secondsGroupEl.querySelector('.second')
    };

  var time = {
    min: t.split(':')[0],
    sec: t.split(':')[1]
  };

  var timeNumbers;

  function updateTimer() {

    var timestr;
    var date = new Date();

    date.setHours(0);
    date.setMinutes(time.min);
    date.setSeconds(time.sec);

    var newDate = new Date(date.valueOf() - 1000);
    var temp = newDate.toTimeString().split(" ");
    var tempsplit = temp[0].split(':');

    time.min = tempsplit[1];
    time.sec = tempsplit[2];

    timestr = time.min + time.sec;
    timeNumbers = timestr.split('');
    updateTimerDisplay(timeNumbers);

    if (timestr === '0000')
      countdownFinished();

    if (timestr != '0000')
      setTimeout(updateTimer, 1000);

  }

  function animateNum(group, arrayValue) {

    TweenMax.killTweensOf(group.querySelector('.number-grp-wrp'));
    TweenMax.to(group.querySelector('.number-grp-wrp'), 1, {
      y: -group.querySelector('.num-' + arrayValue).offsetTop
    });

  }

  setTimeout(updateTimer, 1000);

}

I'm unsure whether the problem lies with the animation, or with the JS code itself.

For clarification: I want the countdown to continue when the tab is inactive, or to 'catch up with itself' when the tab comes back in to focus.

I know that setTimeout and setInterval can cause issues with inactive tabs, but I'm not entirely sure how to fix this.

Any help would be much appreciated!

like image 894
Adam Ayrton Stoner Avatar asked Mar 11 '23 00:03

Adam Ayrton Stoner


1 Answers

For this you can use the HTML5 Visibility API for detecting if the browser tab is active or not. And use regular binding of event handlers for focus and blur for the browser window.

Basically you pause() the timeline when you blur out of the tab, and then play() when you give the tab refocus. Example of this in action:

http://codepen.io/jonathan/pen/sxgJl

// Set the name of the hidden property and the change event for visibility
var hidden, visibilityChange; 
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support 
   hidden = "hidden";
   visibilityChange = "visibilitychange";
} else if (typeof document.mozHidden !== "undefined") {
    hidden = "mozHidden";
    visibilityChange = "mozvisibilitychange";
} else if (typeof document.msHidden !== "undefined") {
    hidden = "msHidden";
    visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
    hidden = "webkitHidden";
    visibilityChange = "webkitvisibilitychange";
}

// If the page is hidden, pause the video;
// if the page is shown, play the video
function handleVisibilityChange() {
   if (document[hidden]) {
      tl.pause();
   } else {
      tl.play();
   }
}

// Warn if the browser doesn't support addEventListener or the Page Visibility API
if (typeof document.addEventListener === "undefined" || typeof document[hidden] === "undefined") {
   // do nothing or throw error via alert()
   alert("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
} else {
   // Handle page visibility change 
   // Pause timeline  
   tl.pause();
}

HTML5 Visibility Docs:

https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API

Regarding GreenSock Forum Topic:

http://forums.greensock.com/topic/9059-cross-browser-to-detect-tab-or-window-is-active-so-animations-stay-in-sync-using-html5-visibility-api/

Also in GSAP the equivalent for setTimeout() is delayedCall()

Provides a simple way to call a function after a set amount of time (or frames). You can optionally pass any number of parameters to the function too.

GSAP delayedCall(): http://greensock.com/docs/#/HTML5/GSAP/TweenMax/delayedCall/

//calls myFunction after 1 second and passes 2 parameters:
TweenMax.delayedCall(1, myFunction, ["param1", "param2"]);

function myFunction(param1, param2) {
    //do stuff
}

I hope this helps!

like image 87
Jonathan Marzullo Avatar answered Mar 20 '23 17:03

Jonathan Marzullo