1

I've found a function for my website that animate my bar skills.

That work but in Chrome Inspector, I see that width don't stop to be changed (it's not visible on screen, just in inspector).

This is my JS code :

    function launchSkills(){
      $(document).ready(function() {
        $('.bar span').hide();
        // HTML5
        $('#bar-one').animate({
          width: '95%'
        }, 1000);
        // CSS3
        $('#bar-two').animate({
          width: '85%'
        }, 1000);
        // Javascript
        $('#bar-three').animate({
          width: '30%'
        }, 1000);
        // jQuery
        $('#bar-four').animate({
          width: '40%'
        }, 1000);
        // PHP
        $('#bar-five').animate({
          width: '40%'
        }, 1000);
        setTimeout(function() {
          $('.bar span').fadeIn('slow');
        }, 1000);
      });
    }

    $(window).scroll(function(){
      $('#skills').each(function(){
        if(isVisible($(this), $(window))){
          launchSkills();
        };
      });
    });

This is my HTML code :

    <div class="container-fluid">
      <div class="row">
        <h4 class="text-center">Langages</h4>
        <noscript style="position: absolute;top: 75px;left: 180px;">
          Impossible d'afficher l'animation sans JavaScript.
        </noscript>
      </div>

      <div class="row">
        <div class="col-md-2">
          <p>HTML5</p>
        </div>
        <div class="col-md-10">
          <p>
            <span id="bar-one" class="bar" style="width: 94.9995%; overflow: hidden;"></span>
          </p>
        </div>
      </div>

      <div class="row">
        <div class="col-md-2">
          <p>CSS3</p>
        </div>
        <div class="col-md-10">
          <p>
            <span id="bar-two" class="bar" style="width: 85.0002%; overflow: hidden;"></span>
          </p>
        </div>
      </div>

      <div class="row">
        <div class="col-md-2">
          <p>Javascript</p>
        </div>
        <div class="col-md-10">
          <p>
            <span id="bar-three" class="bar" style="width: 30.0009%; overflow: hidden;"></span>
          </p>
        </div>
      </div>

      <div class="row">
        <div class="col-md-2">
          <p>jQuery</p>
        </div>
        <div class="col-md-10">
          <p>
            <span id="bar-four" class="bar" style="width: 39.9988%; overflow: hidden;"></span>
          </p>
        </div>
      </div>

      <div class="row">
        <div class="col-md-2">
          <p>PHP</p>
        </div>
        <div class="col-md-10">
          <p>
            <span id="bar-five" class="bar" style="width: 39.9997%; overflow: hidden;"></span>
          </p>
        </div>
      </div>
    </div>

Can you see the problem ? I tried to add .stop() after "1000)" but the animation didn't work...

Yann
  • 39
  • 6

2 Answers2

0

The main problem is that you're not taking into account the fact that window.scroll fires continuously, but there are some other issues here as well.

function launchSkills(){
  $(document).ready(function() { // This is unnecessary. See (1) below
    // animation code omitted
  });
}

$(window).scroll(function(){ // This will fire continuously during scroll. See (2)
  $('#skills').each(function(){ // This is unnecessary. See (3)
    if(isVisible($(this), $(window))){ // See (4)
      launchSkills();
    };
  });
});
  1. Waiting for the document.ready event is not necessary here, because the function is called from a scroll event -- which can only be triggered after the document is ready.

  2. The scroll event fires continuously, so you're repeatedly calling launchSkills throughout the duration of the scroll event, stacking up repeated animations. (For the second iteration and beyond, the width of the items being animated is already at the end position because that's where the first iteration left it; this is why the animation shown in your video only covers a sub-pixel range.) You'll need to debounce the scroll event or otherwise force it to fire it only once.

  3. There can only be one element with ID "skills", so there's no reason to loop through a .each here; this will at most match one element.

  4. I assume your isVisible function returns true when the element in its first param is within the viewport? You can pass $('#skills') directly to the function instead of using $(this) inside .each(). (I'm not sure why the second parameter would be necessary there, it can probably be removed unless you're using it for something not obvious in the given code.)

End result could look something like this:

function launchSkills(){
  // animation code here, without the document.ready
}

/* the event namespace allows you to unbind that event without 
   affecting other functions also bound to window scroll.  I've 
   used ".foo" here but it can be anything:
*/
$(window).on("scroll.foo", function(){    
  if(isVisible($('#skills'), $(window))){
    launchSkills();
    $(window).off("scroll.foo"); // stop firing after first successful run
  };
});

