Don Rhummy
Don Rhummy

Reputation: 25890

Why is this animation choppy and sometimes have long delay before it executes?

This jquery animation is very choppy in firefox and in both firefox and chrome it frequently has a noticeable delay (~1 second) before it actually starts animating (if I put code to write out tot he console when the onclick handler is called, that will show up immeadiately, but the animation call will have a delay). This delay is not every time, but if you click maybe 5-6 times, you'll see it at least once.

<!doctype html>
<html>
    <head>
    <title>Test Lag</title>

    <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>

    <style>
        .base
        {
            position: absolute;
            top: 507px;
            left: 0px;
            width: 1000px;
            height: 40px;
            z-index: 0;
        }

        .one
        {
            position: absolute;
            top: 2px;
            left: 2px;
            width: 994px;
            height: 34px;
            background-color: #ffffff;
            border: solid 1px #505050;
            z-index: 3;
            opacity: 0.5;
            filter: alpha(opacity=50);
        }

        .oneA
        {
            position: absolute;
            top: 0px;
            left: 0px;
            width: 966px;
            height: 6px;
            margin: 10px;
            background-color: #999999;
            border: solid #cccccc 4px;

        }

        .two
        {
            position: absolute;
            top: 1px;
            left: 1px;
            width: 996px;
            height: 36px;
            background-color: #e8e8e8;
            border: solid 1px #505050;
            z-index: 2;
            opacity: 0.25;
            filter: alpha(opacity=25);
        }

        .three
        {
            position: absolute;
            top: 0px;
            left: 0px;
            width: 998px;
            height: 38px;
            background-color: #e8e8e8;
            border: solid 1px #505050;
            z-index: 1;
            opacity: 0.12;
            filter: alpha(opacity=12);
        }

        .four
        {
            position: absolute;
            top: 17px;
            left: 17px;
            width: 966px;
            height: 6px;
            background-color: #e8e8e8;
            z-index: 0;
            opacity: 0.5;
            filter: alpha(opacity=50);
        }

        .five
        {
            position: absolute;
            top: 17px;
            left: 17px;
            width: 966px;
            height: 366px;
            z-index: 4;
            overflow: hidden;
        }
    </style>
    </head>
    <body>

    <div id ="base" class="base">
        <div id="one" class="one">
        <div id="oneA" class="oneA"></div>
        </div>
        <div id="two" class="two"></div>
        <div id="three" class="three"></div>
        <div id="four" class="four"></div>
        <div id="five" class="five">There's some text in here.</div>
    </div>

    <script>
       var isOn = false;

       var jq_base = $('#base');
       var jq_one = $('#one');
       var jq_oneA = $('#oneA');
       var jq_two = $('#two');
       var jq_three = $('#three');
       var jq_four = $('#four');

       var baseTop = 96;
       var baseStartTop =507;

       var baseHeight = 400;
       var oneHeight = 394;
       var oneAHeight = 366;
       var twoHeight = 396;
       var threeHeight = 398;
       var fourHeight = 366;

       var baseStartH = 40;
       var oneStartH = 34;
       var oneAStartH = 6;
       var twoStartH = 36;
       var threeStartH = 38;
       var fourStartH = 6

       document.onclick = function()
       {
           //It's opened
           if ( isOn )
           {
               jq_one.animate( { height: oneStartH }, { duration: 300, queue: false } );
               jq_oneA.animate( { height: oneAStartH }, { duration: 300, queue: false } );
               jq_two.animate( { height: twoStartH }, { duration: 300, queue: false } );
               jq_three.animate( { height: threeStartH }, { duration: 300, queue: false } );
               jq_four.animate( { height: fourStartH }, { duration: 300, queue: false } );
               jq_base.animate(
                   { height: baseStartH },
                   {
                       duration: 300,
                       queue: false,
                       step: function (now)
                       {
                           if ( now <= ( baseStartH + 10 ) ) jq_base.animate( { top: baseStartTop }, 800 );
                       }
                   }
               );

               isOn = false;
           }

           //It's closed
           else
           {
               jq_base.animate(
                   { top: baseTop },
                   {
                       duration: 800,
                       step: function (now)
                       {
                           if ( now <= 100 )
                           {
                               jq_base.animate( { height: baseHeight }, { duration: 300, queue: false } );
                               jq_one.animate( { height: oneHeight }, { duration: 300, queue: false } );
                               jq_oneA.animate( { height: oneAHeight }, { duration: 300, queue: false } );
                               jq_two.animate( { height: twoHeight }, { duration: 300, queue: false } );
                               jq_three.animate( { height: threeHeight }, { duration: 300, queue: false } );
                               jq_four.animate( { height: fourHeight }, { duration: 300, queue: false } );
                           }
                       }
                   }
               );
               isOn = true;
           }
       }
    </script>
    </body>
</html>

DEMO: http://jsfiddle.net/fnswz/

Upvotes: 0

Views: 556

Answers (1)

nnnnnn
nnnnnn

Reputation: 150080

I think the problem is in the following part of the if (isOn) branch:

  jq_base.animate(
      { height: baseStartH },
      {
          duration: 300,
          queue: false,
          step: function (now)
          {
              if ( now <= ( baseStartH + 10 ) )
                 jq_base.animate( { top: baseStartTop }, 800 );
          }
      }
  );

Specifically, within the step function of that particular animate() call you start another animation with quite a long duration (800ms), and because it is in the step, even with the if test you are starting multiple animations with that long duration.

That means that although the process reaches a point where it looks finished because everything has moved to its final position, behind the scenes these extra animations haven't finished running and so it doesn't respond properly to subsequent clicks. If you move that 800ms animation out of the step function and simple put it afterwards it seems to make everything work much more smoothly. (At least, it seems much better in Chrome: as I said in my comment above I don't have FF on this computer so I can't test that.)

Here's a demo with the change I'm talking about: http://jsfiddle.net/fnswz/1/

You may want to set a flag animationRunning when you start the animation and then unset it using animate()'s complete callback, so that you can test the flag and ignore clicks until the current animation has finished, but just the change above made a big improvement for me.

(By the way, why are you using document.onclick = ... when you're using jQuery?)

Upvotes: 2

Related Questions