import React, { useEffect, useState } from 'react'; import { DataHoverClearEvent, DataHoverEvent, FALLBACK_COLOR, FieldDisplay, formattedValueToString, getFieldDisplayValues, PanelProps, } from '@grafana/data'; import { PieChart } from './PieChart'; import { PieChartLegendOptions, PieChartLegendValues, PieChartOptions } from './types'; import { Subscription } from 'rxjs'; import { LegendDisplayMode, usePanelContext, useTheme2, VizLayout, VizLegend, VizLegendItem, SeriesVisibilityChangeBehavior, } from '@grafana/ui'; const defaultLegendOptions: PieChartLegendOptions = { displayMode: LegendDisplayMode.List, placement: 'right', calcs: [], values: [PieChartLegendValues.Percent], }; interface Props extends PanelProps {} /** * @beta */ export function PieChartPanel(props: Props) { const { data, timeZone, fieldConfig, replaceVariables, width, height, options } = props; const theme = useTheme2(); const highlightedTitle = useSliceHighlightState(); const fieldDisplayValues = getFieldDisplayValues({ fieldConfig, reduceOptions: options.reduceOptions, data: data.series, theme: theme, replaceVariables, timeZone, }); return ( {(vizWidth: number, vizHeight: number) => { return ( ); }} ); } function getLegend(props: Props, displayValues: FieldDisplay[]) { const legendOptions = props.options.legend ?? defaultLegendOptions; if (legendOptions.displayMode === LegendDisplayMode.Hidden) { return undefined; } const total = displayValues .filter((item) => { return !item.field.custom?.hideFrom?.viz; }) .reduce((acc, item) => item.display.numeric + acc, 0); const legendItems = displayValues.map((value, idx) => { const hidden = value.field.custom.hideFrom.viz; const display = value.display; return { label: display.title ?? '', color: display.color ?? FALLBACK_COLOR, yAxis: 1, disabled: hidden, getItemKey: () => (display.title ?? '') + idx, getDisplayValues: () => { const valuesToShow = legendOptions.values ?? []; let displayValues = []; if (valuesToShow.includes(PieChartLegendValues.Value)) { displayValues.push({ numeric: display.numeric, text: formattedValueToString(display), title: 'Value' }); } if (valuesToShow.includes(PieChartLegendValues.Percent)) { const fractionOfTotal = hidden ? 0 : display.numeric / total; const percentOfTotal = fractionOfTotal * 100; displayValues.push({ numeric: fractionOfTotal, percent: percentOfTotal, text: hidden ? '-' : percentOfTotal.toFixed(0) + '%', title: valuesToShow.length > 1 ? 'Percent' : undefined, }); } return displayValues; }, }; }); return ( ); } function useSliceHighlightState() { const [highlightedTitle, setHighlightedTitle] = useState(); const { eventBus } = usePanelContext(); useEffect(() => { const setHighlightedSlice = (event: DataHoverEvent) => { setHighlightedTitle(event.payload.dataId); }; const resetHighlightedSlice = (event: DataHoverClearEvent) => { setHighlightedTitle(undefined); }; const subs = new Subscription() .add(eventBus.getStream(DataHoverEvent).subscribe({ next: setHighlightedSlice })) .add(eventBus.getStream(DataHoverClearEvent).subscribe({ next: resetHighlightedSlice })); return () => { subs.unsubscribe(); }; }, [setHighlightedTitle, eventBus]); return highlightedTitle; }