Skip to content

Instantly share code, notes, and snippets.

@lelandbatey
Last active January 8, 2022 21:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lelandbatey/7ca16176ed74d3e5ecdc63dd732390b4 to your computer and use it in GitHub Desktop.
Save lelandbatey/7ca16176ed74d3e5ecdc63dd732390b4 to your computer and use it in GitHub Desktop.
Color clock - represent the hands of a clock as the "color edges" of a pie chart
<!DOCTYPE html>
<html lang="en">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<!--<script src="timemachine.js"></script>-->
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment-with-locales.min.js"></script>-->
<body style="margin: 0;">
<canvas id='canvas' width='1000' height='1000'></canvas>
</body>
<script>
// timemachine.config({
// // dateString: '5. May 2018, 04:21:47 PDT',
// dateString: '5. May 2018, 05:27:14 PDT',
// tick: true
// });
function mod(lhs, n) {
return ((lhs%n)+n)%n;
};
// let _COLORS_ = ['red', 'green', 'blue', 'pink', 'grey'];
let _COLORS_ = ['#550800', '#50A162', '#012C34', '#D49E6A', '#801F15', '#106022', '#0F444F', '#804915', '#D4746A', '#00400E', '#437983', '#552900'];
function getColorsBy60(num) {
num = Math.floor(num);
let idx = mod(num, 60) % (_COLORS_.length-1);
let second = (idx+1) % (_COLORS_.length-1);
// console.log(idx, second);
return [_COLORS_[idx], _COLORS_[second]];
}
function roundTo(n, digits) {
if (digits === undefined) {
digits = 0;
}
var multiplicator = Math.pow(10, digits);
n = parseFloat((n * multiplicator).toFixed(11));
return Math.round(n) / multiplicator;
}
/*
// The mysterious constants in the below getClockHandsCrossBin are merely odd
// ways of formatting the original fractions calculated in the mathematica
// stackexchange linked below. The following code can be used as an example to
// convert those fractions into times-past-midnight when the hands cross, which is
// the format actually use in the code:
function fractions_to_timestamps() {
var print = console.log;
function zeropad(x, pad, chr) {
return String(x).padStart(pad, chr);
}
var times = [0, 720 / 11, 1440 / 11, 2160 / 11, 2880 / 11, 3600 / 11, 4320 / 11, 5040 / 11, 5760 / 11, 6480 / 11, 7200 / 11];
let first = times[1];
function fmttime(first) {
//print(`first: ${first}`);
//print(`first % 1: ${first % 1}`);
//print(`first | 0: ${first | 0}`);
let minutes = first | 0; // Only the minutes post midnight
let minfrac = first % 1; // The remaining fraction of a minute
//print(`minutes / 60: ${minutes / 60}`);
//print(`minfrac * 60: ${minfrac * 60}`);
let hoursafter = (minutes / 60) | 0; // Hours after midnight when this crossover occurs
let mininhour = (minutes % 60); // Minutes remaining in hour when crossover happens
let secinmin = (minfrac * 60) | 0;
let msinsec = (((minfrac * 60) % 1) * 1000) | 0;
//print(`hoursafter : ${hoursafter}`);
//print(`mininhour: ${mininhour}`);
//print(`secinmin: ${secinmin}`);
//print(`msinsec: ${msinsec}`);
var tp = (x) => zeropad(x, 2, '0');
let nicerep = `${hoursafter}:${tp(mininhour)}:${tp(secinmin)}.${zeropad(msinsec, 3, 0)}`;
print(nicerep);
}
for (var i = 0; i < times.length; i++) {
fmttime(times[i]);
}
}
fractions_to_timestamps();
*/
function getClockHandsCrossBin() {
// The times that the hour and minutes hands cross. Originally found here:
// https://mathematica.stackexchange.com/a/582
//
// [0, 720/11, 1440/11, 2160/11, 2880/11, 3600/11, 4320/11, 5040/11, 5760/11, 6480/11, 7200/11]
// ['00:00:00', '01:05:27', '02:10:54', '03:16:21', '04:21:49', '05:27:16', '06:32:43', '07:38:10', '08:43:38', '09:49:05', '10:54:32']
let crossing_hours = [0, 10527.2727, 21054.5454, 31621.8181, 42149.0909, 52716.3636, 63243.6363, 73810.909, 84338.1818, 94905.4545, 105432.7272];
// Format the current moment in these terms
let now = new Date();
let hour = now.getHours() % 12;
let minute = String(now.getMinutes()).padStart(2, '0');
let second = String(now.getSeconds()).padStart(2, '0');
let milliseconds = String(now.getMilliseconds()).padStart(3, '0');
let str = `${hour}${minute}${second}.${milliseconds}`;
let curtime = parseFloat(str, 10);
let bin = 0;
for (var i = 0; i < crossing_hours.length; i++) {
if (crossing_hours[i] <= curtime) {
bin = i;
}
}
// if (roundTo(curtime, 1) === 42149.9 ) {
// debugger;
// }
// console.log(str, bin);
return bin;
}
/// Moment returns a number representing the number of milliseconds that have passed since the epoch
/// time (1970).
function nowtime() {
return Date.now();
}
function minute_of_hour() {
return ((nowtime()/1000) % 3600) / 60;
}
function hour_of_day() {
return ((nowtime()/1000) % (24 * 60 * 60)) / (24 * 60 * 60);
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
$(document).ready(() => {
var canv = document.getElementById('canvas');
canv.height = $(window).height();
canv.width = $(window).width();
var context = canv.getContext('2d');
context.fillStyle = 'black';
context.fillRect(0, 0, canv.width, canv.height);
let sx = canv.width/2;
let sy = canv.height/2;
let circle_rad = 2*Math.PI;
let twelve_oclock = 0.75 * circle_rad;
function draw_pie_slice(origin, radius, start_angle, end_angle) {
let [sx, sy] = origin;
context.beginPath();
context.moveTo(sx, sy);
context.arc(sx, sy, radius, start_angle, end_angle);
context.lineTo(sx, sy);
context.fill();
}
function get_12hour_progress(relative_start) {
if (typeof relative_start === "undefined") {
relative_start = twelve_oclock;
}
let halfday_ms = (12 * 60 * 60 * 1000);
// Instead of getting moment, we're going to hack together a different way to get the current time in the local time zone
let now = new Date();
let now_ms = now.getMilliseconds();
let now_seconds = now.getSeconds() * 1000;
let now_minutes = now.getMinutes() * 60 * 1000;
let now_hours = (now.getHours() % 12) * 60 * 60 * 1000;
let now_cumulative_ms = now_ms + now_seconds + now_minutes + now_hours;
let halfday_progress = (now_cumulative_ms % halfday_ms) / halfday_ms;
let hdnp = (circle_rad * halfday_progress) + relative_start;
return hdnp % circle_rad;
}
function get_hour_progress(relative_start) {
if (typeof relative_start === "undefined") {
relative_start = twelve_oclock;
}
let hour_progress = (nowtime() % 3600000) / 3600000;
let hnp = (circle_rad*hour_progress) + relative_start;
let hour_rad_progress = hnp % circle_rad;
return hour_rad_progress;
}
function get_minute_progress(relative_start) {
let minute_progress = (nowtime() % 60000) / 60000;
let mnp = (circle_rad*minute_progress) + relative_start;
return mnp % circle_rad;
}
function do_the_frame() {
// let [bg, fg] = getColorsBy60(hour_of_day()% 12);
let [bg, fg] = getColorsBy60(getClockHandsCrossBin());
// console.log(bg, fg);
context.fillStyle = 'lightgrey';
context.fillRect(0, 0, canv.width, canv.height);
let clock_radius = sy*0.9;
// Get our "progress" through the 12-hour block
let halfday_rad_progress = get_12hour_progress();
// Get our "progress" through the current hour
let hour_rad_progress = get_hour_progress();
// Get our "progress" through the current minute
// let minute_rad_progress = get_minute_progress(hour_rad_progress);
// console.log(halfday_rad_progress, hour_rad_progress, Date.now(), bg, fg);
// if (hour_rad_progress < halfday_rad_progress && halfday_rad_progress - hour_rad_progress < 0.05) {
// context.fillStyle = fg;
// } else {
// context.fillStyle = bg;
// }
context.fillStyle = bg;
// Draw the background circle
context.beginPath();
context.arc(sx, sy, clock_radius, twelve_oclock, twelve_oclock+circle_rad);
context.fill();
context.beginPath();
context.fillStyle = fg;
draw_pie_slice([sx, sy], clock_radius, halfday_rad_progress, hour_rad_progress);
window.requestAnimationFrame(do_the_frame);
}
do_the_frame();
});
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment