I am updating a numeric value
inside an element
by doing intervalled ajax requests
.
To make the whole thing a bit more alive,
I had a slightly different approach to this kind of animation. Based on these assumptions:
So, if you want to animate a simple text like "+300% gross margin", only the numeric part will be animated.
Moreover, all params have now a default value for start
, end
and duration
.
https://codepen.io/lucamurante/pen/gZVymW
function animateValue(obj, start = 0, end = null, duration = 3000) {
if (obj) {
// save starting text for later (and as a fallback text if JS not running and/or google)
var textStarting = obj.innerHTML;
// remove non-numeric from starting text if not specified
end = end || parseInt(textStarting.replace(/\D/g, ""));
var range = end - start;
// no timer shorter than 50ms (not really visible any way)
var minTimer = 50;
// calc step time to show all interediate values
var stepTime = Math.abs(Math.floor(duration / range));
// never go below minTimer
stepTime = Math.max(stepTime, minTimer);
// get current time and calculate desired end time
var startTime = new Date().getTime();
var endTime = startTime + duration;
var timer;
function run() {
var now = new Date().getTime();
var remaining = Math.max((endTime - now) / duration, 0);
var value = Math.round(end - (remaining * range));
// replace numeric digits only in the original string
obj.innerHTML = textStarting.replace(/([0-9]+)/g, value);
if (value == end) {
clearInterval(timer);
}
}
timer = setInterval(run, stepTime);
run();
}
}
animateValue(document.getElementById('value'));
#value {
font-size: 50px;
}
<div id="value">+300% gross margin</div>
This is what i came up with:
function animateVal(obj, start=0, end=100, steps=100, duration=500) {
start = parseFloat(start)
end = parseFloat(end)
let stepsize = (end - start) / steps
let current = start
var stepTime = Math.abs(Math.floor(duration / (end - start)));
let stepspassed = 0
let stepsneeded = (end - start) / stepsize
let x = setInterval( () => {
current += stepsize
stepspassed++
obj.innerHTML = Math.round(current * 1000) / 1000
if (stepspassed >= stepsneeded) {
clearInterval(x)
}
}, stepTime)
}
animateVal(document.getElementById("counter"), 0, 200, 300, 200)