PlotLegend: Memoize for better performance (#56123)

This commit is contained in:
kay delaney 2022-10-14 09:51:27 +01:00 committed by GitHub
parent 08ffcfdf16
commit e819ed0f51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 98 deletions

View File

@ -9,8 +9,8 @@ export interface Props extends React.HTMLAttributes<HTMLDivElement> {
gradient?: string; gradient?: string;
} }
export const SeriesIcon = React.forwardRef<HTMLDivElement, Props>( export const SeriesIcon = React.memo(
({ color, className, gradient, ...restProps }, ref) => { React.forwardRef<HTMLDivElement, Props>(({ color, className, gradient, ...restProps }, ref) => {
const theme = useTheme2(); const theme = useTheme2();
let cssColor: string; let cssColor: string;
@ -36,7 +36,7 @@ export const SeriesIcon = React.forwardRef<HTMLDivElement, Props>(
}; };
return <div data-testid="series-icon" ref={ref} className={className} style={styles} {...restProps} />; return <div data-testid="series-icon" ref={ref} className={className} style={styles} {...restProps} />;
} })
); );
SeriesIcon.displayName = 'SeriesIcon'; SeriesIcon.displayName = 'SeriesIcon';

View File

@ -110,4 +110,4 @@ export function VizLegend<T>({
} }
} }
VizLegend.displayName = 'Legend'; VizLegend.displayName = 'VizLegend';

View File

