import React, { useMemo } from 'react' import { useAtom } from 'jotai' import { max, sum } from 'd3-array' import { useGG, tooltipState, TooltipContent, XTooltip, YTooltip, Aes, themeState, TooltipProps, } from '@graphique/graphique' import { DefaultTooltip } from './DefaultTooltip' import { FocusType, Position } from '../types' interface StackMidpoint { groupVal: string yVal: string | number xVal: number } interface Props { x: (d: Datum) => number | undefined y: (d: Datum) => number | undefined yAdj?: number aes?: Aes focusType: FocusType stackMidpoints?: StackMidpoint[] position: Position } export const Tooltip = ({ x, y, yAdj = 0, aes, focusType, stackMidpoints, position, }: Props) => { const { ggState } = useGG() || {} const { id, scales, copiedScales, height } = ggState || { height: 0, } const [{ datum, xFormat, yFormat, content }] = useAtom>(tooltipState) const [{ geoms }] = useAtom(themeState) const yVal = useMemo( () => datum && datum[0] && aes?.y && aes.y(datum[0]), [datum, aes], ) const yCoord = useMemo( () => (datum?.[0] && (y(datum?.[0]) ?? 0) + (focusType === FocusType.GROUP ? yAdj : 0)) || 0, [yAdj, datum, y, focusType], ) const group = useMemo( () => scales?.groupAccessor || (() => '__group'), [scales], ) const hasGroup = useMemo(() => { const datumGroup = datum?.length && group(datum?.[0])?.toString() return datumGroup && scales?.groups?.includes(datumGroup) }, [scales?.groups, group, datum]) const xVal = useMemo(() => { if ( focusType === FocusType.INDIVIDUAL && stackMidpoints && datum && datum?.length ) { const datumGroup = group(datum[0]) const focusedStack = stackMidpoints.find( ({ yVal: stackY, groupVal }) => stackY === yVal && groupVal === datumGroup, ) return focusedStack ? scales?.xScale(focusedStack.xVal) : undefined } if (position === Position.FILL) return scales?.xScale(1) if ( position === Position.STACK && datum && scales?.groups && aes?.x && scales.xScale ) { return scales.xScale(sum(datum.map((d) => aes.x(d) as number))) } return datum ? max(datum, (d) => x(d)) : undefined }, [datum, scales, geoms, aes, focusType, stackMidpoints, yVal, group]) const fillDomain = copiedScales?.fillScale?.domain() const groupVals = useMemo(() => { const vals = datum && datum .filter((d) => aes?.x(d)) .sort( (a, b) => fillDomain!.indexOf(String(group(a))) - fillDomain!.indexOf(String(group(b))), ) .map((md) => { const thisGroup = group(md) const mark = ( ) return { datum, group: thisGroup, mark, x: xVal, y: yVal, formattedX: xFormat ? xFormat(aes?.x(md)) : aes?.x(md), formattedY: yFormat ? yFormat(yVal) : String(yVal), } }) return vals as TooltipContent[] }, [ datum, yVal, group, x, aes, yFormat, xFormat, copiedScales, geoms, scales, ]) const tooltipValue = content ? datum &&
{content(groupVals)}
: datum && if (datum && groupVals[0] && focusType === FocusType.INDIVIDUAL && hasGroup) return (
) return datum && groupVals[0] ? (
) : null }