Skip to content

Instantly share code, notes, and snippets.

@baohouse
Last active April 24, 2018 05:36
Show Gist options
  • Save baohouse/22cc90a817bc11ec2f4c04d18a75e069 to your computer and use it in GitHub Desktop.
Save baohouse/22cc90a817bc11ec2f4c04d18a75e069 to your computer and use it in GitHub Desktop.
Set background color by time of day
document.addEventListener('DOMContentLoaded', function () {
/**
* Palette is ordered by time. The first color will be midnight (new day),
* and the last color will be just before midnight.
*/
var palette = [
'#f6ebcf',
'#fbfafb',
'#eff2ed'
];
var now = new Date();
var color = getColorByTimeOfDay(now.getHours(), now.getMinutes(), now.getSeconds());
document.body.style.backgroundColor = color;
/**
* Just grabs any color from the palette
*/
function getRandomColor() {
var randomIndex = Math.floor(Math.random() * palette.length);
return palette[randomIndex];
}
/**
* @param {number} hours [0, 23]
* @param {number} minutes [0, 59]
* @param {number} seconds [0, 59]
*
* @return {string} color
*
* Given that there are 86400 seconds in a day, we want to find the nth
* step out of 86400 steps in the palette. Even if the palette has fewer
* steps, then each palette color is treated as a marker, and we have
* to interpolate between the two closest markers.
*/
function getColorByTimeOfDay(hours, minutes, seconds) {
var currentStep = hours * 60 * 60 + minutes * 60 + seconds; // [0, 86399]
var markers = findClosestPaletteColors(currentStep);
return rgbArrayToHex(
interpolateColor(
hexToRgbArray(markers.lower.color),
hexToRgbArray(markers.upper.color),
(currentStep - markers.lower.step) / ((markers.upper.step - markers.lower.step) || 1)
)
);
}
function findClosestPaletteColors(currentStep) {
var currentIndex = (currentStep + 1) / 86400 * palette.length; // Can be float
var lowerIndex = Math.floor(currentIndex) - 1; // [0, paletteSize]
var upperIndex = Math.ceil(currentIndex) - 1; // [0, paletteSize]
/**
* 3-element palette: [0, 1, 2] => steps [0, 43199, 86399]
* 4-element palette: [0, 1, 2, 3] => steps [0, 28799, 57599, 86399]
*/
return {
lower: {
index: lowerIndex,
step: (lowerIndex + 1) * 86400 / palette.length - 1,
color: palette[lowerIndex]
},
upper: {
index: upperIndex,
step: (upperIndex + 1) * 86400 / palette.length - 1,
color: palette[upperIndex]
}
}
}
/**
* Interpolates two [r,g,b] colors and returns an [r,g,b] of the result
* Taken from the awesome ROT.js roguelike dev library at
* https://github.com/ondras/rot.js
*/
function interpolateColor(color1, color2, factor) {
if (arguments.length < 3) { factor = 0.5; }
var result = color1.slice();
for (var i = 0; i < 3; i++) {
result[i] = Math.round(result[i] + factor * (color2[i] - color1[i]));
}
return result;
};
/**
* Converts a #ffffff hex string into an [r,g,b] array
*/
function hexToRgbArray(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? [
parseInt(result[1], 16),
parseInt(result[2], 16),
parseInt(result[3], 16)
] : null;
};
/**
* Converts [r,g,b] array into a #ffffff hex string
*/
function rgbArrayToHex(rgb) {
return "#" + ((1 << 24) + (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]).toString(16).slice(1);
};
});
@baohouse
Copy link
Author

@visualgui You can think of each specified color as a stop marker, and the color chosen is at the time of load. The page background will not change until you change page or reload the page, and even then, it would be very incremental. Imagine if you have only two colors, black at midnight (0:00), white at noon (12:00), and black at just-before-midnight (23:59). If you load the page at 6:00am, it would interpolate between black at 0:00 and white at 12:00, so you'd have a 50% gray.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment