How do I make numbers Auto increment upon Page view

Hello,

An example, would drive this question best. Check out this page:

https://www.phishlabs.com/

As you see once you scroll a little down, you have these Counters, such as:

X% of targeted attacks use spear phishing
Y% of espionage attacks involve phishing
etc.

My Question is:
How do we get to have such Counters start upon that section of the Page coming into view?

That is I would think, there should be a JavaScript event handler, like:
OnPointView
which will trigger, as OnMouseView does, which would then allow us to call a JS function which would then run this increment, Is there such a JS event?
If not, then how do we do this? That is have Counters start running upon a given section of a Web page coming into view.

Regards,

Hi there WorldNews,

perhaps this little example will show you what is happening…

[code]

untitled document body { min-height:60em; margin-top:30em; }
I am inactive and y=0

[/code]

coothead

coothead, this is for sure in the direction of what I am looking for.
Although I was hoping for a JS event handler which would reside in a DIV and be triggered when that DIV comes into focus (view).

But If that is not possible, back to your suggestion: How would we know the pageYOffset value for a given DIV?
I mean is it always the same value across different Screen sizes, iPad vs Laptop, etc.?

Regards,

coothead, Follow up.
I have been working with your Code idea. And I am running into problems.
You can see the Test page here:

http://www.immersite.net/eng/test_counter.php

So problems:

1- I want the Code related to DIV “info” coming into view, being called only once! Bu if I set the

if (y == 100) {

	if (counter == 0)
	{
		run_counter('info');
		++counter;
	}
}

Then it will not run at all!
So I got around that via adding the if (counter == 0) and keeping if (y > 100) {

2- Once I call the function run_counter, I want it to call itself until it has filled the id=“info” to 1000, with the increment job done visually for its effect. However the call to this function from itself via var timerId = setTimeout(run_counter, 1000); is not working out!

Ideas please?

You need to check if y > 100 rather than == because it’s rather unlikely that you’re scrolling to exactly 100px. And instead of checking if counter == 0 you might also just remove the event listener, which is maybe a bit cleaner since you don’t need it any more anyway.

This actually could work… that is, if you don’t expect the element id as an argument of run_counter. Otherwise you’ll get an

[quote=“Console”]Uncaught TypeError: Cannot read property ‘innerHTML’ of null
[/quote]

However, on your live site you have it like

var timerId = setTimeout(run_counter(item),  9000); 

If you want to pass an argument you might do this like

var timerId = setTimeout(function() {
    run_counter(item);
},  9000); 

Alternatively, you could just use setInterval. Here’s a fiddle with some of the things mentioned.

Hi there WorldNews,

does this get you a little closer to your objective…

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1">
<title>untitled document</title>
<style media="screen">
body {
    margin:10em 0;
    background-color: #666;
    background-image: linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff), 
                      linear-gradient(-45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%, #fff);
    background-size: 4em 4em;
    background-attachment:fixed;
 }
.box {
    min-height: 50em;
    padding: 1em;
    margin: auto;
    border: 0.1em solid #000;
    background-color: #444;
    box-sizing: border-box;
    color: #ccc;
 }
#info {
    padding: 3em 0;
    margin: auto;
    border: 0.1em solid #999;
    background-color: #fff;
    box-sizing: border-box;
    font-size: 2em;
    text-align: center;
 }
.newposition {
    position: fixed;
    left: 0;
    right: 0;
    top: 50%;
 }   
</style>
</head>
<body> 
<div class="box"></div>
<div id="info"></div>
<div class="box"></div>
<script>
(function() {
   'use strict';
   var el=document.getElementById('info');
   var el2=document.getElementsByClassName('box')[0].style;
   var temp=el.offsetTop;
   var temp1=window.innerHeight/2;
   var c=0;
   var test=true;
   var st;
   var delay=25;
window.onresize=function() {
   temp=el.offsetTop;
   temp1=window.innerHeight/2;
   el.className='';
   return temp;
 }
window.onscroll=function() {
   var y=window.pageYOffset;
if(y>temp-temp1) {
   el.className='newposition';
   el2.marginBottom=el.offsetHeight+'px';
if(test===true) {
   countup();
   test=false;
  }
 }
else {
   el.className='';
   el2.marginBottom=0;
  }
 }
function countup() {
if(c>1000) {
   clearTimeout(st);
   return;
 }
   el.innerHTML=c;
   c++;
   st=setTimeout(countup,delay);  
 }
}());
</script>
</body>
</html>

