TimeSeriesPanel: Null points no longer get tooltips (#42371)

* TimeSeriesPanel: Null points no longer get tooltips

Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
kay delaney 2021-12-17 10:38:08 +00:00 committed by GitHub
parent 7c5d5c0128
commit 4855fe78f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 25 additions and 25 deletions

View File

@ -344,19 +344,19 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor
let seriesData = self.data[seriesIdx];
if (seriesData[hoveredIdx] == null) {
let nonNullLft = hoveredIdx,
nonNullRgt = hoveredIdx,
let nonNullLft = null,
nonNullRgt = null,
i;
i = hoveredIdx;
while (nonNullLft === hoveredIdx && i-- > 0) {
while (nonNullLft == null && i-- > 0) {
if (seriesData[i] != null) {
nonNullLft = i;
}
}
i = hoveredIdx;
while (nonNullRgt === hoveredIdx && i++ < seriesData.length) {
while (nonNullRgt == null && i++ < seriesData.length) {
if (seriesData[i] != null) {
nonNullRgt = i;
}
@ -365,19 +365,19 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor
let xVals = self.data[0];
let curPos = self.valToPos(cursorXVal, 'x');
let rgtPos = self.valToPos(xVals[nonNullRgt], 'x');
let lftPos = self.valToPos(xVals[nonNullLft], 'x');
let rgtPos = nonNullRgt == null ? Infinity : self.valToPos(xVals[nonNullRgt], 'x');
let lftPos = nonNullLft == null ? -Infinity : self.valToPos(xVals[nonNullLft], 'x');
let lftDelta = curPos - lftPos;
let rgtDelta = rgtPos - curPos;
if (lftDelta <= rgtDelta) {
if (lftDelta <= hoverProximityPx) {
hoveredIdx = nonNullLft;
hoveredIdx = nonNullLft!;
}
} else {
if (rgtDelta <= hoverProximityPx) {
hoveredIdx = nonNullRgt;
hoveredIdx = nonNullRgt!;
}
}
}

View File

@ -1,3 +1,6 @@
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { useMountedState } from 'react-use';
import uPlot from 'uplot';
import {
CartesianCoords2D,
DashboardCursorSync,
@ -10,9 +13,6 @@ import {
TimeZone,
} from '@grafana/data';
import { TooltipDisplayMode } from '@grafana/schema';
import React, { useEffect, useLayoutEffect, useState } from 'react';
import { useMountedState } from 'react-use';
import uPlot from 'uplot';
import { useTheme2 } from '../../../themes/ThemeContext';
import { Portal } from '../../Portal/Portal';
import { SeriesTable, SeriesTableRowProps, VizTooltipContainer } from '../../VizTooltip';
@ -43,6 +43,7 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
renderTooltip,
...otherProps
}) => {
const plotInstance = useRef<uPlot>();
const theme = useTheme2();
const [focusedSeriesIdx, setFocusedSeriesIdx] = useState<number | null>(null);
const [focusedPointIdx, setFocusedPointIdx] = useState<number | null>(null);
@ -60,7 +61,6 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
// Add uPlot hooks to the config, or re-add when the config changed
useLayoutEffect(() => {
let plotInstance: uPlot | undefined = undefined;
let bbox: DOMRect | undefined = undefined;
const plotMouseLeave = () => {
@ -69,7 +69,7 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
}
setCoords(null);
setIsActive(false);
plotInstance?.root.classList.remove('plot-active');
plotInstance.current?.root.classList.remove('plot-active');
};
const plotMouseEnter = () => {
@ -77,16 +77,14 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
return;
}
setIsActive(true);
plotInstance?.root.classList.add('plot-active');
plotInstance.current?.root.classList.add('plot-active');
};
// cache uPlot plotting area bounding box
config.addHook('syncRect', (u, rect) => {
bbox = rect;
});
config.addHook('syncRect', (u, rect) => (bbox = rect));
config.addHook('init', (u) => {
plotInstance = u;
plotInstance.current = u;
u.over.addEventListener('mouseleave', plotMouseLeave);
u.over.addEventListener('mouseenter', plotMouseEnter);
@ -155,9 +153,9 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
return () => {
setCoords(null);
if (plotInstance) {
plotInstance.over.removeEventListener('mouseleave', plotMouseLeave);
plotInstance.over.removeEventListener('mouseenter', plotMouseEnter);
if (plotInstance.current) {
plotInstance.current.over.removeEventListener('mouseleave', plotMouseLeave);
plotInstance.current.over.removeEventListener('mouseenter', plotMouseEnter);
}
};
}, [config, setCoords, setIsActive, setFocusedPointIdx, setFocusedPointIdxs]);
@ -174,7 +172,7 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
const xFieldFmt = xField.display || getDisplayProcessor({ field: xField, timeZone, theme });
let tooltip: React.ReactNode = null;
const xVal = xFieldFmt(xField!.values.get(focusedPointIdx)).text;
let xVal = xFieldFmt(xField!.values.get(focusedPointIdx)).text;
if (!renderTooltip) {
// when interacting with a point in single mode
@ -185,8 +183,10 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
return null;
}
const dataIdx = focusedPointIdxs?.[focusedSeriesIdx] ?? focusedPointIdx;
xVal = xFieldFmt(xField!.values.get(dataIdx)).text;
const fieldFmt = field.display || getDisplayProcessor({ field, timeZone, theme });
const display = fieldFmt(field.values.get(focusedPointIdx));
const display = fieldFmt(field.values.get(dataIdx));
tooltip = (
<SeriesTable
@ -247,7 +247,7 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({
);
};
function isCursourOutsideCanvas({ left, top }: uPlot.Cursor, canvas: DOMRect) {
function isCursorOutsideCanvas({ left, top }: uPlot.Cursor, canvas: DOMRect) {
if (left === undefined || top === undefined) {
return false;
}
@ -264,7 +264,7 @@ export function positionTooltip(u: uPlot, bbox: DOMRect) {
const cL = u.cursor.left || 0;
const cT = u.cursor.top || 0;
if (isCursourOutsideCanvas(u.cursor, bbox)) {
if (isCursorOutsideCanvas(u.cursor, bbox)) {
const idx = u.posToIdx(cL);
// when cursor outside of uPlot's canvas
if (cT < 0 || cT > bbox.height) {