import { css } from '@emotion/css'; import { useMemo } from 'react'; import { FALLBACK_COLOR, PanelProps } from '@grafana/data'; import { alpha } from '@grafana/data/src/themes/colorManipulator'; import { config } from '@grafana/runtime'; import { TooltipDisplayMode, TooltipPlugin2, UPlotChart, VizLayout, VizLegend, VizLegendItem, useStyles2, useTheme2, } from '@grafana/ui'; import { TooltipHoverMode } from '@grafana/ui/src/components/uPlot/plugins/TooltipPlugin2'; import { getDisplayValuesForCalcs } from '@grafana/ui/src/components/uPlot/utils'; import { getDataLinks } from '../status-history/utils'; import { XYChartTooltip } from './XYChartTooltip'; import { Options } from './panelcfg.gen'; import { prepConfig } from './scatter'; import { prepSeries } from './utils'; type Props2 = PanelProps; export const XYChartPanel2 = (props: Props2) => { const styles = useStyles2(getStyles); const theme = useTheme2(); let { mapping, series: mappedSeries } = props.options; // regenerate series schema when mappings or data changes let series = useMemo( () => prepSeries(mapping, mappedSeries, props.data.series, props.fieldConfig), // eslint-disable-next-line react-hooks/exhaustive-deps [mapping, mappedSeries, props.data.series, props.fieldConfig] ); // if series changed due to mappings or data structure, re-init config & renderers let { builder, prepData } = useMemo( () => prepConfig(series, config.theme2), // eslint-disable-next-line react-hooks/exhaustive-deps [mapping, mappedSeries, props.data.structureRev, props.fieldConfig, props.options.tooltip] ); // generate data struct for uPlot mode: 2 let data = useMemo( () => prepData(series), // eslint-disable-next-line react-hooks/exhaustive-deps [series] ); // todo: handle errors let error = builder == null || data.length === 0 ? 'Err' : ''; // TODO: React.memo() const renderLegend = () => { if (!props.options.legend.showLegend) { return null; } const items: VizLegendItem[] = []; series.forEach((s, idx) => { let yField = s.y.field; let config = yField.config; let custom = config.custom; if (!custom.hideFrom?.legend) { items.push({ yAxis: 1, // TODO: pull from y field label: s.name.value, color: alpha(s.color.fixed ?? FALLBACK_COLOR, 1), getItemKey: () => `${idx}-${s.name.value}`, fieldName: yField.state?.displayName ?? yField.name, disabled: yField.state?.hideFrom?.viz ?? false, getDisplayValues: () => getDisplayValuesForCalcs(props.options.legend.calcs, yField, theme), }); } }); const { placement, displayMode, width, sortBy, sortDesc } = props.options.legend; return ( ); }; if (error) { return (

{error}

); } return ( {(vizWidth: number, vizHeight: number) => ( {props.options.tooltip.mode !== TooltipDisplayMode.None && ( { const xySeries = series[seriesIdx - 1]; return getDataLinks(xySeries.y.field, dataIdx); }} render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2, viaSync, dataLinks) => { return ( ); }} maxWidth={props.options.tooltip.maxWidth} /> )} )} ); }; const getStyles = () => ({ legend: css({ div: { justifyContent: 'flex-start', }, }), });