BarChart: Highlight bars option for easier interaction (#60530)

* Add bar highlighter plugin to BarChart

* refactor feature

* Horizontal bars can also be hovered

* Tooltip mode UI reflects settings when stacked and bar highlight toggled

* rename variables

* override tooltip option + zIndex on hover box

* change option desc and simplify condition
This commit is contained in:
Victor Marin 2023-01-11 10:30:01 +02:00 committed by GitHub
parent f9daf61e96
commit 2cf628e37a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 40 additions and 2 deletions

View File

@ -20,6 +20,7 @@ import {
measureText,
PlotLegend,
Portal,
StackingMode,
TooltipDisplayMode,
UPlotConfigBuilder,
UPLOT_AXIS_FONT_SIZE,
@ -168,6 +169,8 @@ export const BarChartPanel: React.FunctionComponent<Props> = ({
const disp = getFieldDisplayName(field, alignedFrame);
seriesIdx = info.aligned.fields.findIndex((f) => disp === getFieldDisplayName(f, info.aligned));
}
const tooltipMode =
options.fullHighlight && options.stacking !== StackingMode.None ? TooltipDisplayMode.Multi : options.tooltip.mode;
return (
<>
@ -195,7 +198,7 @@ export const BarChartPanel: React.FunctionComponent<Props> = ({
rowIndex={datapointIdx}
columnIndex={seriesIdx}
sortOrder={options.tooltip.sort}
mode={options.tooltip.mode}
mode={tooltipMode}
/>
</>
);
@ -280,6 +283,7 @@ export const BarChartPanel: React.FunctionComponent<Props> = ({
text,
xTickLabelRotation,
xTickLabelSpacing,
fullHighlight,
} = options;
return preparePlotConfigBuilder({
@ -305,6 +309,7 @@ export const BarChartPanel: React.FunctionComponent<Props> = ({
getColor,
fillOpacity,
allFrames: info.viz,
fullHighlight,
});
};

View File

@ -60,6 +60,7 @@ export interface BarsOptions {
xSpacing?: number;
xTimeAuto?: boolean;
negY?: boolean[];
fullHighlight?: boolean;
}
/**
@ -315,6 +316,17 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) {
}
let barRect = { x: lft, y: top, w: wid, h: hgt, sidx: seriesIdx, didx: dataIdx };
if (opts.fullHighlight) {
if (opts.xOri === ScaleOrientation.Horizontal) {
barRect.y = 0;
barRect.h = u.bbox.height;
} else {
barRect.x = 0;
barRect.w = u.bbox.width;
}
}
qt.add(barRect);
if (showValue !== VisibilityMode.Never) {
@ -429,6 +441,9 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) {
u.root.querySelectorAll('.u-cursor-pt').forEach((el) => {
if (el instanceof HTMLElement) {
el.style.borderRadius = '0';
if (opts.fullHighlight) {
el.style.zIndex = '-1';
}
}
});
};

View File

@ -53,6 +53,8 @@ Panel: thema.#Lineage & {
barWidth: float64 & >= 0 & <= 1 | *0.97
// Controls the width of groups. 1 = max with, 0 = min width.
groupWidth: float64 & >= 0 & <= 1 | *0.7
// Enables mode which highlights the entire bar area and shows tooltip when cursor hovers over highlighted area
fullHighlight: bool | *false
} @cuetsy(kind="interface")
PanelFieldConfig: {
ui.AxisConfig

View File

@ -25,6 +25,10 @@ export interface PanelOptions extends ui.OptionsWithLegend, ui.OptionsWithToolti
* TODO docs
*/
colorByField?: string;
/**
* Enables mode which highlights the entire bar area and shows tooltip when cursor hovers over highlighted area
*/
fullHighlight: boolean;
/**
* Controls the width of groups. 1 = max with, 0 = min width.
*/
@ -63,6 +67,7 @@ export interface PanelOptions extends ui.OptionsWithLegend, ui.OptionsWithToolti
export const defaultPanelOptions: Partial<PanelOptions> = {
barRadius: 0,
barWidth: 0.97,
fullHighlight: false,
groupWidth: 0.7,
orientation: ui.VizOrientation.Auto,
showValue: ui.VisibilityMode.Auto,

View File

@ -220,6 +220,11 @@ export const plugin = new PanelPlugin<PanelOptions, PanelFieldConfig>(BarChartPa
max: 0.5,
step: 0.05,
},
})
.addBooleanSwitch({
path: 'fullHighlight',
name: 'Highlight full area on hover',
defaultValue: defaultPanelOptions.fullHighlight,
});
builder.addFieldNamePicker({
@ -228,7 +233,10 @@ export const plugin = new PanelPlugin<PanelOptions, PanelFieldConfig>(BarChartPa
description: 'Use the color value for a sibling field to color each bar value.',
});
commonOptionsBuilder.addTooltipOptions(builder);
if (!context.options?.fullHighlight || context.options?.stacking === StackingMode.None) {
commonOptionsBuilder.addTooltipOptions(builder);
}
commonOptionsBuilder.addLegendOptions(builder);
commonOptionsBuilder.addTextSizeOptions(builder, false);
})

View File

@ -108,6 +108,7 @@ describe('BarChart utils', () => {
text: {
valueSize: 10,
},
fullHighlight: false,
rawValue: (seriesIdx: number, valueIdx: number) => frame.fields[seriesIdx].values.get(valueIdx),
};

View File

@ -79,6 +79,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptionsEX> = ({
xTickLabelSpacing = 0,
legend,
timeZone,
fullHighlight,
}) => {
const builder = new UPlotConfigBuilder();
@ -118,6 +119,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptionsEX> = ({
xSpacing: xTickLabelSpacing,
xTimeAuto: frame.fields[0]?.type === FieldType.time && !frame.fields[0].config.unit?.startsWith('time:'),
negY: frame.fields.map((f) => f.config.custom?.transform === GraphTransform.NegativeY),
fullHighlight,
};
const config = getConfig(opts, theme);