If there's any chance that #skills will be inside the viewport on page load, you can call $(window).trigger('scroll') to force the above to fire immediately. Note that if you do this, you will need to wait for document ready (by either using a single document.ready handler wrapped around all the scripts, or by placing the script at the end of the document.)

Daniel Beck
  • 20,653
  • 5
  • 38
  • 53
  • Thanks a lot for all these very clear explanations ! That work perfectly ! Thank you very much :) – Yann Sep 06 '17 at 19:41
  • Ah, right, `unbind` unbinds everything on the event. I'll update the code to include a namespace – Daniel Beck Sep 06 '17 at 19:43
  • Sorry i've edited my message, I proceeded in another way : add "data-spy="scroll" data-target=".navbar" data-offset="50"" in my and delete the scrollspy code in JS :) – Yann Sep 06 '17 at 19:46
  • That works too. It was sloppy of me to throw an `unbind` at the window scroll event, since there are often other events attached to that which you wouldn't want to mess with; so it's worth including the namespace in the answer even if you've found a different workaround – Daniel Beck Sep 06 '17 at 19:48
  • You're an angel, thank you veeery much ! Greetings from France :) – Yann Sep 06 '17 at 19:51
  • Cheers! Happy to help. – Daniel Beck Sep 06 '17 at 19:52
-1

This is what i could do with given code.

I wrapped scroll event listener inside document.ready() function. and same removed from launchSkills().

Please find the working snippet below

  function launchSkills(){
        $('.bar span').hide();
        // HTML5
        $('#bar-one').animate({
          width: '95%'
        }, 1000);
        // CSS3
        $('#bar-two').animate({
          width: '85%'
        }, 1000);
        // Javascript
        $('#bar-three').animate({
          width: '30%'
        }, 1000);
        // jQuery
        $('#bar-four').animate({
          width: '40%'
        }, 1000);
        // PHP
        $('#bar-five').animate({
          width: '40%'
        }, 1000);
        setTimeout(function() {
          $('.bar span').fadeIn('slow');
        }, 1000);
    }
 $(document).ready(function() {
    $(window).scroll(function(){
      
          launchSkills();
    });
    });
.bar{
background-color:blue;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container-fluid">
      <div class="row">
        <h4 class="text-center">Langages</h4>
        <noscript style="position: absolute;top: 75px;left: 180px;">
          Impossible d'afficher l'animation sans JavaScript.
        </noscript>
      </div>

      <div class="row">
        <div class="col-md-2">
          <p>HTML5</p>
        </div>
        <div class="col-md-10">
          <p>
            <span id="bar-one" class="bar" style="width: 94.9995%; overflow: hidden;">s</span>
          </p>
        </div>
      </div>

      <div class="row">
        <div class="col-md-2">
          <p>CSS3</p>
        </div>
        <div class="col-md-10">
          <p>
            <span id="bar-two" class="bar" style="width: 85.0002%; overflow: hidden;">s</span>
          </p>
        </div>
      </div>

      <div class="row">
        <div class="col-md-2">
          <p>Javascript</p>
        </div>
        <div class="col-md-10">
          <p>
            <span id="bar-three" class="bar" style="width: 30.0009%; overflow: hidden;">s</span>
          </p>
        </div>
      </div>

      <div class="row">
        <div class="col-md-2">
          <p>jQuery</p>
        </div>
        <div class="col-md-10">
          <p>
            <span id="bar-four" class="bar" style="width: 39.9988%; overflow: hidden;">s</span>
          </p>
        </div>
      </div>

      <div class="row">
        <div class="col-md-2">
          <p>PHP</p>
        </div>
        <div class="col-md-10">
          <p>
            <span id="bar-five" class="bar" style="width: 39.9997%; overflow: hidden;">s</span>
          </p>
        </div>
      </div>
    </div>
Dhiraj
  • 1,430
  • 11
  • 21
  • This doesn't solve the issue they asked about: all you've done is move the document.ready handler from one place to another (and removed the `isVisible` check which was presumably there for a reason.) – Daniel Beck Sep 06 '17 at 16:45
  • Thanks for the input daniel. but it is very hard to analyse the question without that much detail to understand exact problem. But i thought creating the working snippet without the issue which is faced by questioner would give some idea. But i still appreciate and consider your comment. – Dhiraj Sep 07 '17 at 06:46