From 8de9c4c373bb446b3ab8efaae716a30ac32576d4 Mon Sep 17 00:00:00 2001 From: Adela Almasan <88068998+adela-almasan@users.noreply.github.com> Date: Thu, 15 Feb 2024 16:29:36 -0600 Subject: [PATCH] Timeseries: Add hover proximity option (#81421) --- .../visualizations/time-series/index.md | 4 ++++ .../uPlot/config/UPlotConfigBuilder.ts | 1 + .../src/options/builder/tooltip.tsx | 17 ++++++++++++++- .../core/components/TimeSeries/TimeSeries.tsx | 3 ++- .../app/core/components/TimeSeries/utils.ts | 21 +++++++++++++++---- .../app/plugins/panel/candlestick/module.tsx | 2 +- .../app/plugins/panel/timeseries/module.tsx | 2 +- public/app/plugins/panel/trend/module.tsx | 2 +- 8 files changed, 43 insertions(+), 9 deletions(-) diff --git a/docs/sources/panels-visualizations/visualizations/time-series/index.md b/docs/sources/panels-visualizations/visualizations/time-series/index.md index ace758155b9..e41c20fa2bb 100644 --- a/docs/sources/panels-visualizations/visualizations/time-series/index.md +++ b/docs/sources/panels-visualizations/visualizations/time-series/index.md @@ -50,6 +50,10 @@ Tooltip options control the information overlay that appears when you hover over {{< docs/shared lookup="visualizations/tooltip-mode.md" source="grafana" version="" >}} +### Hover proximity + +This option controls how close your cursor must be to a data point before the tooltip appears. Values are in pixels. + ## Legend options Legend options control the series names and statistics that appear under or to the right of the graph. diff --git a/packages/grafana-ui/src/components/uPlot/config/UPlotConfigBuilder.ts b/packages/grafana-ui/src/components/uPlot/config/UPlotConfigBuilder.ts index 7abf30d0907..df4badf622e 100644 --- a/packages/grafana-ui/src/components/uPlot/config/UPlotConfigBuilder.ts +++ b/packages/grafana-ui/src/components/uPlot/config/UPlotConfigBuilder.ts @@ -313,6 +313,7 @@ type UPlotConfigPrepOpts = {}> = { tweakAxis?: (opts: AxisProps, forField: Field) => AxisProps; // Identifies the shared key for uPlot cursor sync eventsScope?: string; + hoverProximity?: number; } & T; /** @alpha */ diff --git a/packages/grafana-ui/src/options/builder/tooltip.tsx b/packages/grafana-ui/src/options/builder/tooltip.tsx index 61da5cef4b1..a5091b48b53 100644 --- a/packages/grafana-ui/src/options/builder/tooltip.tsx +++ b/packages/grafana-ui/src/options/builder/tooltip.tsx @@ -4,6 +4,7 @@ import { OptionsWithTooltip, TooltipDisplayMode, SortOrder } from '@grafana/sche export function addTooltipOptions( builder: PanelOptionsEditorBuilder, singleOnly = false, + setProximity = false, defaultOptions?: Partial ) { const category = ['Tooltip']; @@ -43,7 +44,21 @@ export function addTooltipOptions( settings: { options: sortOptions, }, - }) + }); + + if (setProximity) { + builder.addNumberInput({ + path: 'tooltip.hoverProximity', + name: 'Hover proximity', + description: 'How close the cursor must be to a point to trigger the tooltip, in pixels', + category, + settings: { + integer: true, + }, + }); + } + + builder .addNumberInput({ path: 'tooltip.maxWidth', name: 'Max width', diff --git a/public/app/core/components/TimeSeries/TimeSeries.tsx b/public/app/core/components/TimeSeries/TimeSeries.tsx index 4441bca98f3..ddc34f0cbd7 100644 --- a/public/app/core/components/TimeSeries/TimeSeries.tsx +++ b/public/app/core/components/TimeSeries/TimeSeries.tsx @@ -20,7 +20,7 @@ export class UnthemedTimeSeries extends Component { prepConfig = (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => { const { eventBus, eventsScope, sync } = this.context; - const { theme, timeZone, renderers, tweakAxis, tweakScale } = this.props; + const { theme, timeZone, options, renderers, tweakAxis, tweakScale } = this.props; return preparePlotConfigBuilder({ frame: alignedFrame, @@ -34,6 +34,7 @@ export class UnthemedTimeSeries extends Component { tweakScale, tweakAxis, eventsScope, + hoverProximity: options?.tooltip?.hoverProximity, }); }; diff --git a/public/app/core/components/TimeSeries/utils.ts b/public/app/core/components/TimeSeries/utils.ts index d5a1916ae32..82ceefbd65a 100644 --- a/public/app/core/components/TimeSeries/utils.ts +++ b/public/app/core/components/TimeSeries/utils.ts @@ -89,6 +89,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ tweakScale = (opts) => opts, tweakAxis = (opts) => opts, eventsScope = '__global_', + hoverProximity, }) => { const builder = new UPlotConfigBuilder(timeZones[0]); @@ -558,20 +559,32 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ builder.scaleKeys = [xScaleKey, yScaleKey]; // if hovered value is null, how far we may scan left/right to hover nearest non-null - const hoverProximityPx = 15; + const DEFAULT_HOVER_NULL_PROXIMITY = 15; + const DEFAULT_FOCUS_PROXIMITY = 30; let cursor: Partial = { + // horizontal proximity / point hover behavior hover: { prox: (self, seriesIdx, hoveredIdx) => { - const yVal = self.data[seriesIdx][hoveredIdx]; - if (yVal === null) { - return hoverProximityPx; + if (hoverProximity != null) { + return hoverProximity; } + // when hovering null values, scan data left/right up to 15px + const yVal = self.data[seriesIdx][hoveredIdx]; + if (yVal === null) { + return DEFAULT_HOVER_NULL_PROXIMITY; + } + + // no proximity limit return null; }, skip: [null], }, + // vertical proximity / series focus behavior + focus: { + prox: hoverProximity ?? DEFAULT_FOCUS_PROXIMITY, + }, }; if (sync && sync() !== DashboardCursorSync.Off && xField.type === FieldType.time) { diff --git a/public/app/plugins/panel/candlestick/module.tsx b/public/app/plugins/panel/candlestick/module.tsx index 0174594015b..2d6c62ab876 100644 --- a/public/app/plugins/panel/candlestick/module.tsx +++ b/public/app/plugins/panel/candlestick/module.tsx @@ -138,7 +138,7 @@ export const plugin = new PanelPlugin(CandlestickPane }); if (config.featureToggles.newVizTooltips) { - commonOptionsBuilder.addTooltipOptions(builder, false, opts); + commonOptionsBuilder.addTooltipOptions(builder, false, true, opts); } commonOptionsBuilder.addLegendOptions(builder); diff --git a/public/app/plugins/panel/timeseries/module.tsx b/public/app/plugins/panel/timeseries/module.tsx index f0f46f2b6a1..4368a297151 100644 --- a/public/app/plugins/panel/timeseries/module.tsx +++ b/public/app/plugins/panel/timeseries/module.tsx @@ -12,7 +12,7 @@ export const plugin = new PanelPlugin(TimeSeriesPanel) .setPanelChangeHandler(graphPanelChangedHandler) .useFieldConfig(getGraphFieldConfig(defaultGraphConfig)) .setPanelOptions((builder) => { - commonOptionsBuilder.addTooltipOptions(builder); + commonOptionsBuilder.addTooltipOptions(builder, false, true); commonOptionsBuilder.addLegendOptions(builder); builder.addCustomEditor({ diff --git a/public/app/plugins/panel/trend/module.tsx b/public/app/plugins/panel/trend/module.tsx index 502840a9fe3..24421f2ea6e 100644 --- a/public/app/plugins/panel/trend/module.tsx +++ b/public/app/plugins/panel/trend/module.tsx @@ -24,7 +24,7 @@ export const plugin = new PanelPlugin(TrendPanel) }, }); - commonOptionsBuilder.addTooltipOptions(builder); + commonOptionsBuilder.addTooltipOptions(builder, false, true); commonOptionsBuilder.addLegendOptions(builder); }) .setSuggestionsSupplier(new TrendSuggestionsSupplier());