2025-04-01 10:38:02 +09:00

125 lines
3.7 KiB
TypeScript

import { ReactNode } from 'react';
import { DataFrame, InterpolateFunction, LinkModel } from '@grafana/data';
import { alpha } from '@grafana/data/src/themes/colorManipulator';
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
import { VizTooltipWrapper } from '@grafana/ui/src/components/VizTooltip/VizTooltipWrapper';
import { ColorIndicator, VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
import { getFieldActions } from '../status-history/utils';
import { XYSeries } from './types2';
import { fmt } from './utils';
export interface Props {
dataIdxs: Array<number | null>;
seriesIdx: number | null | undefined;
isPinned: boolean;
dismiss: () => void;
data: DataFrame[];
xySeries: XYSeries[];
replaceVariables: InterpolateFunction;
dataLinks: LinkModel[];
}
function stripSeriesName(fieldName: string, seriesName: string) {
if (fieldName !== seriesName && fieldName.includes(' ')) {
fieldName = fieldName.replace(seriesName, '').trim();
}
return fieldName;
}
export const XYChartTooltip = ({
dataIdxs,
seriesIdx,
data,
xySeries,
dismiss,
isPinned,
replaceVariables,
dataLinks,
}: Props) => {
const rowIndex = dataIdxs.find((idx) => idx !== null)!;
const series = xySeries[seriesIdx! - 1];
const xField = series.x.field;
const yField = series.y.field;
const sizeField = series.size.field;
const colorField = series.color.field;
let label = series.name.value;
let seriesColor = series.color.fixed;
// let colorField = series.color.field;
// let pointColor: string;
// if (colorField != null) {
// pointColor = colorField.display?.(colorField.values[rowIndex]).color!;
// }
const headerItem: VizTooltipItem = {
label,
value: '',
color: alpha(seriesColor ?? '#fff', 0.5),
colorIndicator: ColorIndicator.marker_md,
};
const contentItems: VizTooltipItem[] = [
{
label: stripSeriesName(xField.state?.displayName ?? xField.name, label),
value: fmt(xField, xField.values[rowIndex]),
},
{
label: stripSeriesName(yField.state?.displayName ?? yField.name, label),
value: fmt(yField, yField.values[rowIndex]),
},
];
// mapped fields for size/color
if (sizeField != null && sizeField !== yField) {
contentItems.push({
label: stripSeriesName(sizeField.state?.displayName ?? sizeField.name, label),
value: fmt(sizeField, sizeField.values[rowIndex]),
});
}
if (colorField != null && colorField !== yField) {
contentItems.push({
label: stripSeriesName(colorField.state?.displayName ?? colorField.name, label),
value: fmt(colorField, colorField.values[rowIndex]),
});
}
series._rest.forEach((field) => {
contentItems.push({
label: stripSeriesName(field.state?.displayName ?? field.name, label),
value: fmt(field, field.values[rowIndex]),
});
});
let footer: ReactNode;
if (seriesIdx != null) {
const hasOneClickLink = dataLinks?.some((dataLink) => dataLink.oneClick === true);
if (isPinned || hasOneClickLink) {
const yFieldFrame = data.find((frame) => frame.fields.includes(yField))!;
const actions = getFieldActions(yFieldFrame, yField, replaceVariables, rowIndex);
footer = <VizTooltipFooter dataLinks={dataLinks} actions={actions} />;
}
}
return (
<VizTooltipWrapper>
<VizTooltipHeader item={headerItem} isPinned={isPinned} />
<VizTooltipContent items={contentItems} isPinned={isPinned} />
{footer}
</VizTooltipWrapper>
);
};