mirror of
https://github.com/nagaoo0/HabbitGrid.git
synced 2026-01-11 23:44:55 +00:00
Add juice to the counter animations
This commit is contained in:
@@ -7,14 +7,19 @@ import React, { useEffect, useRef, useState } from 'react';
|
|||||||
*/
|
*/
|
||||||
function AnimatedCounter({ value, duration = 1000, start = 0, format = v => v }) {
|
function AnimatedCounter({ value, duration = 1000, start = 0, format = v => v }) {
|
||||||
const [displayValue, setDisplayValue] = useState(start);
|
const [displayValue, setDisplayValue] = useState(start);
|
||||||
|
const [animating, setAnimating] = useState(false);
|
||||||
|
const [direction, setDirection] = useState('up');
|
||||||
const rafRef = useRef();
|
const rafRef = useRef();
|
||||||
const startRef = useRef(start);
|
const startRef = useRef(start);
|
||||||
const valueRef = useRef(value);
|
const valueRef = useRef(value);
|
||||||
|
const prevValueRef = useRef(start);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
startRef.current = displayValue;
|
startRef.current = displayValue;
|
||||||
valueRef.current = value;
|
valueRef.current = value;
|
||||||
let startTime;
|
let startTime;
|
||||||
|
setAnimating(true);
|
||||||
|
setDirection(value > prevValueRef.current ? 'up' : value < prevValueRef.current ? 'down' : direction);
|
||||||
function animate(ts) {
|
function animate(ts) {
|
||||||
if (!startTime) startTime = ts;
|
if (!startTime) startTime = ts;
|
||||||
const progress = Math.min((ts - startTime) / duration, 1);
|
const progress = Math.min((ts - startTime) / duration, 1);
|
||||||
@@ -22,13 +27,28 @@ function AnimatedCounter({ value, duration = 1000, start = 0, format = v => v })
|
|||||||
setDisplayValue(current);
|
setDisplayValue(current);
|
||||||
if (progress < 1) {
|
if (progress < 1) {
|
||||||
rafRef.current = requestAnimationFrame(animate);
|
rafRef.current = requestAnimationFrame(animate);
|
||||||
|
} else {
|
||||||
|
setAnimating(false);
|
||||||
|
prevValueRef.current = current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rafRef.current = requestAnimationFrame(animate);
|
rafRef.current = requestAnimationFrame(animate);
|
||||||
return () => cancelAnimationFrame(rafRef.current);
|
return () => cancelAnimationFrame(rafRef.current);
|
||||||
}, [value, duration]);
|
}, [value, duration]);
|
||||||
|
|
||||||
return <span>{format(displayValue)}</span>;
|
// Animation styles
|
||||||
|
const styles = {
|
||||||
|
display: 'inline-block',
|
||||||
|
transition: 'transform 0.4s cubic-bezier(.68,-0.55,.27,1.55), color 0.4s',
|
||||||
|
transform: animating ? 'scale(1.25) rotate(-5deg)' : 'scale(1)',
|
||||||
|
color: animating ? (direction === 'up' ? '#22c55e' : direction === 'down' ? '#ef4444' : undefined) : undefined,
|
||||||
|
fontWeight: animating ? 700 : undefined,
|
||||||
|
filter: animating ? (direction === 'up' ? 'drop-shadow(0 0 8px #22c55e88)' : direction === 'down' ? 'drop-shadow(0 0 8px #ef444488)' : undefined) : undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span style={styles}>{format(displayValue)}</span>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AnimatedCounter;
|
export default AnimatedCounter;
|
||||||
|
|||||||
Reference in New Issue
Block a user