Skip to content

Commit

Permalink
Update tooltip to account for iframe offsets
Browse files Browse the repository at this point in the history
  • Loading branch information
lapidus committed Jun 3, 2024
1 parent 7de85df commit e81f116
Showing 1 changed file with 51 additions and 5 deletions.
56 changes: 51 additions & 5 deletions packages/visx-xychart/src/components/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,22 @@ function defaultRenderGlyph<Datum extends object>(props: RenderTooltipGlyphProps
return <DefaultGlyph {...props} />;
}

function getIframeOffsets(target) {
let offsetX = 0;
let offsetY = 0;
let currentWindow = target.ownerDocument.defaultView;

while (currentWindow && currentWindow.frameElement) {
const frameElement = currentWindow.frameElement;
const frameRect = frameElement.getBoundingClientRect();
offsetX += frameRect.left;
offsetY += frameRect.top;
currentWindow = currentWindow.parent;
}

return { x: offsetX, y: offsetY };
}

function TooltipInner<Datum extends object>({
debounce,
detectBounds,
Expand Down Expand Up @@ -132,15 +148,46 @@ function TooltipInner<Datum extends object>({
zIndex,
});

function getIframeOffsets(target) {
let offsetX = 0;
let offsetY = 0;
let currentWindow = target.ownerDocument.defaultView;

while (currentWindow && currentWindow.frameElement) {
const frameElement = currentWindow.frameElement;
const frameRect = frameElement.getBoundingClientRect();
offsetX += frameRect.left;
offsetY += frameRect.top;
currentWindow = currentWindow.parent;
}

return { x: offsetX, y: offsetY };
}

// To correctly position itself in a Portal, the tooltip must know its container bounds
// this is done by rendering an invisible node whose ref can be used to find its parentElement
const setContainerRef = useCallback(
(ownRef: HTMLElement | SVGElement | null) => {
containerRef(ownRef?.parentElement ?? null);
if (ownRef && ownRef.parentElement instanceof Element) {
const iframeOffsets = getIframeOffsets(ownRef);
const parentRect = ownRef.parentElement.getBoundingClientRect();
const adjustedContainer = {
...ownRef.parentElement,
getBoundingClientRect: () => ({
...parentRect,
x: parentRect.x + iframeOffsets.x,
y: parentRect.y + iframeOffsets.y,
left: parentRect.left + iframeOffsets.x,
top: parentRect.top + iframeOffsets.y,
}),
};
containerRef(adjustedContainer);
} else {
containerRef(null);
}
},
[containerRef],
);

const tooltipContent = tooltipContext?.tooltipOpen
? renderTooltip({ ...tooltipContext, colorScale })
: null;
Expand Down Expand Up @@ -301,10 +348,9 @@ function TooltipInner<Datum extends object>({
</svg>
</TooltipInPortal>
)}
{glyphProps.map(({ x, y, ...props }, i) => (
// We render glyps in a portal so that they can overflow the container if necessary
{glyphProps.map(({ key, x, y, ...props }) => (
<TooltipInPortal
key={i}
key={key}
className="visx-tooltip-glyph"
left={x}
top={y}
Expand Down

0 comments on commit e81f116

Please sign in to comment.