2

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?

cannydare
  • 150
  • 1
  • 9

2 Answers2

1

Here you go! Change the 2000ms to 7200000 to have it slowly fade over a period of 2 hours. Also put it on Fiddle: https://jsfiddle.net/pbfuauzg/3/

I've been experimenting with the time-difference between the setInterval() and fadeIn() durations. For now, I've gotten best results when the fade() is just slightly shorter than the setInterval functions (i.e. 500 milliseconds). See code below.

I've also cleaned up your CSS because you were unnecessarily repeating a lot of code. Can I have a cookie now, please :D?

Please note: the interval between each background is not exactly 2 hours in your script (you have a background for 15:00h and a background for 16:00h for example). To make it work perfectly, you'll have to set these times with 2 hour intervals, in stead of alternating 1 h and 3 hour intervals!

var timeBetweenBackgrounds = 2000; // in milliseconds - change this to 7200000 for 2 hours

var d = new Date();
var hour = d.getHours();
var bgNumber = getPicture(hour);

$(document).ready(function() {

  $('#backgroundOne').addClass('bg-' + bgNumber);

  setBackground();
  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 <= 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;
};
body {
  overflow: hidden;
}

.bg {
  width: 100vw;
  height: 100vh;
  position: absolute;
  background-size: cover;
  background-repeat: no-repeat;
  z-index: 99;
  opacity: 0.7;
}

.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" style="display: none;">

</div>
Laurens Swart
  • 1,234
  • 9
  • 24
  • 1
    You sir, deserve many cookies! Thank you so much! One thing - Will this 'remember' (for use of a better word) the transition duration based on the time of day? If someone logs on at 8am, will it start in between transitions at 50% or will the transition amount start from 0? Ideally we want everything in sync, doesn't matter if the two suns are showing as that's all being changed! Otherwise we might get a sunset at 12pm :P – cannydare Mar 26 '17 at 11:30
1

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>
Laurens Swart
  • 1,234
  • 9
  • 24
  • 1
    I have no words. You are amazing! Thank you so much for taking the time to help with this. It's working perfectly! The 2 hour increments are exactly what I'm working with, as before we wanted sunset to last a bit longer because it was pretty :) But now because of the gradual fade, people will see the sunset change over a period of time. This is going to be beautiful. I cannot thank you enough! You can visit [bitday.me](http://www.bitday.me) for the current version, and when the new version is ready it will be replaced here :) I've already added you to the contributors list! – cannydare Mar 26 '17 at 13:30
  • 1
    Cool! Looks great! Glad I could be a part of something awesome! Once you can, please select the 2nd answer and please +1 them if you can :) (not sure how long you have to wait with your stackrep). Oh and let me know if you need anymore help, I'd be glad to help out wherever needed! – Laurens Swart Mar 26 '17 at 14:54
  • 1
    I can't until I have 15rep :( But as soon as I do I'll +1! The minuteovershoot on page load seemed to be making the current background transparent but there is no visible background underneath, so I have set the overshoot to 0.01 and it seemed to resolve. I am changing the time constantly on my computer to test it out, along with page reloads and this seems to be the best solution so far. Good news is that I might have an alpha version ready by this evening :) If I do I'll post the dev link on here. – cannydare Mar 26 '17 at 16:00
  • 1
    Cool! You should have 15 now :-) (hehe) – Laurens Swart Mar 26 '17 at 16:02
  • 1
    The minuteovershoot should make both backgrounds (current and next) a little bit more transparent (max 0.49) depending on where we are in the time block. I.e. if we're 1:59 hours in a timeblock, the hour will add 0.50, and the 59 minutes will ad 59/60 * 0.50 = 0.49 opacity as well, making overall opacity 0.99 – Laurens Swart Mar 26 '17 at 16:04
  • Hey Laurens check it out - [here](http://bitday.me) - I did leave it running all night and background didn't seem to fade together but the sun and moon worked okay. You're on the credits as well :) It's about 8:30 right now and the background is barely visible because of the opacity. Not sure what to, can't seem to find errors in the console. – cannydare Mar 27 '17 at 07:34