type Times = number[];
type Cats = [string, Times]
const MATRIX: Cats[] = [["o0", [1, 5, 8, 9, 11]],
["o1", [2, 5, 6, 10, 11]],
["o2", [3, 6, 7, 9, 11]],
["o3", [4, 7, 8, 10, 11]]];
const TEMPLATE = `
`;
type Face = "hours" | "minutes" | "seconds"
const isFace = (v: unknown): v is Face => {
if (typeof v === "string" && ["hours", "minutes", "seconds"].includes(v)) { return true; }
throw new Error(`Expected a Face, got ${v}`);
}
class DominoClock extends HTMLElement {
elements: { [K in Face]: HTMLDivElement };
timer: number;
constructor() {
super()
this.timer = 0;
this.innerHTML = TEMPLATE;
this.elements = Object.fromEntries(
Array.from(this.getElementsByTagName('div'))
.filter((element) => element.className === "face")
.map((element) => [isFace(element.id) && element.id, element]));
this.paint = this.paint.bind(this);
}
connectedCallback() {
this.timer = window.setTimeout(this.paint, 250)
}
tock(board: Face, time: number) {
const dots = Array.from(this.elements[board].getElementsByTagName('div'));
dots.forEach((element) => element.style.opacity = "0");
dots.forEach((element) => {
const row = MATRIX.find((i) => Array.from(element.classList).includes(i[0]));
if (!row) { console.log(`Didn't find a row for ${element.className}?`); return; }
if (row[1].includes(time)) {
element.style.opacity = "1"
}
});
}
paint() {
const now = new Date();
const rawHours = now.getHours();
const hours = rawHours > 12 ? rawHours - 12 : rawHours;
this.tock("hours", hours);
this.tock("minutes", Math.floor(now.getUTCMinutes() / 5));
this.tock("seconds", Math.floor(now.getUTCSeconds() / 5));
window.clearTimeout(this.timer);
this.timer = window.setTimeout(this.paint, 250);
}
}
customElements.define('domino-clock', DominoClock);