mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
TooltipPlugin: add crosshair exception (#37285)
* TooltipPlugin: add crosshair exception * TooltipPlugin: set active plot and add class * Plot: hide cursor pts when not active in crosshair mode * TooltipPlugin: clean up adding class * TooltipPlugin: rename crosshair class * rename class, move up to chart root element Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
@@ -17,3 +17,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
border-bottom: 1px dashed rgba(120, 120, 130, 0.5);
|
border-bottom: 1px dashed rgba(120, 120, 130, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.shared-crosshair:not(.plot-active) .u-cursor-pt {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Portal } from '../../Portal/Portal';
|
|||||||
import { usePlotContext } from '../context';
|
import { usePlotContext } from '../context';
|
||||||
import {
|
import {
|
||||||
CartesianCoords2D,
|
CartesianCoords2D,
|
||||||
|
DashboardCursorSync,
|
||||||
DataFrame,
|
DataFrame,
|
||||||
FALLBACK_COLOR,
|
FALLBACK_COLOR,
|
||||||
FieldType,
|
FieldType,
|
||||||
@@ -22,6 +23,7 @@ interface TooltipPluginProps {
|
|||||||
data: DataFrame;
|
data: DataFrame;
|
||||||
config: UPlotConfigBuilder;
|
config: UPlotConfigBuilder;
|
||||||
mode?: TooltipDisplayMode;
|
mode?: TooltipDisplayMode;
|
||||||
|
sync?: DashboardCursorSync;
|
||||||
// Allows custom tooltip content rendering. Exposes aligned data frame with relevant indexes for data inspection
|
// 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.
|
// 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;
|
renderTooltip?: (alignedFrame: DataFrame, seriesIdx: number | null, datapointIdx: number | null) => React.ReactNode;
|
||||||
@@ -34,6 +36,7 @@ const TOOLTIP_OFFSET = 10;
|
|||||||
*/
|
*/
|
||||||
export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
|
export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
|
||||||
mode = TooltipDisplayMode.Single,
|
mode = TooltipDisplayMode.Single,
|
||||||
|
sync,
|
||||||
timeZone,
|
timeZone,
|
||||||
config,
|
config,
|
||||||
renderTooltip,
|
renderTooltip,
|
||||||
@@ -46,6 +49,7 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
|
|||||||
const [focusedPointIdxs, setFocusedPointIdxs] = useState<Array<number | null>>([]);
|
const [focusedPointIdxs, setFocusedPointIdxs] = useState<Array<number | null>>([]);
|
||||||
const [coords, setCoords] = useState<CartesianCoords2D | null>(null);
|
const [coords, setCoords] = useState<CartesianCoords2D | null>(null);
|
||||||
const plotInstance = plotCtx.plot;
|
const plotInstance = plotCtx.plot;
|
||||||
|
const [isActive, setIsActive] = useState<boolean>(false);
|
||||||
|
|
||||||
const pluginId = `TooltipPlugin`;
|
const pluginId = `TooltipPlugin`;
|
||||||
|
|
||||||
@@ -57,19 +61,35 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const plotMouseLeave = () => {
|
const plotMouseLeave = () => {
|
||||||
setCoords(null);
|
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) {
|
if (plotCtx && plotCtx.plot) {
|
||||||
plotCtx.plot.over.addEventListener('mouseleave', plotMouseLeave);
|
plotCtx.plot.over.addEventListener('mouseleave', plotMouseLeave);
|
||||||
|
plotCtx.plot.over.addEventListener('mouseenter', plotMouseEnter);
|
||||||
|
if (sync === DashboardCursorSync.Crosshair) {
|
||||||
|
plotCtx.plot.root.classList.add('shared-crosshair');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
setCoords(null);
|
setCoords(null);
|
||||||
if (plotCtx && plotCtx.plot) {
|
if (plotCtx && plotCtx.plot) {
|
||||||
plotCtx.plot.over.removeEventListener('mouseleave', plotMouseLeave);
|
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
|
// Add uPlot hooks to the config, or re-add when the config changed
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@@ -120,7 +140,7 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
|
|||||||
}
|
}
|
||||||
}, [plotCtx, config, setFocusedPointIdx, setFocusedSeriesIdx, setCoords]);
|
}, [plotCtx, config, setFocusedPointIdx, setFocusedSeriesIdx, setCoords]);
|
||||||
|
|
||||||
if (!plotInstance || focusedPointIdx === null || mode === TooltipDisplayMode.None) {
|
if (!plotInstance || focusedPointIdx === null || (!isActive && sync === DashboardCursorSync.Crosshair)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { DashboardCursorSync, Field, PanelProps } from '@grafana/data';
|
import { Field, PanelProps } from '@grafana/data';
|
||||||
import { config } from '@grafana/runtime';
|
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 { getFieldLinksForExplore } from 'app/features/explore/utils/links';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { AnnotationsPlugin } from './plugins/AnnotationsPlugin';
|
import { AnnotationsPlugin } from './plugins/AnnotationsPlugin';
|
||||||
@@ -53,12 +53,15 @@ export const TimeSeriesPanel: React.FC<TimeSeriesPanelProps> = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ZoomPlugin config={config} onZoom={onChangeTimeRange} />
|
<ZoomPlugin config={config} onZoom={onChangeTimeRange} />
|
||||||
|
{options.tooltip.mode === TooltipDisplayMode.None || (
|
||||||
<TooltipPlugin
|
<TooltipPlugin
|
||||||
data={alignedDataFrame}
|
data={alignedDataFrame}
|
||||||
config={config}
|
config={config}
|
||||||
mode={sync === DashboardCursorSync.Tooltip ? TooltipDisplayMode.Multi : options.tooltip.mode}
|
mode={options.tooltip.mode}
|
||||||
|
sync={sync}
|
||||||
timeZone={timeZone}
|
timeZone={timeZone}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
{/* Renders annotation markers*/}
|
{/* Renders annotation markers*/}
|
||||||
{data.annotations && (
|
{data.annotations && (
|
||||||
<AnnotationsPlugin annotations={data.annotations} config={config} timeZone={timeZone} />
|
<AnnotationsPlugin annotations={data.annotations} config={config} timeZone={timeZone} />
|
||||||
|
|||||||
Reference in New Issue
Block a user