VizTooltips: Don't use y scales for sync, since they rarely match (#81031)

This commit is contained in:
Leon Sorokin 2024-01-23 00:08:03 -06:00 committed by GitHub
parent 2a53ae637e
commit 391f3ca615
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 90 additions and 50 deletions

View File

@ -13,6 +13,7 @@ import { CloseButton } from './CloseButton';
export const DEFAULT_TOOLTIP_WIDTH = 300;
export const DEFAULT_TOOLTIP_HEIGHT = 600;
export const TOOLTIP_OFFSET = 10;
// todo: barchart? histogram?
export const enum TooltipHoverMode {
@ -40,7 +41,8 @@ interface TooltipPlugin2Props {
isPinned: boolean,
dismiss: () => void,
// selected time range (for annotation triggering)
timeRange: TimeRange2 | null
timeRange: TimeRange2 | null,
viaSync: boolean
) => React.ReactNode;
maxWidth?: number;
@ -155,13 +157,14 @@ export const TooltipPlugin2 = ({
let winHeight = htmlEl.clientHeight - 16;
window.addEventListener('resize', (e) => {
winWidth = htmlEl.clientWidth - 5;
winHeight = htmlEl.clientHeight - 5;
winWidth = htmlEl.clientWidth - 16;
winHeight = htmlEl.clientHeight - 16;
});
let selectedRange: TimeRange2 | null = null;
let seriesIdxs: Array<number | null> = plot?.cursor.idxs!.slice()!;
let closestSeriesIdx: number | null = null;
let viaSync = false;
let pendingRender = false;
let pendingPinned = false;
@ -217,7 +220,7 @@ export const TooltipPlugin2 = ({
isHovering: _isHovering,
contents:
_isHovering || selectedRange != null
? renderRef.current(_plot!, seriesIdxs, closestSeriesIdx, _isPinned, dismiss, selectedRange)
? renderRef.current(_plot!, seriesIdxs, closestSeriesIdx, _isPinned, dismiss, selectedRange, viaSync)
: null,
dismiss,
};
@ -225,6 +228,7 @@ export const TooltipPlugin2 = ({
setState(state);
selectedRange = null;
viaSync = false;
};
const dismiss = () => {
@ -410,46 +414,62 @@ export const TooltipPlugin2 = ({
// fires on mousemoves
config.addHook('setCursor', (u) => {
let { left = -10, top = -10 } = u.cursor;
let { left = -10, top = -10, event } = u.cursor;
if (left >= 0 || top >= 0) {
let { width, height } = sizeRef.current!;
viaSync = event == null;
let clientX = u.rect.left + left;
let clientY = u.rect.top + top;
let transform = '';
if (offsetY) {
if (clientY + height < winHeight || clientY - height < 0) {
offsetY = 0;
} else if (offsetY !== -height) {
offsetY = -height;
}
// this means it's a synthetic event from uPlot's sync
if (viaSync) {
// TODO: smarter positioning here to avoid viewport clipping?
transform = `translateX(${left}px) translateY(${u.rect.height / 2}px) translateY(-50%)`;
} else {
if (clientY + height > winHeight && clientY - height >= 0) {
offsetY = -height;
let { width, height } = sizeRef.current!;
width += TOOLTIP_OFFSET;
height += TOOLTIP_OFFSET;
let clientX = u.rect.left + left;
let clientY = u.rect.top + top;
if (offsetY !== 0) {
if (clientY + height < winHeight || clientY - height < 0) {
offsetY = 0;
} else if (offsetY !== -height) {
offsetY = -height;
}
} else {
if (clientY + height > winHeight && clientY - height >= 0) {
offsetY = -height;
}
}
if (offsetX !== 0) {
if (clientX + width < winWidth || clientX - width < 0) {
offsetX = 0;
} else if (offsetX !== -width) {
offsetX = -width;
}
} else {
if (clientX + width > winWidth && clientX - width >= 0) {
offsetX = -width;
}
}
const shiftX = left + (offsetX === 0 ? TOOLTIP_OFFSET : -TOOLTIP_OFFSET);
const shiftY = top + (offsetY === 0 ? TOOLTIP_OFFSET : -TOOLTIP_OFFSET);
const reflectX = offsetX === 0 ? '' : 'translateX(-100%)';
const reflectY = offsetY === 0 ? '' : 'translateY(-100%)';
// TODO: to a transition only when switching sides
// transition: transform 100ms;
transform = `translateX(${shiftX}px) ${reflectX} translateY(${shiftY}px) ${reflectY}`;
}
if (offsetX) {
if (clientX + width < winWidth || clientX - width < 0) {
offsetX = 0;
} else if (offsetX !== -width) {
offsetX = -width;
}
} else {
if (clientX + width > winWidth && clientX - width >= 0) {
offsetX = -width;
}
}
const shiftX = offsetX !== 0 ? 'translateX(-100%)' : '';
const shiftY = offsetY !== 0 ? 'translateY(-100%)' : '';
// TODO: to a transition only when switching sides
// transition: transform 100ms;
const transform = `${shiftX} translateX(${left}px) ${shiftY} translateY(${top}px)`;
if (_isHovering) {
if (domRef.current != null) {
domRef.current.style.transform = transform;

View File

@ -81,7 +81,7 @@ exports[`GraphNG utils preparePlotConfigBuilder 1`] = `
"key": "__global_",
"scales": [
"x",
"__fixed/na-na/na-na/auto/linear/na/number",
null,
],
},
},

View File

@ -643,8 +643,8 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
return true;
},
},
scales: [xScaleKey, yScaleKey],
// match: [() => true, (a, b) => a === b],
scales: [xScaleKey, null],
// match: [() => true, () => false],
};
}

View File

@ -234,7 +234,7 @@ export const CandlestickPanel = ({
const enableAnnotationCreation = Boolean(canAddAnnotations && canAddAnnotations());
const showNewVizTooltips =
config.featureToggles.newVizTooltips && (sync == null || sync() === DashboardCursorSync.Off);
config.featureToggles.newVizTooltips && (sync == null || sync() !== DashboardCursorSync.Tooltip);
return (
<TimeSeries
@ -269,7 +269,11 @@ export const CandlestickPanel = ({
hoverMode={TooltipHoverMode.xAll}
queryZoom={onChangeTimeRange}
clientZoom={true}
render={(u, dataIdxs, seriesIdx, isPinned = false, dismiss, timeRange2) => {
render={(u, dataIdxs, seriesIdx, isPinned = false, dismiss, timeRange2, viaSync) => {
if (viaSync) {
return null;
}
if (timeRange2 != null) {
setNewAnnotationRange(timeRange2);
dismiss();

View File

@ -160,7 +160,7 @@ export const HeatmapPanel = ({
const dataRef = useRef(info);
dataRef.current = info;
const showNewVizTooltips =
config.featureToggles.newVizTooltips && (sync == null || sync() === DashboardCursorSync.Off);
config.featureToggles.newVizTooltips && (sync == null || sync() !== DashboardCursorSync.Tooltip);
const builder = useMemo(() => {
const scaleConfig: ScaleDistributionConfig = dataRef.current?.heatmap?.fields[1].config?.custom?.scaleDistribution;
@ -243,7 +243,11 @@ export const HeatmapPanel = ({
config={builder}
hoverMode={TooltipHoverMode.xyOne}
queryZoom={onChangeTimeRange}
render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2) => {
render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2, viaSync) => {
if (viaSync) {
return null;
}
if (timeRange2 != null) {
setNewAnnotationRange(timeRange2);
dismiss();

View File

@ -603,7 +603,7 @@ export function prepConfig(opts: PrepConfigOpts) {
if (sync && sync() !== DashboardCursorSync.Off) {
cursor.sync = {
key: eventsScope,
scales: [xScaleKey, yScaleKey],
scales: [xScaleKey, null],
filters: {
pub: (type: string, src: uPlot, x: number, y: number, w: number, h: number, dataIdx: number) => {
if (x < 0) {

View File

@ -167,7 +167,7 @@ export const StateTimelinePanel = ({
}
const enableAnnotationCreation = Boolean(canAddAnnotations && canAddAnnotations());
const showNewVizTooltips =
config.featureToggles.newVizTooltips && (sync == null || sync() === DashboardCursorSync.Off);
config.featureToggles.newVizTooltips && (sync == null || sync() !== DashboardCursorSync.Tooltip);
return (
<TimelineChart
@ -207,7 +207,11 @@ export const StateTimelinePanel = ({
config={builder}
hoverMode={TooltipHoverMode.xOne}
queryZoom={onChangeTimeRange}
render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2) => {
render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2, viaSync) => {
if (viaSync) {
return null;
}
if (timeRange2 != null) {
setNewAnnotationRange(timeRange2);
dismiss();

View File

@ -196,7 +196,7 @@ export const StatusHistoryPanel = ({
}
const showNewVizTooltips =
config.featureToggles.newVizTooltips && (sync == null || sync() === DashboardCursorSync.Off);
config.featureToggles.newVizTooltips && (sync == null || sync() !== DashboardCursorSync.Tooltip);
return (
<TimelineChart
@ -235,7 +235,11 @@ export const StatusHistoryPanel = ({
config={builder}
hoverMode={TooltipHoverMode.xyOne}
queryZoom={onChangeTimeRange}
render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2) => {
render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2, viaSync) => {
if (viaSync) {
return null;
}
if (timeRange2 != null) {
setNewAnnotationRange(timeRange2);
dismiss();

View File

@ -52,7 +52,7 @@ export const TimeSeriesPanel = ({
const enableAnnotationCreation = Boolean(canAddAnnotations && canAddAnnotations());
const showNewVizTooltips =
config.featureToggles.newVizTooltips && (sync == null || sync() === DashboardCursorSync.Off);
config.featureToggles.newVizTooltips && (sync == null || sync() !== DashboardCursorSync.Tooltip);
// temp range set for adding new annotation set by TooltipPlugin2, consumed by AnnotationPlugin2
const [newAnnotationRange, setNewAnnotationRange] = useState<TimeRange2 | null>(null);
@ -113,7 +113,11 @@ export const TimeSeriesPanel = ({
}
queryZoom={onChangeTimeRange}
clientZoom={true}
render={(u, dataIdxs, seriesIdx, isPinned = false, dismiss, timeRange2) => {
render={(u, dataIdxs, seriesIdx, isPinned = false, dismiss, timeRange2, viaSync) => {
if (viaSync) {
return null;
}
if (timeRange2 != null) {
setNewAnnotationRange(timeRange2);
dismiss();