So I have many of the sites for the solution everyone is some package but i dont need any of the package its should be only using pure js in Reactjs <div className="odometer-value">100</div>
There are bunch of libraries which provides it by default with cool visual representation, But as you said you are looking for plain implementation so I just wrote something in couple of minutes.
Assuming you are not looking for fancy animations and just a counter counting up/down on value change is fine, below code should work for you.
import { useEffect, useState } from "react";
import "./SpeedoMeter.css";
export default function SpeedoMeter({ value }) {
// Current shown value
const [currentValue, setCurrentValue] = useState(0);
// Target Value to reach
const [targetValue, setTargetValue] = useState(0);
// Number of step to reach
const steps = 10;
// Latency between each step, if this is 0 then the count up/down is very instant and wont work
const lag = 1;
// Updating target value
useEffect(() => {
setTargetValue(value);
}, [value]);
// Updating Current value to follow target value, a feedback loop if made so that useEffect depencency can be leveraged.
// Note: This is not super accurate in timing/animations
useEffect(() => {
if (currentValue !== targetValue) {
setTimeout(() => {
setCurrentValue((prevCurr) => {
let distance = Math.abs(targetValue - currentValue);
let stepSize = Math.ceil(distance / steps);
return currentValue < targetValue
? currentValue + stepSize
: currentValue - stepSize;
});
}, lag);
}
}, [currentValue, targetValue]);
return (
<div className="speedo-wrap">
{(currentValue + "").split("").map((val, idx) => (
<div className="speedo-digit" style={{ marginTop: `-${val}em` }}>
<div data-val="0">0</div>
<div data-val="1">1</div>
<div data-val="2">2</div>
<div data-val="3">3</div>
<div data-val="4">4</div>
<div data-val="5">5</div>
<div data-val="6">6</div>
<div data-val="7">7</div>
<div data-val="8">8</div>
<div data-val="9">9</div>
</div>
))}
</div>
);
}
CSS
.speedo-wrap {
display: flex;
justify-content: center;
height: 1rem;
font-size: 1rem;
line-height: 1rem;
overflow: hidden;
}
.speedo-digit {
transition: 1s all;
}
USAGE
<SpeedoMeter value={10000} />
Adding CodeSandbox for same: https://codesandbox.io/s/basic-react-speedometer-gsv5yc?file=/src/SpeedoMeter.js
Additionally, animations can be easily controlled with cubic-bezier, visual representation of digits can also be changes with minimal side-effect, speed/steps can be controlled.
EDIT: Created a library with same
Github NPM
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With