@ -15,7 +15,7 @@ interface Props {
/** /**
* @internal * @internal
*/ */
export const VizLegendSeriesIcon: React.FunctionComponent<Props> = ({ seriesName, color, gradient, readonly }) => { export const VizLegendSeriesIcon = React.memo(({ seriesName, color, gradient, readonly }: Props) => {
const { onSeriesColorChange } = usePanelContext(); const { onSeriesColorChange } = usePanelContext();
const onChange = useCallback( const onChange = useCallback(
(color: string) => { (color: string) => {
@ -40,6 +40,6 @@ export const VizLegendSeriesIcon: React.FunctionComponent<Props> = ({ seriesName
); );
} }
return <SeriesIcon color={color} gradient={gradient} />; return <SeriesIcon color={color} gradient={gradient} />;
}; });
VizLegendSeriesIcon.displayName = 'VizLegendSeriesIcon'; VizLegendSeriesIcon.displayName = 'VizLegendSeriesIcon';

View File

@ -27,115 +27,110 @@ interface PlotLegendProps extends VizLegendOptions, Omit<VizLayoutLegendProps, '
config: UPlotConfigBuilder; config: UPlotConfigBuilder;
} }
export const PlotLegend: React.FC<PlotLegendProps> = ({ export const PlotLegend: React.FC<PlotLegendProps> = React.memo(
data, ({ data, config, placement, calcs, displayMode, ...vizLayoutLegendProps }) => {
config, const theme = useTheme2();
placement, const legendItems = config
calcs, .getSeries()
displayMode, .map<VizLegendItem | undefined>((s) => {
...vizLayoutLegendProps const seriesConfig = s.props;
}) => { const fieldIndex = seriesConfig.dataFrameFieldIndex;
const theme = useTheme2(); const axisPlacement = config.getAxisPlacement(s.props.scaleKey);
const legendItems = config
.getSeries()
.map<VizLegendItem | undefined>((s) => {
const seriesConfig = s.props;
const fieldIndex = seriesConfig.dataFrameFieldIndex;
const axisPlacement = config.getAxisPlacement(s.props.scaleKey);
if (!fieldIndex) { if (!fieldIndex) {
return undefined; return undefined;
} }
const field = data[fieldIndex.frameIndex]?.fields[fieldIndex.fieldIndex]; const field = data[fieldIndex.frameIndex]?.fields[fieldIndex.fieldIndex];
if (!field || field.config.custom?.hideFrom?.legend) { if (!field || field.config.custom?.hideFrom?.legend) {
return undefined; return undefined;
} }
const label = getFieldDisplayName(field, data[fieldIndex.frameIndex]!, data); const label = getFieldDisplayName(field, data[fieldIndex.frameIndex]!, data);
const scaleColor = getFieldSeriesColor(field, theme); const scaleColor = getFieldSeriesColor(field, theme);
const seriesColor = scaleColor.color; const seriesColor = scaleColor.color;
return { return {
disabled: !(seriesConfig.show ?? true), disabled: !(seriesConfig.show ?? true),
fieldIndex, fieldIndex,
color: seriesColor, color: seriesColor,
label, label,
yAxis: axisPlacement === AxisPlacement.Left ? 1 : 2, yAxis: axisPlacement === AxisPlacement.Left ? 1 : 2,
getDisplayValues: () => { getDisplayValues: () => {
if (!calcs?.length) { if (!calcs?.length) {
return []; return [];
}
const fmt = field.display ?? defaultFormatter;
let countFormatter: DisplayProcessor | null = null;
const fieldCalcs = reduceField({
field,
reducers: calcs,
});
return calcs.map<DisplayValue>((reducerId) => {
const fieldReducer = fieldReducers.get(reducerId);
let formatter = fmt;
if (fieldReducer.id === ReducerID.diffperc) {
formatter = getDisplayProcessor({
field: {
...field,
config: {
...field.config,
unit: 'percent',
},
},
theme,
});
} }
if ( const fmt = field.display ?? defaultFormatter;
fieldReducer.id === ReducerID.count || let countFormatter: DisplayProcessor | null = null;
fieldReducer.id === ReducerID.changeCount ||
fieldReducer.id === ReducerID.distinctCount const fieldCalcs = reduceField({
) { field,
if (!countFormatter) { reducers: calcs,
countFormatter = getDisplayProcessor({ });
return calcs.map<DisplayValue>((reducerId) => {
const fieldReducer = fieldReducers.get(reducerId);
let formatter = fmt;
if (fieldReducer.id === ReducerID.diffperc) {
formatter = getDisplayProcessor({
field: { field: {
...field, ...field,
config: { config: {
...field.config, ...field.config,
unit: 'none', unit: 'percent',
}, },
}, },
theme, theme,
}); });
} }
formatter = countFormatter;
}
return { if (
...formatter(fieldCalcs[reducerId]), fieldReducer.id === ReducerID.count ||
title: fieldReducer.name, fieldReducer.id === ReducerID.changeCount ||
description: fieldReducer.description, fieldReducer.id === ReducerID.distinctCount
}; ) {
}); if (!countFormatter) {
}, countFormatter = getDisplayProcessor({
getItemKey: () => `${label}-${fieldIndex.frameIndex}-${fieldIndex.fieldIndex}`, field: {
}; ...field,
}) config: {
.filter((i) => i !== undefined) as VizLegendItem[]; ...field.config,
unit: 'none',
},
},
theme,
});
}
formatter = countFormatter;
}
return ( return {
<VizLayout.Legend placement={placement} {...vizLayoutLegendProps}> ...formatter(fieldCalcs[reducerId]),
<VizLegend title: fieldReducer.name,
placement={placement} description: fieldReducer.description,
items={legendItems} };
displayMode={displayMode} });
sortBy={vizLayoutLegendProps.sortBy} },
sortDesc={vizLayoutLegendProps.sortDesc} getItemKey: () => `${label}-${fieldIndex.frameIndex}-${fieldIndex.fieldIndex}`,
/> };
</VizLayout.Legend> })
); .filter((i) => i !== undefined) as VizLegendItem[];
};
return (
<VizLayout.Legend placement={placement} {...vizLayoutLegendProps}>
<VizLegend
placement={placement}
items={legendItems}
displayMode={displayMode}
sortBy={vizLayoutLegendProps.sortBy}
sortDesc={vizLayoutLegendProps.sortDesc}
/>
</VizLayout.Legend>
);
}
);
PlotLegend.displayName = 'PlotLegend'; PlotLegend.displayName = 'PlotLegend';