From 523689b52520daec75ec44ccdc0bac1fd3e52c02 Mon Sep 17 00:00:00 2001 From: Marshall Polaris Date: Thu, 29 Sep 2022 22:45:31 -0700 Subject: [PATCH] Keep tooltip within bounds of chart (well, for non-FR charts) (#970) --- web/components/charts/helpers.tsx | 53 ++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/web/components/charts/helpers.tsx b/web/components/charts/helpers.tsx index ea436213..b7948298 100644 --- a/web/components/charts/helpers.tsx +++ b/web/components/charts/helpers.tsx @@ -25,6 +25,8 @@ export type YScale

= P extends Point ? AxisScale : never export const MARGIN = { top: 20, right: 10, bottom: 20, left: 40 } export const MARGIN_X = MARGIN.right + MARGIN.left export const MARGIN_Y = MARGIN.top + MARGIN.bottom +const MARGIN_STYLE = `${MARGIN.top}px ${MARGIN.right}px ${MARGIN.bottom}px ${MARGIN.left}px` +const MARGIN_XFORM = `translate(${MARGIN.left}, ${MARGIN.top})` export const XAxis = (props: { w: number; h: number; axis: Axis }) => { const { h, axis } = props @@ -128,7 +130,7 @@ export const SVGChart = >(props: { Tooltip?: TooltipComponent

}) => { const { children, w, h, xAxis, yAxis, onMouseOver, onSelect, Tooltip } = props - const [mouseState, setMouseState] = useState() + const [mouseState, setMouseState] = useState<{ pos: TooltipPosition; p: P }>() const overlayRef = useRef(null) const innerW = w - MARGIN_X const innerH = h - MARGIN_Y @@ -170,7 +172,8 @@ export const SVGChart = >(props: { const [mouseX, mouseY] = pointer(ev) const p = onMouseOver(mouseX, mouseY) if (p != null) { - setMouseState({ top: mouseY - 10, left: mouseX + 60, p }) + const pos = getTooltipPosition(mouseX, mouseY, innerW, innerH) + setMouseState({ pos, p }) } else { setMouseState(undefined) } @@ -184,15 +187,15 @@ export const SVGChart = >(props: { return (

{mouseState && Tooltip && ( - + )} - + - + {children} @@ -214,20 +217,48 @@ export const SVGChart = >(props: { ) } +export type TooltipPosition = { + top?: number + right?: number + bottom?: number + left?: number +} + +export const getTooltipPosition = ( + mouseX: number, + mouseY: number, + w: number, + h: number +) => { + const result: TooltipPosition = {} + if (mouseX <= (3 * w) / 4) { + result.left = mouseX + 10 // in the left three quarters + } else { + result.right = w - mouseX + 10 // in the right quarter + } + if (mouseY <= h / 4) { + result.top = mouseY + 10 // in the top quarter + } else { + result.bottom = h - mouseY + 10 // in the bottom three quarters + } + return result +} + export type TooltipProps

= { p: P; xScale: XScale

} export type TooltipComponent

= React.ComponentType> -export type TooltipPosition = { top: number; left: number } -export const TooltipContainer = ( - props: TooltipPosition & { className?: string; children: React.ReactNode } -) => { - const { top, left, className, children } = props +export const TooltipContainer = (props: { + pos: TooltipPosition + className?: string + children: React.ReactNode +}) => { + const { pos, className, children } = props return (

{children}