Skip to content

Commit c1d28e5

Browse files
committed
Improve CustomItemTooltip to include individual trials, headers and style
1 parent c29c6b6 commit c1d28e5

2 files changed

Lines changed: 149 additions & 22 deletions

File tree

src/components/benchmarks/CustomItemTooltip.tsx

Lines changed: 145 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,76 @@ import Popper from "@mui/material/Popper";
44
import Paper from "@mui/material/Paper";
55
import Stack from "@mui/material/Stack";
66
import Typography from "@mui/material/Typography";
7+
import Divider from "@mui/material/Divider";
8+
import Box from "@mui/material/Box";
79
import { useItemTooltip, useMouseTracker } from "@mui/x-charts";
810
import { generateVirtualElement } from "./generateVirtualElement";
11+
import { BulkPoint, ProcessedTrialData, SoloPoint } from "@/types/global";
912

10-
export function CustomItemTooltip() {
13+
interface CustomItemTooltipProps {
14+
datePoints?: Record<string, ProcessedTrialData[]>;
15+
}
16+
17+
export function CustomItemTooltip({ datePoints = {} }: CustomItemTooltipProps) {
1118
const tooltipData = useItemTooltip();
12-
const mousePosition = useMouseTracker(); // Track the mouse position on chart.
19+
const mousePosition = useMouseTracker();
1320

1421
if (!tooltipData || !mousePosition) {
15-
// No data to display
1622
return null;
1723
}
1824

19-
// The pointer type can be used to have different behavior based on pointer type.
25+
const isSoloOrBulkPoint = (
26+
value: unknown
27+
): value is SoloPoint | BulkPoint => {
28+
return value !== null && typeof value === "object" && "id" in value;
29+
};
30+
2031
const isMousePointer = mousePosition?.pointerType === "mouse";
21-
// Adapt the tooltip offset to the size of the pointer.
2232
const yOffset = isMousePointer ? 0 : 40 - mousePosition.height;
33+
const getRangeMarkerType = () => {
34+
if (isSoloOrBulkPoint(tooltipData.value)) {
35+
const id = tooltipData.value.id;
36+
if (id.startsWith("min-")) return "Lowest Score";
37+
if (id.startsWith("max-")) return "Highest Score";
38+
}
39+
return null;
40+
};
41+
42+
const getFormattedDate = () => {
43+
if (isSoloOrBulkPoint(tooltipData.value)) {
44+
let dateString = tooltipData.value.id;
45+
46+
// If it's a range marker, extract the actual date from the id
47+
if (dateString.startsWith("min-") || dateString.startsWith("max-")) {
48+
dateString = dateString.replace(/^(min-|max-)/, "");
49+
}
50+
51+
const date = new Date(dateString);
52+
return date.toLocaleDateString("en-US", {
53+
month: "long",
54+
day: "numeric",
55+
year: "numeric",
56+
});
57+
}
58+
return "Unknown Date";
59+
};
60+
61+
const getTrialsForPoint = () => {
62+
if (!datePoints) return [];
2363

24-
console.log("tooltipData.value", tooltipData.value);
64+
if (isSoloOrBulkPoint(tooltipData.value)) {
65+
const dateKey = tooltipData.value.id;
66+
if (dateKey && datePoints[dateKey]) {
67+
return datePoints[dateKey];
68+
}
69+
}
70+
71+
return [];
72+
};
73+
74+
const trials = getTrialsForPoint();
75+
const formattedDate = getFormattedDate();
76+
const isMultiTrial = trials.length > 1;
2577

2678
return (
2779
<NoSsr>
@@ -43,29 +95,102 @@ export function CustomItemTooltip() {
4395
]}
4496
>
4597
<Paper
46-
elevation={0}
98+
elevation={2}
4799
sx={{
48100
m: 1,
49-
p: 1.5,
50-
border: "solid",
51-
borderWidth: 2,
52-
borderColor: "divider",
101+
p: 2,
102+
minWidth: 250,
103+
maxWidth: 350,
53104
}}
54105
>
55-
<Stack direction="row" alignItems="center">
56-
<div
57-
style={{
58-
width: 11,
59-
height: 11,
60-
borderRadius: "50%",
106+
<Typography variant="subtitle1" sx={{ fontWeight: "bold", mb: 1 }}>
107+
{formattedDate}
108+
</Typography>
109+
110+
<Stack direction="row" alignItems="center" spacing={1}>
111+
<Box
112+
sx={{
113+
width: 12,
114+
height: 12,
61115
backgroundColor: tooltipData.color,
62116
}}
63117
/>
64-
<Typography sx={{ ml: 2 }} fontWeight="light">
65-
{tooltipData.label}
118+
<Typography variant="body2" sx={{ fontWeight: "medium" }}>
119+
{getRangeMarkerType()
120+
? `${getRangeMarkerType()}`
121+
: tooltipData.label}
122+
</Typography>
123+
<Typography variant="body2" sx={{ fontWeight: "bold", ml: "auto" }}>
124+
{tooltipData.formattedValue}
66125
</Typography>
67-
<Typography sx={{ ml: 2 }}>{tooltipData.formattedValue}</Typography>
68126
</Stack>
127+
128+
{trials.length > 0 && (
129+
<>
130+
<Divider sx={{ my: 1 }} />
131+
<Typography variant="body2" sx={{ fontWeight: "bold", mb: 1 }}>
132+
{isMultiTrial && (
133+
<Typography
134+
variant="body2"
135+
sx={{ fontWeight: "bold", mb: 1 }}
136+
>
137+
Individual Trials
138+
</Typography>
139+
)}
140+
</Typography>
141+
142+
<Stack spacing={0.5}>
143+
{trials.map((trial, idx) => (
144+
<Stack
145+
key={trial.trial_data_id || idx}
146+
direction="row"
147+
justifyContent="space-between"
148+
alignItems="center"
149+
sx={{
150+
py: 0.25,
151+
px: 1,
152+
backgroundColor:
153+
idx % 2 === 0 ? "action.hover" : "transparent",
154+
borderRadius: 0.5,
155+
}}
156+
>
157+
<Typography variant="body2" sx={{ fontSize: "0.8rem" }}>
158+
{isMultiTrial ? `Trial ${idx + 1}` : "Trial Detail"}
159+
</Typography>
160+
<Typography
161+
variant="body2"
162+
sx={{ fontSize: "0.8rem", fontWeight: "medium" }}
163+
>
164+
{trial.successRate?.toFixed(1)}%
165+
</Typography>
166+
<Typography
167+
variant="body2"
168+
sx={{ fontSize: "0.75rem", color: "text.secondary" }}
169+
>
170+
({trial.success}/{trial.numberOfAttempts})
171+
</Typography>
172+
</Stack>
173+
))}
174+
</Stack>
175+
176+
{trials.length > 0 && (
177+
<Typography
178+
variant="body2"
179+
sx={{
180+
fontSize: "0.75rem",
181+
color: "text.secondary",
182+
mt: 1,
183+
fontStyle: "italic",
184+
}}
185+
>
186+
Staff:{" "}
187+
{Array.from(new Set(trials.map((t) => t.staffName))).join(
188+
", "
189+
)}
190+
</Typography>
191+
)}
192+
</>
193+
)}
69194
</Paper>
70195
</Popper>
71196
</NoSsr>

src/types/global.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ export interface ProcessedTrialData extends TrialData {
6464

6565
export const valueFormatter = (point: SoloPoint | BulkPoint): string => {
6666
if ("numberOfTrials" in point) {
67-
return `${point.y.toFixed(1)}% (${point.numberOfTrials} trials) [${point.staffNames.join(" ")}]`;
67+
return `${point.y.toFixed(1)}% avg (${point.numberOfTrials} trials)`;
6868
} else {
69-
return `${point.y.toFixed(1)}% (${point.success} / ${point.numberOfAttempts}) [${point.staffName}]`;
69+
return `${point.y.toFixed(1)}% avg over ${point.numberOfAttempts} attempt${
70+
point.numberOfAttempts !== 1 ? "s" : ""
71+
}`;
7072
}
7173
};

0 commit comments

Comments
 (0)