On a site I have a number counter that always increases, without any fancy animation. Now I need to animate it every time the number updates, like this:
Which HTML (+CSS +JS if needed) code can I use for this? Thanks!
P.S.: The number has 2 decimals and uses "," as a decimal separator.
According to the illustration, this already unmaintained library came to mind:
const el = document.querySelector('.odometer')
const od = new Odometer({
el: el,
value: 1234, // default value
// Any option (other than auto and selector) can be passed in here
format: '( ddd),dd',
theme: 'default',
})
// change to new value
od.update(9876)
// or
el.innerHTML = 9876
<link rel="stylesheet" href="http://github.hubspot.com/odometer/themes/odometer-theme-default.css" />
<script src="http://github.hubspot.com/odometer/odometer.js"></script>
<div class="odometer"></div>
const values = [4753, 8170]
const el = document.querySelector('.odometer')
const od = new Odometer({
el: el,
value: values[0], // default value
// Any option (other than auto and selector) can be passed in here
format: '( ddd),dd',
theme: 'default',
})
let index = 1
function infiniteUpdate() {
od.update(values[index])
index = (index + 1) % values.length
setTimeout(infiniteUpdate, 6000)
}
infiniteUpdate()
@import url('https://fonts.googleapis.com/css2?family=Lexend&display=swap');
body {
background-color: #6c48ff;
}
.circle {
margin: 0 auto;
height: 150px;
width: 150px;
border-radius: 50%;
background-color: #242400;
border: 10px solid #fc6caa;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
color: #fff;
font-size: 37px;
}
/* change font-family */
.circle,
.odometer-value {
font-family: 'Lexend', sans-serif;
}
/* change default duration from 3s to 5s */
/* https://github.com/HubSpot/odometer/issues/91 */
.odometer.odometer-animating-up .odometer-ribbon-inner, .odometer.odometer-animating-down.odometer-animating .odometer-ribbon-inner {
-webkit-transition-duration: 5s !important;
-moz-transition-duration: 5s !important;
-ms-transition-duration: 5s !important;
-o-transition-duration: 5s !important;
transition-duration: 5s !important;
}
/* add shadow */
.odometer::before, .odometer::after {
content: '';
position: absolute;
z-index: 10;
left: 0;
width: 100%;
height: 9px;
}
.odometer::before {
top: 0;
background: linear-gradient(to bottom, rgba(36, 36, 0, 1), rgba(36, 36, 0, 0));
}
.odometer::after {
bottom: 0;
background: linear-gradient(to top, rgba(36, 36, 0, 1), rgba(36, 36, 0, 0));
}
<link rel="stylesheet" href="http://github.hubspot.com/odometer/themes/odometer-theme-default.css" />
<script src="http://github.hubspot.com/odometer/odometer.js"></script>
<div class="circle">
<div>$</div>
<div class="odometer"></div>
</div>
A quick idea for the decimal value: You can insert two odometers. The first one counts the whole number, the second one counts the fractional part. This way, you can handle them separately from each other.
const values = [100.2, 109.2]
const elNumber = document.querySelector('.odometer-number')
const odNumber = new Odometer({
el: elNumber,
value: parseInt(values[0].toString().split('.')[0]), // default value
// Any option (other than auto and selector) can be passed in here
format: '( ddd)',
theme: 'default',
})
const elFract = document.querySelector('.odometer-fractional')
const odFract = new Odometer({
el: elFract,
value: parseInt(values[0].toString().split('.')[1]), // default value
// Any option (other than auto and selector) can be passed in here
format: 'd',
theme: 'default',
})
let index = 1
function infiniteUpdate() {
const value = values[index]
const newNumber = parseInt(value.toString().split('.')[0])
const newFract = parseInt(value.toString().split('.')[1])
odNumber.update(newNumber)
odFract.update(newFract)
index = (index + 1) % values.length
setTimeout(infiniteUpdate, 6000)
}
infiniteUpdate()
@import url('https://fonts.googleapis.com/css2?family=Lexend&display=swap');
body {
background-color: #6c48ff;
}
.circle {
margin: 0 auto;
height: 150px;
width: 150px;
border-radius: 50%;
background-color: #242400;
border: 10px solid #fc6caa;
display: flex;
align-items: center;
justify-content: center;
gap: 2px;
color: #fff;
font-size: 37px;
}
/* change font-family */
.circle,
.odometer-value {
font-family: 'Lexend', sans-serif;
}
/* change default duration from 3s to 5s */
/* https://github.com/HubSpot/odometer/issues/91 */
.odometer.odometer-animating-up .odometer-ribbon-inner, .odometer.odometer-animating-down.odometer-animating .odometer-ribbon-inner {
-webkit-transition-duration: 5s !important;
-moz-transition-duration: 5s !important;
-ms-transition-duration: 5s !important;
-o-transition-duration: 5s !important;
transition-duration: 5s !important;
}
/* add shadow */
.odometer::before, .odometer::after {
content: '';
position: absolute;
z-index: 10;
left: 0;
width: 100%;
height: 9px;
}
.odometer::before {
top: 0;
background: linear-gradient(to bottom, rgba(36, 36, 0, 1), rgba(36, 36, 0, 0));
}
.odometer::after {
bottom: 0;
background: linear-gradient(to top, rgba(36, 36, 0, 1), rgba(36, 36, 0, 0));
}
<link rel="stylesheet" href="http://github.hubspot.com/odometer/themes/odometer-theme-default.css" />
<script src="http://github.hubspot.com/odometer/odometer.js"></script>
<div class="circle">
<div>$</div>
<div class="odometer odometer-number"></div>
<div>,</div>
<div class="odometer odometer-fractional"></div>
</div>