jqueryhtmlcssfadeto

jQuery fadeTo based on time of day


I'm working on an open source project called BitDay that I started a while ago on Reddit.

I have 12 elements as CSS classes, each has their own background image.

Right now, the jQuery I have fetches the time, and based on the time of day applies an extension to the class name, so every 2 hours the background will change

$(function() {
  $('.clock').hide();
  $('.music').hide();

  //Cache these for performance
  $h1 = $('h1');
  $h3 = $('h3');
  $body = $('body');

  //Sets the font size based on scale
  var setScale = function(elem, scaleFactor) {
    var scaleSource = $body.width(),
      maxScale = 500,
      minScale = 100; //Tweak these values to taste

    var fontSize = scaleSource * scaleFactor; //Multiply the width of the body by the scaling factor:
    if (fontSize > maxScale) fontSize = maxScale;
    if (fontSize < minScale) fontSize = minScale;

    elem.css('font-size', fontSize + '%');
  }

  //Resize fonts
  setScale($h1, .2);
  setScale($h3, .10);

  //Resize font based on windows size
  $(window).resize(function() {
    setScale($h1, .2);
    setScale($h3, .10);
  });

  //Check visited cookie
  var visited = $.cookie("visited")

  if (visited == null) {
    //Fade our title page into the real wallpaper.
    setTimeout(function() {

      //Set the background
      var d = new Date();
      var hour = d.getHours();
      var cssClass = getPicture(hour);

      //Made our waiting div the active div
      $('.bg-tobe').removeClass('bg-tobe').addClass('bg-' + cssClass);

      //Fade out the active and put it in a waiting state
      $('.bg-splash').fadeOut(function() {
        $('.bg-splash').removeClass('bg-splash').addClass('bg-tobe');
      });

      //Fade in the new bg and clock. Fade out the title
      $('.bg-' + cssClass).fadeIn();
      $('.title').fadeOut();

      updateClock();
      $('.clock').fadeIn();
      $('.music').fadeIn();
    }, 0);
  } else {
    //Set the background
    var d = new Date();
    var hour = d.getHours();
    var cssClass = getPicture(hour);

    //Made our waiting div the active div
    $('.bg-tobe').removeClass('bg-tobe').addClass('bg-' + cssClass);
    $('.bg-splash').removeClass('bg-splash').addClass('bg-tobe');

    //Fade in bg and fade out title
    $('.bg-' + cssClass).fadeIn('1000');
    $('.title').fadeOut('slow');

    //Set up clock and music
    updateClock();
    $('.clock').fadeIn('slow');
    $('.music').fadeIn('slow');
  }

  // set cookie
  $.cookie('visited', 'yes', {
    expires: 30,
    path: '/'
  });

  //Start updating the clock
  setInterval('updateClock()', 1000);

});

//Determines the picture to use based on the hour
function getPicture(hour) {
  if (hour >= 23 || hour <= 2)
    return 11;
  else if (hour >= 22)
    return 10;
  else if (hour >= 21)
    return 9;
  else if (hour >= 19)
    return 8;
  else if (hour >= 16)
    return 7;
  else if (hour >= 15)
    return 6;
  else if (hour >= 13)
    return 5;
  else if (hour >= 12)
    return 4;
  else if (hour >= 10)
    return 3;
  else if (hour >= 7)
    return 2;
  else if (hour >= 5)
    return 1;
  else
    return 0;
};

function updateClock() {
  var d = new Date();
  var hours = d.getHours();
  var mins = d.getMinutes();
  var ampm = hours < 12 ? "AM" : "PM";

  //Formatting
  mins = ((mins < 10) ? "0" : "") + mins;
  hours = (hours > 12) ? hours - 12 : hours;
  hours = (hours == 0) ? 12 : hours;
  hours = ((hours < 10) ? "0" : "") + hours;

  var str = hours + ":" + mins + " " + ampm;

  //Set the new time
  var $clock = $('.clock h3');
  var oldStr = $clock.text();
  $clock.text(str);

  //Check if the hour has changed
  var oldHour = getMilitaryHour(oldStr);
  if (oldStr.length == 0) return;
  var currHour = d.getHours();
  if (currHour != oldHour) {

    //Change bgs
    var cssClass = getPicture(currHour);
    var oldClass = getPicture(oldHour);

    if (cssClass != oldClass) {

      //Make our waiting div the active div
      $('.bg-tobe').removeClass('bg-tobe').addClass('bg-' + cssClass);

      //Fade in the new bg
      $('.bg-' + cssClass).fadeIn('5000');

      //Fade out the active and put it in a waiting state
      $('.bg-' + oldClass).fadeOut(function() {
        $('.bg-' + oldClass).removeClass('bg-' + oldClass).addClass('bg-tobe');
      });
    }
  }
};

