import { FC, useEffect, useState } from "react"; import { PlayerRanking } from "./types"; import { useSession } from "./Session"; interface RaceChartProps { playerRanks: PlayerRanking[]; std: boolean; } const determineNiceWidth = (width: number) => { const max = 1080; if (width >= max) return max; else if (width > 768) return width * 0.8; else return width * 0.96; }; const RaceChart: FC = ({ playerRanks, std }) => { const [width, setWidth] = useState(determineNiceWidth(window.innerWidth)); const height = (playerRanks.length + 1) * 40; const { players } = useSession(); useEffect(() => { const handleResize = () => { setWidth(determineNiceWidth(window.innerWidth)); }; window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); }; }, []); const padding = 24; const gap = 8; const maxValue = Math.max(...playerRanks.map((player) => player.rank)) + 1; const barHeight = (height - 2 * padding) / playerRanks.length; const fontSize = Math.min(barHeight - 1.5 * gap, width / 22); return ( {playerRanks.map((playerRank, index) => ( ))} {playerRanks.map((playerRank, index) => { const player = players!.find((p) => p.id === playerRank.p_id); return ( {`${String(index + 1).padStart(2)}. ${player?.display_name}`} p.display_name.length))) * fontSize * 0.66 } y={index * barHeight + barHeight / 2 + padding + gap / 2} width={(1 - playerRank.rank / maxValue) * width} height={barHeight - 8} // subtract 2 for some spacing between bars fontSize={0.8 * fontSize} fill="aliceblue" stroke="#36c" fontWeight={"bold"} fontFamily="monospace" strokeWidth={4} paintOrder={"stroke fill"} style={{ whiteSpace: "pre" }} > {`${String(playerRank.rank).padStart(5)} ± ${playerRank.std} N = ${playerRank.n}`} ); })} ); }; export default RaceChart;