Skip to content

Commit 4735698

Browse files
committed
fix: properly format the data values in the new chart legend tooltip
This PR also adds a bit of transparency to the tooltip flyover.
1 parent d6c8b44 commit 4735698

File tree

3 files changed

+69
-42
lines changed

3 files changed

+69
-42
lines changed

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

Lines changed: 65 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class MyTooltipLegendLabel extends React.PureComponent<ChartLegendLabelProps> {
5757
return (
5858
<ChartLegendTooltipLabel
5959
{...this.props}
60-
dx={((dx || 0) * BaseChart.legendLabelStyle.fontSize) / 14 - 6}
60+
dx={((dx || 0) * BaseChart.legendLabelStyle.fontSize) / 14}
6161
style={BaseChart.legendLabelStyle}
6262
legendLabelComponent={<MyTooltipLabel />}
6363
/>
@@ -243,6 +243,7 @@ export default class BaseChart extends React.PureComponent<Props> {
243243
)
244244
}
245245

246+
/** @return UI for one y axis */
246247
private yAxis(axis: BaseChartProps["yAxes"][number]) {
247248
if (axis) {
248249
// re: the + BaseChart.fontSize * N: shift the axis labels over a bit, to overlap with the ticks
@@ -282,6 +283,43 @@ export default class BaseChart extends React.PureComponent<Props> {
282283
}
283284
}
284285

286+
/** @return UI for all of the y axes */
287+
private yAxes(chart: BaseChartProps) {
288+
return chart.series.flatMap(({ impl, stroke, fill = stroke, data }, idx) => {
289+
const yAxis =
290+
chart.yAxes[idx] ||
291+
chart.yAxes
292+
.slice(0, idx)
293+
.reverse()
294+
.find((_) => _ && _.y)
295+
const y = yAxis ? yAxis.y : undefined
296+
297+
const props = {
298+
style:
299+
impl === "ChartArea"
300+
? this.areaStyle(stroke, fill)
301+
: impl === "ChartLine"
302+
? this.lineStyle(fill)
303+
: this.lineDashStyle(fill),
304+
data,
305+
y,
306+
}
307+
308+
const chartui =
309+
impl === "ChartArea" ? (
310+
<ChartArea key={idx} interpolation="monotoneX" name={data[idx].name} {...props} />
311+
) : (
312+
<ChartLine key={idx} interpolation="monotoneX" name={data[idx].name} {...props} />
313+
)
314+
315+
if (chart.yAxes[idx]) {
316+
return [...this.yAxis(chart.yAxes[idx]), chartui]
317+
} else {
318+
return [chartui]
319+
}
320+
})
321+
}
322+
285323
private areaStyle(stroke: string, fill: string, strokeWidth = 2.5, fillOpacity = 0.1): ChartAreaProps["style"] {
286324
return { data: { stroke, strokeWidth, fill, fillOpacity } }
287325
}
@@ -305,11 +343,15 @@ export default class BaseChart extends React.PureComponent<Props> {
305343
)
306344
}
307345

308-
private getTooltipLabels({ datum }: { datum: { name: string; y: number } }) {
346+
/** @return the formatted data value to display in the `<ChartLegendTooltip />` */
347+
private getTooltipLabels(formatMap: Record<string, Format>, { datum }: { datum: { name: string; y: number } }) {
309348
// TODO: format these e.g. x% or xC or x Gi
310-
return `${datum.y}`
349+
const format = formatMap[datum.name]
350+
const formatter = format ? BaseChart.formatters[format] : undefined
351+
return formatter ? formatter(datum.y) : `${datum.y}`
311352
}
312353

354+
/** @return the `legendData` model for `<ChartLegendTooltip/>` */
313355
private getLegendData(chart: BaseChartProps): ChartLegendTooltipProps["legendData"] {
314356
return chart.series.map(({ data, stroke, fill }) => ({
315357
childName: data[0].name,
@@ -318,9 +360,25 @@ export default class BaseChart extends React.PureComponent<Props> {
318360
}))
319361
}
320362

363+
/** @return the UI for the idx-th chart in the chart set of this.props.charts */
321364
private chart(chart: BaseChartProps, idx: number) {
322-
// ariaTitle={chart.title}
323365
const CursorVoronoiContainer = createContainer("voronoi", "cursor")
366+
367+
// map from data series name to format (used in getTooltipLabels())
368+
const formatMap = chart.yAxes.reduce((M, yAxis, idx, yAxes) => {
369+
if (!yAxis) {
370+
yAxis = yAxes
371+
.slice(0, idx)
372+
.reverse()
373+
.find((_) => _)
374+
}
375+
if (yAxis) {
376+
const label = chart.series[idx].data[0].name || yAxis.label
377+
M[label] = yAxis.format
378+
}
379+
return M
380+
}, {} as Record<string, Format>)
381+
324382
return (
325383
<div className="codeflare-chart-container" key={idx}>
326384
<Chart
@@ -331,10 +389,11 @@ export default class BaseChart extends React.PureComponent<Props> {
331389
domain={chart.domain}
332390
containerComponent={
333391
<CursorVoronoiContainer
334-
labels={this.getTooltipLabels}
392+
labels={this.getTooltipLabels.bind(this, formatMap)}
335393
labelComponent={
336394
<ChartLegendTooltip
337395
isCursorTooltip
396+
flyoutStyle={{ fillOpacity: 0.825 }}
338397
labelComponent={<MyTooltipContent />}
339398
legendData={this.getLegendData(chart)}
340399
title={(datum: any) => `${new Date(datum.x + this.props.timeRange.min).toLocaleString()}`}
@@ -347,39 +406,7 @@ export default class BaseChart extends React.PureComponent<Props> {
347406
>
348407
{this.title(chart)}
349408
{this.xAxis()}
350-
{chart.series.flatMap(({ impl, stroke, fill = stroke, data }, idx) => {
351-
const yAxis =
352-
chart.yAxes[idx] ||
353-
chart.yAxes
354-
.slice(0, idx)
355-
.reverse()
356-
.find((_) => _ && _.y)
357-
const y = yAxis ? yAxis.y : undefined
358-
359-
const props = {
360-
style:
361-
impl === "ChartArea"
362-
? this.areaStyle(stroke, fill)
363-
: impl === "ChartLine"
364-
? this.lineStyle(fill)
365-
: this.lineDashStyle(fill),
366-
data,
367-
y,
368-
}
369-
370-
const chartui =
371-
impl === "ChartArea" ? (
372-
<ChartArea key={idx} interpolation="monotoneX" name={data[idx].name} {...props} />
373-
) : (
374-
<ChartLine key={idx} interpolation="monotoneX" name={data[idx].name} {...props} />
375-
)
376-
377-
if (chart.yAxes[idx]) {
378-
return [...this.yAxis(chart.yAxes[idx]), chartui]
379-
} else {
380-
return [chartui]
381-
}
382-
})}
409+
{this.yAxes(chart)}
383410
</Chart>
384411
</div>
385412
)

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,19 @@ export default class GPUChart extends React.PureComponent<Props, State> {
4343
private static charts(props: Props): BaseChartProps[] {
4444
return Object.entries(props.logs).map(([node, lines]) => {
4545
const d1 = lines.map((line) => ({
46-
name: BaseChart.nodeNameLabel(node) + " GPU Utilization",
46+
name: BaseChart.nodeNameLabel(node) + " GPU",
4747
x: line.timestamp - props.timeRange.min,
4848
y: line.utilizationGPU,
4949
}))
5050

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

5757
const d3 = lines.map((line) => ({
58-
name: BaseChart.nodeNameLabel(node) + " GPU Temperature",
58+
name: BaseChart.nodeNameLabel(node) + " Temperature",
5959
x: line.timestamp - props.timeRange.min,
6060
y: line.temperatureGPU,
6161
}))

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export default class VmstatChart extends React.PureComponent<Props, State> {
3939
private static charts(props: Props): BaseChartProps[] {
4040
return Object.entries(props.logs).map(([node, lines]) => {
4141
const d1 = lines.map((line) => ({
42-
name: BaseChart.nodeNameLabel(node) + " CPU Utilization",
42+
name: BaseChart.nodeNameLabel(node) + " CPU",
4343
x: line.timestamp - props.timeRange.min,
4444
y: 100 - line.idle,
4545
}))

0 commit comments

Comments
 (0)