//Returns the military hour from a string formatted in standard time.
function getMilitaryHour(str) {
  var hour = parseInt(str.substring(0, 2));
  var ampm = str.substring(str.length - 2);

  if (ampm == 'PM' && hour != 12)
    return hour + 12;
  else if (ampm == 'AM' && hour == 12)
    return 0;
  else
    return hour;
}

#container {
    height: 100vh;
    position: relative;
}

.bg {
    width: 100vw;
    height: 100vh;
    position: absolute;
    z-index: 99;
    opacity: 0.7;
}


/* Change the background! */

.bg-0 {
    background-image: url("http://i.imgur.com/qexylYA.png");
    width: 100%;
    height: 100%;
    background-size: cover;
    background-repeat: no-repeat;
    margin: 0;
    padding: 0; }

.bg-1 {
    background-image: url("http://i.imgur.com/cRvIYLJ.png");
    width: 100%;
    height: 100%;
    background-size: cover;
    background-repeat: no-repeat;
    margin: 0;
    padding: 0; }

.bg-2 {
    background-image: url("http://i.imgur.com/UusvZC8.png");
    width: 100%;
    height: 100%;
    background-size: cover;
    background-repeat: no-repeat;
    margin: 0;
    padding: 0; }

.bg-3 {
    background-image: url("http://i.imgur.com/URjIjZS.png");
    width: 100%;
    height: 100%;
    background-size: cover;
    background-repeat: no-repeat;
    margin: 0;
    padding: 0; }

.bg-4 {
    background-image: url("http://i.imgur.com/Fy7kANa.png");
    width: 100%;
    height: 100%;
    background-size: cover;
    background-repeat: no-repeat;
    margin: 0;
    padding: 0; }

.bg-5 {
    background-image: url("http://i.imgur.com/e2lvJ8q.png");
    width: 100%;
    height: 100%;
    background-size: cover;
    background-repeat: no-repeat;
    margin: 0;
    padding: 0; }

.bg-6 {
    background-image: url("http://i.imgur.com/JEslGSe.png");
    width: 100%;
    height: 100%;
    background-size: cover;
    background-repeat: no-repeat;
    margin: 0;
    padding: 0; }

.bg-7 {
    background-image: url("http://i.imgur.com/v2h0qzb.png");
    width: 100%;
    height: 100%;
    background-size: cover;
    background-repeat: no-repeat;
    margin: 0;
    padding: 0; }

.bg-8 {
    background-image: url("http://i.imgur.com/xyfqUsX.png");
    width: 100%;
    height: 100%;
    background-size: cover;
    background-repeat: no-repeat;
    margin: 0;
    padding: 0; }

.bg-9 {
    background-image: url("http://i.imgur.com/XbIlhvL.png");
    width: 100%;
    height: 100%;
    background-size: cover;
    background-repeat: no-repeat;
    margin: 0;
    padding: 0; }

.bg-10 {
    background-image: url("http://i.imgur.com/xDAIc6P.png");
    width: 100%;
    height: 100%;
    background-size: cover;
    background-repeat: no-repeat;
    margin: 0;
    padding: 0; }

.bg-11 {
    background-image: url("http://i.imgur.com/kaCxCBi.png");
    width: 100%;
    height: 100%;
    background-size: cover;
    background-repeat: no-repeat;
    margin: 0;
    padding: 0; }
<div id="container">
    <div class="bg-splash"></div>
    <div class="bg-tobe" style="display: none;"></div>
</div>

But instead of checking the hour and changing instantly, I would like the images to slowly fade into one another, over the course of 2 hours.

So say for example at 7am, bg-1 is applied with 100% opacity. From here, it fades in real time into bg-2. At 8am, bg-1 will be be 50% opacity, 8:30am 25% opacity and so on. All the while bg-2 will slowly be more and more visible. Then at 9am, bg-1 is 0% opacity and bg-2 is 100% opacity and it goes on like that for the next 10 images. It should create a nice graudal transition effect.

