Function not executing once when in viewport - javascript

I have a simple counter, which when in viewport, I want it to count up to a set number.
However, I have two issues...
Function declaration for reference:
function numberCounter() {
$('.counter').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({
countNum: $this.text()
}).animate({
countNum: countTo
},
{
duration: 1500,
easing: 'linear',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
$this.text(this.countNum);
}
});
});
};
Approach 1 isInViewport():
With the following code block, the function is being executed for every pixel scrolled within the div. This results in the counter jittering and not count up unless the user stops scrolling.
$(window).on(' scroll', function() {
if ($('.numberTicker').isInViewport()) {
console.log("test");
numberCounter();
$(window).off('resize scroll');
}
});
Approach 2 visible():
To resolve the above, I thought checking if the div is visible on viewport will execute the function once, however, the counter doesn't seem to work at all with this?
jQuery(document).ready(function($){
var ticker = $('.numberTicker');
if(ticker.visible(true)) {
numberCounter();
}
});
Where am I going wrong?
Full demo:
function numberCounter() {
$('.counter').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({
countNum: $this.text()
}).animate({
countNum: countTo
},
{
duration: 1500,
easing: 'linear',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
$this.text(this.countNum);
}
});
});
};
jQuery(document).ready(function($){
var ticker = $('.numberTicker');
if(ticker.visible(true)) {
numberCounter();
}
});
// $(window).on(' scroll', function() {
// if ($('.numberTicker').isInViewport()) {
// console.log("test");
// numberCounter();
// $(window).off('resize scroll');
// }
// });
.spacer {
height: 400px;
background-color: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- is visible plugin -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-visible/1.2.0/jquery.visible.min.js"></script>
<div class="spacer">scroll down</div>
<div class="numberTicker">
<h3 class="counter" data-count="50">50</h3>
</div>

Related

How do I start my scroll counter again if the user scrolls back to the section?

I've made a animated counter that starts counting once you scroll into view. How do I restart the counter when a user scrolls back to the counter?
I'm sure it will be something simple that I don't know yet. Thanks for any help given, much appreciated.
var a = 0;
$(window).scroll(function() {
var oTop = $('#counter').offset().top - window.innerHeight;
if (a == 0 && $(window).scrollTop() > oTop) {
$('.counter-value').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({
countNum: $this.text()
}).animate({
countNum: countTo
}, {
duration: 2000,
easing: 'swing',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
$this.text(this.countNum);
//alert('finished');
}
});
});
a = 1;
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="numbers">
<div class="container" id="counter">
<h6 class="red-title">BY THE NUMBERS</h6>
<h2 class="stats-heading">We’ll always measure up to your expectations</h2>
<div class="numbers-box">
<h1 class="counter-value" data-count="50">0</h1>
<h6>years of experience</h6>
</div>
<div class="numbers-box">
<h1 class="counter-value" data-count="37">0</h1>
<h6>countires supplied</h6>
</div>
<div class="numbers-box">
<h1 class="counter-value" data-count="128">0</h1>
<h6>group automation employees</h6>
</div>
</div>
</section>
How's this?
https://codepen.io/jonolayton/pen/MWmLJze
You'll probably want to fiddle with it to make it fire accurately... I've edited some of the CSS in CodePen too, so check it on there.
Also - it only restarts when the counting has already stopped. Otherwise it could get really annoying.
var runAlready;
var counting;
function startCounter(a) {
runAlready = true;
counting = true;
$('.counter-value').each(function() {
var $this = $(this);
$this.text(a);
countTo = $this.attr('data-count');
$({
countNum: $this.text()
}).animate({
countNum: countTo
},
{
duration: 2000,
easing: 'swing',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
$this.text(this.countNum);
counting = false;
}
});
})
}
$(window).scroll(function() {
var oTop = $('#counter').offset().top;
var a = 0;
if (!runAlready && $(window).scrollTop() > oTop || !counting && $(window).scrollTop() < oTop) {
startCounter(a);
}
});

JS run a data-count in percentage, not in numbers

