Home > Software design >  jquery counter activate on viewport
jquery counter activate on viewport

Time:01-08

I have copied this counter code from https://bestjquery.com/tutorial/counter/demo155/ It works good, but when I put it at the bottom of page, it starts immediately and will finish counting before I scroll to view it. I want it start counting when it appears on viewport. Thank you. This is the code:

$(document).ready(function() {
  $('.counter-value').each(function() {
    $(this).prop('Counter', 0).animate({
      Counter: $(this).text()
    }, {
      duration: 3500,
      easing: 'swing',
      step: function(now) {
        $(this).text(Math.ceil(now));
      }
    });
  });
});
.counter {
  background: #fff;
  font-family: 'Noto Sans JP', sans-serif;
  text-align: center;
  width: 210px;
  padding: 0 0 25px;
  margin: 0 auto 15px;
  border-radius: 10px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
  position: relative;
}

.counter:before {
  content: "";
  background: #fff;
  width: 30px;
  height: 30px;
  border-radius: 5px 0;
  box-shadow: 4px 4px 4px rgba(0, 0, 0, 0.07);
  transform: translateX(-50%) rotate(45deg);
  position: absolute;
  bottom: -15px;
  left: 50%;
}

.counter .counter-value {
  color: #fff;
  background: linear-gradient(to right, #19bbd2, #2778ee);
  font-size: 38px;
  font-weight: 300;
  padding: 0 0 3px;
  margin: 0 0 25px;
  border-radius: 10px 10px 0 0;
  display: block;
}

.counter h3 {
  color: #2778ee;
  font-size: 18px;
  font-weight: 900;
  letter-spacing: 0.5px;
  text-transform: capitalize;
  margin: 0 0 25px;
}

.counter .counter-icon {
  color: #fff;
  background: linear-gradient(to right, #19bbd2, #2778ee);
  font-size: 40px;
  line-height: 60px;
  width: 65px;
  height: 65px;
  margin: 0 auto;
  border-radius: 10px;
}

.counter.purple .counter-value,
.counter.purple .counter-icon {
  background: linear-gradient(to right, #8f70e7, #c452ef);
}

.counter.purple h3 {
  color: #c452ef;
}

.counter.magenta .counter-value,
.counter.magenta .counter-icon {
  background: linear-gradient(to right, #e84a94, #ae379b);
}

.counter.magenta h3 {
  color: #ae379b;
}

.counter.yellow .counter-value,
.counter.yellow .counter-icon {
  background: linear-gradient(to right, #fecb4b, #e69814);
}

.counter.yellow h3 {
  color: #e69814;
}

@media screen and (max-width:990px) {
  .counter {
    margin-bottom: 45px;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<div >
  <div >
    <div >
      <div >
        <span >343</span>
        <h3>Web Designing</h3>
        <div >
          <i ></i>
        </div>
      </div>
    </div>
    <div >
      <div >
        <span >324</span>
        <h3>Web Development</h3>
        <div >
          <i ></i>
        </div>
      </div>
    </div>
  </div>
</div>

CodePudding user response:

Try like below. Added description in comments.

  1. Add additional class pending in your span with like <span >324</span>. This pending class is used to check whether animation is already started or not. If its already started then we don't want to re-animate it.
  2. Added new function setAnimation() in script.
  3. Used Utility Function to check whether element is visible or not. Referenced from How to check if element is visible after scrolling?.
  4. Add scroll event and call setAnimation() on scroll.

setAnimation function.

// create new function which will trigger your animation
function setAnimation() {
  // add additional class pending to your .counter-value element to check whether animation is pending or not
  // retrieve only pending elements and loop over it
  $('.counter-value.pending').each(function() {
    // check if element is in view and visible
    var isElementInView = Utils.isElementInView($(this), false);    
    if (isElementInView) {
      // if visible then remove class pending so it won't animate multiple times
      $(this).removeClass('pending');
      // initialize animation
      $(this).prop('Counter', 0).animate({
        Counter: $(this).text()
      }, {
        duration: 3500,
        easing: 'swing',
        step: function(now) {
          $(this).text(Math.ceil(now));
        }
      });
    }
  });
}

Try entire code below. Note : Added <div style="height:200px;"></div> just for testing purpose only.

$(document).ready(function() {
  // call newly created function
  setAnimation();
});

// add scroll event to check for animation on scroll
$(document).scroll(function() {
  // call newly created function
  setAnimation();
});

// Create new function which will trigger your animation
function setAnimation() {
  // add additional class pending to your .counter-value element to check whether animation is pending or not
  // retrieve only pending elements and loop over it
  $('.counter-value.pending').each(function() {
    // check if element is in view and visible
    var isElementInView = Utils.isElementInView($(this), false);    
    if (isElementInView) {
      // if visible then remove class pending so it won't animate multiple times
      $(this).removeClass('pending');
      // initialize animation
      $(this).prop('Counter', 0).animate({
        Counter: $(this).text()
      }, {
        duration: 3500,
        easing: 'swing',
        step: function(now) {
          $(this).text(Math.ceil(now));
        }
      });
    }
  });
}

// Added util code from https://stackoverflow.com/questions/487073/how-to-check-if-element-is-visible-after-scrolling
function Utils() {

}

Utils.prototype = {
  constructor: Utils,
  isElementInView: function(element, fullyInView) {
    var pageTop = $(window).scrollTop();
    var pageBottom = pageTop   $(window).height();
    var elementTop = $(element).offset().top;
    var elementBottom = elementTop   $(element).height();

    if (fullyInView === true) {
      return ((pageTop < elementTop) && (pageBottom > elementBottom));
    } else {
      return ((elementTop <= pageBottom) && (elementBottom >= pageTop));
    }
  }
};

var Utils = new Utils();
.counter {
  background: #fff;
  font-family: 'Noto Sans JP', sans-serif;
  text-align: center;
  width: 210px;
  padding: 0 0 25px;
  margin: 0 auto 15px;
  border-radius: 10px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
  position: relative;
}

.counter:before {
  content: "";
  background: #fff;
  width: 30px;
  height: 30px;
  border-radius: 5px 0;
  box-shadow: 4px 4px 4px rgba(0, 0, 0, 0.07);
  transform: translateX(-50%) rotate(45deg);
  position: absolute;
  bottom: -15px;
  left: 50%;
}

.counter .counter-value {
  color: #fff;
  background: linear-gradient(to right, #19bbd2, #2778ee);
  font-size: 38px;
  font-weight: 300;
  padding: 0 0 3px;
  margin: 0 0 25px;
  border-radius: 10px 10px 0 0;
  display: block;
}

.counter h3 {
  color: #2778ee;
  font-size: 18px;
  font-weight: 900;
  letter-spacing: 0.5px;
  text-transform: capitalize;
  margin: 0 0 25px;
}

.counter .counter-icon {
  color: #fff;
  background: linear-gradient(to right, #19bbd2, #2778ee);
  font-size: 40px;
  line-height: 60px;
  width: 65px;
  height: 65px;
  margin: 0 auto;
  border-radius: 10px;
}

.counter.purple .counter-value,
.counter.purple .counter-icon {
  background: linear-gradient(to right, #8f70e7, #c452ef);
}

.counter.purple h3 {
  color: #c452ef;
}

.counter.magenta .counter-value,
.counter.magenta .counter-icon {
  background: linear-gradient(to right, #e84a94, #ae379b);
}

.counter.magenta h3 {
  color: #ae379b;
}

.counter.yellow .counter-value,
.counter.yellow .counter-icon {
  background: linear-gradient(to right, #fecb4b, #e69814);
}

.counter.yellow h3 {
  color: #e69814;
}

@media screen and (max-width:990px) {
  .counter {
    margin-bottom: 45px;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<div  style="height:200px;"></div>
<div >
  <div >
    <div >
      <div >
        <span >343</span>
        <h3>Web Designing</h3>
        <div >
          <i ></i>
        </div>
      </div>
    </div>
    <div >
      <div >
        <span >324</span>
        <h3>Web Development</h3>
        <div >
          <i ></i>
        </div>
      </div>
    </div>
  </div>
</div>

  •  Tags:  
  • Related