Scroll functions all firing together in Safari - javascript

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');
}
});
});

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

Function not executing once when in viewport

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>

Script gets triggered at bottom of div instead of top

I want to make a count up script to be triggered when i reach a specific div, but instead of when it reaches top of the div it starts when it reaches the bottom, why so?
my html:
<div id="status_counter" class="status_bar">
<div class="container text-center">
<div class="row">
<div class="col-sm-3">
<div class="counter-item">
<h2><div class="counter" data-count="33">0</div></h2>
</div>
</div>
<div class="col-sm-3">
<div class="counter-item">
<h2><div class="counter" data-count="25">0</div></h2>!-
</div>
</div>
<div class="col-sm-3">
<div class="counter-item">
<h2><div class="counter" data-count="15">0</div></h2>
</div>
</div>
<div class="col-sm-3">
<div class="counter-item">
<h2><div class="counter" data-count="42">0</div></h2>
</div>
</div>
</div>
</div>
</div>
my counter.js:
var eventFired = false,
objectPositionTop = $('#status_counter').offset().top;
$(window).on('scroll', function() {
var currentPosition = $(document).scrollTop();
if (currentPosition > objectPositionTop && eventFired === false) {
eventFired = true;
$('.counter').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({ countNum: $this.text()}).animate({
countNum: countTo
},
{
duration: 2000,
easing:'linear',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
$this.text(this.countNum);
//alert('finished');
}
});
});
}
});
Currently: when is scroll down to the status_counter it doesnt trigger my script until i scroll down to the bottom of it.
I would like my Count up script to be triggered as soon as the status_counter div appears on my screen, so when the top/start of status_counter div reaches the bottom of the screen.
If I understand your question well this should work:
var eventFired = false,
objectPositionTop = $('#status_counter').offset().top,
objectPositionBottom = objectPositionTop;
$(window).on('scroll', function() {
var currentPositionBottom = $(document).scrollTop() + $(window).height();
if (currentPositionBottom > objectPositionBottom && eventFired === false) {
eventFired = true;
$('.counter').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({countNum: $this.text()}).animate({
countNum: countTo
}, {
duration: 2000,
easing:'linear',
step: function() {
$this.text(Math.floor(this.countNum));
}, complete: function() {
$this.text(this.countNum);
}
});
});
}
});
You need to check the bottom position of the element vs the bottom position of the window (which is the scrollHeight + the window height):
objectPositionTop = $('#status_counter').offset().top;
objectPositionBottom = objectPositionTop + $('#status_counter').height();
And inside the scroll you can use:
var currentPositionBottom = $(document).scrollTop() + $(window).height();
if (currentPositionBottom > objectPositionBottom && eventFired === false) {
Here is a fork of your code:
https://jsfiddle.net/rop0g9gz/1/
Catch the div you want to count when you over it:
var exampleDiv = document.getElementById("#YOUR-DIV-ID")
and attach it to the mouseover event:
exampleDiv.addEventListener('mouseover' , your-count-function)

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