views:

635

answers:

2

I am trying to cause a block to "pulsate" between 100% opacity and some partially transparent opacity. I want to do this with the functionality that is built into the jQuery core, if possible. I would rather not add a plugin to get this effect. Here is the code that i am trying to use:

    $(document).ready(function() {
 function pulsate() {
  $("#pulsating-block").animate({opacity: 0.2}, 3000).animate({opacity: 1}, 3000, null, function() {pulsate()});
 }
 pulsate();  });

The problem is that each time the animation completes, it pauses for about a second before looping again. How can I keep it from pausing so that I get a smooth "pulsating" effect? (Note: the animation is exaggerated in this example to highlight the problem that I am having)

A: 

try

 function pulsate() {
      $("#pulsating-block").animate({opacity: 0.2}, 3000,function(){
          $(this).animate({opacity: 1}, 3000, null, function() {pulsate()});
      });
     }
Funky Dude
Thanks for the quick reply! Unfortunately, that doesn't seem to fix the problem I'm having. (You might be able to see the problem better if you reduce the duration to 500 milliseconds) The problem is that after returning to 100% opacity, the animation seems to stall before it begins to dim the duration again. The element stays at 100% opacity for about half or a whole second before it starts dimming again. It doesn't seem to pause at 20% opacity (which is how I want it to work).
Tim Mackey
+3  A: 

Perhaps your issue is with the "swing" easing function jQuery uses by default.

You might want to try the "linear" easing function instead:

$(document).ready(function() {
  function pulsate() {
    $("#pulsating-block").
      animate({opacity: 0.2}, 3000, 'linear').
      animate({opacity: 1}, 3000, 'linear', pulsate);
  }
  pulsate();
});

I've also coded up a small pulsate plugin that includes a "bounce" easing function that may be more to your liking. I should note that the plugin uses a continuous calculation to perform the animation, not two separate fade-in/fade-out animations, so it might help with the "pause" issue. (To be honest, I still don't see the pause you are talking about.)

Working Demo

http://jsbin.com/isicu (editable via http://jsbin.com/isicu/edit)

Full Source

JavaScript

(function ($) {
  $.fn.pulsate = function (properties, duration, type, speed, callback) {
    type = type || 'Swing'
    speed = speed || 'Normal';
    this.animate(properties, duration, 'pulsate' + type + speed, callback);
  };

  function createPulsateLinear (speed) {
    speed *= 2;
    return function (p, n) {
      return (Math.asin(Math.sin(Math.PI * n / speed)) + Math.PI / 2) / Math.PI;
    }
  }

  function createPulsateSwing (speed) {
    return function (p, n) {
      return (1 + Math.sin(n / speed)) / 2;
    }
  }

  function createPulsateBounce (speed) {
    speed *= 2;
    return function (p, n) {
      return (
        ((Math.asin(Math.sin(Math.PI * n / speed)) + Math.PI / 2) / Math.PI) *
        (Math.sin(Math.PI * n / speed) + 1) / -2 + 1
      );
    }
  }

  var speeds = {
    fast: 100,
    normal: 200,
    slow: 400
  }

  $.extend(jQuery.easing, {
    pulsateLinearFast: createPulsateLinear(speeds.fast),
    pulsateLinearNormal: createPulsateLinear(speeds.normal),
    pulsateLinearSlow: createPulsateLinear(speeds.slow),
    pulsateSwingFast: createPulsateSwing(speeds.fast),
    pulsateSwingNormal: createPulsateSwing(speeds.normal),
    pulsateSwingSlow: createPulsateSwing(speeds.slow),
    pulsateBounceFast: createPulsateBounce(speeds.fast),
    pulsateBounceNormal: createPulsateBounce(speeds.normal),
    pulsateBounceSlow: createPulsateBounce(speeds.slow)
  });
})(jQuery);

$(document).ready(function() {
  var
    pulsatingBlocks = $('.pulsating-block'),
    forever = 5 * 24 * 60 * 60 * 1000; // 5 days! (Which is forever in Internet time)

  pulsatingBlocks.filter('.opacity').each(function () {
    $(this).pulsate({opacity: 0.2}, forever, this.className.split(' ')[0], 'Slow');
  });

  pulsatingBlocks.filter('.top').each(function () {
    $(this).pulsate({top: 100}, forever, this.className.split(' ')[0], 'Slow');
  });

});

HTML

<!DOCTYPE html>
<html>
<head>
<script class="jsbin" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.js"&gt;&lt;/script&gt;
<meta charset=utf-8 />
<title>Pulsate</title>
<style>
  div { clear: left; margin-bottom: 2em; }
  .pulsating-block {
    width: 6em; height: 4em;
    margin: 0.5em; margin-right: 10em;
    float: left; clear: none; position: relative;
    background: lightblue;
    text-align: center;
    padding-top: 2em;
    font: bold 1em sans-serif;
  }
</style>
</head>
<body>
  <div>
    <div class="Linear opacity pulsating-block">linear</div>
    <div class="Swing opacity pulsating-block">swing</div>
    <div class="Bounce opacity pulsating-block">bounce</div>
  </div>
  <div>
    <div class="Linear top pulsating-block"></div>
    <div class="Swing top pulsating-block"></div>
    <div class="Bounce top pulsating-block"></div>
  </div>
</body>
</html>
brianpeiris
Thanks, Brian! Your function is exactly what I was trying to reach in the end. I wasn't sure how to write the code so that it could handle more than just opacity, but this does it! I'm a little embarrassed...It turns out that the problem I was seeing had nothing to do with the code, but rather with my monitor calibration(!). The example I was using was a black block fading in and out on a white background. My monitor was clipping off the lower range of blacks, and that made it look as if the animation stopped momentarily. Doh! Thank you, though, this script is exactly what I needed. Fantastic!
Tim Mackey
Glad I could help. I figured the problem was more visual than technical. Good job noticing that it was your monitor, that is one obscure "bug" :P
brianpeiris