mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
TooltipPlugin2: Improve containment inside ancestors that hide overflow (#81442)
This commit is contained in:
parent
d34bd1dc90
commit
6a61c3da2e
@ -146,20 +146,23 @@ export const TooltipPlugin2 = ({
|
||||
|
||||
let _plot = plot;
|
||||
let _isHovering = isHovering;
|
||||
let _someSeriesIdx = false;
|
||||
let _isPinned = isPinned;
|
||||
let _style = style;
|
||||
|
||||
const updateHovering = () => {
|
||||
_isHovering = closestSeriesIdx != null || (hoverMode === TooltipHoverMode.xAll && _someSeriesIdx);
|
||||
};
|
||||
|
||||
let offsetX = 0;
|
||||
let offsetY = 0;
|
||||
|
||||
let htmlEl = document.documentElement;
|
||||
let winWidth = htmlEl.clientWidth - 16;
|
||||
let winHeight = htmlEl.clientHeight - 16;
|
||||
|
||||
window.addEventListener('resize', (e) => {
|
||||
winWidth = htmlEl.clientWidth - 16;
|
||||
winHeight = htmlEl.clientHeight - 16;
|
||||
});
|
||||
let containRect = {
|
||||
lft: 0,
|
||||
top: 0,
|
||||
rgt: screen.width,
|
||||
btm: screen.height,
|
||||
};
|
||||
|
||||
let selectedRange: TimeRange2 | null = null;
|
||||
let seriesIdxs: Array<number | null> = plot?.cursor.idxs!.slice()!;
|
||||
@ -290,6 +293,51 @@ export const TooltipPlugin2 = ({
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const haltAncestorId = 'pageContent';
|
||||
const scrollbarWidth = 16;
|
||||
|
||||
// if we're in a container that can clip the tooltip, we should try to stay within that rather than window edges
|
||||
u.over.addEventListener(
|
||||
'mouseenter',
|
||||
() => {
|
||||
// clamp to viewport bounds
|
||||
let htmlEl = document.documentElement;
|
||||
let winWid = htmlEl.clientWidth - scrollbarWidth;
|
||||
let winHgt = htmlEl.clientHeight - scrollbarWidth;
|
||||
|
||||
let lft = 0,
|
||||
top = 0,
|
||||
rgt = winWid,
|
||||
btm = winHgt;
|
||||
|
||||
// find nearest scrollable container where overflow is not visible, (stop at #pageContent)
|
||||
let par: HTMLElement | null = u.root;
|
||||
|
||||
while (par != null && par.id !== haltAncestorId) {
|
||||
let style = getComputedStyle(par);
|
||||
let overflowX = style.getPropertyValue('overflow-x');
|
||||
let overflowY = style.getPropertyValue('overflow-y');
|
||||
|
||||
if (overflowX !== 'visible' || overflowY !== 'visible') {
|
||||
let rect = par.getBoundingClientRect();
|
||||
lft = Math.max(rect.x, lft);
|
||||
top = Math.max(rect.y, top);
|
||||
rgt = Math.min(lft + rect.width, rgt);
|
||||
btm = Math.min(top + rect.height, btm);
|
||||
break;
|
||||
}
|
||||
|
||||
par = par.parentElement;
|
||||
}
|
||||
|
||||
containRect.lft = lft;
|
||||
containRect.top = top;
|
||||
containRect.rgt = rgt;
|
||||
containRect.btm = btm;
|
||||
},
|
||||
{ capture: true }
|
||||
);
|
||||
});
|
||||
|
||||
config.addHook('setSelect', (u) => {
|
||||
@ -372,44 +420,22 @@ export const TooltipPlugin2 = ({
|
||||
yDrag = false;
|
||||
});
|
||||
|
||||
// fires on data value hovers/unhovers (before setSeries)
|
||||
config.addHook('setLegend', (u) => {
|
||||
seriesIdxs = _plot?.cursor!.idxs!.slice()!;
|
||||
|
||||
let hoveredSeriesIdx = seriesIdxs.findIndex((v, i) => i > 0 && v != null);
|
||||
let _isHoveringNow = hoveredSeriesIdx !== -1;
|
||||
|
||||
// setSeries may not fire if focus.prox is not set, so we set closestSeriesIdx here instead
|
||||
if (hoverMode === TooltipHoverMode.xyOne) {
|
||||
closestSeriesIdx = hoveredSeriesIdx;
|
||||
}
|
||||
|
||||
if (_isHoveringNow) {
|
||||
// create
|
||||
if (!_isHovering) {
|
||||
_isHovering = true;
|
||||
}
|
||||
} else {
|
||||
// destroy...TODO: debounce this
|
||||
if (_isHovering) {
|
||||
_isHovering = false;
|
||||
}
|
||||
}
|
||||
|
||||
scheduleRender();
|
||||
});
|
||||
|
||||
// fires on series focus/proximity changes
|
||||
// e.g. to highlight the hovered/closest series
|
||||
// TODO: we only need this for multi/all mode?
|
||||
config.addHook('setSeries', (u, seriesIdx) => {
|
||||
// don't jiggle focused series styling when there's only one series
|
||||
// const isMultiSeries = u.series.length > 2;
|
||||
|
||||
// if (hoverModeRef.current === TooltipHoverMode.xAll && closestSeriesIdx !== seriesIdx) {
|
||||
closestSeriesIdx = seriesIdx;
|
||||
updateHovering();
|
||||
scheduleRender();
|
||||
});
|
||||
|
||||
// fires on data value hovers/unhovers
|
||||
config.addHook('setLegend', (u) => {
|
||||
seriesIdxs = _plot?.cursor!.idxs!.slice()!;
|
||||
_someSeriesIdx = seriesIdxs.some((v, i) => i > 0 && v != null);
|
||||
|
||||
updateHovering();
|
||||
scheduleRender();
|
||||
// }
|
||||
});
|
||||
|
||||
// fires on mousemoves
|
||||
@ -435,25 +461,25 @@ export const TooltipPlugin2 = ({
|
||||
let clientY = u.rect.top + top;
|
||||
|
||||
if (offsetY !== 0) {
|
||||
if (clientY + height < winHeight || clientY - height < 0) {
|
||||
if (clientY + height < containRect.btm || clientY - height < 0) {
|
||||
offsetY = 0;
|
||||
} else if (offsetY !== -height) {
|
||||
offsetY = -height;
|
||||
}
|
||||
} else {
|
||||
if (clientY + height > winHeight && clientY - height >= 0) {
|
||||
if (clientY + height > containRect.btm && clientY - height >= 0) {
|
||||
offsetY = -height;
|
||||
}
|
||||
}
|
||||
|
||||
if (offsetX !== 0) {
|
||||
if (clientX + width < winWidth || clientX - width < 0) {
|
||||
if (clientX + width < containRect.rgt || clientX - width < 0) {
|
||||
offsetX = 0;
|
||||
} else if (offsetX !== -width) {
|
||||
offsetX = -width;
|
||||
}
|
||||
} else {
|
||||
if (clientX + width > winWidth && clientX - width >= 0) {
|
||||
if (clientX + width > containRect.rgt && clientX - width >= 0) {
|
||||
offsetX = -width;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user