i have this code and i want it to count in percentage, not in numbers how it is showed in the next code, how can i do it?
if someone could help me please, i'm not very good at Javascript
/* Counter - CountTo */
var a = 0;
$(window).scroll(function() {
if ($('#counter').length) { // checking if CountTo section exists in the page, if not it will not run the script and avoid errors
var oTop = $('#counter').offset().top - window.innerHeight;
if (a == 0 && $(window).scrollTop() > oTop) {
$('.counter-value').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({
countNum: $this.text()
}).animate({
countNum: countTo
},
{
duration: 2000,
easing: 'swing',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
$this.text(this.countNum);
//alert('finished');
},
complete: function() {
$this.text(commaSeparateNumber(this.countNum));
//alert('finished');
}
});
});
a = 1;
}
}
});
<div class="cell">
<div class="counter-value number-count" data-count="97%">1%</div>
<p class="counter-info p-small">Percentage</p>
</div>
Just add % after the text.
$this.text(Math.floor(this.countNum)+"%");
$this.text(this.countNum+"%");
$this.text(commaSeparateNumber(this.countNum)+"%");
or use css ::after (better way in my opinion because you can control the '%' style):
.counter-value::after{
content:'%';
}
And if your counter isn't percentaged - just divide it by the max value it can be and multiply by 100

Scroll functions all firing together in Safari

I have made a few scroll functions with anchor tags that when the anchor reaches the top of the page, it then triggers certain animations. Super simple stuff.
But for some reason in Safari, as soon as the first anchor point is reached, they all fire at the same time. This defeats the point.
I think it may be the way I am checking for when the user scrolls, but I think someone with a bit more knowledge than me can help.
I have attached a snippet for you to look at -
CODE -
//SCROLL TO TRIGGER CHARTS
$(function() {
var oTop = $('#chartAnchor').offset().top - window.innerHeight;
var chartHidden = true;
$(window).scroll(function() {
var pTop = $('body').scrollTop();
if ((pTop > oTop) && (chartHidden)) {
chartHidden = false;
makeCharts();
}
});
});
//TOTAL VIEWS COUNTER FUNCTIONS
$(function() {
var oTop = $('#stat-anchor').offset().top - window.innerHeight;
var chartHidden = true;
$(window).scroll(function() {
var pTop = $('body').scrollTop();
if ((pTop > oTop) && (chartHidden)) {
chartHidden = false;
$('.counter').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({
countNum: $this.text()
}).animate({
countNum: countTo
},
{
duration: 1500,
easing: 'linear',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
var finalNum = this.countNum.toString().replace(/(\d+)(\d{6})/, '$1' + ',' + '$2');
finalNum = finalNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
$this.text(finalNum);
ready = false;
}
});
});
}
});
});
//GENDERS COUNTER FUNCTIONS
$(function() {
var oTop = $('#gender-anchor').offset().top - window.innerHeight;
var chartHidden = true;
$(window).scroll(function() {
var pTop = $('body').scrollTop();
if ((pTop > oTop) && (chartHidden)) {
$('.male').addClass('left');
$('.female').addClass('right');
chartHidden = false;
$('.counter2').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({
countNum: $this.text()
}).animate({
countNum: countTo
},
{
duration: 1500,
easing: 'linear',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
var finalNum = this.countNum;
$this.text(finalNum + '%');
}
});
});
//Affinity & Age Animations
$('.affinity-info').css('opacity', '1');
$('.user-age').css('opacity', '1');
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<a class="view-demos" id="chartAnchor" href="mailto:adrian#hsm.co.za">Enquire for more stats</a>
<div class="mobile-stat-wrap" id="stat-anchor">
<img class="device-icon" src="img/mobileIcon.png">
<p class="device-icon-head">Mobile</p>
<p id="mobile-stat" class="device-stat">7,302,872</p>
</div>
<div class="counter-wrap col-12">
<p class="stats-heading-small">Total Views</p>
<div class="counter" data-count="16400708">0</div>
</div>
<div class="gender-wrap">
<div class="center-wrap">
<p class="stats-heading-small">Gender</p>
<div class="male">
<img class="gender-icon" src="img/male.png">
<p class="gender-stat counter2" id="male-stat" data-count="55">%</p>
</div>
<div class="female">
<img class="gender-icon" src="img/female.png">
<p class="gender-stat counter2" id="female-stat" data-count="45">%</p>
<span id="gender-anchor"></span>
</div>
</div>
<div class="affinity-info-wrap col-12">
<img class="affinity-info" src="img/affinityInfo.png">
<img class="user-age" src="img/userAge.png">
</div>
</div>
Don't subtract window height to get the location of your anchor.
$(function() {
//Don't need to subtract the top offset by window innerHeight
//var oTop = $('#gender-anchor').offset().top - window.innerHeight;
var oTop = $('#gender-anchor').offset().top;
var chartHidden = true;
$(window).scroll(function() {
var pTop = $('body').scrollTop();
if ((pTop > oTop) && (chartHidden)) {
$('.male').addClass('left');
$('.female').addClass('right');
chartHidden = false;
$('.counter2').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({
countNum: $this.text()
}).animate({
countNum: countTo
},
{
duration: 1500,
easing: 'linear',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
var finalNum = this.countNum;
$this.text(finalNum + '%');
}
});
});
//Affinity & Age Animations
$('.affinity-info').css('opacity', '1');
$('.user-age').css('opacity', '1');
}
});
});

