feat: add RaceChart

This commit is contained in:
julius 2025-02-24 17:53:01 +01:00
parent 5fef47f692
commit d6e5d0334c
Signed by: julius
GPG Key ID: C80A63E6A5FD7092
2 changed files with 100 additions and 0 deletions

29
src/MVPChart.tsx Normal file
View File

@ -0,0 +1,29 @@
import { useEffect, useState } from "react";
import { apiAuth } from "./api";
import BarChart from "./BarChart";
import { PlayerRanking } from "./types";
import RaceChart from "./RaceChart";
const MVPChart = () => {
const [data, setData] = useState({} as PlayerRanking[]);
const [loading, setLoading] = useState(true);
const [showStd, setShowStd] = useState(false);
async function loadData() {
setLoading(true);
await apiAuth("analysis/mvp", null)
.then(json => json as Promise<PlayerRanking[]>).then(json => { setData(json.sort((a, b) => a.rank - b.rank)) })
setLoading(false);
}
useEffect(() => { loadData() }, [])
return (
<>
{loading ? <span className="loader" /> : <RaceChart std={showStd} players={data} />
}
</>)
}
export default MVPChart;

71
src/RaceChart.tsx Normal file
View File

@ -0,0 +1,71 @@
import { FC, useEffect, useState } from 'react';
import { PlayerRanking } from './types';
interface RaceChartProps {
players: 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<RaceChartProps> = ({ players, std }) => {
// State to store window's width and height
const [width, setWidth] = useState(determineNiceWidth(window.innerWidth));
const [height, setHeight] = useState(window.innerHeight);
// Update state on resize
useEffect(() => {
const handleResize = () => {
setWidth(determineNiceWidth(window.innerWidth));
setHeight(window.innerHeight);
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
const padding = 24;
const gap = 8
const maxValue = Math.max(...players.map((player) => player.rank)) + 1;
const barHeight = (height - 2 * padding) / players.length;
return (
<svg width={width} height={height}>
{players.map((player, index) => (
<rect
key={index}
x={0}
y={index * barHeight + padding}
width={(1 - player.rank / maxValue) * width}
height={barHeight - gap} // subtract 2 for some spacing between bars
fill="#36c"
/>))}
{players.map((player, index) => (
<text
key={index}
x={4}
y={index * barHeight + barHeight / 2 + padding + gap / 2}
width={(1 - player.rank / maxValue) * width}
height={barHeight - 8} // subtract 2 for some spacing between bars
fontSize="24px"
fill="aliceblue"
stroke='#36c'
strokeWidth={0.8}
fontWeight={"bold"}
>{player.name}</text>
))}
</svg>
)
}
export default RaceChart;