Skip to content

Commit bd3b3ea

Browse files
Pablo Carmonastarpit
Pablo Carmona
authored andcommitted
feat: use fancy legend tooltips in charts
this requires a change from voronoicontainer to cursorvoronoicontainer implementation
1 parent 6b4b82e commit bd3b3ea

File tree

2 files changed

+78
-12
lines changed

2 files changed

+78
-12
lines changed

plugins/plugin-codeflare/src/components/Chart.tsx

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,56 @@ import {
2727
ChartLabelProps,
2828
ChartLine,
2929
ChartLineProps,
30-
ChartTooltip,
31-
ChartVoronoiContainer,
30+
ChartLegendTooltip,
31+
ChartLegendTooltipContent,
32+
ChartLegendTooltipContentProps,
33+
ChartLegendTooltipLabel,
34+
ChartLegendTooltipProps,
35+
ChartLegendLabelProps,
36+
createContainer,
3237
} from "@patternfly/react-charts"
3338

3439
import "../../web/scss/components/Dashboard/Charts.scss"
3540

3641
type Format = "celsius" | "percentage" | "timestamp" | "memory"
3742

43+
class MyTooltipLabel extends React.PureComponent<ChartLabelProps> {
44+
public render() {
45+
return <ChartLabel {...this.props} style={BaseChart.legendLabelStyle} />
46+
}
47+
}
48+
49+
class MyTooltipLegendLabel extends React.PureComponent<ChartLegendLabelProps> {
50+
public render() {
51+
const dx =
52+
typeof this.props.dx === "number"
53+
? this.props.dx
54+
: typeof this.props.dx === "string"
55+
? parseInt(this.props.dx, 10)
56+
: 0
57+
return (
58+
<ChartLegendTooltipLabel
59+
{...this.props}
60+
dx={((dx || 0) * BaseChart.legendLabelStyle.fontSize) / 14 - 6}
61+
style={BaseChart.legendLabelStyle}
62+
legendLabelComponent={<MyTooltipLabel />}
63+
/>
64+
)
65+
}
66+
}
67+
68+
class MyTooltipContent extends React.PureComponent<ChartLegendTooltipContentProps> {
69+
public render() {
70+
return (
71+
<ChartLegendTooltipContent
72+
{...this.props}
73+
labelComponent={<MyTooltipLegendLabel />}
74+
titleComponent={<ChartLabel style={BaseChart.legendTitleStyle} />}
75+
/>
76+
)
77+
}
78+
}
79+
3880
export type Series = {
3981
impl: "ChartArea" | "ChartLine" | "ChartDashedLine"
4082
stroke: string
@@ -99,6 +141,14 @@ export default class BaseChart extends React.PureComponent<Props> {
99141
private static readonly labelColor = "var(--color-text-01)"
100142
private static readonly fontFamily = "var(--font-sans-serif)"
101143

144+
/** See our overrides above */
145+
public static readonly legendLabelStyle = {
146+
fontSize: BaseChart.fontSize,
147+
fontFamily: BaseChart.fontFamily,
148+
fill: "var(--color-base00)",
149+
}
150+
public static readonly legendTitleStyle = Object.assign({}, BaseChart.legendLabelStyle, { fontWeight: "bold" })
151+
102152
public static readonly axisStyle: ChartAxisProps["style"] = {
103153
ticks: { strokeOpacity: 0 },
104154
tickLabels: {
@@ -255,8 +305,22 @@ export default class BaseChart extends React.PureComponent<Props> {
255305
)
256306
}
257307

308+
private getTooltipLabels({ datum }: { datum: { name: string; y: number } }) {
309+
// TODO: format these e.g. x% or xC or x Gi
310+
return `${datum.y}`
311+
}
312+
313+
private getLegendData(chart: BaseChartProps): ChartLegendTooltipProps["legendData"] {
314+
return chart.series.map(({ data, stroke, fill }) => ({
315+
childName: data[0].name,
316+
name: data[0].name?.replace(/^\S+\s*/, ""),
317+
symbol: { fill: fill || stroke },
318+
}))
319+
}
320+
258321
private chart(chart: BaseChartProps, idx: number) {
259322
// ariaTitle={chart.title}
323+
const CursorVoronoiContainer = createContainer("voronoi", "cursor")
260324
return (
261325
<div className="codeflare-chart-container" key={idx}>
262326
<Chart
@@ -266,16 +330,18 @@ export default class BaseChart extends React.PureComponent<Props> {
266330
height={BaseChart.dimensions.height}
267331
domain={chart.domain}
268332
containerComponent={
269-
<ChartVoronoiContainer
270-
voronoiDimension="x"
271-
constrainToVisibleArea
272-
labels={({ datum }) => `${datum.name.replace(/^\S+\s*/, "")}: ${datum.y}`}
333+
<CursorVoronoiContainer
334+
labels={this.getTooltipLabels}
273335
labelComponent={
274-
<ChartTooltip
275-
style={{ fontSize: BaseChart.fontSize, fill: "var(--color-text-01)", textAnchor: "end" }}
276-
flyoutStyle={{ fill: "var(--color-base00)", strokeWidth: 0.5, stroke: "var(--color-base02)" }}
336+
<ChartLegendTooltip
337+
isCursorTooltip
338+
labelComponent={<MyTooltipContent />}
339+
legendData={this.getLegendData(chart)}
340+
title={(datum: any) => `${new Date(datum.x + this.props.timeRange.min).toLocaleString()}`}
277341
/>
278342
}
343+
mouseFollowTooltips
344+
voronoiPadding={20}
279345
/>
280346
}
281347
>
@@ -303,9 +369,9 @@ export default class BaseChart extends React.PureComponent<Props> {
303369

304370
const chartui =
305371
impl === "ChartArea" ? (
306-
<ChartArea key={idx} interpolation="monotoneX" {...props} />
372+
<ChartArea key={idx} interpolation="monotoneX" name={data[idx].name} {...props} />
307373
) : (
308-
<ChartLine key={idx} interpolation="monotoneX" {...props} />
374+
<ChartLine key={idx} interpolation="monotoneX" name={data[idx].name} {...props} />
309375
)
310376

311377
if (chart.yAxes[idx]) {

plugins/plugin-codeflare/src/components/GPUChart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default class GPUChart extends React.PureComponent<Props, State> {
4949
}))
5050

5151
const d2 = lines.map((line) => ({
52-
name: BaseChart.nodeNameLabel(node) + " GPU Memory Utilization",
52+
name: BaseChart.nodeNameLabel(node) + " GPU Memory",
5353
x: line.timestamp - props.timeRange.min,
5454
y: line.utilizationMemory,
5555
}))

0 commit comments

Comments
 (0)