Shadow Motion Effect in 5 Lines Of jQuery

written by aext on April 22, 2010 in Javascript with 96 comments

Who doesn’t love motion effects, right? shadows following the motion of movements while in a fighting scene, some of my favorite scenes are from The Matrix, Kung Fu Hustle, etc. I don’t event know how this effect is called, but sure is an awesome effect. The good news is that now-a-days we can create animations and play with them. It’s no an easy task to control distance and motion (the complex the code, the better control). The amazing part is that something like this can be done with 5 lines of jQuery!

Starting from a simple jQuery animation


If you are cool or at least have worked with jQuery, you can easily implement this animation. I will do an example with a moving ‘dot’ from left to right using animate() function:

$("#ball").stop(true).animate({left:500}, 1000).animate({left:0}, 1000);

The result:

 

The dot you see above was created using CSS3 (I’m sorry some IE users that I don’t have time for styling this ball, so you are viewing the ugly square. I’m really sorry!):

#ball {
    display: block;
    width: 80px;
    height: 80px;
    background: #333;
    -moz-border-radius: 40px; /* FF1+ */
    -webkit-border-radius: 40px; /* Saf3+, Chrome */
    border-radius: 40px; /* Opera 10.5, IE 9 */
    position: absolute;
    top: 50px;
    left: 50px;
}

Boring? Here is Shadow Motion


Basically, jQuery or even CSS3 doesn’t have any built-in effect or property to make shadows (I mean in plural, more than one shadow). When I watched some fighting scenes in movies, and I wondered, can jQuery can do something like it?

parsons-dance-company-man-flying

Oh yeah! jQuery can create this effect. The trick is here: lets create some images then make it follow the first animation and fadeout… NOPE, no this way. Lets look back at the example above. jQuery have a function named clone(). The .clone() method is a convenient way to duplicate elements on a page. Use this method, you can duplicate a specific element into many copies. Please note that it doesn’t make sense when we duplicate to many html elements with the same ID attribute. The best way is use class name for the element instead. However, it doesn’t mean we don’t have any way to duplicate the element by ID.

In this case, I will remove it and set a name for class attribute (remember to create css style for new class name):

$("#ball").clone().removeAttr("id").attr({class:"ball"})
                   .appendTo("#demo");

I’ve tried to duplicated ball in specific numbers. However, the motion depends on the speed of the main element. That’s how we will control the duplicated elements by the time. If the motion is moving fast, we will duplicate it fast, and, if the motion is moving slowly, we’ll need one or two frames duplicated… You need jQuery Timer to do such thing.

In each instance of time, we’ll make one copy.

$("#ball").everyTime(80, function() {  

    $("#ball").clone().removeAttr("id").attr({class:"ball"})
                   .appendTo("#demo")
                   .everyTime(480, function() {
                    $(this).remove();
    });

});  

$("#ball").stop(true).animate({left:500}, 1000)
          .animate({left:0}, 1000, function(){

                $("#ball").stopTime();

}); Â

The code above will duplicate one copy every 80 milliseconds. But if don’t break the clone method, you will have have enough balls for Olympic games in 100 years. Inside the everyTime(), I call again this method but restrict it in every 480 ms to remove the duplicated one. Let count, we will have 6 (480/80) copies go after the main element.

The result:

 

Almost there, Lets do the fadeout effect.

$("#ball").everyTime(80, function() {

    $(this).animate({left:500}, 1000).animate({left:0}, 1000);

    $(this).clone().removeAttr("id").attr({class:"ball"})
           .appendTo("#demo").fadeOut(480, function() {
                $(this).remove();
    });

});

The final result:

 

To control the time for duplicating, you can also use window.setInterval(); to replace the everyTime() method.

Boring? See, this is ajax loading effect!! (Windows user please see here)

 

The code:

function animateit() {

    var deg=0;
    var dif=3;

    var centerX;
    var centerY;

    centerX = $('#demo4').width()/4+20;
    centerY = $('#demo4').height()/2;

    $("#ball4").everyTime(1, function(){

        /* Increment the angle: */
        deg+=dif;

        /* Calculate for the animation in circle */
        var eSin = Math.sin(deg*Math.PI/180);
        var eCos = Math.cos(deg*Math.PI/180);

        /* Setting the css properties */

        $(this).css({
            top:centerX+120*eSin,
            left:centerY+120*eCos
        });
    });

    /* Setting up new timer for shadow with 10 shadows in total */              
    $("#ball4").everyTime(80, function() {
        $(this).clone().removeAttr("id").attr({"class":"ball"})
               .appendTo("#demo4").fadeOut(800, function() {
                            $(this).remove();
          });
    });

}

Bug?


Yes, the ugly truth about this bug is processor usage. The weird is it happens only with Windows OS even when I’m running a 8Gbs ram machine (Windows 7) – the same with Windows Vista. However, the animation works very well in Mac OS. If you are a Windows user and not happy with what you see here, you can check it via Mac screenshot below.

Any suggestion for a better CPU usage optimization in Windows would be appreciated.

What do you think?


This effect can be used for any animation if you want to implement the shadow motion (I’m not sure if the term I’m using is correct… please help me on getting a proper name). Any suggestion for better control would be appreciated! This tutorial is just providing you an idea for such animation with jQuery. I’ll work on optimize this effect, maybe I will write a little more, then probably publish the plugin. If you want to contribute a suggestion, please do so by commenting, Cheers!