You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
91 lines
2.1 KiB
JavaScript
91 lines
2.1 KiB
JavaScript
// SARS-CoV-2-Viz
|
|
// Animated COVID case count visualization
|
|
// Copyright 2022 Edward L. Platt <ed@elplatt.com>
|
|
|
|
function UI() {
|
|
|
|
let frames = [];
|
|
let currentFrame = 0;
|
|
let msPerFrame = 500;
|
|
let playing = false;
|
|
let onTick = null;
|
|
|
|
let animate = function () {
|
|
if (playing) {
|
|
setTimeout(animate, msPerFrame);
|
|
}
|
|
if (onTick) {
|
|
onTick(currentFrame);
|
|
}
|
|
currentFrame = (currentFrame + 7) % frames.length;
|
|
};
|
|
|
|
let node = document.createElement("div");
|
|
|
|
let controls = document.createElement("div");
|
|
controls.classList.add("hidden");
|
|
node.appendChild(controls);
|
|
|
|
let play = document.createElement("button");
|
|
play.innerText = 'play';
|
|
play.id = 'play';
|
|
controls.appendChild(play);
|
|
play.addEventListener(
|
|
"click", () => {
|
|
if (playing) {
|
|
play.innerText = 'play';
|
|
playing = false;
|
|
} else {
|
|
play.innerText = 'pause';
|
|
playing = true;
|
|
animate();
|
|
}
|
|
});
|
|
|
|
let display = document.createElement("div");
|
|
display.id = "display";
|
|
let mainDisplay = document.createElement("div");
|
|
mainDisplay.id = "main-display";
|
|
let secondaryDisplays = {};
|
|
display.appendChild(mainDisplay);
|
|
node.appendChild(display);
|
|
|
|
return {
|
|
node: node,
|
|
display: (s, id=null) => {
|
|
if (id === null) {
|
|
mainDisplay.innerText = s;
|
|
} else {
|
|
secondaryDisplays[id].innerText = s;
|
|
}
|
|
},
|
|
addDisplay: (id) => {
|
|
let secondary = document.createElement("div");
|
|
secondary.id = `display-${id}`;
|
|
display.appendChild(secondary);
|
|
secondaryDisplays[id] = secondary;
|
|
},
|
|
showControls: (show=true) => {
|
|
if (show) {
|
|
controls.classList.remove("hidden");
|
|
} else {
|
|
controls.classList.add("hidden");
|
|
}
|
|
},
|
|
clearDisplays: () => {
|
|
mainDisplay.innerText = '';
|
|
for (const [id, d] of Object.entries(secondaryDisplays)) {
|
|
d.remove();
|
|
}
|
|
secondaryDisplays = {};
|
|
},
|
|
onTick: (f) => { onTick = f; },
|
|
setFrames: (newFrames, current) => {
|
|
frames = newFrames;
|
|
currentFrame = current;
|
|
},
|
|
setMsPerFrame: (newMsPerFrame) => { msPerFrame = newMsPerFrame; }
|
|
}
|
|
}
|
|
|