mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
TooltipPlugin2: Absorb ZoomPlugin (#78160)
This commit is contained in:
parent
1ebdf390e6
commit
768fde02aa
@ -23,6 +23,12 @@ export const enum TooltipHoverMode {
|
|||||||
interface TooltipPlugin2Props {
|
interface TooltipPlugin2Props {
|
||||||
config: UPlotConfigBuilder;
|
config: UPlotConfigBuilder;
|
||||||
hoverMode: TooltipHoverMode;
|
hoverMode: TooltipHoverMode;
|
||||||
|
|
||||||
|
// x only
|
||||||
|
queryZoom?: (range: { from: number; to: number }) => void;
|
||||||
|
// y-only, via shiftKey
|
||||||
|
clientZoom?: boolean;
|
||||||
|
|
||||||
render: (
|
render: (
|
||||||
u: uPlot,
|
u: uPlot,
|
||||||
dataIdxs: Array<number | null>,
|
dataIdxs: Array<number | null>,
|
||||||
@ -67,10 +73,15 @@ const INITIAL_STATE: TooltipContainerState = {
|
|||||||
dismiss: () => {},
|
dismiss: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// min px width that triggers zoom
|
||||||
|
const MIN_ZOOM_DIST = 5;
|
||||||
|
|
||||||
|
const maybeZoomAction = (e?: MouseEvent | null) => e != null && !e.ctrlKey && !e.metaKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @alpha
|
* @alpha
|
||||||
*/
|
*/
|
||||||
export const TooltipPlugin2 = ({ config, hoverMode, render }: TooltipPlugin2Props) => {
|
export const TooltipPlugin2 = ({ config, hoverMode, render, clientZoom = false, queryZoom }: TooltipPlugin2Props) => {
|
||||||
const domRef = useRef<HTMLDivElement>(null);
|
const domRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const [{ plot, isHovering, isPinned, contents, style, dismiss }, setState] = useReducer(mergeState, INITIAL_STATE);
|
const [{ plot, isHovering, isPinned, contents, style, dismiss }, setState] = useReducer(mergeState, INITIAL_STATE);
|
||||||
@ -101,6 +112,9 @@ export const TooltipPlugin2 = ({ config, hoverMode, render }: TooltipPlugin2Prop
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let yZoomed = false;
|
||||||
|
let yDrag = false;
|
||||||
|
|
||||||
let _plot = plot;
|
let _plot = plot;
|
||||||
let _isHovering = isHovering;
|
let _isHovering = isHovering;
|
||||||
let _isPinned = isPinned;
|
let _isPinned = isPinned;
|
||||||
@ -195,6 +209,34 @@ export const TooltipPlugin2 = ({ config, hoverMode, render }: TooltipPlugin2Prop
|
|||||||
config.addHook('init', (u) => {
|
config.addHook('init', (u) => {
|
||||||
setState({ plot: (_plot = u) });
|
setState({ plot: (_plot = u) });
|
||||||
|
|
||||||
|
// detect shiftKey and mutate drag mode from x-only to y-only
|
||||||
|
if (clientZoom) {
|
||||||
|
u.over.addEventListener(
|
||||||
|
'mousedown',
|
||||||
|
(e) => {
|
||||||
|
if (!maybeZoomAction(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.button === 0 && e.shiftKey) {
|
||||||
|
yDrag = true;
|
||||||
|
|
||||||
|
u.cursor.drag!.x = false;
|
||||||
|
u.cursor.drag!.y = true;
|
||||||
|
|
||||||
|
let onUp = (e: MouseEvent) => {
|
||||||
|
u.cursor.drag!.x = true;
|
||||||
|
u.cursor.drag!.y = false;
|
||||||
|
document.removeEventListener('mouseup', onUp, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('mouseup', onUp, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// this handles pinning
|
// this handles pinning
|
||||||
u.over.addEventListener('click', (e) => {
|
u.over.addEventListener('click', (e) => {
|
||||||
// only pinnable tooltip is visible *and* is within proximity to series/point
|
// only pinnable tooltip is visible *and* is within proximity to series/point
|
||||||
@ -205,6 +247,79 @@ export const TooltipPlugin2 = ({ config, hoverMode, render }: TooltipPlugin2Prop
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
config.addHook('setSelect', (u) => {
|
||||||
|
if (clientZoom || queryZoom != null) {
|
||||||
|
if (maybeZoomAction(u.cursor!.event)) {
|
||||||
|
if (clientZoom && yDrag) {
|
||||||
|
if (u.select.height >= MIN_ZOOM_DIST) {
|
||||||
|
for (let key in u.scales!) {
|
||||||
|
if (key !== 'x') {
|
||||||
|
const maxY = u.posToVal(u.select.top, key);
|
||||||
|
const minY = u.posToVal(u.select.top + u.select.height, key);
|
||||||
|
|
||||||
|
u.setScale(key, { min: minY, max: maxY });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yZoomed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
yDrag = false;
|
||||||
|
} else if (queryZoom != null) {
|
||||||
|
if (u.select.width >= MIN_ZOOM_DIST) {
|
||||||
|
const minX = u.posToVal(u.select.left, 'x');
|
||||||
|
const maxX = u.posToVal(u.select.left + u.select.width, 'x');
|
||||||
|
|
||||||
|
queryZoom({ from: minX, to: maxX });
|
||||||
|
|
||||||
|
yZoomed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// manually hide selected region (since cursor.drag.setScale = false)
|
||||||
|
u.setSelect({ left: 0, width: 0, top: 0, height: 0 }, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (clientZoom || queryZoom != null) {
|
||||||
|
config.setCursor({
|
||||||
|
bind: {
|
||||||
|
dblclick: (u) => () => {
|
||||||
|
if (!maybeZoomAction(u.cursor!.event)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientZoom && yZoomed) {
|
||||||
|
for (let key in u.scales!) {
|
||||||
|
if (key !== 'x') {
|
||||||
|
// @ts-ignore (this is not typed correctly in uPlot, assigning nulls means auto-scale / reset)
|
||||||
|
u.setScale(key, { min: null, max: null });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yZoomed = false;
|
||||||
|
} else if (queryZoom != null) {
|
||||||
|
let xScale = u.scales.x;
|
||||||
|
|
||||||
|
const frTs = xScale.min!;
|
||||||
|
const toTs = xScale.max!;
|
||||||
|
const pad = (toTs - frTs) / 2;
|
||||||
|
|
||||||
|
queryZoom({ from: frTs - pad, to: toTs + pad });
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
config.addHook('setData', (u) => {
|
||||||
|
yZoomed = false;
|
||||||
|
yDrag = false;
|
||||||
|
});
|
||||||
|
|
||||||
// fires on data value hovers/unhovers (before setSeries)
|
// fires on data value hovers/unhovers (before setSeries)
|
||||||
config.addHook('setLegend', (u) => {
|
config.addHook('setLegend', (u) => {
|
||||||
let hoveredSeriesIdx = _plot!.cursor.idxs!.findIndex((v, i) => i > 0 && v != null);
|
let hoveredSeriesIdx = _plot!.cursor.idxs!.findIndex((v, i) => i > 0 && v != null);
|
||||||
|
Loading…
Reference in New Issue
Block a user