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:
nikki-kiga
2021-08-02 11:25:51 -07:00
committed by GitHub
parent 6906a74179
commit 9fa8f5cc95
3 changed files with 37 additions and 10 deletions

View File

@@ -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;
}

View File

@@ -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;
} }

View File

@@ -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} />