How make reusable code in jQuery?

I have code on the link below, and I need to use it several times for any places. I set different value for bars, of course it works wrong. So, the bad answer is set id to each span and copy code for them several times.
Please, give me a tip how to rewrite code that I don't need to repeat again and again.
P.S. yes, I know about progressbar.js and other libraries but in this place I need to handle bar from html elements.
$(document).ready(function() {
$(".blackbar > span").each(function() {
var percentWidth = $('.blackbar > span').data('width');
$(this).animate({
width: $(this).data("width") + "%"
}, 800);
$({
countNum: 0
}).animate({
countNum: percentWidth
}, {
duration: 800,
easing: 'linear',
step: function() {
$('.barvalue').text(Math.floor(this.countNum)).append(" %");
},
complete: function() {
$('.barvalue').text(this.countNum).append(" %");
}
});
});
});
JSFiddle example
You want to loop over each .barbox, and then find the span for the bar and the span for the value, and use them appropriately...
$(document).ready(function(){
$(".barbox").each(function() {
var $barbox = $(this);
var $barSpan = $barbox.find('.blackbar > span');
var $barValue = $barbox.find('.barvalue');
var percentWidth = $barSpan.data('width');
$barSpan.animate({
width: percentWidth + "%"
}, 800);
$({countNum: 0}).animate({countNum: percentWidth}, {
duration: 800,
easing: 'linear',
step: function() {
$barValue.text(Math.floor(this.countNum) + " %");
},
complete: function() {
$barValue.text(this.countNum + " %");
}
});
});
});
https://jsfiddle.net/vsp6vuuh/2/
https://jsfiddle.net/SeanWessell/8919job4/
Set variables for $span and the $barvalue.
$(".blackbar > span").each(function() {
var $span = $(this);
var $barvalue = $span.closest('.b-item__barbox.barbox').find('.barvalue');
var percentWidth = $span.data('width');
$span.animate({
width: percentWidth + "%"
}, 800);
$({
countNum: 0
}).animate({
countNum: percentWidth
}, {
duration: 800,
easing: 'linear',
step: function() {
$barvalue.text(Math.floor(this.countNum)).append(" %");
},
complete: function() {
$barvalue.text(this.countNum).append(" %");
}
});
});

Start counter on the scroll

I use two function on JQuery.
The first one is a counter (View here) and the second for start the counter when the Div is center on the window.
Counter
JS :
$('.counter').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({
countNum: $this.text()
}).animate({
countNum: countTo
},
{
duration: 3000,
easing: 'linear',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
$this.text(this.countNum);
}
});
});
HTML :
<div class="counter" data-count="10000">0</div>
https://jsfiddle.net/a52e24Ls/
*
*
Scroll detection
JS :
$(window).scroll(function() {
startCounter();
});
$(window).load(function(){
startCounter();
});
function startCounter(){
$('.contributorTitle').each(function(i) {
var bottom_of_object = $(this).position().top + ($(this).outerHeight()/2);
var bottom_of_window = $(window).scrollTop() + $(window).height();
if (bottom_of_object < bottom_of_window){
}
});
}
I thinks, i put the JS counter inside
if (bottom_of_object < bottom_of_window){
}
But it does not work. I want the counter start whan the window is center.

Categories