Proper way to write a perfect animation using jquery

139 views Asked by At

Current scenario:

I have a list of divs which contains set of elements which scrolls automatically based on the number of divs present. This list of divs is placed inside a parent div and with fixed height.

Requirements:

  • Do not animate i.e. scroll if the length of divs present inside is less than 4.
  • Animate at same speed till the last div and scroll back from bottom to top vice versa.
  • Stop the scroll on hover of any child div.

Achieved:

  • Scrolling is done i.e. it does not scroll if less than 4 elements present.
  • Scroll stops on hover of any child div.
  • Animate till bottom element and start from beginning.

Problems facing at present:

  • Scrolling does not happen at same speed. It starts slowly, increases speed and ends slowly.
  • After hover which stops scrolling, when it starts again, it starts slowly again.
  • Once reached the end, it stays there for a few seconds and then starts from beginning.

DEMONSTRATION

HTML

<div id="events_partial" class="container body-content col-md-12 col-lg-12 set-max-height">
    <div class="row sec-container" id="secContainer">
        <div style="top: -550.242px; opacity: 1;" id="secDetails">
            <div class="container">
                <p><h3><strong> Program in Place 1 &nbsp;on&nbsp;11/22/2015</strong></h3></p>
                <p>
                  Program Description which is a very long text on document and it  can be more than 2 lines
                </p>
            </div>
            <div class="container">
                <p><h3><strong> Program in Place 1 &nbsp;on&nbsp;11/22/2015</strong></h3></p>
                <p>
                  Program Description which is a very long text on document and it  can be more than 2 lines
                </p>
            </div>
            <div class="container">
                <p><h3><strong> Program in Place 1 &nbsp;on&nbsp;11/22/2015</strong></h3></p>
                <p>
                  Program Description which is a very long text on document and it  can be more than 2 lines
                </p>
            </div>

            <div class="container">
                <p><h3><strong> Program in Place 1 &nbsp;on&nbsp;11/22/2015</strong></h3></p>
                <p>
                  Program Description which is a very long text on document and it  can be more than 2 lines
                </p>
            </div>
            <div class="container">
                <p><h3><strong> Program in Place 1 &nbsp;on&nbsp;11/22/2015</strong></h3></p>
                <p>
                  Program Description which is a very long text on document and it  can be more than 2 lines
                </p>
            </div>
            <div class="container">
                <p><h3><strong> Program in Place 1 &nbsp;on&nbsp;11/22/2015</strong></h3></p>
                <p>
                  Program Description which is a very long text on document and it  can be more than 2 lines
                </p>
            </div>
            <div class="container">
                <p><h3><strong> Program in Place 1 &nbsp;on&nbsp;11/22/2015</strong></h3></p>
                <p>
                  Program Description which is a very long text on document and it  can be more than 2 lines
                </p>
            </div>
            <div class="container">
                <p><h3><strong> Program in Place 1 &nbsp;on&nbsp;11/22/2015</strong></h3></p>
                <p>
                  Program Description which is a very long text on document and it  can be more than 2 lines
                </p>
            </div>
      </div>
    </div>
</div>

CSS

#events_partial {
    min-height: 385px !important;
    margin-top: 57px;
    overflow: hidden;
}
.set-max-height {
    max-height: 385px !important;
    padding-top: 30px !important;
}

.sec-container {
    overflow: hidden !important;
    min-height: 200px;
}

#secDetails {
    position: absolute;
    margin-top: 0px;
}

JS

var animateTime = 50000; //kept varying time because as number of items increases the speed time decreased
var shouldAnimate = true;
if ($("#secDetails .container").length < 4) {
    shouldAnimate = false;
}
if ($("#secDetails .container").length >= 4 && $("#secDetails .container").length < 9)
    animateTime = 10000;
function marqueePlay() {
   if (shouldAnimate) {
       $("#secDetails").animate(
       {
            top: $("#events_partial").height() - $("#secDetails").height(),
            opacity: 1
       }, animateTime, function () {
             $("#secDetails").css("top", 1);
             $("#secDetails").css("opacity", 1);
             marqueePlay();
       });
    }
}
marqueePlay();
$("#secDetails").hover(function () {
    $(this).stop(); //Stop the animation when mouse in
},
function () {
    marqueePlay(); //Start the animation when mouse out
});

Any help much appreciated.

1

There are 1 answers

6
Tahir Ahmed On BEST ANSWER

Here is what I have been able to understand.

