diff --git a/package.json b/package.json index c30c744..2bde31e 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,8 @@ "singleQuote": true, "tabWidth": 2, "trailingComma": "es5", - "useTabs": false + "useTabs": false, + "semi": false }, "react-native-builder-bob": { "source": "src", diff --git a/src/AnimatedLineGraph.tsx b/src/AnimatedLineGraph.tsx index 08f2bc4..e573609 100644 --- a/src/AnimatedLineGraph.tsx +++ b/src/AnimatedLineGraph.tsx @@ -14,6 +14,7 @@ import { Group, Shadow, PathCommand, + useValueEffect, } from '@shopify/react-native-skia' import type { AnimatedLineGraphProps } from './LineGraphProps' import { createGraphPath } from './CreateGraphPath' @@ -41,6 +42,8 @@ export function AnimatedLineGraph({ TopAxisLabel, BottomAxisLabel, selectionDotShadowColor, + gestureHoldDuration = 300, + resetPositionOnRelease = true, ...props }: AnimatedLineGraphProps): React.ReactElement { const [width, setWidth] = useState(0) @@ -158,7 +161,9 @@ export function AnimatedLineGraph({ [interpolateProgress] ) - const { gesture, isActive, x } = useHoldOrPanGesture({ holdDuration: 300 }) + const { gesture, isActive, x } = useHoldOrPanGesture({ + holdDuration: gestureHoldDuration, + }) const circleX = useValue(0) const circleY = useValue(0) const pathEnd = useValue(0) @@ -168,6 +173,15 @@ export function AnimatedLineGraph({ [circleRadius] ) + useValueEffect(pathEnd, (pathEndValue) => { + const index = Math.round(pathEndValue * points.length) + const pointIndex = Math.min(Math.max(index, 0), points.length - 1) + const dataPoint = points[Math.round(pointIndex)] + if (dataPoint != null && onPointSelected) { + runOnJS(onPointSelected)(dataPoint) + } + }) + const setFingerX = useCallback( (fingerX: number) => { const y = getYForX(commands.current, fingerX) @@ -177,13 +191,8 @@ export function AnimatedLineGraph({ circleX.current = fingerX } pathEnd.current = fingerX / width - - const index = Math.round((fingerX / width) * points.length) - const pointIndex = Math.min(Math.max(index, 0), points.length - 1) - const dataPoint = points[Math.round(pointIndex)] - if (dataPoint != null) onPointSelected?.(dataPoint) }, - [circleX, circleY, onPointSelected, pathEnd, points, width] + [circleX, circleY, pathEnd, width] ) const setIsActive = useCallback( (active: boolean) => { @@ -193,17 +202,25 @@ export function AnimatedLineGraph({ damping: 50, velocity: 0, }) - if (!active) pathEnd.current = 1 + if (!active && resetPositionOnRelease) pathEnd.current = 1 if (active) onGestureStart?.() else onGestureEnd?.() }, - [circleRadius, onGestureEnd, onGestureStart, pathEnd] + [ + circleRadius, + onGestureEnd, + onGestureStart, + pathEnd, + resetPositionOnRelease, + ] ) useAnimatedReaction( - () => x.value, - (fingerX) => { - runOnJS(setFingerX)(fingerX) + () => [x.value, isActive.value], + ([fingerX, isActiveValue]) => { + if (isActiveValue) { + runOnJS(setFingerX)(fingerX as number) + } }, [isActive, setFingerX, width, x] ) @@ -220,11 +237,18 @@ export function AnimatedLineGraph({ Math.min(0.15, pathEnd.current), pathEnd.current, pathEnd.current, + pathEnd.current, 1, ], [pathEnd] ) + useEffect(() => { + if (width != null) { + setFingerX(width) + } + }, [width, setFingerX]) + return ( diff --git a/src/LineGraphProps.ts b/src/LineGraphProps.ts index bdfe411..9a3a898 100644 --- a/src/LineGraphProps.ts +++ b/src/LineGraphProps.ts @@ -62,6 +62,16 @@ export type AnimatedLineGraphProps = BaseLineGraphProps & { * The element that gets rendered below the Graph (usually the "min" point/value of the Graph) */ BottomAxisLabel?: () => React.ReactElement | null + + /** + * Hold duration for the graph gesture + */ + gestureHoldDuration?: number + + /** + * Wether to reset or not the circle position when releasing the gesture + */ + resetPositionOnRelease?: boolean } export type LineGraphProps =