coothead

m3g4p0p, your code works fine. That is now the Counter is actually counting up 1 at a time at the specified timestop interval time rather than before when the counter would all of a sudden, in 1 second, jump to the max set value of 1000.

My question is WHY you code is working and mine was not!!!
When mine was calling that function from inside the function this way:

var timerId = setTimeout(run_counter(item), 100);

and yours is doing it slightly different this way:
var timerId = setTimeout(function() { run_counter(item); }, 100);

I am really curious to know what is the bizzare JavaScript logic here where the call to function setTimeout(run_counter(item), 100) was not working but the way you have done it is working!

Thanks

I think I will stick to my Code, as per your original suggestion and additions by m3g4p0p, which code is now running the Counter just real nice as you can see in that sample page.

But I still have one KEY question: that is in an actual production page, the counter(s) are going to be a few pages down from the top. So how do we know the (near) exact window.pageYOffset for a DIV so that we will SET the condition:

if (window.pageYOffset > xyz) {

    if (counter == 0)
    {
        run_counter('info');
        ++counter;
    }
}  

to be at the near y location of that given DIV. So that the counter will start running only as that DIV comes into actual view of the user?
I trust you know what I mean.

Regards,

That’s how callback functions work: you’ll pass a function to setTimeout, and setTimeout will call this function after the specified amount of time. However, a callback function will get its arguments (if any) from the function that calls it – you can’t just pass a call to a function. Maybe this code will illustrate:

// This function takes a number and a callback function as arguments,
// and in turn calls the callback function with the result as an argument
// so that it can be processed within that callback function
var addOne = function(number, callback) {
    return callback(number + 1);
};

// Here you can see how the result is passed to that function
addOne(10, function(result) {
    console.log(result); //logs "11"
});

// However, you could just as well pass the name of the function to
// call back; in this case, it's maybe a bit less obvious what is happening
var outputFunc = function(result) {
    console.log(result);
};

addOne(10, outputFunc); // logs "11"

// As you can see, it doesn't make sense to pass arguments to the
// callback function (and thus call it!) at this point since it gets their
// arguments from the function that actually does calls it -- that's 
// the whole point! :-) Thus this: 
addOne(10, outputFunc());

// throws a "TypeError: callback is not a function" -- you didn't pass
// a function, you called it. You could make it work again however,
// if outputFunc in turn returns a callback function like this:
var outputFunc2 = function() {
    
    return function(result) {
        console.log(result);
    };
}

addOne(10, outputFunc2()); // logs "11"

// But then it might get a little mind-twisting :-)

Hope this helps… it may look a little confusing at first, but it makes totally sense.

m3g4p0p, thanks for this info. I have to read and test it in detail later.

However, do you have an answer to my 2nd follow up question?
That is:
“how do we know the (near) exact window.pageYOffset for a DIV so that we will SET the right value for Y to trigger it”, when the DIV comes into view?

Thanx

Have a look at .getBoundingClientRect() – element.getBoundingClientRect().top gives you the element’s horizontal offset relative to the top edge of the viewport, so it enters the view when element.getBoundingClientRect().top < window.screen.height.

Waypoints is a javascript library for making it easy to call a function when an element is scrolled into view.

Hi,

Can you show an example of a Page that is using this to trigger a JS Function call when the DIV with this comes into view?

Also, how would you embed this into a DIV so that when this DIV comes into view then this Waypoints JS event allows us to call the desired JS function?

Thanks,

m3g, how do you add this code into a Page to print out the YPosition of that DIV?

Like so:

<html>
<head>
    <title>Page</title>
    <style>
    #output {
      position: fixed;
      top: 0;
      left: 0;
    }

    #scroll {
      font-size: 40px;
      margin-top: 2000px;
      margin-bottom: 2000px;
      text-align: right;
      background-color: yellow;
      color: cyan;
    }

    div {
      font-family: "monospace";
      padding: 20px;
    }
    </style>
