Reputation: 13
So I found this codepen tutorial that helped me get number counters on my page. It works perfectly however the counter is found down in the footer and the counter actually starts on page load. So by the time you get to the bottom of the page, the counter animation has already taken place. How would i alter this javascript so the counter doesn't start till I hit the above target div or counter div. For example lets say I have
<div id="services">
//Stuff Here
</div>
<div class="counter-wrap">
<div class="container">
<div class="row">
<div class="col-sm-4">
<h2 class="timer count-title count-number" data-to="300" data-speed="1500"></h2>
<p class="count-text ">SomeText GoesHere</p>
</div>
<div class="col-sm-4">
<h2 class="timer count-title count-number" data-to="800" data-speed="1500"></h2>
<p class="count-text ">SomeText GoesHere</p>
</div>
<div class="col-sm-4">
<h2 class="timer count-title count-number" data-to="950" data-speed="1500"></h2>
<p class="count-text ">SomeText GoesHere</p>
</div>
</div>
</div>
</div>
So the counter animation should start till i hit the "services" id. JS:
(function ($) {
$.fn.countTo = function (options) {
options = options || {};
return $(this).each(function () {
// set options for current element
var settings = $.extend({}, $.fn.countTo.defaults, {
from: $(this).data('from'),
to: $(this).data('to'),
speed: $(this).data('speed'),
refreshInterval: $(this).data('refresh-interval'),
decimals: $(this).data('decimals')
}, options);
// how many times to update the value, and how much to increment the value on each update
var loops = Math.ceil(settings.speed / settings.refreshInterval),
increment = (settings.to - settings.from) / loops;
// references & variables that will change with each update
var self = this,
$self = $(this),
loopCount = 0,
value = settings.from,
data = $self.data('countTo') || {};
$self.data('countTo', data);
// if an existing interval can be found, clear it first
if (data.interval) {
clearInterval(data.interval);
}
data.interval = setInterval(updateTimer, settings.refreshInterval);
// initialize the element with the starting value
render(value);
function updateTimer() {
value += increment;
loopCount++;
render(value);
if (typeof(settings.onUpdate) == 'function') {
settings.onUpdate.call(self, value);
}
if (loopCount >= loops) {
// remove the interval
$self.removeData('countTo');
clearInterval(data.interval);
value = settings.to;
if (typeof(settings.onComplete) == 'function') {
settings.onComplete.call(self, value);
}
}
}
function render(value) {
var formattedValue = settings.formatter.call(self, value, settings);
$self.html(formattedValue);
}
});
};
$.fn.countTo.defaults = {
from: 0, // the number the element should start at
to: 0, // the number the element should end at
speed: 1000, // how long it should take to count between the target numbers
refreshInterval: 100, // how often the element should be updated
decimals: 0, // the number of decimal places to show
formatter: formatter, // handler for formatting the value before rendering
onUpdate: null, // callback method for every time the element is updated
onComplete: null // callback method for when the element finishes updating
};
function formatter(value, settings) {
return value.toFixed(settings.decimals);
}
}(jQuery));
jQuery(function ($) {
// custom formatting example
$('.count-number').data('countToOptions', {
formatter: function (value, options) {
return value.toFixed(options.decimals).replace(/\B(?=(?:\d{3})+(?!\d))/g, ',');
}
});
// start all the timers
$('.timer').each(count);
function count(options) {
var $this = $(this);
options = $.extend({}, options || {}, $this.data('countToOptions') || {});
$this.countTo(options);
}
});
Codepen example: http://codepen.io/syedrafeeq/pen/rcfsJ
Upvotes: 1
Views: 11890
Reputation: 3546
You could check if element is visible in viewport with this:
$.fn.isOnScreen = function(){
var win = $(window);
var viewport = {
top : win.scrollTop(),
left : win.scrollLeft()
};
viewport.right = viewport.left + win.width();
viewport.bottom = viewport.top + win.height();
var bounds = this.offset();
bounds.right = bounds.left + this.outerWidth();
bounds.bottom = bounds.top + this.outerHeight();
return (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom));
};
And then start the timers on scroll like this:
$(document).on( 'scroll', function(){
$('.timer').each(count).isOnScreen();
});
Something like this: https://jsfiddle.net/snb7be2c/
I set new <div>
and added some css so it is in footer.
Update
Run animation just once: https://jsfiddle.net/_jakob/snb7be2c/1/
Upvotes: 4