JSFiddle - React, Tailwind, and code Playground
HTML
<div id="container">
<div class="strip">
<div class="digit">
<div> </div><div>0</div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div>
</div>
</div>
<div class="strip">
<div class="digit">
<div> </div><div>0</div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div>
</div>
</div>
<div class="strip">
<div class="digit">
<div> </div><div>0</div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div>
</div>
</div>
<div class="strip">
<div class="grouping">
<div> </div><div>,</div>
</div>
</div>
<div class="strip">
<div class="digit">
<div> </div><div>0</div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div>
</div>
</div>
<div class="strip">
<div class="digit">
<div> </div><div>0</div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div>
</div>
</div>
<div class="strip">
<div class="digit">
<div> </div><div>0</div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div>
</div>
</div>
<div class="strip">
<div class="decimal">
<div> </div><div>.</div>
</div>
</div>
<div class="strip">
<div class="digit">
<div> </div><div>0</div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div>
</div>
</div>
<div class="strip">
<div class="digit">
...
CSS
#container {
font-family: Arial, sans-serif;
font-size: 36px;
display: flex;
width: fit-content;
padding: 10px;
}
.strip {
height: 1.1em;
overflow: hidden;
}
.digit > div {
display: block;
}
JavaScript
/*
https://github.com/northcoder-repo/ticker-demo
https://developer.mozilla.org/en-US/docs/Web/API/Element/animate
https://developer.mozilla.org/en-US/docs/Web/API/KeyframeEffect/KeyframeEffect#parameters
https://developer.mozilla.org/en-US/docs/Web/API/Animation/finished
*/
// run the spinner asynchronously,
// with one job per number strip:
function spin(number) {
for (let i = 0; i < strips.length; i++) {
spinArray.push(spinner);
spinParams.push({
number: number,
strip: strips[i],
idx: i,
});
}
const spinTasks = spinArray.map((func, index) => {
return func(spinParams[index]);
});
(async () => {
try {
// fire off all the promises and wait for them to complete:
const results = await Promise.all(spinTasks);
console.log('All tasks completed. Results:', results.join(''));
} catch (error) {
console.error('One of the tasks failed:', error);
} finally {
cleanUp();
}
})();
}
//
// animation logic which transitions from the currently
// displayed number to a new number, with color changes
// and a spinning dial effect for each digit:
//
const spinner = async (data) => {
const color = chooseColor(data.number, prevNumber);
const numberStr = formatNumberAsString(data.number);
const stripShift = calculateStripShift(numberStr[data.idx]);
const transform = 'translateY(' + stripShift + 'px)';
const keyframes = [
// aiming for an effect where the color changes
// promptly, but does not reset to black until
// after the new number has been displayed:
{ offset: 0.1, color: color },
{ offset: 0.4, transform: transform },
{ offset: 0.8, color: color },
{ offset: 1.0, color: 'black', transform: transform },
];
const options = { duration: 5000, fill: 'both' };
data.strip.animate(keyframes, options);
return numberStr[data.idx];
};
// determine how many pixels to shift
//...