</head>
<body>
    <div id="output">
        Y position: <span></span>px<br>
        Is visible: <span></span>
    </div>
    <div id="scroll">Scroll here!</div>
    <script>
    var scrollHandler = function() {
        var yPosition = document.getElementById('scroll')
                .getBoundingClientRect().top,
            screenHeight = window.screen.height;

        document.querySelectorAll('#output span')[0].innerHTML = yPosition;
        document.querySelectorAll('#output span')[1].innerHTML =
            (yPosition < screenHeight && yPosition > 0) ? 'yes' : 'no';
    };

    window.addEventListener('scroll', scrollHandler);
    </script>
</body>
</html>

The Waypoint docs are pretty good

var waypoint = new Waypoint({
  element: document.getElementById('blah'),
  handler: function(direction) {
    alert("I'm at the bottom of the viewport!")
  },
  offset: '100%'
})

Hi,

I put your sample code here:

http://www.immersite.net/test_xy.php

but why is the Y position value going lower as I go down the page rather than going higher!

I mean the whole point of this issue is that to fire a JavaScript code as a certain DIV way down from the top of the page comes into view. So that is why we want to know the Y value of that DIV accuraetly and fire the JS code associated with that DIV only when it comes into view. As you can see on home page of this site, here: http://www.immersite.net/
where the codes running the counters are to be fired ONLY when the DIV containing them comes into view but for some people they are firing before the DIV comes into view.

Regards,

Hi there WorldNews,

my example uses…

   element.offsetTop+element.offsetHeight-window.innerHeight

…to make the “number auto increment” start only when it’s
container is fully visible, and,unlike your example, it also
works for various window height dimensions. :sunglasses:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1">
<title>untitled document</title>
<style media="screen">
body {
    margin:0.5em;
 }
#info {
    padding: 3em 0;
    margin: auto;
    border: 0.1em solid #ccc;
    background-color: #fff;
    box-sizing: border-box;
    text-align: center;
 }
.newposition {
    position: fixed;
    left: 0.5em;
    right: 0.5em;
    top: 0;
 }
#number {
    display:inline-block;
    padding:0.5em;
    border: 0.06em dotted #ccc;
    font-size: 2em;
 } 
</style>
</head>
<body> 
<div class="box"></div>
<div id="info"><span id="number">0</span></div>
<div class="box"></div>
<script>
(function() {
   'use strict';
   var el=document.getElementById('info');
   var num=document.getElementById('number');
   var el2=document.getElementsByClassName('box')[0].style;
   var infotop=el.offsetTop;
   var numtop=num.offsetTop;
   var numhgt=num.offsetHeight;
   var winhgt=window.innerHeight;
   var c=0;
   var st;
   var delay=25;
   var y;
window.onresize=function() {
if(y<infotop){ 
   el2.marginBottom=0;
 }
   infotop=el.offsetTop;
   numtop=num.offsetTop;
   winhgt=window.innerHeight;
   el.className='';
 };
window.onscroll=function() {
if(y<infotop){ 
   el2.marginBottom=0;
 }
   y=window.pageYOffset; 
if(y>numtop+numhgt-winhgt){ 
if(c===0) {
   countup();
   }
  }
if(y>infotop) {
   el.className='newposition';
   el2.marginBottom=el.offsetHeight+'px';
 }
else {
   el.className='';
   el2.marginBottom=0;
  }
 };
function countup() {
if(c>1000) {
   clearTimeout(st);
   return;
 }
   num.innerHTML=c;
   c++;
   st=setTimeout(countup,delay);  
 }
}());
</script>
</body>
</html>

coothead

From the link to MDN I provided, first sentence:

The Element.getBoundingClientRect() method returns the size of an element and its position relative to the viewport.

It follows that when you scroll down and the element gets closer to the viewport, the value goes lower. ;-) There are other possibilities though, as @coothead nicely demonstrated.

Hi there WorldNews,

there was an error in my previous post :scream::

In consequence of having another of my “Brain Fart” attacks, this CSS …

.box { min-height: 50em; border: 0.1em solid #000; background-color: #999; }
…was, unfortunately, omitted from my previous post. :mask:

coothead