The Problem:

  • There is a default ease in action that you want to get rid of. The slow start, mid fast and slow ending in an animation is one of the different easing that can be applied to an animation. In your case, you clearly do not want it and you would want things to animate in a very linear fashion.
  • There is no direct way of resuming a jQuery animation that I know of. So after stopping the animation on hover, when you call marqueePlay() again, it will try to animate the remaining distance in the time defined in animateTime variable. Distance gets reduced, but time gets re-applied. Hence, your animations seems to travel slower for a little time then gets back to normal speed. It just seems that way but in fact, it behaves exactly as it should.

The Proposed Solution:

  • Based on my understanding above, your linear animation can very easily be achieved using requestAnimationFrame API.
  • Avoiding animate() method of jQuery allows us to easily pause & resume our animations using a simple boolean flag.

Below is the snippet in action or if you are interested in viewing it as a jsFiddle.

Snippet:

// [http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/]
window.requestAnimFrame=(function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(callback){window.setTimeout(callback,1000/60);};})();
var secDetails=$('#secDetails');
var container=secDetails.find('.container');
var eventsPartial=$('#events_partial');
var currTop=0;
var destTop=eventsPartial.height()-secDetails.height()-parseInt(eventsPartial.css('margin-top'));
var isPaused=false;
var isFirstLoop=true;
var speed=1;
if(container.length>=4&&container.length<9){
 requestAnimFrame(render);
 secDetails.hover(function(){isPaused=true;},function(){isPaused=false;});
 currTop=destTop;
}
function render(){
 requestAnimFrame(render);
 if(!isPaused){
  secDetails.css({transform:'translate3d(1px,'+roundDecimal(currTop,2)+'px,0px)'});
  currTop+=!isFirstLoop?-speed:speed;
  if(currTop>0) isFirstLoop=false;
  if(currTop<=destTop) currTop=0;
 }
}
function roundDecimal(value,place){ return Math.round(value*Math.pow(10,place))/Math.pow(10,place); }
#events_partial {
 min-height: 385px !important;
 margin-top: 57px;
 overflow: hidden;
}
.set-max-height {
 max-height: 385px !important;
 padding-top: 30px !important;
}
.sec-container {
 overflow: hidden !important;
 min-height: 200px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="events_partial" class="container body-content col-md-12 col-lg-12 set-max-height">
 <div class="row sec-container" id="secContainer">
  <div id="secDetails">
   <div class="container">
                <h3><strong> Program in Place 1 &nbsp;on&nbsp;11/22/2015</strong></h3><p>Program Description which is a very long text on document and it can be more than 2 lines</p>
   </div>
   <div class="container">
    <h3><strong> Program in Place 2 &nbsp;on&nbsp;11/22/2015</strong></h3><p>Program Description which is a very long text on document and it can be more than 2 lines</p>
   </div>
   <div class="container">
    <h3><strong> Program in Place 3 &nbsp;on&nbsp;11/22/2015</strong></h3><p>Program Description which is a very long text on document and it can be more than 2 lines</p>
   </div>
   <div class="container">
    <h3><strong> Program in Place 4 &nbsp;on&nbsp;11/22/2015</strong></h3><p>Program Description which is a very long text on document and it can be more than 2 lines</p>
   </div>
   <div class="container">
    <h3><strong> Program in Place 5 &nbsp;on&nbsp;11/22/2015</strong></h3><p>Program Description which is a very long text on document and it can be more than 2 lines</p>
   </div>
   <div class="container">
    <h3><strong> Program in Place 6 &nbsp;on&nbsp;11/22/2015</strong></h3><p>Program Description which is a very long text on document and it can be more than 2 lines</p>
   </div>
   <div class="container">
    <h3><strong> Program in Place 7 &nbsp;on&nbsp;11/22/2015</strong></h3><p>Program Description which is a very long text on document and it can be more than 2 lines</p>
   </div>
   <div class="container">
    <h3><strong> Program in Place 8 &nbsp;on&nbsp;11/22/2015</strong></h3><p>Program Description which is a very long text on document and it can be more than 2 lines</p>
   </div>
  </div>
 </div>
</div>

Let me know if anything is unclear.

P.S. Although personally, I don't like the sudden jump that happens when it reaches the bottom-most and then brings the first-one into display again and starts animating again. But I can understand that it is a requirement in your scenario, perhaps it just fits to be this way. It is a taste thing. I would have had them moving up and down animating like a yoyo if I had it my way ;).

Update: Here is your yoyo jsFiddle. Also forgot to mention that you can control the speed of the animations using the speed variable in the code. Hope this helps.