Clean up chart tooltip handling (#959)
This commit is contained in:
		
							parent
							
								
									be010da9f5
								
							
						
					
					
						commit
						8862425120
					
				|  | @ -32,7 +32,8 @@ const getBetPoints = (bets: Bet[]) => { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const BinaryChartTooltip = (props: SingleValueHistoryTooltipProps<Bet>) => { | const BinaryChartTooltip = (props: SingleValueHistoryTooltipProps<Bet>) => { | ||||||
|   const { x, y, xScale, datum } = props |   const { p, xScale } = props | ||||||
|  |   const { x, y, datum } = p | ||||||
|   const [start, end] = xScale.domain() |   const [start, end] = xScale.domain() | ||||||
|   return ( |   return ( | ||||||
|     <Row className="items-center gap-2 text-sm"> |     <Row className="items-center gap-2 text-sm"> | ||||||
|  |  | ||||||
|  | @ -162,7 +162,8 @@ export const ChoiceContractChart = (props: { | ||||||
| 
 | 
 | ||||||
|   const ChoiceTooltip = useMemo( |   const ChoiceTooltip = useMemo( | ||||||
|     () => (props: MultiValueHistoryTooltipProps<Bet>) => { |     () => (props: MultiValueHistoryTooltipProps<Bet>) => { | ||||||
|       const { x, y, xScale, datum } = props |       const { p, xScale } = props | ||||||
|  |       const { x, y, datum } = p | ||||||
|       const [start, end] = xScale.domain() |       const [start, end] = xScale.domain() | ||||||
|       const legendItems = sortBy( |       const legendItems = sortBy( | ||||||
|         y.map((p, i) => ({ |         y.map((p, i) => ({ | ||||||
|  |  | ||||||
|  | @ -25,7 +25,8 @@ const getNumericChartData = (contract: NumericContract) => { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const NumericChartTooltip = (props: SingleValueDistributionTooltipProps) => { | const NumericChartTooltip = (props: SingleValueDistributionTooltipProps) => { | ||||||
|   const { x, y } = props |   const { p } = props | ||||||
|  |   const { x, y } = p | ||||||
|   return ( |   return ( | ||||||
|     <span className="text-sm"> |     <span className="text-sm"> | ||||||
|       <strong>{formatPct(y, 2)}</strong> {formatLargeNumber(x)} |       <strong>{formatPct(y, 2)}</strong> {formatLargeNumber(x)} | ||||||
|  |  | ||||||
|  | @ -46,7 +46,8 @@ const getBetPoints = (bets: Bet[], scaleP: (p: number) => number) => { | ||||||
| const PseudoNumericChartTooltip = ( | const PseudoNumericChartTooltip = ( | ||||||
|   props: SingleValueHistoryTooltipProps<Bet> |   props: SingleValueHistoryTooltipProps<Bet> | ||||||
| ) => { | ) => { | ||||||
|   const { x, y, xScale, datum } = props |   const { p, xScale } = props | ||||||
|  |   const { x, y, datum } = p | ||||||
|   const [start, end] = xScale.domain() |   const [start, end] = xScale.domain() | ||||||
|   return ( |   return ( | ||||||
|     <Row className="items-center gap-2 text-sm"> |     <Row className="items-center gap-2 text-sm"> | ||||||
|  |  | ||||||
|  | @ -3,7 +3,6 @@ import { bisector } from 'd3-array' | ||||||
| import { axisBottom, axisLeft } from 'd3-axis' | import { axisBottom, axisLeft } from 'd3-axis' | ||||||
| import { D3BrushEvent } from 'd3-brush' | import { D3BrushEvent } from 'd3-brush' | ||||||
| import { ScaleTime, ScaleContinuousNumeric } from 'd3-scale' | import { ScaleTime, ScaleContinuousNumeric } from 'd3-scale' | ||||||
| import { pointer } from 'd3-selection' |  | ||||||
| import { | import { | ||||||
|   curveLinear, |   curveLinear, | ||||||
|   curveStepAfter, |   curveStepAfter, | ||||||
|  | @ -18,17 +17,25 @@ import { | ||||||
|   AreaPath, |   AreaPath, | ||||||
|   AreaWithTopStroke, |   AreaWithTopStroke, | ||||||
|   TooltipContent, |   TooltipContent, | ||||||
|   TooltipContainer, |  | ||||||
|   TooltipPosition, |  | ||||||
|   formatPct, |   formatPct, | ||||||
| } from './helpers' | } from './helpers' | ||||||
| import { useEvent } from 'web/hooks/use-event' | import { useEvent } from 'web/hooks/use-event' | ||||||
| 
 | 
 | ||||||
| export type MultiPoint<T = never> = { x: Date; y: number[]; datum?: T } | export type MultiPoint<T = never> = { | ||||||
| export type HistoryPoint<T = never> = { x: Date; y: number; datum?: T } |   x: Date | ||||||
| export type DistributionPoint<T = never> = { x: number; y: number; datum?: T } |   y: number[] | ||||||
| 
 |   datum?: T | ||||||
| type PositionValue<P> = TooltipPosition & { p: P } | } | ||||||
|  | export type HistoryPoint<T = never> = { | ||||||
|  |   x: Date | ||||||
|  |   y: number | ||||||
|  |   datum?: T | ||||||
|  | } | ||||||
|  | export type DistributionPoint<T = never> = { | ||||||
|  |   x: number | ||||||
|  |   y: number | ||||||
|  |   datum?: T | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| const getTickValues = (min: number, max: number, n: number) => { | const getTickValues = (min: number, max: number, n: number) => { | ||||||
|   const step = (max - min) / (n - 1) |   const step = (max - min) / (n - 1) | ||||||
|  | @ -48,8 +55,6 @@ export const SingleValueDistributionChart = <T,>(props: { | ||||||
| 
 | 
 | ||||||
|   const [viewXScale, setViewXScale] = |   const [viewXScale, setViewXScale] = | ||||||
|     useState<ScaleContinuousNumeric<number, number>>() |     useState<ScaleContinuousNumeric<number, number>>() | ||||||
|   const [mouseState, setMouseState] = |  | ||||||
|     useState<PositionValue<DistributionPoint<T>>>() |  | ||||||
|   const xScale = viewXScale ?? props.xScale |   const xScale = viewXScale ?? props.xScale | ||||||
| 
 | 
 | ||||||
|   const px = useCallback((p: DistributionPoint<T>) => xScale(p.x), [xScale]) |   const px = useCallback((p: DistributionPoint<T>) => xScale(p.x), [xScale]) | ||||||
|  | @ -69,16 +74,12 @@ export const SingleValueDistributionChart = <T,>(props: { | ||||||
|       setViewXScale(() => |       setViewXScale(() => | ||||||
|         xScale.copy().domain([xScale.invert(mouseX0), xScale.invert(mouseX1)]) |         xScale.copy().domain([xScale.invert(mouseX0), xScale.invert(mouseX1)]) | ||||||
|       ) |       ) | ||||||
|       setMouseState(undefined) |  | ||||||
|     } else { |     } else { | ||||||
|       setViewXScale(undefined) |       setViewXScale(undefined) | ||||||
|       setMouseState(undefined) |  | ||||||
|     } |     } | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   const onMouseOver = useEvent((ev: React.PointerEvent) => { |   const onMouseOver = useEvent((mouseX: number) => { | ||||||
|     if (ev.pointerType === 'mouse') { |  | ||||||
|       const [mouseX, mouseY] = pointer(ev) |  | ||||||
|     const queryX = xScale.invert(mouseX) |     const queryX = xScale.invert(mouseX) | ||||||
|     const item = data[xBisector.left(data, queryX) - 1] |     const item = data[xBisector.left(data, queryX) - 1] | ||||||
|     if (item == null) { |     if (item == null) { | ||||||
|  | @ -86,22 +87,10 @@ export const SingleValueDistributionChart = <T,>(props: { | ||||||
|       // so your queryX is out of bounds
 |       // so your queryX is out of bounds
 | ||||||
|       return |       return | ||||||
|     } |     } | ||||||
|       const p = { x: queryX, y: item.y, datum: item.datum } |     return { x: queryX, y: item.y, datum: item.datum } | ||||||
|       setMouseState({ top: mouseY - 10, left: mouseX + 60, p }) |  | ||||||
|     } |  | ||||||
|   }) |  | ||||||
| 
 |  | ||||||
|   const onMouseLeave = useEvent(() => { |  | ||||||
|     setMouseState(undefined) |  | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div className="relative"> |  | ||||||
|       {mouseState && Tooltip && ( |  | ||||||
|         <TooltipContainer className="text-sm" {...mouseState}> |  | ||||||
|           <Tooltip xScale={xScale} {...mouseState.p} /> |  | ||||||
|         </TooltipContainer> |  | ||||||
|       )} |  | ||||||
|     <SVGChart |     <SVGChart | ||||||
|       w={w} |       w={w} | ||||||
|       h={h} |       h={h} | ||||||
|  | @ -109,7 +98,7 @@ export const SingleValueDistributionChart = <T,>(props: { | ||||||
|       yAxis={yAxis} |       yAxis={yAxis} | ||||||
|       onSelect={onSelect} |       onSelect={onSelect} | ||||||
|       onMouseOver={onMouseOver} |       onMouseOver={onMouseOver} | ||||||
|         onMouseLeave={onMouseLeave} |       Tooltip={Tooltip} | ||||||
|     > |     > | ||||||
|       <AreaWithTopStroke |       <AreaWithTopStroke | ||||||
|         color={color} |         color={color} | ||||||
|  | @ -120,16 +109,13 @@ export const SingleValueDistributionChart = <T,>(props: { | ||||||
|         curve={curveLinear} |         curve={curveLinear} | ||||||
|       /> |       /> | ||||||
|     </SVGChart> |     </SVGChart> | ||||||
|     </div> |  | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export type SingleValueDistributionTooltipProps<T = unknown> = | export type SingleValueDistributionTooltipProps<T = unknown> = { | ||||||
|   DistributionPoint<T> & { |   p: DistributionPoint<T> | ||||||
|     xScale: React.ComponentProps< |   xScale: React.ComponentProps<typeof SingleValueDistributionChart<T>>['xScale'] | ||||||
|       typeof SingleValueDistributionChart<T> | } | ||||||
|     >['xScale'] |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
| export const MultiValueHistoryChart = <T,>(props: { | export const MultiValueHistoryChart = <T,>(props: { | ||||||
|   data: MultiPoint<T>[] |   data: MultiPoint<T>[] | ||||||
|  | @ -144,7 +130,6 @@ export const MultiValueHistoryChart = <T,>(props: { | ||||||
|   const { colors, data, yScale, w, h, Tooltip, pct } = props |   const { colors, data, yScale, w, h, Tooltip, pct } = props | ||||||
| 
 | 
 | ||||||
|   const [viewXScale, setViewXScale] = useState<ScaleTime<number, number>>() |   const [viewXScale, setViewXScale] = useState<ScaleTime<number, number>>() | ||||||
|   const [mouseState, setMouseState] = useState<PositionValue<MultiPoint<T>>>() |  | ||||||
|   const xScale = viewXScale ?? props.xScale |   const xScale = viewXScale ?? props.xScale | ||||||
| 
 | 
 | ||||||
|   type SP = SeriesPoint<MultiPoint<T>> |   type SP = SeriesPoint<MultiPoint<T>> | ||||||
|  | @ -177,16 +162,12 @@ export const MultiValueHistoryChart = <T,>(props: { | ||||||
|       setViewXScale(() => |       setViewXScale(() => | ||||||
|         xScale.copy().domain([xScale.invert(mouseX0), xScale.invert(mouseX1)]) |         xScale.copy().domain([xScale.invert(mouseX0), xScale.invert(mouseX1)]) | ||||||
|       ) |       ) | ||||||
|       setMouseState(undefined) |  | ||||||
|     } else { |     } else { | ||||||
|       setViewXScale(undefined) |       setViewXScale(undefined) | ||||||
|       setMouseState(undefined) |  | ||||||
|     } |     } | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   const onMouseOver = useEvent((ev: React.PointerEvent) => { |   const onMouseOver = useEvent((mouseX: number) => { | ||||||
|     if (ev.pointerType === 'mouse') { |  | ||||||
|       const [mouseX, mouseY] = pointer(ev) |  | ||||||
|     const queryX = xScale.invert(mouseX) |     const queryX = xScale.invert(mouseX) | ||||||
|     const item = data[xBisector.left(data, queryX) - 1] |     const item = data[xBisector.left(data, queryX) - 1] | ||||||
|     if (item == null) { |     if (item == null) { | ||||||
|  | @ -194,22 +175,10 @@ export const MultiValueHistoryChart = <T,>(props: { | ||||||
|       // so your queryX is out of bounds
 |       // so your queryX is out of bounds
 | ||||||
|       return |       return | ||||||
|     } |     } | ||||||
|       const p = { x: queryX, y: item.y, datum: item.datum } |     return { x: queryX, y: item.y, datum: item.datum } | ||||||
|       setMouseState({ top: mouseY - 10, left: mouseX + 60, p }) |  | ||||||
|     } |  | ||||||
|   }) |  | ||||||
| 
 |  | ||||||
|   const onMouseLeave = useEvent(() => { |  | ||||||
|     setMouseState(undefined) |  | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div className="relative"> |  | ||||||
|       {mouseState && Tooltip && ( |  | ||||||
|         <TooltipContainer top={mouseState.top} left={mouseState.left}> |  | ||||||
|           <Tooltip xScale={xScale} {...mouseState.p} /> |  | ||||||
|         </TooltipContainer> |  | ||||||
|       )} |  | ||||||
|     <SVGChart |     <SVGChart | ||||||
|       w={w} |       w={w} | ||||||
|       h={h} |       h={h} | ||||||
|  | @ -217,7 +186,7 @@ export const MultiValueHistoryChart = <T,>(props: { | ||||||
|       yAxis={yAxis} |       yAxis={yAxis} | ||||||
|       onSelect={onSelect} |       onSelect={onSelect} | ||||||
|       onMouseOver={onMouseOver} |       onMouseOver={onMouseOver} | ||||||
|         onMouseLeave={onMouseLeave} |       Tooltip={Tooltip} | ||||||
|     > |     > | ||||||
|       {series.map((s, i) => ( |       {series.map((s, i) => ( | ||||||
|         <AreaPath |         <AreaPath | ||||||
|  | @ -231,11 +200,11 @@ export const MultiValueHistoryChart = <T,>(props: { | ||||||
|         /> |         /> | ||||||
|       ))} |       ))} | ||||||
|     </SVGChart> |     </SVGChart> | ||||||
|     </div> |  | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export type MultiValueHistoryTooltipProps<T = unknown> = MultiPoint<T> & { | export type MultiValueHistoryTooltipProps<T = unknown> = { | ||||||
|  |   p: MultiPoint<T> | ||||||
|   xScale: React.ComponentProps<typeof MultiValueHistoryChart<T>>['xScale'] |   xScale: React.ComponentProps<typeof MultiValueHistoryChart<T>>['xScale'] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -252,7 +221,6 @@ export const SingleValueHistoryChart = <T,>(props: { | ||||||
|   const { color, data, pct, yScale, w, h, Tooltip } = props |   const { color, data, pct, yScale, w, h, Tooltip } = props | ||||||
| 
 | 
 | ||||||
|   const [viewXScale, setViewXScale] = useState<ScaleTime<number, number>>() |   const [viewXScale, setViewXScale] = useState<ScaleTime<number, number>>() | ||||||
|   const [mouseState, setMouseState] = useState<PositionValue<HistoryPoint<T>>>() |  | ||||||
|   const xScale = viewXScale ?? props.xScale |   const xScale = viewXScale ?? props.xScale | ||||||
| 
 | 
 | ||||||
|   const px = useCallback((p: HistoryPoint<T>) => xScale(p.x), [xScale]) |   const px = useCallback((p: HistoryPoint<T>) => xScale(p.x), [xScale]) | ||||||
|  | @ -276,16 +244,12 @@ export const SingleValueHistoryChart = <T,>(props: { | ||||||
|       setViewXScale(() => |       setViewXScale(() => | ||||||
|         xScale.copy().domain([xScale.invert(mouseX0), xScale.invert(mouseX1)]) |         xScale.copy().domain([xScale.invert(mouseX0), xScale.invert(mouseX1)]) | ||||||
|       ) |       ) | ||||||
|       setMouseState(undefined) |  | ||||||
|     } else { |     } else { | ||||||
|       setViewXScale(undefined) |       setViewXScale(undefined) | ||||||
|       setMouseState(undefined) |  | ||||||
|     } |     } | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   const onMouseOver = useEvent((ev: React.PointerEvent) => { |   const onMouseOver = useEvent((mouseX: number) => { | ||||||
|     if (ev.pointerType === 'mouse') { |  | ||||||
|       const [mouseX, mouseY] = pointer(ev) |  | ||||||
|     const queryX = xScale.invert(mouseX) |     const queryX = xScale.invert(mouseX) | ||||||
|     const item = data[xBisector.left(data, queryX) - 1] |     const item = data[xBisector.left(data, queryX) - 1] | ||||||
|     if (item == null) { |     if (item == null) { | ||||||
|  | @ -293,22 +257,10 @@ export const SingleValueHistoryChart = <T,>(props: { | ||||||
|       // so your queryX is out of bounds
 |       // so your queryX is out of bounds
 | ||||||
|       return |       return | ||||||
|     } |     } | ||||||
|       const p = { x: queryX, y: item.y, datum: item.datum } |     return { x: queryX, y: item.y, datum: item.datum } | ||||||
|       setMouseState({ top: mouseY - 10, left: mouseX + 60, p }) |  | ||||||
|     } |  | ||||||
|   }) |  | ||||||
| 
 |  | ||||||
|   const onMouseLeave = useEvent(() => { |  | ||||||
|     setMouseState(undefined) |  | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div className="relative"> |  | ||||||
|       {mouseState && Tooltip && ( |  | ||||||
|         <TooltipContainer top={mouseState.top} left={mouseState.left}> |  | ||||||
|           <Tooltip xScale={xScale} {...mouseState.p} /> |  | ||||||
|         </TooltipContainer> |  | ||||||
|       )} |  | ||||||
|     <SVGChart |     <SVGChart | ||||||
|       w={w} |       w={w} | ||||||
|       h={h} |       h={h} | ||||||
|  | @ -316,7 +268,7 @@ export const SingleValueHistoryChart = <T,>(props: { | ||||||
|       yAxis={yAxis} |       yAxis={yAxis} | ||||||
|       onSelect={onSelect} |       onSelect={onSelect} | ||||||
|       onMouseOver={onMouseOver} |       onMouseOver={onMouseOver} | ||||||
|         onMouseLeave={onMouseLeave} |       Tooltip={Tooltip} | ||||||
|     > |     > | ||||||
|       <AreaWithTopStroke |       <AreaWithTopStroke | ||||||
|         color={color} |         color={color} | ||||||
|  | @ -327,10 +279,10 @@ export const SingleValueHistoryChart = <T,>(props: { | ||||||
|         curve={curveStepAfter} |         curve={curveStepAfter} | ||||||
|       /> |       /> | ||||||
|     </SVGChart> |     </SVGChart> | ||||||
|     </div> |  | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export type SingleValueHistoryTooltipProps<T = unknown> = HistoryPoint<T> & { | export type SingleValueHistoryTooltipProps<T = unknown> = { | ||||||
|  |   p: HistoryPoint<T> | ||||||
|   xScale: React.ComponentProps<typeof SingleValueHistoryChart<T>>['xScale'] |   xScale: React.ComponentProps<typeof SingleValueHistoryChart<T>>['xScale'] | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,13 @@ | ||||||
| import { ReactNode, SVGProps, memo, useRef, useEffect, useMemo } from 'react' | import { | ||||||
| import { select } from 'd3-selection' |   ReactNode, | ||||||
|  |   SVGProps, | ||||||
|  |   memo, | ||||||
|  |   useRef, | ||||||
|  |   useEffect, | ||||||
|  |   useMemo, | ||||||
|  |   useState, | ||||||
|  | } from 'react' | ||||||
|  | import { pointer, select } from 'd3-selection' | ||||||
| import { Axis } from 'd3-axis' | import { Axis } from 'd3-axis' | ||||||
| import { brushX, D3BrushEvent } from 'd3-brush' | import { brushX, D3BrushEvent } from 'd3-brush' | ||||||
| import { area, line, curveStepAfter, CurveFactory } from 'd3-shape' | import { area, line, curveStepAfter, CurveFactory } from 'd3-shape' | ||||||
|  | @ -108,19 +116,18 @@ export const AreaWithTopStroke = <P,>(props: { | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const SVGChart = <X, Y>(props: { | export const SVGChart = <X, Y, P, XS>(props: { | ||||||
|   children: ReactNode |   children: ReactNode | ||||||
|   w: number |   w: number | ||||||
|   h: number |   h: number | ||||||
|   xAxis: Axis<X> |   xAxis: Axis<X> | ||||||
|   yAxis: Axis<Y> |   yAxis: Axis<Y> | ||||||
|   onSelect?: (ev: D3BrushEvent<any>) => void |   onSelect?: (ev: D3BrushEvent<any>) => void | ||||||
|   onMouseOver?: (ev: React.PointerEvent) => void |   onMouseOver?: (mouseX: number, mouseY: number) => P | undefined | ||||||
|   onMouseLeave?: (ev: React.PointerEvent) => void |   Tooltip?: TooltipContent<{ xScale: XS } & { p: P }> | ||||||
|   pct?: boolean |  | ||||||
| }) => { | }) => { | ||||||
|   const { children, w, h, xAxis, yAxis, onMouseOver, onMouseLeave, onSelect } = |   const { children, w, h, xAxis, yAxis, onMouseOver, onSelect, Tooltip } = props | ||||||
|     props |   const [mouseState, setMouseState] = useState<TooltipPosition & { p: P }>() | ||||||
|   const overlayRef = useRef<SVGGElement>(null) |   const overlayRef = useRef<SVGGElement>(null) | ||||||
|   const innerW = w - MARGIN_X |   const innerW = w - MARGIN_X | ||||||
|   const innerH = h - MARGIN_Y |   const innerH = h - MARGIN_Y | ||||||
|  | @ -139,6 +146,7 @@ export const SVGChart = <X, Y>(props: { | ||||||
|         if (!justSelected.current) { |         if (!justSelected.current) { | ||||||
|           justSelected.current = true |           justSelected.current = true | ||||||
|           onSelect(ev) |           onSelect(ev) | ||||||
|  |           setMouseState(undefined) | ||||||
|           if (overlayRef.current) { |           if (overlayRef.current) { | ||||||
|             select(overlayRef.current).call(brush.clear) |             select(overlayRef.current).call(brush.clear) | ||||||
|           } |           } | ||||||
|  | @ -156,7 +164,29 @@ export const SVGChart = <X, Y>(props: { | ||||||
|     } |     } | ||||||
|   }, [innerW, innerH, onSelect]) |   }, [innerW, innerH, onSelect]) | ||||||
| 
 | 
 | ||||||
|  |   const onPointerMove = (ev: React.PointerEvent) => { | ||||||
|  |     if (ev.pointerType === 'mouse' && onMouseOver) { | ||||||
|  |       const [mouseX, mouseY] = pointer(ev) | ||||||
|  |       const p = onMouseOver(mouseX, mouseY) | ||||||
|  |       if (p != null) { | ||||||
|  |         setMouseState({ top: mouseY - 10, left: mouseX + 60, p }) | ||||||
|  |       } else { | ||||||
|  |         setMouseState(undefined) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const onPointerLeave = () => { | ||||||
|  |     setMouseState(undefined) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   return ( |   return ( | ||||||
|  |     <div className="relative"> | ||||||
|  |       {mouseState && Tooltip && ( | ||||||
|  |         <TooltipContainer top={mouseState.top} left={mouseState.left}> | ||||||
|  |           <Tooltip xScale={xAxis.scale() as XS} p={mouseState.p} /> | ||||||
|  |         </TooltipContainer> | ||||||
|  |       )} | ||||||
|       <svg className="w-full" width={w} height={h} viewBox={`0 0 ${w} ${h}`}> |       <svg className="w-full" width={w} height={h} viewBox={`0 0 ${w} ${h}`}> | ||||||
|         <clipPath id={clipPathId}> |         <clipPath id={clipPathId}> | ||||||
|           <rect x={0} y={0} width={innerW} height={innerH} /> |           <rect x={0} y={0} width={innerW} height={innerH} /> | ||||||
|  | @ -173,12 +203,13 @@ export const SVGChart = <X, Y>(props: { | ||||||
|             height={innerH} |             height={innerH} | ||||||
|             fill="none" |             fill="none" | ||||||
|             pointerEvents="all" |             pointerEvents="all" | ||||||
|           onPointerEnter={onMouseOver} |             onPointerEnter={onPointerMove} | ||||||
|           onPointerMove={onMouseOver} |             onPointerMove={onPointerMove} | ||||||
|           onPointerLeave={onMouseLeave} |             onPointerLeave={onPointerLeave} | ||||||
|           /> |           /> | ||||||
|         </g> |         </g> | ||||||
|       </svg> |       </svg> | ||||||
|  |     </div> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user