<div class="container">
<input id="slider" class="slider" type="range" min="0" max="20000" step="5000" list="values" value="20000">
<datalist id="values">
<option value="0" label="0"></option>
<option value="5000" label="5000"></option>
<option value="10000" label="10000"></option>
<option value="15000" label="15000"></option>
<option value="20000" label="20000"></option>
</datalist>
<div class="number" id="number">
<div class="left" id="left"></div>
<div class="separator" id="separator">,</div>
<div class="right" id="right">0</div>
</div>
</div>
<svg class="svgFilter" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="blurFilter">
<feGaussianBlur id="blurFilterItem" in="SourceGraphic" stdDeviation="13,0" />
</filter>
</defs>
</svg>
.number {
display: flex;
align-items: center;
font-size: 6rem;
justify-content: flex-end;
.animate {
filter: url("#blurFilter");
}
.left,
.right {
min-width: 11rem;
text-align: right;
}
.right {
padding-right: 1rem;
}
.separator {
opacity: 0;
transition: opacity 0.1s ease;
&.show {
opacity: 1;
}
}
}
.svgFilter {
display: block;
width: 0;
height: 0;
}
.slider {
accent-color: black;
background: red;
min-width: min(20rem, 60vw);
}
.container {
display: flex;
flex-direction: column;
gap: 2rem;
}
body {
display: grid;
place-items: center;
height: 100vh;
width: 100vw;
background: #ffc107;
font-style: italic;
padding: 1;
font-weight: bold;
}
:root {
--labs-sys-color-on-background: black;
}
* {
box-sizing: border-box;
}
const number = document.getElementById("number");
const left = document.getElementById("left");
const rights = document.getElementById("right");
const slider = document.getElementById("slider");
let target = 20000;
let current = 0;
const step = 42;
const start = () => {
right.classList.add("animate");
update();
};
slider.addEventListener("input", (event) => {
target = +event.target.value;
start();
});
const updateValues = () => {
const [first, ...rest] = current.toLocaleString("en-US").split(",").reverse();
thousends = rest.reverse();
const thousendsString = thousends.join("");
if (+left.innerText != thousendsString) {
left.classList.add("animate");
} else {
left.classList.remove("animate");
}
left.innerText = thousendsString;
right.innerText = first;
};
const update = () => {
if (target - current > 0) {
current += step;
} else {
current -= step;
}
if (current >= 1000) {
separator.classList.add("show");
} else {
separator.classList.remove("show");
}
updateValues();
if (Math.abs(target - current) > step) {
requestAnimationFrame(update);
} else {
requestAnimationFrame(() => {
current = target;
updateValues();
left.classList.remove("animate");
right.classList.remove("animate");
});
}
};
requestAnimationFrame(start);