presentation/components/diagram.component.ts
presentation/components/diagram.component.ts is a file in Bane's Lab Site. 68 lines of code and 15 definitions.
import {
DIAGRAM_WALKED_CLASS,
DIAGRAM_WALKING_CLASS,
DIAGRAM_WALK_ATTRIBUTE,
DIAGRAM_WALK_PAUSE_MS,
DIAGRAM_WALK_SEPARATOR,
DIAGRAM_WALK_STEP_MS,
REDUCED_MOTION_QUERY,
} from "#configuration/constants/diagram.constants";
import type { Disposer } from "#types/base.types";
const ID_SELECTOR = "[id]";
const prefersStill = function prefersStill(): boolean {
return typeof globalThis.matchMedia === "function" && globalThis.matchMedia(REDUCED_MOTION_QUERY).matches;
};
const stepsIn = function stepsIn(canvas: Element): readonly Element[] {
const order = canvas.querySelector(`[${DIAGRAM_WALK_ATTRIBUTE}]`)?.getAttribute(DIAGRAM_WALK_ATTRIBUTE) ?? "";
const byId = new Map([...canvas.querySelectorAll(ID_SELECTOR)].map((element) => [element.id, element]));
return order.split(DIAGRAM_WALK_SEPARATOR).flatMap((id) => {
const element = byId.get(id);
return element === undefined ? [] : [element];
});
};
export const attachDiagramWalk = function attachDiagramWalk(canvas: Element): Disposer {
const steps = stepsIn(canvas);
if (steps.length === 0 || prefersStill()) {
return () => {};
}
canvas.classList.add(DIAGRAM_WALKING_CLASS);
let head = 0;
let visible = false;
let timer: ReturnType<typeof setTimeout> | null = null;
const clear = function clear(): void {
for (const step of steps) {
step.classList.remove(DIAGRAM_WALKED_CLASS);
}
head = 0;
};
const tick = function tick(): void {
timer = null;
if (!visible) {
return;
}
const step = steps[head];
if (step === undefined) {
clear();
timer = setTimeout(tick, DIAGRAM_WALK_STEP_MS);
return;
}
step.classList.add(DIAGRAM_WALKED_CLASS);
head += 1;
timer = setTimeout(tick, head >= steps.length ? DIAGRAM_WALK_PAUSE_MS : DIAGRAM_WALK_STEP_MS);
};
const observer = new IntersectionObserver((entries) => {
visible = entries.some((entry) => entry.isIntersecting);
if (visible && timer === null) {
tick();
}
});
observer.observe(canvas);
return () => {
observer.disconnect();
if (timer !== null) {
clearTimeout(timer);
}
clear();
canvas.classList.remove(DIAGRAM_WALKING_CLASS);
};
};