86 lines
2.3 KiB
TypeScript
86 lines
2.3 KiB
TypeScript
import localPoint from "@visx/event/lib/localPoint";
|
|
import { Point } from "@visx/point";
|
|
import { Tooltip } from "@visx/tooltip";
|
|
import React from "react";
|
|
|
|
import styles from "./TooltipWrapper.module.css";
|
|
|
|
type TooltipWrapperProps = {
|
|
top?: number;
|
|
left?: number;
|
|
className?: string;
|
|
header?: string;
|
|
children?: React.ReactNode;
|
|
};
|
|
|
|
// Finds the SVG Element which is the outmost from element (highest parent of element which is svg)
|
|
|
|
function getOutmostSVG(element: Element): SVGElement | undefined {
|
|
let rootSVG: HTMLElement | Element | null = element;
|
|
let current: HTMLElement | Element | null = element;
|
|
|
|
while (current) {
|
|
console.log(current);
|
|
if (current.tagName == "svg") {
|
|
rootSVG = current;
|
|
}
|
|
current = current.parentElement;
|
|
}
|
|
|
|
return rootSVG as SVGElement;
|
|
}
|
|
|
|
const TooltipWrapper = ({
|
|
top,
|
|
left,
|
|
className,
|
|
header,
|
|
children,
|
|
}: TooltipWrapperProps) => {
|
|
return (
|
|
<Tooltip
|
|
top={top}
|
|
left={left}
|
|
className={`${styles.tooltip} ${className ?? ""}`}
|
|
unstyled
|
|
applyPositionStyle
|
|
>
|
|
{header ? <span className={styles.header}>{header}</span> : null}
|
|
{children ? <div className={styles.body}>{children}</div> : null}
|
|
</Tooltip>
|
|
);
|
|
};
|
|
|
|
function getTooltipPosition(
|
|
e: React.MouseEvent<
|
|
SVGTextElement | SVGPathElement | SVGLineElement,
|
|
MouseEvent
|
|
>
|
|
) {
|
|
// ownerSVGElement is given by visx docs but not recognized by typescript
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore
|
|
const eventElement = e.target.ownerSVGElement as Element;
|
|
const eventSvgCoords = localPoint(eventElement, e) as Point;
|
|
const rootSVG: SVGElement | undefined = getOutmostSVG(eventElement);
|
|
|
|
if (!rootSVG) {
|
|
console.error("Failed to find parent SVG for tooltip!");
|
|
return { x: 0, y: 0 };
|
|
}
|
|
const rootSVGLeft = rootSVG.getBoundingClientRect().left ?? 0;
|
|
const parentDivLeft =
|
|
rootSVG.parentElement?.getBoundingClientRect().left ?? 0;
|
|
|
|
// visx localPoint does not account for the horizontal shift due to centering of the parent element,
|
|
// so manually add any shift from that
|
|
const alignmentOffset = rootSVGLeft - parentDivLeft;
|
|
|
|
return {
|
|
x: eventSvgCoords.x + alignmentOffset,
|
|
y: eventSvgCoords.y,
|
|
};
|
|
}
|
|
|
|
export { TooltipWrapper, getTooltipPosition };
|