diff --git a/packages/grafana-ui/src/components/uPlot/Plot.scss b/packages/grafana-ui/src/components/uPlot/Plot.scss index cce7ccc2bd1..2544d8075c8 100644 --- a/packages/grafana-ui/src/components/uPlot/Plot.scss +++ b/packages/grafana-ui/src/components/uPlot/Plot.scss @@ -17,3 +17,7 @@ width: 100%; border-bottom: 1px dashed rgba(120, 120, 130, 0.5); } + +.shared-crosshair:not(.plot-active) .u-cursor-pt { + display: none !important; +} diff --git a/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin.tsx b/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin.tsx index b063df8cdc1..93e02a31372 100644 --- a/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin.tsx +++ b/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin.tsx @@ -3,6 +3,7 @@ import { Portal } from '../../Portal/Portal'; import { usePlotContext } from '../context'; import { CartesianCoords2D, + DashboardCursorSync, DataFrame, FALLBACK_COLOR, FieldType, @@ -22,6 +23,7 @@ interface TooltipPluginProps { data: DataFrame; config: UPlotConfigBuilder; mode?: TooltipDisplayMode; + sync?: DashboardCursorSync; // Allows custom tooltip content rendering. Exposes aligned data frame with relevant indexes for data inspection // Use field.state.origin indexes from alignedData frame field to get access to original data frame and field index. renderTooltip?: (alignedFrame: DataFrame, seriesIdx: number | null, datapointIdx: number | null) => React.ReactNode; @@ -34,6 +36,7 @@ const TOOLTIP_OFFSET = 10; */ export const TooltipPlugin: React.FC = ({ mode = TooltipDisplayMode.Single, + sync, timeZone, config, renderTooltip, @@ -46,6 +49,7 @@ export const TooltipPlugin: React.FC = ({ const [focusedPointIdxs, setFocusedPointIdxs] = useState>([]); const [coords, setCoords] = useState(null); const plotInstance = plotCtx.plot; + const [isActive, setIsActive] = useState(false); const pluginId = `TooltipPlugin`; @@ -57,19 +61,35 @@ export const TooltipPlugin: React.FC = ({ useEffect(() => { const plotMouseLeave = () => { setCoords(null); + setIsActive(false); + if (plotCtx.plot) { + plotCtx.plot.root.classList.remove('plot-active'); + } + }; + + const plotMouseEnter = () => { + setIsActive(true); + if (plotCtx.plot) { + plotCtx.plot.root.classList.add('plot-active'); + } }; if (plotCtx && plotCtx.plot) { plotCtx.plot.over.addEventListener('mouseleave', plotMouseLeave); + plotCtx.plot.over.addEventListener('mouseenter', plotMouseEnter); + if (sync === DashboardCursorSync.Crosshair) { + plotCtx.plot.root.classList.add('shared-crosshair'); + } } return () => { setCoords(null); if (plotCtx && plotCtx.plot) { plotCtx.plot.over.removeEventListener('mouseleave', plotMouseLeave); + plotCtx.plot.over.removeEventListener('mouseenter', plotMouseEnter); } }; - }, [plotCtx.plot?.root, setCoords]); + }, [plotCtx.plot?.root]); // Add uPlot hooks to the config, or re-add when the config changed useLayoutEffect(() => { @@ -120,7 +140,7 @@ export const TooltipPlugin: React.FC = ({ } }, [plotCtx, config, setFocusedPointIdx, setFocusedSeriesIdx, setCoords]); - if (!plotInstance || focusedPointIdx === null || mode === TooltipDisplayMode.None) { + if (!plotInstance || focusedPointIdx === null || (!isActive && sync === DashboardCursorSync.Crosshair)) { return null; } diff --git a/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx b/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx index bfb77536cde..47e7e91ff18 100644 --- a/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx +++ b/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx @@ -1,6 +1,6 @@ -import { DashboardCursorSync, Field, PanelProps } from '@grafana/data'; +import { Field, PanelProps } from '@grafana/data'; import { config } from '@grafana/runtime'; -import { TooltipDisplayMode, usePanelContext, TimeSeries, TooltipPlugin, ZoomPlugin } from '@grafana/ui'; +import { usePanelContext, TimeSeries, TooltipPlugin, ZoomPlugin, TooltipDisplayMode } from '@grafana/ui'; import { getFieldLinksForExplore } from 'app/features/explore/utils/links'; import React, { useMemo } from 'react'; import { AnnotationsPlugin } from './plugins/AnnotationsPlugin'; @@ -53,12 +53,15 @@ export const TimeSeriesPanel: React.FC = ({ return ( <> - + {options.tooltip.mode === TooltipDisplayMode.None || ( + + )} {/* Renders annotation markers*/} {data.annotations && (