diff --git a/src/components/d3/D3Chart.tsx b/src/components/d3/D3Chart.tsx index 9e8bee9..0581b9c 100644 --- a/src/components/d3/D3Chart.tsx +++ b/src/components/d3/D3Chart.tsx @@ -115,7 +115,7 @@ const _D3Chart = >({ height: givenHeight = '100%', loading, offset: _offset, - animDurationMs = 200, + animDurationMs = 20, backgroundColor = 'transparent', ticks, plugins, @@ -417,7 +417,7 @@ const _D3Chart = >({ charts={charts} {...plugins?.legend} /> - charts={charts} {...plugins?.tooltip} /> + charts={charts} {...plugins?.tooltip} zoomState={currentZoomState}/> diff --git a/src/components/d3/plugins/D3Tooltip.tsx b/src/components/d3/plugins/D3Tooltip.tsx index 1d16cb7..820e48a 100644 --- a/src/components/d3/plugins/D3Tooltip.tsx +++ b/src/components/d3/plugins/D3Tooltip.tsx @@ -76,6 +76,7 @@ export const makeDefaultRender = (): D3RenderFunc export type D3TooltipProps = Partial> & { charts: ChartRegistry[], + zoomState?: d3.ZoomTransform | null, } function _D3Tooltip({ @@ -86,7 +87,8 @@ function _D3Tooltip({ position: _position = 'bottom', className = '', style: _style = {}, - limit = 2 + limit = 2, + zoomState, }: D3TooltipProps) { const { mouseState, zoneRect, subscribe } = useD3MouseZone() const [tooltipBody, setTooltipBody] = useState() @@ -94,6 +96,7 @@ function _D3Tooltip({ const [position, setPosition] = useState(_position ?? 'bottom') const [visible, setVisible] = useState(false) const [fixed, setFixed] = useState(false) + const [currentZoom, setCurrentZoom] = useState(null); const tooltipRef = useRef(null) @@ -113,7 +116,7 @@ function _D3Tooltip({ }, [subscribe, visible]) useEffect(() => { - if (!tooltipRef.current || !zoneRect || fixed) return + if (!tooltipRef.current || !zoneRect || fixed || !visible) return const rect = tooltipRef.current.getBoundingClientRect() if (!mouseState.visible) return @@ -121,8 +124,9 @@ function _D3Tooltip({ const offsetX = -rect.width / 2 // По центру const offsetY = 15 // Чуть выше курсора - const left = Math.max(10, Math.min(zoneRect.width - rect.width - 10, mouseState.x + offsetX)) + const left = mouseState.x + offsetX let top = mouseState.y - offsetY - rect.height + setPosition(top <= 0 ? 'top' : 'bottom') if (top <= 0) top = mouseState.y + offsetY @@ -131,7 +135,34 @@ function _D3Tooltip({ left, top, })) - }, [tooltipRef.current, mouseState, zoneRect, fixed]) + }, [tooltipRef.current, mouseState, zoneRect, fixed, visible]) + + useEffect(() => { + if (!zoomState) return + + setCurrentZoom(zoomState) + + if (!fixed) { + setVisible(false) + return + } + + const offsetX = Number(style.left) + Number(width) + 7 + + if (zoneRect && ((offsetX <= zoneRect.left) || (offsetX > zoneRect.right)) || zoomState.k !== currentZoom?.k) { + setVisible(false) + setFixed(false) + return + } + + const distanceMoveX = currentZoom ? currentZoom.x - zoomState.x : 1 + + setStyle((prevStyle) => ({ + ...prevStyle, + left: prevStyle?.left ? +prevStyle.left - distanceMoveX : 0, + })) + }, [zoomState, fixed]) + useEffect(() => { if (fixed) return