JSFiddle - React, Tailwind, and code Playground

by Mladen Mihajlovic

HTML

<canvas id="odometer" width="200" height="60"></canvas>

JavaScript

const canvas = document.getElementById('odometer');
const ctx = canvas.getContext('2d');

// Set starting and ending numbers
let startNumber = 0;
let endNumber = 100;

// Set animation duration
const animationDuration = 10000; // 10 seconds

// Set animation start time
let animationStartTime;

// Set font style
ctx.font = 'bold 50px Arial';

// Function to update the odometer value
function updateOdometer(timestamp) {
  if (!animationStartTime) {
    animationStartTime = timestamp;
  }

  const progress = timestamp - animationStartTime;
  const percentage = Math.min(progress / animationDuration, 1);
  const currentNumber = Math.round(startNumber + percentage * (endNumber - startNumber));

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // Draw each digit
  const digitWidth = 50;
  const digitHeight = 50;
  let x = (canvas.width - digitWidth * currentNumber.toString().length) / 2;
  let y = (canvas.height - digitHeight) / 2;

  currentNumber
    .toString()
    .split('')
    .forEach((digit, i) => {
      const digitY = parseInt(digit) * digitHeight;
      ctx.drawImage(
        odometerDigits,
        i * 50,
        digitY,
        odometerDigits.width,
        digitHeight,
        x,
        y,
        digitWidth,
        digitHeight
      );

      y += digitHeight;
    });

  if (percentage < 1) {
    requestAnimationFrame(updateOdometer);
  }
}

// Load digit images
const odometerDigits = new Image();
odometerDigits.src = 'https://iili.io/HwKu1SI.png';
odometerDigits.onload = () => {
  requestAnimationFrame(updateOdometer);
};