diff --git a/special/new-year.js b/special/new-year.js index 658dbce..eaf19c3 100644 --- a/special/new-year.js +++ b/special/new-year.js @@ -2,7 +2,7 @@ const EXPLOSION_TIME = 100; const EXPLOSION_SIZE = 100; const NUM_PARTICLES = 12; const SPEED = 2; -let OVERRIDE_ROCKETS = false; +let OVERRIDE_STATE = null; function HSVtoRGB(h, s, v) { var r, g, b, i, f, p, q, t; @@ -32,14 +32,28 @@ const updateSize = () => { canvas.height = window.innerHeight; }; +const STATE_NONE = "NONE"; +const STATE_COUNTDOWN = "COUNTDOWN"; +const STATE_FIREWORKS = "FIREWORKS"; + let rockets = []; -let rocketsAreFiring = false; +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'; @@ -48,62 +62,119 @@ window.addEventListener("keyup", e => { setInterval(() => { const theTime = new Date(); - if (!OVERRIDE_ROCKETS && (theTime.getDate() != 1 || theTime.getMonth() != 0 || theTime.getHours() != 0)) { - rockets = []; - rocketsAreFiring = false; - return; + + 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; + } } - rocketsAreFiring = true; - 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) }); + 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 (!rocketsAreFiring) { + if (state == STATE_NONE) { ctx.clearRect(0, 0, canvas.width, canvas.height); return; } - 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); - } - - }); - const theTime = new Date(); - 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); + + 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";