Commit 2a0d4554 authored by Connor McEwen's avatar Connor McEwen Committed by GitHub

fix: animation on mount wasn't happening (#4839)

parent 9e959ca4
...@@ -8,6 +8,8 @@ import { useTheme } from 'styled-components/macro' ...@@ -8,6 +8,8 @@ import { useTheme } from 'styled-components/macro'
import { LineChartProps } from './LineChart' import { LineChartProps } from './LineChart'
type AnimatedInLineChartProps<T> = Omit<LineChartProps<T>, 'height' | 'width' | 'children'>
const config = { const config = {
duration: 800, duration: 800,
easing: easeCubicInOut, easing: easeCubicInOut,
...@@ -23,10 +25,7 @@ function AnimatedInLineChart<T>({ ...@@ -23,10 +25,7 @@ function AnimatedInLineChart<T>({
curve, curve,
color, color,
strokeWidth, strokeWidth,
width, }: AnimatedInLineChartProps<T>) {
height,
children,
}: LineChartProps<T>) {
const lineRef = useRef<SVGPathElement>(null) const lineRef = useRef<SVGPathElement>(null)
const [lineLength, setLineLength] = useState(0) const [lineLength, setLineLength] = useState(0)
const [shouldAnimate, setShouldAnimate] = useState(false) const [shouldAnimate, setShouldAnimate] = useState(false)
...@@ -41,49 +40,54 @@ function AnimatedInLineChart<T>({ ...@@ -41,49 +40,54 @@ function AnimatedInLineChart<T>({
}, },
}) })
const effectDependency = lineRef.current // We need to check to see after the "invisble" line has been drawn
// what the length is to be able to animate in the line for the first time
// This will run on each render to see if there is a new line length
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => { useEffect(() => {
if (lineRef.current) { if (lineRef.current) {
setLineLength(lineRef.current.getTotalLength()) const length = lineRef.current.getTotalLength()
setShouldAnimate(true) if (length !== lineLength) {
setLineLength(length)
}
if (length > 0 && !shouldAnimate && !hasAnimatedIn) {
setShouldAnimate(true)
}
} }
}, [effectDependency]) })
const theme = useTheme() const theme = useTheme()
const lineColor = color ?? theme.accentAction const lineColor = color ?? theme.accentAction
return ( return (
<svg width={width} height={height}> <Group top={marginTop}>
<Group top={marginTop}> <LinePath curve={curve} x={getX} y={getY}>
<LinePath curve={curve} x={getX} y={getY}> {({ path }) => {
{({ path }) => { const d = path(data) || ''
const d = path(data) || '' return (
return ( <>
<> <animated.path
d={d}
ref={lineRef}
strokeWidth={strokeWidth}
strokeOpacity={hasAnimatedIn ? 1 : 0}
fill="none"
stroke={lineColor}
/>
{shouldAnimate && lineLength !== 0 && (
<animated.path <animated.path
d={d} d={d}
ref={lineRef}
strokeWidth={strokeWidth} strokeWidth={strokeWidth}
strokeOpacity={hasAnimatedIn ? 1 : 0}
fill="none" fill="none"
stroke={lineColor} stroke={lineColor}
strokeDashoffset={spring.frame.to((v) => v * lineLength)}
strokeDasharray={lineLength}
/> />
{shouldAnimate && lineLength !== 0 && ( )}
<animated.path </>
d={d} )
strokeWidth={strokeWidth} }}
fill="none" </LinePath>
stroke={lineColor} </Group>
strokeDashoffset={spring.frame.to((v) => v * lineLength)}
strokeDasharray={lineLength}
/>
)}
</>
)
}}
</LinePath>
</Group>
{children}
</svg>
) )
} }
......
...@@ -263,6 +263,10 @@ export function PriceChart({ width, height, prices }: PriceChartProps) { ...@@ -263,6 +263,10 @@ export function PriceChart({ width, height, prices }: PriceChartProps) {
* making it unacceptable for shorter durations / smaller variances. * making it unacceptable for shorter durations / smaller variances.
*/ */
const curveTension = timePeriod === TimePeriod.HOUR ? 1 : 0.9 const curveTension = timePeriod === TimePeriod.HOUR ? 1 : 0.9
const getX = useMemo(() => (p: PricePoint) => timeScale(p.timestamp), [timeScale])
const getY = useMemo(() => (p: PricePoint) => rdScale(p.value), [rdScale])
const curve = useMemo(() => curveCardinal.tension(curveTension), [curveTension])
return ( return (
<> <>
<ChartHeader> <ChartHeader>
...@@ -279,16 +283,15 @@ export function PriceChart({ width, height, prices }: PriceChartProps) { ...@@ -279,16 +283,15 @@ export function PriceChart({ width, height, prices }: PriceChartProps) {
message={prices && prices.length === 0 ? <NoV3DataMessage /> : <MissingDataMessage />} message={prices && prices.length === 0 ? <NoV3DataMessage /> : <MissingDataMessage />}
/> />
) : ( ) : (
<AnimatedInLineChart <svg width={width} height={graphHeight}>
data={prices} <AnimatedInLineChart
getX={(p: PricePoint) => timeScale(p.timestamp)} data={prices}
getY={(p: PricePoint) => rdScale(p.value)} getX={getX}
marginTop={margin.top} getY={getY}
curve={curveCardinal.tension(curveTension)} marginTop={margin.top}
strokeWidth={2} curve={curve}
width={width} strokeWidth={2}
height={graphHeight} />
>
{crosshair !== null ? ( {crosshair !== null ? (
<g> <g>
<AxisBottom <AxisBottom
...@@ -348,7 +351,7 @@ export function PriceChart({ width, height, prices }: PriceChartProps) { ...@@ -348,7 +351,7 @@ export function PriceChart({ width, height, prices }: PriceChartProps) {
onMouseMove={handleHover} onMouseMove={handleHover}
onMouseLeave={resetDisplay} onMouseLeave={resetDisplay}
/> />
</AnimatedInLineChart> </svg>
)} )}
<TimeOptionsWrapper> <TimeOptionsWrapper>
<TimeOptionsContainer> <TimeOptionsContainer>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment