Reputation: 61
I would like to display numbers that count up as soon as the viewer scrolls down to look at that area of the screen. The goal is to make the numbers count up consecutively until they reach the desired amount. My question is how to do that with the existing code provided.
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'));
.statistics {
padding-top: 30px;
padding-bottom: 30px;
}
.statistics h1 {
letter-spacing: 1.0px;
font-family: 'Lora', serif;
font-weight: 500;
text-align: center;
font-size: 5em;
color: #39CEAF;
}
#value {
font-size: 100px;
font-color: blue;
}
<div id="statistics" class="statistics container-fluid">
<div class="col-md-4">
<h1 id="value1">100+</h1>
<h2>People receiving opportunities in the first 36 hours</h2>
</div>
<div class="col-md-4">
<h1 id="value2">400+</h1>
<h2>People receiving opportunities in the first month</h2>
</div>
<div class="col-md-4">
<h1 id="value3">800+</h1>
<h2>People receiving opportunities currently</h2>
</div>
</div>
Upvotes: 0
Views: 283
Reputation: 31992
Add an event listener for scroll
, check if the element is visible to the client, and if so, call the animateValue
function. To prevent it from animating again and again, we can keep track with a custom data attribute (data-animated
).
function animateValue(obj, start = 0, end = null, duration = 3000) {
if (obj) {
var textStarting = obj.innerHTML;
end = end || parseInt(textStarting.replace(/\D/g, ""));
var range = end - start;
var minTimer = 50;
var stepTime = Math.abs(Math.floor(duration / range));
stepTime = Math.max(stepTime, minTimer);
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 = textStarting.replace(/([0-9]+)/g, value);
if (value == end) {
clearInterval(timer);
}
}
timer = setInterval(run, stepTime);
run();
}
}
const toAnimate = document.querySelectorAll('h1');
function checkElements() {
toAnimate.forEach(function(e) {
if (isVisible(e) && e.getAttribute('data-animated') != "true") {
animateValue(e);
e.setAttribute('data-animated', 'true');
}
})
}
document.addEventListener("scroll", checkElements);
checkElements();
function isVisible(el) {
/* https://stackoverflow.com/a/7557433/14251221 */
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
.statistics {
padding-top: 30px;
padding-bottom: 30px;
}
.statistics h1 {
letter-spacing: 1.0px;
font-family: 'Lora', serif;
font-weight: 500;
text-align: center;
font-size: 5em;
color: #39CEAF;
}
#value {
font-size: 100px;
font-color: blue;
}
<div id="statistics" class="statistics container-fluid">
<div class="col-md-4">
<h1 id="value1" data-animated="false">100+</h1>
<h2>People receiving opportunities in the first 36 hours</h2>
</div>
<div class="col-md-4">
<h1 id="value2" data-animated="false">400+</h1>
<h2>People receiving opportunities in the first month</h2>
</div>
<div class="col-md-4">
<h1 id="value3" data-animated="false">800+</h1>
<h2>People receiving opportunities currently</h2>
</div>
</div>
Upvotes: 1
Reputation: 65796
You're trying to run your code by passing it an element that doesn't exist (animateValue(document.getElementById('value'));
). If I pass valid DOM references, it appears to work.
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('value1'));
animateValue(document.getElementById('value2'));
animateValue(document.getElementById('value3'));
.statistics {
padding-top: 30px;
padding-bottom: 30px;
}
.statistics h1 {
letter-spacing: 1.0px;
font-family: 'Lora', serif;
font-weight: 500;
text-align: center;
font-size: 5em;
color: #39CEAF;
}
#value {
font-size: 100px;
font-color: blue;
}
<div id="statistics" class="statistics container-fluid">
<div class="col-md-4">
<h1 id="value1">100+</h1>
<h2>People receiving opportunities in the first 36 hours</h2>
</div>
<div class="col-md-4">
<h1 id="value2">400+</h1>
<h2>People receiving opportunities in the first month</h2>
</div>
<div class="col-md-4">
<h1 id="value3">800+</h1>
<h2>People receiving opportunities currently</h2>
</div>
</div>
Upvotes: 1