Here's the kicker though - As this is going to be a start screen for over thousands of users, we want it to remember the transition amount at any given time, so if a user logs on at 8:30am, it will show bg-1 at 25% opacity, blended into bg-2.

Really racking my brain with this one, could anyone please help?


Solution

  • I've decided to add a new answer to keep the one above preserved, as it works a little bit differently and the answer below is quite more complex.

    I've implemented your "kicker" feature request so that the fading starts somewhere halfway if we're in between two backgrounds (which I call "time blocks" in the comments below). Please see my code below.

    Please note: as I stated in my previous answer, I've had to change the background timings to exact intervals of 2 hours (see bottom of javascript code). The backgrounds might no longer perfectly reflect real life sunset/dawn anymore. Having some backgrounds last for up to 4 hours while others only last for 1 hour would require a lot more coding, so I hope you can live with this :-).

    I have set the timer to 7200000 milliseconds (2 hours), so you'll have to check the console log (and Inspect Element on the background images) to see that it's actually working. I've added a console log to show you at what background images and opacities it starts. For example, right now, since it's almost 3PM here, it will start at background 7 being almost completely faded in:

    CURRENT TIME IS: 14:59. STARTING BACKGROUNDS ARE: bg-6 (opacity 0.01, fading OUT); bg-7 (opacity 0.99, fading IN).
    

    3 minutes later, it will start fading out bg-7 (since we're in a new time-block) and start fading in the next background, which is bg-8:

    CURRENT TIME IS: 15:02. STARTING BACKGROUNDS ARE: bg-7 (opacity 0.98, fading OUT); bg-8 (opacity 0.02, fading IN).
    

    I'd be very happy to see the end product, and if you'd like to add my name to the credits I'd very much appreciate it! Good luck!

    Oh and here's the new fiddle: https://jsfiddle.net/LaurensSwart/2go9g5n5/1/

    var timeBetweenBackgrounds = 7200000; // in milliseconds - change this to 7200000 for 2 hour between every image
    
    var d = new Date();
    var hour = d.getHours();
    var minutes = d.getMinutes();
    var bgNumber = getPicture(hour);
    
    $(document).ready(function() {
    
      // Determine starting background images:
    
      if (bgNumber < 11) {
        var bgNumberNext = bgNumber + 1;
      }
      if (bgNumber == 11) {
        var bgNumberNext = 0;
      }
      
      $('#backgroundOne').addClass('bg-' + bgNumber);
      $('#backgroundTwo').addClass('bg-' + bgNumberNext);
      
      // Get time overshoot (i.e. how far (in percentage) are we in a certain time-block):
      // Every block is 2 hours, so 1 hour into a block would be 50% (0.50)
      // Every minute would be 1/120th of a block (minutes / 60 * 0.50)
      
      var timeovershoot= 0;
      
      // Add 50% to the current block if we're in the second hour of a block (see hour definition on the bottom and adjust this if necessary):
      
      if (hour == 0 || hour == 22 || hour == 20 || hour == 18 || hour == 16 || hour == 14 || hour == 12 || hour == 10 || hour == 8 || hour == 6 || hour == 4 || hour == 2){
        timeovershoot= timeovershoot + 0.5;
      }
      
      // Calculate minute overshoot and add this to the time overshoot:
      
      minuteovershoot= (minutes/60)*0.5;
      timeovershoot= timeovershoot + minuteovershoot;
      
      // Calculate time remaining till this block ends (to determine how long to continue fading for):
      
      percentageOfBlockDone= timeovershoot;
      percentageOfBlockRemaining= 1-percentageOfBlockDone;
      secondsInBlockRemaining= timeBetweenBackgrounds * percentageOfBlockRemaining;
      
      console.log('CURRENT TIME IS: ' + hour + ':' + minutes + '. STARTING BACKGROUNDS ARE: bg-' + bgNumber + ' (opacity ' + percentageOfBlockRemaining.toFixed(2) + ', fading OUT); bg-' + bgNumberNext + ' (opacity ' + percentageOfBlockDone.toFixed(2) + ', fading IN).')
      
      // Set opacity values adjusted to percentage of current block that has elapsed:
      // We're fading div ONE out, so this will have an opacity of the percentage still remaining in this block,
      // and we're fading div TWO in, so this will have an opacity of percentage done in this block.
      
      $('#backgroundOne').css('opacity',percentageOfBlockRemaining);
      $('#backgroundTwo').css('opacity',percentageOfBlockDone);
    
      // Adjust fade timers and start fading:
      
      $('#backgroundOne').fadeTo(secondsInBlockRemaining, 0);
      $('#backgroundTwo').fadeTo(secondsInBlockRemaining, 1, function(){
      
      	// Once we're done finishing fading the time block that we started in, continue like normal:
      
      	 window.setInterval(setBackground, timeBetweenBackgrounds);
         
      });
    
    });
    
    var activeBackground = bgNumber;
    var activeDiv = 1;
    
    function setBackground() {
    
      if (activeDiv == 1) {
    
        if (activeBackground < 11) {
          var nextBackground = activeBackground + 1;
        }
        if (activeBackground == 11) {
          var nextBackground = 0;
        }
        console.log('Current background = ' + activeBackground + '. Next background = ' + nextBackground + '. Fading out container One. Fading in container Two.');
        $('#backgroundTwo').attr('class', 'bg').addClass('bg-' + nextBackground).fadeIn(timeBetweenBackgrounds);
        $('#backgroundOne').fadeOut((timeBetweenBackgrounds - 500), function() {
          activeBackground = nextBackground;
          activeDiv = 2;
        });
    
      }
      if (activeDiv == 2) {
    
        if (activeBackground < 11) {
          var nextBackground = activeBackground + 1;
        }
        if (activeBackground == 11) {
          var nextBackground = 0;
        }
        console.log('Current background = ' + activeBackground + '. Next background = ' + nextBackground + '. Fading out container Two. Fading in container One.');
        $('#backgroundOne').attr('class', 'bg').addClass('bg-' + nextBackground).fadeIn(timeBetweenBackgrounds);
        $('#backgroundTwo').fadeOut((timeBetweenBackgrounds - 500), function() {
          activeBackground = nextBackground;
          activeDiv = 1;
        });
    
      }
    
    }
    
    
    //Determines the picture to use based on the hour
    function getPicture(hour) {
      if (hour >= 23 || hour <= 1)
        return 11;
      else if (hour >= 21)
        return 10;
      else if (hour >= 19)
        return 9;
      else if (hour >= 17)
        return 8;
      else if (hour >= 15)
        return 7;
      else if (hour >= 13)
        return 6;
      else if (hour >= 11)
        return 5;
      else if (hour >= 9)
        return 4;
      else if (hour >= 7)
        return 3;
      else if (hour >= 5)
        return 2;
      else if (hour >= 3)
        return 1;
      else
        return 0;
    };
    body {
      overflow: hidden;
    }
    
    .bg {
      width: 100vw;
      height: 100vh;
      position: absolute;
      background-size: cover;
      background-repeat: no-repeat;
      z-index: 99;
      opacity: 0.7;
      margin: 0;
      padding: 0;
    }
    
    .bg-0 {
      background-image: url("http://i.imgur.com/qexylYA.png");
    }
    
    .bg-1 {
      background-image: url("http://i.imgur.com/cRvIYLJ.png");
    }
    
    .bg-2 {
      background-image: url("http://i.imgur.com/UusvZC8.png");
    }
    
    .bg-3 {
      background-image: url("http://i.imgur.com/URjIjZS.png");
    }
    
    .bg-4 {
      background-image: url("http://i.imgur.com/Fy7kANa.png");
    }
    
    .bg-5 {
      background-image: url("http://i.imgur.com/e2lvJ8q.png");
    }
    
    .bg-6 {
      background-image: url("http://i.imgur.com/JEslGSe.png");
    }
    
    .bg-7 {
      background-image: url("http://i.imgur.com/v2h0qzb.png");
    }
    
    .bg-8 {
      background-image: url("http://i.imgur.com/xyfqUsX.png");
    }
    
    .bg-9 {
      background-image: url("http://i.imgur.com/XbIlhvL.png");
    }
    
    .bg-10 {
      background-image: url("http://i.imgur.com/xDAIc6P.png");
    }
    
    .bg-11 {
      background-image: url("http://i.imgur.com/kaCxCBi.png");
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div class="bg" id="backgroundOne">
    
    </div>
    <div class="bg" id="backgroundTwo">
    
    </div>