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 _plot = plot;
|
||||||
let _isHovering = isHovering;
|
let _isHovering = isHovering;
|
||||||
|
let _someSeriesIdx = false;
|
||||||
let _isPinned = isPinned;
|
let _isPinned = isPinned;
|
||||||
let _style = style;
|
let _style = style;
|
||||||
|
|
||||||
|
const updateHovering = () => {
|
||||||
|
_isHovering = closestSeriesIdx != null || (hoverMode === TooltipHoverMode.xAll && _someSeriesIdx);
|
||||||
|
};
|
||||||
|
|
||||||
let offsetX = 0;
|
let offsetX = 0;
|
||||||
let offsetY = 0;
|
let offsetY = 0;
|
||||||
|
|
||||||
let htmlEl = document.documentElement;
|
let containRect = {
|
||||||
let winWidth = htmlEl.clientWidth - 16;
|
lft: 0,
|
||||||
let winHeight = htmlEl.clientHeight - 16;
|
top: 0,
|
||||||
|
rgt: screen.width,
|
||||||
window.addEventListener('resize', (e) => {
|
btm: screen.height,
|
||||||
winWidth = htmlEl.clientWidth - 16;
|
};
|
||||||
winHeight = htmlEl.clientHeight - 16;
|
|
||||||
});
|
|
||||||
|
|
||||||
let selectedRange: TimeRange2 | null = null;
|
let selectedRange: TimeRange2 | null = null;
|
||||||
let seriesIdxs: Array<number | null> = plot?.cursor.idxs!.slice()!;
|
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) => {
|
config.addHook('setSelect', (u) => {
|
||||||
@ -372,44 +420,22 @@ export const TooltipPlugin2 = ({
|
|||||||
yDrag = false;
|
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
|
// fires on series focus/proximity changes
|
||||||
// e.g. to highlight the hovered/closest series
|
// e.g. to highlight the hovered/closest series
|
||||||
// TODO: we only need this for multi/all mode?
|
// TODO: we only need this for multi/all mode?
|
||||||
config.addHook('setSeries', (u, seriesIdx) => {
|
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;
|
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();
|
scheduleRender();
|
||||||
// }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// fires on mousemoves
|
// fires on mousemoves
|
||||||
@ -435,25 +461,25 @@ export const TooltipPlugin2 = ({
|
|||||||
let clientY = u.rect.top + top;
|
let clientY = u.rect.top + top;
|
||||||
|
|
||||||
if (offsetY !== 0) {
|
if (offsetY !== 0) {
|
||||||
if (clientY + height < winHeight || clientY - height < 0) {
|
if (clientY + height < containRect.btm || clientY - height < 0) {
|
||||||
offsetY = 0;
|
offsetY = 0;
|
||||||
} else if (offsetY !== -height) {
|
} else if (offsetY !== -height) {
|
||||||
offsetY = -height;
|
offsetY = -height;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (clientY + height > winHeight && clientY - height >= 0) {
|
if (clientY + height > containRect.btm && clientY - height >= 0) {
|
||||||
offsetY = -height;
|
offsetY = -height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offsetX !== 0) {
|
if (offsetX !== 0) {
|
||||||
if (clientX + width < winWidth || clientX - width < 0) {
|
if (clientX + width < containRect.rgt || clientX - width < 0) {
|
||||||
offsetX = 0;
|
offsetX = 0;
|
||||||
} else if (offsetX !== -width) {
|
} else if (offsetX !== -width) {
|
||||||
offsetX = -width;
|
offsetX = -width;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (clientX + width > winWidth && clientX - width >= 0) {
|
if (clientX + width > containRect.rgt && clientX - width >= 0) {
|
||||||
offsetX = -width;
|
offsetX = -width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user