Effect where numbers count as the element appears [duplicate] - javascript
I am updating a numeric value inside an element by doing intervalled ajax requests.
To make the whole thing a bit more alive, I want to count from the current value to the new one, by partially in- or decreasing the value over a time of n sec.
So basically something like this:
<div id="value">100</div>
<script type="text/javascript">
/** Decrease $value (over a time of 2 seconds) till it reaches 25 */
$value.increaseAnimation(-75, {duration:2});
</script>
Is there a javascript library for doing so?
You can just code it yourself pretty simply:
function animateValue(id, start, end, duration) {
if (start === end) return;
var range = end - start;
var current = start;
var increment = end > start? 1 : -1;
var stepTime = Math.abs(Math.floor(duration / range));
var obj = document.getElementById(id);
var timer = setInterval(function() {
current += increment;
obj.innerHTML = current;
if (current == end) {
clearInterval(timer);
}
}, stepTime);
}
animateValue("value", 100, 25, 5000);
#value {
font-size: 50px;
}
<div id="value">100</div>
Here's is a more accurate version that self adjusts in case the timer intervals aren't perfectly accurate (which they sometimes aren't):
function animateValue(id, start, end, duration) {
// assumes integer values for start and end
var obj = document.getElementById(id);
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));
obj.innerHTML = value;
if (value == end) {
clearInterval(timer);
}
}
timer = setInterval(run, stepTime);
run();
}
animateValue("value", 100, 25, 5000);
#value {
font-size: 50px;
}
<div id="value">100</div>
Current solutions do update more often than needed. Here a frame based approach, which is accurate:
function animateValue(obj, start, end, duration) {
let startTimestamp = null;
const step = (timestamp) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
obj.innerHTML = Math.floor(progress * (end - start) + start);
if (progress < 1) {
window.requestAnimationFrame(step);
}
};
window.requestAnimationFrame(step);
}
const obj = document.getElementById('value');
animateValue(obj, 100, -25, 2000);
div {font-size: 50px;}
<div id="value">100</div>
I had a slightly different approach to this kind of animation. Based on these assumptions:
there is a starting text (as fallback for non-JS browser or google
indexing)
this text can contains non-numeric chars
the function take an element directly as first param (as opposed to an
element Id)
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>
Now we can animate counters (and a lot of things that cannot be animated before) with CSS variables and new #property. No javascript needed. Currently supports only Chrome and Edge.
#property --n {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
body {
display: flex;
}
.number {
animation: animate var(--duration) forwards var(--timing, linear);
counter-reset: num var(--n);
font-weight: bold;
font-size: 3rem;
font-family: sans-serif;
padding: 2rem;
}
.number::before {
content: counter(num);
}
#keyframes animate {
from {
--n: var(--from);
}
to {
--n: var(--to);
}
}
<div class="number" style="--from: 0; --to: 100; --duration: 2s;"></div>
<div class="number" style="--from: 10; --to: 75; --duration: 5s; --timing: ease-in-out"></div>
<div class="number" style="--from: 100; --to: 0; --duration: 5s; --timing: ease"></div>
const counters = document.querySelectorAll('.counters');
counters.forEach(counter => {
let count = 0;
const updateCounter = () => {
const countTarget = parseInt(counter.getAttribute('data-counttarget'));
count++;
if (count < countTarget) {
counter.innerHTML = count;
setTimeout(updateCounter, 1);
} else {
counter.innerHTML = countTarget;
}
};
updateCounter();
});
<p class="counters" data-counttarget="50"></p>
<p class="counters" data-counttarget="100"></p>
<p class="counters" data-counttarget="500"></p>
<p class="counters" data-counttarget="1000"></p>
This works well. However, I needed to use a comma within the number. Below is the updated code which checks for commas. Hope someone finds this useful if they stumble across this post.
function animateValue(id, start, end, duration) {
// check for commas
var isComma = /[0-9]+,[0-9]+/.test(end);
end = end.replace(/,/g, '');
// assumes integer values for start and end
var obj = document.getElementById(id);
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));
obj.innerHTML = value;
if (value == end) {
clearInterval(timer);
}
// Preserve commas if input had commas
if (isComma) {
while (/(\d+)(\d{3})/.test(value.toString())) {
value = value.toString().replace(/(\d+)(\d{3})/, '$1'+','+'$2');
}
}
}
var timer = setInterval(run, stepTime);
run();
}
animateValue("value", 100, 25, 2000);
HTML
<!DOCTYPE html>
<html>
<head>
<title>Count</title>
</head>
<body>
<div id="value">1000</div>
</body>
</html>
JAVASCRIPT snippet
Here is a simple js function decrementing values from a given start number to an end number (object prototype)..
function getCounter(startCount,endcount,time,html){
objects = {
//you can alternateif you want yo add till you reach the endcount
startCount:startCount,
endCount:endcount,
timer:time
}
this.function = function(){
let startTm = objects.startCount,
timer = objects.timer,
endCount = objects.endCount;
//if you want it to add a number just replace the -1 with +1
/*and dont forget to change the values in the object prototype given a variable of counter*/
let increament = startTm < endCount ? 1:-1;
timmer = setInterval(function(){
startTm += increament;
html.innerHTML = startTm ;
if(startTm == endCount){
clearInterval(timmer);
}
},timer);
}
}
// input your startCount,endCount the timer.....
let doc = document.getElementById('value');
let counter = new getCounter(1000,1,10,doc);
//calling the function in the object
counter.function();
Check out this demo https://jsfiddle.net/NevilPaul2/LLk0bzvm/
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)
Here is one version where increments grow by some defined multiplier (mul).
frameDelay is the time delay for each increment. This looks a bit better if you have values that camn
function cAnimate(id, start, end, frameDelay = 100, mul = 1.2) {
var obj = document.getElementById(id);
var increment = 2;
var current = start;
var timer = setInterval(function() {
current += increment;
increment *= mul;
if (current >= end) {
current = end;
clearInterval(timer);
}
obj.innerHTML = Math.floor(current).toLocaleString();
}, frameDelay);
}
cAnimate("counter", 1, 260000, 50);
I used a mixture of all of these to create a function that updates a BehaviorSubject.
function animateValue(subject, timerRef, startValue, endValue, duration){
if (timerRef) { clearInterval(timerRef); }
const minInterval = 100;
const valueRange = endValue - startValue;
const startTime = new Date().getTime();
const endTime = startTime + (duration * 1000);
const interval = Math.max((endTime-startTime)/valueRange, minInterval);
function run() {
const now = new Date().getTime();
const rangePercent = Math.min(1-((endTime-now)/(endTime-startTime)),1);
const value = Math.round(rangePercent * valueRange+startValue);
subject.next(value);
if (rangePercent >= 1) {
clearInterval(timerRef);
}
}
timerRef = setInterval(run, interval);
run();
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
</style>
</head>
<body style="width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center;">
<h1 style="font-size: 50px;" data-value="3212">0</h1>
<script>
let e = document.querySelector('h1');
let v = Number(e.dataset.value);
let i = Math.floor(v/10);
let r = v%10;
function increment() {
let c = Number(e.innerText);
if (c<v) {
if (v-c===i+r) {
e.innerText = c+i+r;
}
else{
e.innerText = c+i;
};
setTimeout(increment,200);
};
};
setTimeout(increment, 200);
</script>
</body>
</html>
Related
Count Animation with css/js? [duplicate]
I am updating a numeric value inside an element by doing intervalled ajax requests. To make the whole thing a bit more alive, I want to count from the current value to the new one, by partially in- or decreasing the value over a time of n sec. So basically something like this: <div id="value">100</div> <script type="text/javascript"> /** Decrease $value (over a time of 2 seconds) till it reaches 25 */ $value.increaseAnimation(-75, {duration:2}); </script> Is there a javascript library for doing so?
You can just code it yourself pretty simply: function animateValue(id, start, end, duration) { if (start === end) return; var range = end - start; var current = start; var increment = end > start? 1 : -1; var stepTime = Math.abs(Math.floor(duration / range)); var obj = document.getElementById(id); var timer = setInterval(function() { current += increment; obj.innerHTML = current; if (current == end) { clearInterval(timer); } }, stepTime); } animateValue("value", 100, 25, 5000); #value { font-size: 50px; } <div id="value">100</div> Here's is a more accurate version that self adjusts in case the timer intervals aren't perfectly accurate (which they sometimes aren't): function animateValue(id, start, end, duration) { // assumes integer values for start and end var obj = document.getElementById(id); 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)); obj.innerHTML = value; if (value == end) { clearInterval(timer); } } timer = setInterval(run, stepTime); run(); } animateValue("value", 100, 25, 5000); #value { font-size: 50px; } <div id="value">100</div>
Current solutions do update more often than needed. Here a frame based approach, which is accurate: function animateValue(obj, start, end, duration) { let startTimestamp = null; const step = (timestamp) => { if (!startTimestamp) startTimestamp = timestamp; const progress = Math.min((timestamp - startTimestamp) / duration, 1); obj.innerHTML = Math.floor(progress * (end - start) + start); if (progress < 1) { window.requestAnimationFrame(step); } }; window.requestAnimationFrame(step); } const obj = document.getElementById('value'); animateValue(obj, 100, -25, 2000); div {font-size: 50px;} <div id="value">100</div>
I had a slightly different approach to this kind of animation. Based on these assumptions: there is a starting text (as fallback for non-JS browser or google indexing) this text can contains non-numeric chars the function take an element directly as first param (as opposed to an element Id) 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>
Now we can animate counters (and a lot of things that cannot be animated before) with CSS variables and new #property. No javascript needed. Currently supports only Chrome and Edge. #property --n { syntax: "<integer>"; initial-value: 0; inherits: false; } body { display: flex; } .number { animation: animate var(--duration) forwards var(--timing, linear); counter-reset: num var(--n); font-weight: bold; font-size: 3rem; font-family: sans-serif; padding: 2rem; } .number::before { content: counter(num); } #keyframes animate { from { --n: var(--from); } to { --n: var(--to); } } <div class="number" style="--from: 0; --to: 100; --duration: 2s;"></div> <div class="number" style="--from: 10; --to: 75; --duration: 5s; --timing: ease-in-out"></div> <div class="number" style="--from: 100; --to: 0; --duration: 5s; --timing: ease"></div>
const counters = document.querySelectorAll('.counters'); counters.forEach(counter => { let count = 0; const updateCounter = () => { const countTarget = parseInt(counter.getAttribute('data-counttarget')); count++; if (count < countTarget) { counter.innerHTML = count; setTimeout(updateCounter, 1); } else { counter.innerHTML = countTarget; } }; updateCounter(); }); <p class="counters" data-counttarget="50"></p> <p class="counters" data-counttarget="100"></p> <p class="counters" data-counttarget="500"></p> <p class="counters" data-counttarget="1000"></p>
This works well. However, I needed to use a comma within the number. Below is the updated code which checks for commas. Hope someone finds this useful if they stumble across this post. function animateValue(id, start, end, duration) { // check for commas var isComma = /[0-9]+,[0-9]+/.test(end); end = end.replace(/,/g, ''); // assumes integer values for start and end var obj = document.getElementById(id); 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)); obj.innerHTML = value; if (value == end) { clearInterval(timer); } // Preserve commas if input had commas if (isComma) { while (/(\d+)(\d{3})/.test(value.toString())) { value = value.toString().replace(/(\d+)(\d{3})/, '$1'+','+'$2'); } } } var timer = setInterval(run, stepTime); run(); } animateValue("value", 100, 25, 2000);
HTML <!DOCTYPE html> <html> <head> <title>Count</title> </head> <body> <div id="value">1000</div> </body> </html> JAVASCRIPT snippet Here is a simple js function decrementing values from a given start number to an end number (object prototype).. function getCounter(startCount,endcount,time,html){ objects = { //you can alternateif you want yo add till you reach the endcount startCount:startCount, endCount:endcount, timer:time } this.function = function(){ let startTm = objects.startCount, timer = objects.timer, endCount = objects.endCount; //if you want it to add a number just replace the -1 with +1 /*and dont forget to change the values in the object prototype given a variable of counter*/ let increament = startTm < endCount ? 1:-1; timmer = setInterval(function(){ startTm += increament; html.innerHTML = startTm ; if(startTm == endCount){ clearInterval(timmer); } },timer); } } // input your startCount,endCount the timer..... let doc = document.getElementById('value'); let counter = new getCounter(1000,1,10,doc); //calling the function in the object counter.function(); Check out this demo https://jsfiddle.net/NevilPaul2/LLk0bzvm/
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)
Here is one version where increments grow by some defined multiplier (mul). frameDelay is the time delay for each increment. This looks a bit better if you have values that camn function cAnimate(id, start, end, frameDelay = 100, mul = 1.2) { var obj = document.getElementById(id); var increment = 2; var current = start; var timer = setInterval(function() { current += increment; increment *= mul; if (current >= end) { current = end; clearInterval(timer); } obj.innerHTML = Math.floor(current).toLocaleString(); }, frameDelay); } cAnimate("counter", 1, 260000, 50);
I used a mixture of all of these to create a function that updates a BehaviorSubject. function animateValue(subject, timerRef, startValue, endValue, duration){ if (timerRef) { clearInterval(timerRef); } const minInterval = 100; const valueRange = endValue - startValue; const startTime = new Date().getTime(); const endTime = startTime + (duration * 1000); const interval = Math.max((endTime-startTime)/valueRange, minInterval); function run() { const now = new Date().getTime(); const rangePercent = Math.min(1-((endTime-now)/(endTime-startTime)),1); const value = Math.round(rangePercent * valueRange+startValue); subject.next(value); if (rangePercent >= 1) { clearInterval(timerRef); } } timerRef = setInterval(run, interval); run(); }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; } </style> </head> <body style="width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center;"> <h1 style="font-size: 50px;" data-value="3212">0</h1> <script> let e = document.querySelector('h1'); let v = Number(e.dataset.value); let i = Math.floor(v/10); let r = v%10; function increment() { let c = Number(e.innerText); if (c<v) { if (v-c===i+r) { e.innerText = c+i+r; } else{ e.innerText = c+i; }; setTimeout(increment,200); }; }; setTimeout(increment, 200); </script> </body> </html>
Playing animation during x seconds using setInterval
I want to display an animated number from 0 to max value y during x seconds. I have tried this following code but it take too much to complete and clear the interval. jQuery('.numbers').each(function(item, index) { const $obj = jQuery(this); let objValue = parseInt($obj.text()), currentValue = 0, speed = 1, time = 4000, step = Math.floor(objValue / time); $obj.text(currentValue); let interVal = setInterval(() => { if (currentValue >= objValue) { clearInterval(interVal); $obj.text(objValue); } $obj.text(currentValue); currentValue += step }, speed); }); <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <span class='numbers'>7586</span> <span class='numbers'>147520</span> How do I play this animation during exactly time seconds?
It is better not to depend on the timing of setInterval(), but the real problem in your script is that you use the floored value to decide the new value to print out. It is better to use Window.requestAnimationFrame() and create a update() function that prints the current number based on the real time elapsed. let start, previousTimeStamp; let numbers = document.querySelectorAll('.numbers'); requestAnimationFrame(update); function update(timestamp) { if (start === undefined) { start = timestamp; } const elapsed = timestamp - start; [...numbers].forEach(elm => { if(!elm.dataset.start){ elm.dataset.start = elm.textContent; } let start = parseInt(elm.dataset.start); elm.textContent = Math.floor(start / 4000 * elapsed); }); if (elapsed < 4000) { previousTimeStamp = timestamp; requestAnimationFrame(update); }else { start = undefined; [...numbers].forEach(elm => { elm.textContent = elm.dataset.start; }); } } <span class='numbers'>7586</span> <span class='numbers'>147520</span>
Random speed in javascript count?
So I have this javascript which basically goes from 0 to 1000 at the same exact speed: HTML: <div id="value">0</div> Javascript: function animateValue(id, start, end, duration) { if (start === end) return; var range = end - start; var current = start; var increment = end > start? 1000 : +1; var stepTime = Math.abs(Math.floor(duration / range)); var obj = document.getElementById(id); var timer = setInterval(function() { current += increment; obj.innerHTML = current; if (current == end) { clearInterval(timer); } }, stepTime); } animateValue("value", 100, 25, 5000); Basically I want the counter to go up with random speed intervals. So as it goes up, it will slow down and speed up completely random until it reaches 1000. How do I achieve that? Thanks for your help.
I don`t understand purpose of duration parameter in function. That is why i used it as a max duration of one iteration. /** * Increment value with random intervals. * #param {string} id - Id of DOM Element. * #param {number} start - Start counter value. Applied immediately. * #param {number} end - End counter value. * #duration {number} duration - Max duration of one iteration in ms. */ function animateValue(id, start, end, duration) { let current = start; const obj = document.getElementById(id); obj.innerHTML = current; // immediately apply start value const setIncrOut = () => { let time = Math.random() * duration; setTimeout(function () { if (current < end) { current += 1; obj.innerHTML = current; setIncrOut(time); } }, time); } setIncrOut(); } animateValue("value", 100, 1001, 1000); <div id="value"></div>
A simplified version: animate(document.querySelector(`#value`), 5, 50, 1000); function animate(elem, start, end, maxDuration) { elem = elem || document.querySelector(`#value`); if (start < end) { elem.textContent = !elem.textContent.trim() ? start : start + 1; return setTimeout( () => animate( elem, start + 1, end, maxDuration ), Math.floor( (Math.random() * maxDuration) ) ); } } #value { font-size: 2rem; font-weight: bold; } <div id="value"></div>
Instead of using setInterval, which has a static pause between iterations you could create your own asynchronous loop that pauses with variable time. Incomplete, but something like... async function setVaryingInterval(callback, start, end, increment) { var step = start; while (step != end) { step += increment; var random = Math.random() * 3000; await new Promise(resolve => setTimeout(resolve, random)); callback(step); } } setVaryingInterval((value) => { // this will be executed with random delays, and the delay can be changed by adding logic to the "random" variable console.log(value); }, 0, 1000, 1); You will need to add logic for speeding up / slowing down, this will simply have a random delay between every interval, but should be easy enough to add if you have a vision on how it should behave. You can paste this code in your dev tools (F12) and see the random behaviour, and tailor it to your needs.
Number increment animation duration slow as numbers increase
I have a count up code here: HTML: <div id="value">700</div> <div id="value2">1000</div> JavaScript: function animateValue(id, start, end, duration) { var start= 0 ; var end = parseInt(document.getElementById(id).textContent, 10); var duration = 10000; var range = end - start; var current = start; var increment = end > start? 1 : -1; var stepTime = Math.abs(Math.floor(duration / range)); var obj = document.getElementById(id); var timer = setInterval(function() { current += increment; obj.innerHTML = current; if (current == end) { clearInterval(timer); } }, stepTime); } animateValue("value2",0,0,0); animateValue("value",0,0,0); In this code numbers start from 0 to end with 10000ms duration. How can I set this duration be slower than this when it's close to the end? For example: Numbers: 0 To 100. Duration : 50ms To 10ms.
Use some easing functions instead of incrementing at a constant rate. Please note, however, that your total execution time will likely always be at least somewhat inaccurate due to the fact that each increment of the value takes some execution time which is not accounted for using this setTimeout approach. The problem is exacerbated by higher values. //No easing function constant (duration, range, current) { return duration / range; } //Linear easing function linear (duration, range, current) { return ((duration * 2) / Math.pow(range, 2)) * current; } //Quadratic easing function quadratic (duration, range, current) { return ((duration * 3) / Math.pow(range, 3)) * Math.pow(current, 2); } function animateValue(id, start, duration, easing) { var end = parseInt(document.getElementById(id).textContent, 10); var range = end - start; var current = start; var increment = end > start? 1 : -1; var obj = document.getElementById(id); var startTime = new Date(); var offset = 1; var remainderTime = 0; var step = function() { current += increment; obj.innerHTML = current; if (current != end) { setTimeout(step, easing(duration, range, current)); } else { console.log('Easing: ', easing); console.log('Elapsed time: ', new Date() - startTime) console.log(''); } }; setTimeout(step, easing(duration, range, start)); } animateValue("value", 0, 10000, constant); animateValue("value2", 0, 10000, linear); animateValue("value3", 0, 10000, quadratic); <div id="value">100</div> <div id="value2">100</div> <div id="value3">100</div>
Make number grow with jQuery using same amount of time for every number
My goal is to perform a jQuery script that'll make any number visually grow from zero until its value with setInterval(). Here's what I came up with: $('.grow').each(function() { var $el = $(this); var max = parseInt($el.text().replace(/\s/g, '')); var refresh = 5; var start = 0; var step = 1; var interval = window.setInterval(function() { start += step; $el.text(start); if(start >= max) clearInterval(interval); }, refresh); }); My problem is I have numbers ranging from a few hundreds to several hundreds thousands. With this script, bigger number take more time to reach their value. My goal is to make any number, regardless of its goal value, take the same amount of time to reach it. I sense that I should divide the number by the number of seconds I want the animation to run and then, set the result as the interval step? I'm inquiring but still seeking for help :) Thanks.
$('.grow').each(function() { var $el = $(this); var max = parseInt($el.text().replace(/\s/g, '')); var duration = 1000; // shared duration of all elements' animation var refresh = 5; var frames = duration / refresh; // number of frames (steps) var start = 0; var step = Math.max(Math.round(max / frames), 1); // step should be >= 1 var interval = window.setInterval(function() { if(start + step < max) { start += step; } else { start = max; clearInterval(interval); } $el.text(start); }, refresh); });
This should work I suppose, $('.grow').each(function() { var $el = $(this); var max = parseInt($el.text().replace(/\s/g, '')); var start = 0; var refresh = 5; var totalSteps = 10; var step = max/totalSteps; function calculate(){ start += step; $el.text(Math.round(start)); if(start < max){ setTimeout(function() { calculate(); }, refresh); } } calculate(); }); This will always finish in 100 steps. I.e. 100*refresh = 100*5 = 500 seconds.