Initial timer
This commit is contained in:
22
index.html
Normal file
22
index.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Inter' rel='stylesheet'>
|
||||||
|
<link rel="stylesheet" href="timer.css" />
|
||||||
|
<script src="timer.js"></script>
|
||||||
|
<title>Croccy Timer</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="timer-box">
|
||||||
|
<div class="timer-bg">
|
||||||
|
<div class="timer-time">
|
||||||
|
<span class="timer-time">00:00</span>
|
||||||
|
</div>
|
||||||
|
<div class="timer-details">
|
||||||
|
</div>
|
||||||
|
<div class="timer-details">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
35
timer.css
Normal file
35
timer.css
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
:root {
|
||||||
|
--break-color: #9020BA;
|
||||||
|
--focus-color: #EED59F;
|
||||||
|
--stage-color: var(--break-color);
|
||||||
|
--clip-path: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.timer-box{
|
||||||
|
height: 175px;
|
||||||
|
width: 397px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.timer-time {
|
||||||
|
font-size: 100px;
|
||||||
|
font-family: Inter;
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0%;
|
||||||
|
text-align: center;
|
||||||
|
color: #453960;
|
||||||
|
}
|
||||||
|
.timer-details {
|
||||||
|
display: fill;
|
||||||
|
font-family: Inter;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
width: 65%;
|
||||||
|
margin: auto;
|
||||||
|
color: #453960;
|
||||||
|
}
|
||||||
189
timer.js
Normal file
189
timer.js
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
|
const websocket = new WebSocket("ws://adamwalsh.name:9533");
|
||||||
|
|
||||||
|
websocket.addEventListener("open", () => {
|
||||||
|
communicate(websocket);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
class Timer {
|
||||||
|
constructor(renderer, end_time, running) {
|
||||||
|
this.renderer = renderer;
|
||||||
|
this.end_time = end_time;
|
||||||
|
this.running = running;
|
||||||
|
|
||||||
|
this.destroying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
render_time() {
|
||||||
|
// Render timer status to the document
|
||||||
|
var timestr;
|
||||||
|
|
||||||
|
if (this.counter < 0) {
|
||||||
|
timestr = "--:--";
|
||||||
|
} else {
|
||||||
|
// How many seconds have passed in this block
|
||||||
|
var dur_seconds = Math.floor( (this.end_time - new Date()) / 1000);
|
||||||
|
var seconds = dur_seconds % 60;
|
||||||
|
dur_seconds = dur_seconds - seconds;
|
||||||
|
var minutes = Math.floor(dur_seconds / 60);
|
||||||
|
var hours = Math.floor(minutes / 60);
|
||||||
|
minutes = minutes - 60 * hours;
|
||||||
|
|
||||||
|
timestr = String(hours).padStart(2, '0') + ':' + String(minutes).padStart(2, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.running) {
|
||||||
|
this.renderer.update_time(timestr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tick() {
|
||||||
|
// Recursive call run per second to update and change stage
|
||||||
|
|
||||||
|
if (this.destroying) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.render_time();
|
||||||
|
setTimeout(this.tick.bind(this), 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimerRenderer {
|
||||||
|
constructor (){
|
||||||
|
this.background = document.getElementsByClassName("timer-bg")[0];
|
||||||
|
this.time_element = document.getElementsByClassName("timer-time")[0];
|
||||||
|
|
||||||
|
this.bg_width = parseInt(
|
||||||
|
window.getComputedStyle(
|
||||||
|
this.background, null
|
||||||
|
).getPropertyValue('width'),
|
||||||
|
10
|
||||||
|
);
|
||||||
|
this.bg_height = parseInt(
|
||||||
|
window.getComputedStyle(
|
||||||
|
this.background, null
|
||||||
|
).getPropertyValue('height'),
|
||||||
|
10
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
update_time (timestr) {
|
||||||
|
this.time_element.textContent = timestr;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_break_color () {
|
||||||
|
this.background.style.setProperty('--stage-color', 'var(--break-color)');
|
||||||
|
this.time_element.style.color = "var(--break-color)";
|
||||||
|
}
|
||||||
|
|
||||||
|
set_focus_color () {
|
||||||
|
this.background.style.setProperty('--stage-color', 'var(--focus-color)');
|
||||||
|
this.time_element.style.color = "var(--focus-color)";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function rectBounds(prop, rectHeight, rectWidth) {
|
||||||
|
var totalCircum = 2 * rectHeight + 2 * rectWidth;
|
||||||
|
var propCircum = prop * totalCircum;
|
||||||
|
let bounds;
|
||||||
|
|
||||||
|
if (propCircum < rectWidth / 2) {
|
||||||
|
var xprop = Math.floor((
|
||||||
|
(rectWidth/2 + propCircum) / rectWidth
|
||||||
|
) * 1000)/10;
|
||||||
|
bounds = [
|
||||||
|
"50% -5%",
|
||||||
|
`${xprop}% -5%`,
|
||||||
|
`${xprop}% 4%`,
|
||||||
|
"50% 4%"
|
||||||
|
];
|
||||||
|
} else if (propCircum < rectWidth / 2 + rectHeight) {
|
||||||
|
var yprop = (
|
||||||
|
(propCircum - rectWidth / 2) / rectHeight
|
||||||
|
) * 100;
|
||||||
|
bounds = [
|
||||||
|
"50% -5%", "110% -5%",
|
||||||
|
`110% ${yprop}%`, `96% ${yprop}%`,
|
||||||
|
"95% 4%", "50% 4%"
|
||||||
|
];
|
||||||
|
} else if (propCircum < 3 * rectWidth / 2 + rectHeight) {
|
||||||
|
var xprop = (
|
||||||
|
((3 * rectWidth/2 + rectHeight) - propCircum) / rectWidth
|
||||||
|
) * 100;
|
||||||
|
bounds = [
|
||||||
|
"50% -5%", "110% -5%",
|
||||||
|
"110% 110%",
|
||||||
|
`${xprop}% 110%`, `${xprop}% 96%`,
|
||||||
|
"95% 96%",
|
||||||
|
"95% 4%", "50% 4%"
|
||||||
|
];
|
||||||
|
} else if (propCircum < 3 * rectWidth / 2 + 2 * rectHeight) {
|
||||||
|
var yprop = (
|
||||||
|
((3 * rectWidth/2 + 2 * rectHeight) - propCircum) / rectHeight
|
||||||
|
) * 100;
|
||||||
|
bounds = [
|
||||||
|
"50% -5%", "110% -5%",
|
||||||
|
"110% 110%", "-5% 110%",
|
||||||
|
`-5% ${yprop}%`, `4% ${yprop}%`,
|
||||||
|
"5% 96%", "95% 96%",
|
||||||
|
"95% 4%", "50% 4%"
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
var xprop = (
|
||||||
|
(propCircum - (3 * rectWidth/2 + 2 * rectHeight)) / rectWidth
|
||||||
|
) * 100;
|
||||||
|
bounds = [
|
||||||
|
"50% -5%", "110% -5%",
|
||||||
|
"110% 110%", "-5% 110%",
|
||||||
|
"-5% -5%",
|
||||||
|
`${xprop}% -5%`, `${xprop}% 4%`,
|
||||||
|
"4% 4%",
|
||||||
|
"5% 96%", "95% 96%",
|
||||||
|
"95% 4%", "50% 4%"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
function communicate(websocket) {
|
||||||
|
console.log("Communicating");
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
websocket.send(JSON.stringify({type: "init", channel: "SubTimer", channelid: params.get('channelid')}));
|
||||||
|
|
||||||
|
var renderer = new TimerRenderer();
|
||||||
|
let timer;
|
||||||
|
|
||||||
|
websocket.addEventListener("message", ({ data }) => {
|
||||||
|
console.log("Rec Event " + data);
|
||||||
|
const event = JSON.parse(data);
|
||||||
|
switch (event.type) {
|
||||||
|
case "DO":
|
||||||
|
let args = event.args;
|
||||||
|
|
||||||
|
// Call the specified method
|
||||||
|
switch (event.method) {
|
||||||
|
case "setTimer":
|
||||||
|
if (timer != null) {
|
||||||
|
timer.destroying = true;
|
||||||
|
}
|
||||||
|
timer = new Timer(
|
||||||
|
renderer,
|
||||||
|
new Date(args.end_at),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
timer.tick();
|
||||||
|
timer.running = args.running;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported method requested: ${event.method}.`)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported event type: ${event.type}.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user