2024-12-29 22:10:18 +01:00

184 lines
5.1 KiB
JavaScript

const EXPLOSION_TIME = 100;
const EXPLOSION_SIZE = 100;
const NUM_PARTICLES = 12;
const SPEED = 2;
let OVERRIDE_STATE = null;
function HSVtoRGB(h, s, v) {
var r, g, b, i, f, p, q, t;
if (arguments.length === 1) {
s = h.s, v = h.v, h = h.h;
}
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return "rgb(" + (r * 255) + "," + (g * 255) + "," + (b * 255) + ")";
}
const canvas = document.getElementById("fireworks-canvas");
const updateSize = () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
const STATE_NONE = "NONE";
const STATE_COUNTDOWN = "COUNTDOWN";
const STATE_FIREWORKS = "FIREWORKS";
let rockets = [];
let state = STATE_NONE;
updateSize();
window.onresize = updateSize;
const ctx = canvas.getContext("2d");
function leftPad(str, len, pad) {
str = "" + str;
while (str.length < len) {
str = pad + str;
}
return str;
}
window.addEventListener("keyup", e => {
if (e.key == 'h') {
canvas.style.display = canvas.style.display == 'none' ? null : 'none';
}
});
setInterval(() => {
const theTime = new Date();
if (OVERRIDE_STATE != null) {
state = OVERRIDE_STATE;
} else if (theTime.getDate() == 1 && theTime.getMonth() == 0 && theTime.getHours() == 0) { // 01.01. 00:00 - 00:59
state = STATE_FIREWORKS;
} else {
const nextYear = new Date('1970-01-01 00:00');
nextYear.setFullYear(theTime.getFullYear() + 1);
const timeUntilMidnight = Math.floor((nextYear - theTime) / 1000);
if(timeUntilMidnight < 4 * 60 * 60) {
state = STATE_COUNTDOWN;
}else {
state = STATE_NONE;
}
}
if (state == STATE_FIREWORKS) {
rockets.push({ x: Math.random() * canvas.width, y: canvas.height, life: (Math.random() * 0.75 + 0.25) * canvas.height, color: HSVtoRGB(Math.random(), 1, 1) });
return;
} else {
rockets = [];
}
}, 300);
setInterval(() => {
if (state == STATE_NONE) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
return;
}
const theTime = new Date();
switch (state) {
case STATE_NONE:
ctx.clearRect(0, 0, canvas.width, canvas.height);
return;
case STATE_COUNTDOWN:
ctx.fillStyle = "#000044ff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
const nextYear = new Date('1970-01-01 00:00');
nextYear.setFullYear(theTime.getFullYear() + 1);
const timeUntilMidnight = Math.floor((nextYear - theTime) / 1000);
const hours = "" + Math.floor(timeUntilMidnight / (60 * 60));
const minutes = "" + Math.floor((timeUntilMidnight / 60) % 60);
const seconds = "" + Math.floor(timeUntilMidnight % 60);
ctx.fillStyle = "orangered";
ctx.textAlign = "center";
ctx.font = "bold 50px Comic Mono";
ctx.fillText("T-" + hours.padStart(2, "0") + ":" + minutes.padStart(2, "0") + ":" + seconds.padStart(2, "0"), canvas.width / 2, canvas.height / 2);
ctx.fillStyle = "white";
ctx.fillText(theTime.getHours().toString().padStart(2, '0') + ":" + theTime.getMinutes().toString().padStart(2, '0') + ":" + theTime.getSeconds().toString().padStart(2, '0'), canvas.width / 2, canvas.height / 2 - 150);
ctx.fillStyle = "lightgray";
ctx.textAlign = "center";
ctx.font = "bold 30px Comic Mono";
let text = "The new year is approaching 👀";
if(hours < 1) {
text = "The final hour has started ⏱️";
if(minutes == 0 && seconds < 60) {
text = "It's the final countdown 😳";
}
}
ctx.fillText(text, canvas.width / 2, canvas.height / 2 + 150);
break; // Draw help
case STATE_FIREWORKS:
ctx.fillStyle = "#000044ff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
rockets.forEach(rocket => {
rocket.life -= SPEED;
if (rocket.life <= EXPLOSION_TIME) {
if (rocket.life <= 0) {
rockets.splice(rockets.indexOf(rocket), 1);
return;
}
const explosionTime = 1 - (rocket.life / EXPLOSION_TIME);
const size = explosionTime * EXPLOSION_SIZE;
for (let i = 0; i < NUM_PARTICLES; i++) {
const angle = i / NUM_PARTICLES * Math.PI * 2;
const px = Math.cos(angle) * size;
const py = Math.sin(angle) * size;
ctx.fillStyle = rocket.color;
ctx.beginPath();
ctx.arc(rocket.x + px, rocket.y + py, 5, 0, Math.PI * 2, true);
ctx.fill();
}
} else {
rocket.y -= SPEED;
ctx.fillStyle = "black";
ctx.fillRect(rocket.x - 5, rocket.y - 5, 10, 10);
}
});
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.font = "bold 50px Comic Mono";
ctx.fillText("Happy new year! 🥳", canvas.width / 2, canvas.height / 2);
ctx.font = "bold 100px Comic Mono";
ctx.fillText(theTime.getHours().toString().padStart(2, '0') + ":" + theTime.getMinutes().toString().padStart(2, '0') + ":" + theTime.getSeconds().toString().padStart(2, '0'), canvas.width / 2, canvas.height / 2 - 150);
break; // Draw help
}
ctx.font = "bold 10px Comic Mono";
ctx.fillStyle = "#0000ff";
ctx.textAlign = "left";
ctx.fillText("Press 'h' to hide", 10, canvas.height - 10);
}, 10);