Search

Rss Posts

Rss Comments

Login

 

FX; Lightweight and Standalone Animation

January 22, 2009

Its one of those unnecessary things, but it sure does look pretty, I’m of course talking about animation. Flash or Javascript based, I find it adds that little some extra for the end-user’s experience; allowing them to fully understand the actions taking place by visually seeing components in transition. Most all mainstream libraries support animation in one way or another, and they are all quite impressive, despite the fact the core of each library essentially works the same.

If your anything like me then what your really looking for is something standalone. After googling for an extensive amount of time, I think I found five pretty good ones: Facebook animation, JSTweener, RUN, Bytefx, and Bernard Sumption’s Animator. These are all great solutions and fairly lightweight tipping in somewhere between 15 and 25 kb (uncompressed), and also support most of the bells and whistles found in the major Javascript libraries. The only knock against them is well actually, only a knock against Facebook’s version, simply because they decided to sniff out Firefox in just one segment of code, close but no cigar.

Now with no further delay, I present to you my version appropriately named FX. The motive here was to create a simple script for your basic animations and of course to be library independent, with emphasis on lightweight. Where I have strayed away from the other solutions I mentioned above is that I’ve stripped out most of the extra features, electing instead for the core functionality. The syntax is similar to that which you would find in YUI, I find it simple yet covers all the bases pretty well. I drew inspiration for the programming behind it from Mootools due to its simplicity as a whole. To use it is pretty simple; just tell it what to do, give it a duration, optional callback, and then let it fly.

Features

  • Perform tween on almost all CSS properties
  • Supports both scroll and color animations
  • Allows for both to and from values for each attribute
  • Supports transitional easing
  • Optionally assign a callback and context to execute the function in upon animation completion
  • Supports IE6+, FF, Opera, Safari, and Chrome
  • No browser detection

Example

The syntax is pretty straigth forward, as I mentioned before it looks similar to what you would find in YUI. The following example demonstrates just some of the attributes supported for animation. For a more impressive sampling of FX, see this example.

var fx = new FX('element', {
    'top': {to: 500},
    'left': {to: 300},
    'width': {from: 100, to: 300},
    'height': {from: 100, to: 200},
    'scrollLeft': {from: 0, to: 50},
    'background-color': {from: '#FF0000', to: '#0000FF'}
}, 1.5, callback, context);
 
fx.start();

At the moment, only pixels are supported as the default units for all animations, and there is only one type of transitional easing available. At some later point in time I will be updating to add support for both of these features, so check back soon!

Download

12 Comments

  1. whatUwant
    Mar 12 at 5:47 AM

    this is really wonderful
    thank you

  2. Apr 23 at 3:04 PM

    Wonderful code.

    Like you, I think it is important the emphasis on lightweight and the independence.

    I would like to make some suggestions that could be used to optimize the parseColor function.

    In the current version the JavaScript engine must recompile the regexps each time you invoke that function. It would be better to put the regexps outside the body of the function and use the exec method inside:


    var colorRegExp1 = /^#?(\w{2})(\w{2})(\w{2})$/;
    var colorRegExp2 = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/;
    var colorRegExp3 = /^#?(\w{1})(\w{1})(\w{1})$/;
    var parseColor = function(str){

    var rgb = colorRegExp1.exec(str);
    if(rgb && rgb.length == 4){
    return [parseInt(rgb[1], 16), parseInt(rgb[2], 16), parseInt(rgb[3], 16)];
    }

    rgb = colorRegExp2.exec(str);
    if(rgb && rgb.length == 4){
    return [parseInt(rgb[1], 10), parseInt(rgb[2], 10), parseInt(rgb[3], 10)];
    }

    rgb = colorRegExp3.exec(str);
    if(rgb && rgb.length == 4){
    return [parseInt(rgb[1] + rgb[1], 16), parseInt(rgb[2] + rgb[2], 16), parseInt(rgb[3] + rgb[3], 16)];
    }

    };

  3. Ryan Morr
    Apr 23 at 3:13 PM

    @joseanpg

    That’s a very good point I must have glossed over. I plan to release a second version sometime in the near future, I’ll definitely include your suggestion, thanks for the tip!

  4. Andres
    May 21 at 10:13 AM

    Hey, would you consider adding more transition functions? That is the only thing it’s stopping me from using your library.

  5. Ryan Morr
    May 21 at 4:50 PM

    @Andres

    I will be adding support for a variety of transitional easing functions in the next version which will be along sometime this summer.

    In addition to that (for anyone else who is interested) the next version will include support for units (px, em, %, etc.), support for Safari 2, and various other performance optimizations such as what joseanpg suggessted.

  6. May 26 at 11:05 AM

    I remember when my framework was light weight.. oh the good old days.. I didn’t hate IE back then

  7. Kim Wang
    Jun 15 at 9:16 PM

    The FX function should be changed to

    this.FX = function(el, attributes, opt) {
    this.el = DOM.get(el);
    this.attributes = attributes;
    this.duration = opt.duration || 0.7;
    this.tweenType = opt.tweenType || “Sine”;
    this.easeType = opt.easeType || “easeInOut”;
    this.callback = opt.callback || function() { };
    this.ctx = opt.ctx || window;

    /**
    * The object to carry the current values for each frame
    * @type Object
    */
    this.frame = {},

    /**
    * The object containing all the ending values for each attribute
    * @type Object
    */
    this.endAttr= {},

    /**
    * The object containing all the starting values for each attribute
    * @type Object
    */
    this.startAttr= {};
    };

  8. Ryan Morr
    Jun 16 at 6:21 PM

    @Kim Wang

    I see what your driving at… you want easing capabilities, don’t worry, its coming.

    Aside from that, I don’t see much difference between your implementation and mine other than moving “frame”, “endAttr”, and “startAttr” into the constructor.

    Not sure what the difference is. Is their a particular reason why you’ve done this?

  9. Kim Wang
    Jun 16 at 8:36 PM

    var fx1 = new FX(‘bar1′, {
    ‘left’: { from: 0, to: 100 }
    });
    fx1.play();

    var fx2 = new FX(‘bar2′, {
    ‘left’: { from: 0, to: 150 }
    });
    fx2.play();

    Here, a property called frame is a pointer to an Object containing one style “left” with value 100.
    Because frame is a reference value, both instances of FX point to the same Object. This means that when
    “150” is added to fx2.frame, it is also reflected in fx1.frame.

  10. Ryan Morr
    Jun 17 at 8:06 PM

    @Kim Wang

    Honestly, not only can I not believe I didn’t notice that, but I’m not sure I ever even knew that. Apparently I don’t know JavaScript prototypes as well as I thought I did.

    I would consider this a bug, and therefore will not wait until version 2 to make this change.

    Thanks for the heads up!

  11. Jul 07 at 12:35 AM

    Hi Ryan,

    It looks like the link to compressed.js is down, when you have a moment could you look into this?

    Thanks
    Alex

  12. Ryan Morr
    Jul 07 at 9:55 AM

    @Alexander

    The link seems to work for me. You might want to try downloading the newer version of this framework just released a few days ago.

Post a comment