cs-2022-class-profile/components/TooltipWrapper.tsx

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 };