49 lines
1.1 KiB
TypeScript
49 lines
1.1 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
import { clamp } from "lodash";
|
|
|
|
interface Props {
|
|
startTime: number | null;
|
|
length: number;
|
|
onTimeout?: () => unknown;
|
|
}
|
|
|
|
const invLerp = (a: number, b: number, x: number): number =>
|
|
clamp((x - b) / (a - b), 0, 1);
|
|
|
|
const Timer = ({ startTime, length, onTimeout }: Props) => {
|
|
const [segs, setSegs] = useState<number>(0);
|
|
const updateTimer = () => {
|
|
if (!startTime) return;
|
|
const endTime = startTime + length;
|
|
const currentTime = Date.now();
|
|
const segs = invLerp(startTime, endTime, currentTime) * 5;
|
|
setSegs(segs);
|
|
if (segs > 0) {
|
|
setTimeout(updateTimer, 100);
|
|
} else if (onTimeout) {
|
|
onTimeout();
|
|
}
|
|
};
|
|
useEffect(() => {
|
|
setTimeout(updateTimer, 100);
|
|
}, [startTime, length]);
|
|
|
|
return (
|
|
<svg viewBox="0 0 90 50" style={{ width: "100%", height: "100%" }}>
|
|
{[5, 4, 3, 2, 1, 2, 3, 4, 5].map((seg, i) => (
|
|
<rect
|
|
x={i * 10}
|
|
y="0"
|
|
width="10"
|
|
height="5"
|
|
key={i}
|
|
fill={seg <= segs ? "yellow" : "black"}
|
|
stroke="blue"
|
|
/>
|
|
))}
|
|
</svg>
|
|
);
|
|
};
|
|
|
|
export default Timer;
|