UNPKG

react-native-chart-kit

Version:

Beautiful React Native charts for dashboards, reports, and data-rich mobile apps.

85 lines (84 loc) 3.31 kB
import { useEffect, useRef, useState } from "react"; import { interpolateLineChartTooltipPosition } from "./tooltip"; const tooltipPositionThreshold = 0.5; export const useAnimatedTooltipModel = (tooltip) => { const latestPositionRef = useRef(undefined); const previousTooltipRef = useRef(undefined); const [animatedPosition, setAnimatedPosition] = useState(undefined); useEffect(() => { let animationFrame = 0; if (!tooltip) { latestPositionRef.current = undefined; previousTooltipRef.current = undefined; animationFrame = requestAnimationFrame(() => { setAnimatedPosition(undefined); }); return () => { cancelAnimationFrame(animationFrame); }; } const targetPosition = { x: tooltip.x, y: tooltip.y }; const currentPosition = latestPositionRef.current ?? targetPosition; const hasPreviousTooltip = previousTooltipRef.current !== undefined; const positionAnimationDuration = tooltip.config.positionAnimationDuration; previousTooltipRef.current = tooltip; if (!hasPreviousTooltip) { latestPositionRef.current = targetPosition; animationFrame = requestAnimationFrame(() => { setAnimatedPosition(targetPosition); }); return () => { cancelAnimationFrame(animationFrame); }; } if (positionAnimationDuration <= 0) { latestPositionRef.current = targetPosition; animationFrame = requestAnimationFrame(() => { setAnimatedPosition(targetPosition); }); return () => { cancelAnimationFrame(animationFrame); }; } const deltaX = Math.abs(currentPosition.x - targetPosition.x); const deltaY = Math.abs(currentPosition.y - targetPosition.y); if (deltaX < tooltipPositionThreshold && deltaY < tooltipPositionThreshold) { latestPositionRef.current = targetPosition; animationFrame = requestAnimationFrame(() => { setAnimatedPosition(targetPosition); }); return () => { cancelAnimationFrame(animationFrame); }; } let startTime; const tick = (timestamp) => { startTime ?? (startTime = timestamp); const progress = Math.min((timestamp - startTime) / positionAnimationDuration, 1); const nextPosition = interpolateLineChartTooltipPosition({ from: currentPosition, progress, to: targetPosition }); latestPositionRef.current = nextPosition; setAnimatedPosition(nextPosition); if (progress < 1) { animationFrame = requestAnimationFrame(tick); } }; animationFrame = requestAnimationFrame(tick); return () => { cancelAnimationFrame(animationFrame); }; }, [tooltip]); if (!tooltip) { return undefined; } const position = animatedPosition ?? { x: tooltip.x, y: tooltip.y }; return { ...tooltip, x: position.x, y: position.y }; };