Skip to content

Commit

Permalink
epa over time chart
Browse files Browse the repository at this point in the history
  • Loading branch information
salvobonsma committed Aug 23, 2024
1 parent 1970d83 commit a91a339
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 13 deletions.
15 changes: 14 additions & 1 deletion app/[eventId]/[teamNumber]/client-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,23 @@ import {cn} from "@/lib/utils";
import KeyBindListener from "@/components/key-bind-listener";
import {Tooltip, TooltipContent, TooltipTrigger} from "@/components/ui/tooltip";
import Matches, {Match} from "@/app/[eventId]/[teamNumber]/matches/matches";
import EPAOverTime from "@/components/epa-over-time";

export const teamDataSchema = z.object({
notes: z.string(),
});

export default function ClientPage({event, team, teamEntry, teamDetails, statistics, events, pastSeasons, matches}: {
export default function ClientPage({
event,
team,
teamEntry,
teamDetails,
statistics,
events,
eventsList,
pastSeasons,
matches
}: {
event: { id: number },
team: { rookieYear: number | null, state: string | null, school: string | null, number: number },
teamEntry: {
Expand Down Expand Up @@ -60,6 +71,7 @@ export default function ClientPage({event, team, teamEntry, teamDetails, statist
teamDetails: ReactNode,
statistics: ReactNode,
events: ReactNode,
eventsList: { eventKey: string, name: string }[]
pastSeasons: ReactNode
}) {
const [status, setStatus] = useState(teamEntry.status as TeamStatus);
Expand Down Expand Up @@ -222,6 +234,7 @@ export default function ClientPage({event, team, teamEntry, teamDetails, statist
<h1 className={"mt"}>Statistics</h1>
<Separator/>
{statistics}
<EPAOverTime matches={matches} events={eventsList}/>
<h1 className={"mt"}>Events</h1>
<Separator/>
{events}
Expand Down
4 changes: 4 additions & 0 deletions app/[eventId]/[teamNumber]/matches/matches.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import MatchView from "@/app/[eventId]/[teamNumber]/matches/matchView";

export type Match = {
key: string,
totalEPA: number,
autoEPA: number,
teleopEPA: number,
endgameEPA: number,
eventKey: string,
matchNumber: number,
winningAlliance: "red" | "blue" | "",
Expand Down
5 changes: 5 additions & 0 deletions app/[eventId]/[teamNumber]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,11 @@ export default async function Team({params}: { params: { eventId: string, teamNu
)
)
}
eventsList={await prisma.teamEvent.findMany({
where: {
teamNumber: teamEntry.teamNumber
}
})}
matches={matches.map(value => ({
...value,
compLevel: value.compLevel as "qm" | "ef" | "qf" | "sf" | "f",
Expand Down
2 changes: 2 additions & 0 deletions app/[eventId]/overview/[teamNumber]/client-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {Button} from "@/components/ui/button";
import EventCard from "@/app/[eventId]/[teamNumber]/event-card";
import ScoutingCharts from "@/app/[eventId]/overview/scouting-charts";
import Matches, {Match} from "@/app/[eventId]/overview/[teamNumber]/matches/matches";
import EPAOverTime from "@/components/epa-over-time";

export default function ClientPage({event, team, teamEntry, matches, matchEntries, scoutedMatches, events}: {
event: Event,
Expand Down Expand Up @@ -246,6 +247,7 @@ export default function ClientPage({event, team, teamEntry, matches, matchEntrie
</Card>
</div>
)}
<EPAOverTime matches={matches} events={events}/>
<h1 className={"mt"}>Events</h1>
<Separator/>
{
Expand Down
4 changes: 4 additions & 0 deletions app/[eventId]/overview/[teamNumber]/matches/matches.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import MatchView from "./matchView";

export type Match = {
key: string,
totalEPA: number,
autoEPA: number,
teleopEPA: number,
endgameEPA: number,
eventKey: string,
matchNumber: number,
winningAlliance: "red" | "blue" | "",
Expand Down
6 changes: 3 additions & 3 deletions app/[eventId]/overview/overview-charts.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import {Bar, BarChart, CartesianGrid, LabelList, Pie, PieChart} from "recharts";
import {Bar, BarChart, CartesianGrid, LabelList, Pie, PieChart, XAxis} from "recharts";

import {ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent} from "@/components/ui/chart";
import {TeamEntry} from "@prisma/client";
Expand Down Expand Up @@ -123,8 +123,8 @@ export default function OverviewCharts({teamEntries}: { teamEntries: TeamEntry[]
<ChartContainer config={config} className="h-48 w-full">
<BarChart accessibilityLayer data={data}>
<CartesianGrid vertical={false}/>
<ChartTooltip content={<ChartTooltipContent className={"w-40"} labelKey={"teamNumber"}
indicator={"line"}/>}/>
<ChartTooltip content={<ChartTooltipContent className={"w-40"} indicator={"line"}/>}/>
<XAxis hide dataKey={"teamNumber"}/>
<Bar dataKey={dataKey} fill={`var(--chart-1)`} radius={2}/>
</BarChart>
</ChartContainer>
Expand Down
6 changes: 3 additions & 3 deletions app/[eventId]/overview/scouting-charts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import {MatchEntry} from "@prisma/client";
import React from "react";
import {ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent} from "@/components/ui/chart";
import {Area, AreaChart, Bar, BarChart, CartesianGrid, LabelList, Pie, PieChart} from "recharts";
import {Area, AreaChart, Bar, BarChart, CartesianGrid, LabelList, Pie, PieChart, XAxis} from "recharts";
import {Card, CardContent, CardDescription, CardHeader, CardTitle} from "@/components/ui/card";

export default function ScoutingCharts({matches, forTeam}: {
Expand Down Expand Up @@ -54,8 +54,8 @@ export default function ScoutingCharts({matches, forTeam}: {
<ChartContainer config={config} className="h-48 w-full">
<BarChart accessibilityLayer data={data}>
<CartesianGrid vertical={false}/>
<ChartTooltip content={<ChartTooltipContent className={"w-40"} labelKey={labelKey}
indicator={"line"}/>}/>
<ChartTooltip content={<ChartTooltipContent className={"w-40"} indicator={"line"}/>}/>
<XAxis hide dataKey={"teamNumber"}/>
<Bar dataKey={dataKey} fill={`var(--chart-1)`} radius={2}/>
</BarChart>
</ChartContainer>
Expand Down
129 changes: 129 additions & 0 deletions components/epa-over-time.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import {Card, CardContent, CardHeader, CardTitle} from "@/components/ui/card";
import React from "react";
import {Area, AreaChart, CartesianGrid, XAxis, YAxis} from "recharts";
import {
ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent
} from "@/components/ui/chart";
import {Match} from "@/app/[eventId]/[teamNumber]/matches/matches";

const chartConfig = {
totalEPA: {
label: "Total EPA",
color: "var(--chart-1)"
},
autoEPA: {
label: "Auto EPA",
},
teleopEPA: {
label: "Teleop EPA",
},
endgameEPA: {
label: "Endgame EPA",
}
} satisfies ChartConfig

export default function EPAOverTime({matches, events}: {
matches: Match[],
events: { eventKey: string, name: string }[]
}) {
const formatedMatches = [...matches]
.filter(value => value.totalEPA >= 0)
.sort((a, b) => a.startTime - b.startTime)
.map(value => ({
...value,
xAxis: `${events.find(value1 => value1.eventKey == value.eventKey)?.name ?? ""}\nMatch ${value.matchNumber}`
}));

return (
<Card className={"mt-sm w-full xl:w-[65em]"}>
<CardHeader className={"flex justify-between"}>
<CardTitle>EPA Over Time</CardTitle>
</CardHeader>
<CardContent>
<ChartContainer className={"h-72 w-full"} config={chartConfig}>
<AreaChart
accessibilityLayer
data={formatedMatches}
>
<CartesianGrid vertical={false}/>
<ChartTooltip
content={
<ChartTooltipContent labelFormatter={(value) => (
<div className={"flex flex-col"}>
<span>{value.split("\n")[0]}</span>
<span>{value.split("\n")[1]}</span>
</div>
)} className={"w-40"}/>
}
cursor={false}
/>
<XAxis
dataKey="xAxis"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.split("\n")[0]}
/>
<YAxis
tickLine={false}
axisLine={false}
tickMargin={8}
tickCount={5}
/>
<Area
dataKey="totalEPA"
type="natural"
// dot={{
// fill: "var(--chart-1)"
// }}
fillOpacity={0}
strokeOpacity={0}
fill="var(--chart-4)"
stroke=""
stackId="b"
/>
<Area
dataKey="autoEPA"
type="natural"
// dot={{
// fill: "var(--chart-1)"
// }}
fillOpacity={0.4}
fill="var(--chart-1)"
stroke="var(--chart-1)"
stackId="a"
/>
<Area
dataKey="teleopEPA"
// dot={{
// fill: "var(--chart-2)"
// }}
type="natural"
fillOpacity={0.4}
fill="var(--chart-2)"
stroke="var(--chart-2)"
stackId="a"
/>
<Area
dataKey="endgameEPA"
type="natural"
// dot={{
// fill: "var(--chart-3)"
// }}
fillOpacity={0.4}
fill="var(--chart-3)"
stroke="var(--chart-3)"
stackId="a"
/>
<ChartLegend content={<ChartLegendContent/>}/>
</AreaChart>
</ChartContainer>
</CardContent>
</Card>
);
}
7 changes: 2 additions & 5 deletions components/ui/chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,11 @@ const ChartTooltipContent = React.forwardRef<
const [item] = payload
const key = `${labelKey || item.dataKey || item.name || "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
let value =
!labelKey && typeof label === "string"
const value =
!labelKey
? config[label as keyof typeof config]?.label || label
: itemConfig?.label

if (labelKey == "teamNumber") value = item.payload.teamNumber;
if (labelKey == "score") value = `${item.payload.score} Scores`;

if (labelFormatter) {
return (
<div className={cn("font-medium", labelClassName)}>
Expand Down
2 changes: 1 addition & 1 deletion components/youtube-embed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import {cn} from "@/lib/utils";
import {Button} from "@/components/ui/button";
import {Match} from "@/app/[eventId]/[teamNumber]/matches/matches";
import {GetEvent} from "@/lib/database/get-event";
import {Match} from "@/app/[eventId]/overview/[teamNumber]/matches/matches";

export default function YoutubeEmbed({id, match, className}: {
id: string | null,
Expand Down

0 comments on commit a91a339

Please sign in to comment.