Matt Snider JavaScript Resource

Understanding JavaScript and Frameworks

Saturday, May 10, 2008

Development Tools Revisited

I went through today and revisited my first article, Development Tools. With the advent of new browser versions and the plethora new development tools, plus improvements on existing tools, it was definitely time to take another look. Most notably, I mention two new browsers IE 8 and FireFox 3, development tools for those browsers, and development tools for Opera and Safari 3.

I have also spent some time working on the Visual Graphing tool, adding a title and the ability to subscribe to Custom Events. I have created a new test page, where I will keep my most up-to-date beta code-base, and will be updating it occasionally.

posted by Matt Snider at 11:33 pm  

Wednesday, May 7, 2008

Visual Graphing in JavaScript

While on vacation, I took some time to have fun writing a JavaScript tool that I have never seen before. While on the plane, I decided to explore graphing in JavaScript, using the old-school TI-85 as a visual model. Even though, I never seen this done before, JavaScript is a fast language and the only reason it may have not already been written, is a lack of purpose. Nevertheless, I felt writing this application was fun exercise and an opportunity to explore writing a graphing program.

To start, we have to consider the how to draw the graph that we will be drawing lines on. We need to draw the x and y axises, and the tick marks on those axises. By default, I assumed that most people would be use a square DOM element, but it can be configured to use rectangular shaped elements as well. When instantiating a new instance of the Grapher, use the following:

Example 1: Instantiating Grapher

var graphNode = $(’graph’); var config = { equation: ‘-5 + Math.pow(x, 2)’, // default is ” tickFreq: 10, // default xRange: 10, // default yRange: 10 // default }; var graph = Core.Widget.Grapher(graphNode, config); graph.redraw();

In this example, the graph will range from -10 to 10 x and y, showing a tick my every other even value in those ranges, which happens to be the defaults assumed by the Object. To support this, the graphNode element need only be square; the Object will manage scale. We are also passing in a default equation so a line is initially drawn with the graph.

Inside the Object, we have several internal objects: ‘node’ (the graph DOM), ‘config’ (configuration of graph), ‘points’ (array of line points), and ‘that’ (the closure safe scope); 5 constants for the axis styles, point styles, and tick styles; and two helper Functions: one to clear the graph complete (’clearGraph’) and the second to only clear the points of the current line (’clearPoints’). The ‘clearGraph’ method removes everything from the graph DOM, and the ‘clearPoints’ method iterates through each point and removes them, while leaving the graph intact.

Example 2: Private Helper Functions

/** * Clears all graph related DOM nodes. * @method clearGraph * @private */ var clearGraph = function() { while (node.firstChild) { node.removeChild(node.firstChild); }; }; /** * Clears all graph point DOM nodes. * @method clearPoints * @private */ var clearPoints = function() { for (var i = points.length - 1; 0 <= i; i -= 1) { points[i].parentNode.removeChild(points[i]); } points = []; };

When the page first loads, or the graph DOM first becomes available, we need to make it look more like a graph. For this reason, there is a private method ‘drawGraph’, that calls ‘clearGraph’, then rebuilds the nodes that causes the DOM to look like a graph:

Example 3: Drawing the Graph

/** * Draws the actual graph: axis’ and ticks. * @method drawGraph * @private */ var drawGraph = function() { clearGraph(); var xAxis = node.appendChild($D.createTag(’div’, {style: XAXIS})); var yAxis = node.appendChild($D.createTag(’div’, {style: YAXIS})); Dom.setStyle(xAxis, ‘top’, config.region.top + config.yMid + ‘px’); Dom.setStyle(xAxis, ‘left’, config.region.left + ‘px’); Dom.setStyle(xAxis, ‘width’, config.width + ‘px’); Dom.setStyle(yAxis, ‘top’, config.region.top + ‘px’); Dom.setStyle(yAxis, ‘left’, config.region.left + config.xMid + ‘px’); Dom.setStyle(yAxis, ‘height’, config.height + ‘px’); for (var i = 0; i < config.tickFreq; i += 1) { var xTick = node.appendChild($D.createTag(’div’, {style: XTICK})); var yTick = node.appendChild($D.createTag(’div’, {style: YTICK})); Dom.setStyle(xTick, ‘left’, config.region.left + config.xTickStep * (i * 2) + ‘px’); Dom.setStyle(xTick, ‘top’, config.region.top + config.yMid - (config.tickFreq / 2) + ‘px’); Dom.setStyle(yTick, ‘left’, config.region.left + config.xMid - (config.tickFreq / 2) + ‘px’); Dom.setStyle(yTick, ‘top’, config.region.top + config.yTickStep * (i * 2) + ‘px’); } };

Once the DOM is clear, we create the x and y axises using the internal ‘config’ Object where we store many cached values about the DOM node and other values computed when the graph Object is instantiated. Both axises are lines that are positioned in the center of the node according to their respective dimension, and the height/width of the graph DOM node. Then we iterated through the tick frequency count and add the tick marks along the axises.

Finally, we need a method to draw lines according to a provided equation containing 1 or more ‘x’. For now, we simply eval the equation, but I intend to validate the equation to only support ‘+’, ‘-’, ‘/’, ‘*’, ‘%’, and all methods on the Math Object. Here is the method to draw the line:

Example 4: Drawing the Line

/** * Draws the line for the equation in a given color. * @method drawLine * @param eq {String} Required. The equation to draw. * @param color {String} Optional. The color of the line. * @private */ var drawLine = function(eq, color) { // iterate on the posible x points, stop when limit is reached or y exceeds grid for (var i = 0; i < config.width; i += 1) { var x = config.xStep * (config.xMid + (config.width > config.xMid ? -i : i)); var y = eval(eq.replace(/x/gi, -x).replace(’–’, ”)); var y2 = config.yMid - (y * config.yTickStep); // stop when exceeding graph range if (y > config.yRange || y < -config.yRange || isNaN(y)) {continue;}; var point = node.appendChild($D.createTag(’div’, {style: POINT})); Dom.setStyle(point, ‘left’, config.region.left + i + ‘px’); Dom.setStyle(point, ‘top’, config.region.top + y2 + ‘px’); if (color) { Dom.setStyle(point, ‘background-color’, color); } points[points.length] = point; } var k = points.length; // iterate on each point, determine if and fill all the y positions for (var j = 0; j < k - 1; j += 1) { var p1 = Dom.getRegion(points[j]); var p2 = Dom.getRegion(points[j + 1]); var useP2 = p2.top > p1.top; var diff = Math.abs(p2.top - p1.top); if (1 < diff) { for (var m = 1; m < diff; m += 1) { var left = m < diff / 2 && useP2 ? p1.left : p2.left; var top = (useP2 ? p1.top : p2.top) + m; var p = node.appendChild($D.createTag(’div’, {style: POINT})); Dom.setStyle(p, ‘left’, left + ‘px’); Dom.setStyle(p, ‘top’, top + ‘px’); if (color) { Dom.setStyle(p, ‘background-color’, color); } points[points.length] = p; } } } };

The method requires an equation and also excepts a color, if you wish to not use black to draw a line. This is forward thinking, so that, once I figure out the best way to do it, each graph will be able to support multiple lines. We iterate through each 1px in the width of the graph DOM node. So we first compute ‘x’ (value of x at pixel i), ‘y’ (value produced by the equation), and y2, the actual top position of the point. These values are rather tricky, because computing x changes depending on whether we are on the left or right of the y-axis, and computing y is done using eval and regex replaces. I learned that the equation ‘-x’ would throw an error computing ‘y’, because it had double negatives, so I fixed that using a simple regex.

When iterating, we ‘continue’ when the value of ‘y’ does not fit inside the configured range, then we create the point DOM node and position it (we would also color it, if a color was provided), and cache the point. Then we iterate through the points and fill in each pixel between point n and ‘n - 1′ when they are more than 1-pixel apart in the y-axis, creating a smooth line. Whichever point is higher determines which point to use as the top offset, and since each point is only 1-pixel separated on the x-axis, we also use the higher point to determine which pixel should be used for the ‘left’ style, depending on how close the fill point is to the point used for the ‘top’ style.

When you bring it all together, you get something like this example: Graph Test. I plan on making the graph colors more customizable, cleaning all equation strings to ensure no tomfoolery, additional graph stuff (like titles, legends, labels, etc.), and supporting multiple lines on a single graph.

posted by Matt Snider at 11:43 pm  

Sunday, April 27, 2008

removeNode and appendNode Methods

First, for everyone following the JavaScript Game Engine project, I am putting it on hold for now. Building an engine to support dynamic games requires a lot of work… a lot more more time than I currently have to devote to the project, and I do not want to release code of questionable quality. I will, however, revisit it from time to time and complete the article series as I am able.

For todays article, I would like to introduce two of my favorite DOM extension methods, “removeNode” and “appendNode”. They are basically, simple wrappers for “removeChild” and “appendChilde” with the added functionality to animate the addition/removal of a DOM nodes. I find these methods to be very useful in providing feedback to a user when they are taking an action that modifies the DOM. Most of the time (and the default animation of this method) an opacity fade does the trick, making the addition/removal of a DOM node tangible to the user, but sometimes you need a different animation, so the methods accept animation arguments as optional parameters. I build these methods on top of YUI animator and either add them to the “YAHOO.util.DOM” or Document Object.

Example 1: AppendNode

Document.appendNode = function(root, elem, ap, fn) { var node = $(elem), parent = $(root); if (parent && node) { parent.appendChild(node); var animParams = (isType(ap, ‘object’)) ? ap : {opacity: {from: 0.25, to: 1}}, anim = new YAHOO.util.Anim(node, animParams, 0.5, YAHOO.util.Easing.easeIn); anim.onComplete.subscribe(function() { if (fn && isType(fn, ‘function’)) {fn(node);} }); anim.animate(); } return node; };

The “appendNode” method has two required parameters: the ‘root’ element to append to, and the ‘node’ to append with. As usual, I have written the “YAHOO.util.Dom.get” method as the ‘$’ shortcut method. By default the method will animate with a fade in from 0.25 opacity to 1 opacity, but you can override it by passing in your own arguments for YUI animation. If you want an event to occur after the animation, then provide a Function as the last argument, however it is also not required; this Function will be passed the newly appended ‘node’ as its only parameter.

Example 2: RemoveNode

Document.removeNode = function(elem, ap, fn, isRemoveListeners) { var node = $(elem), parent = node.parentNode; if (parent) { var animParams = (isType(ap, ‘object’)) ? ap : {opacity: {from: 1, to: 0.25}}, anim = new YAHOO.util.Anim(node, animParams, 0.5, YAHOO.util.Easing.easeOut); if (isRemoveListeners) {Event.purgeElement(node, true);} anim.onComplete.subscribe(function() { parent.removeChild(node); if (fn && isType(fn, ‘function’)) {fn();} }); anim.animate(); } };

The “removeNode” method is very similar to the “appendNode” method, with the noted exception that the animation must occur before the actual removal of the child-node. You do not need to pass in the ‘root’ Element as we can extract that directly from the provided node. Lastly, if you have attached any listeners to the node or its children, you should probably remove them. I leveraged YUIs “YAHOO.util.Event.purgeElement” (shortcut name of “Event.purgeElement”) method for this, which will recursively remove the events attached to your node and its children, when you pass true as the last parameters (isRemoveListeners), otherwise no events will be removed.

Again, these methods are simple, but very handy. I have found it is almost always useful to provide feedback to users when they are adding/removing DOM nodes, and these methods abstract the logic away, so that I can do just about anything I need. If you’d like to give them a try, I have provided a test page.

posted by Matt Snider at 12:34 pm  

Wednesday, April 23, 2008

News: Ext Gotcha and YUI Hidden Gems

Unfortunately, I am too busy this week to finish the game project that I have been working on. Not wanting to leave you all hanging, I found some noteworthy news:

Ext JS 2.1 Now GPL (was LGPL)

Basically, this means that if you modify the Ext Framework and use it on your project, then your project is also under the GPL license. For more information, check out what Dietrich Kappe wrote on Agile Ajax, Ext JS 2.1 Now GPL (was LGPL).

Hidden Gems in the YAHOO Object

There is a lot of useful functionality attached directly to the YAHOO Object that has not been well noted. Find out more on the YUI Blog, Hidden Gems in the YAHOO Object.

posted by Matt Snider at 4:55 pm  

Sunday, April 20, 2008

Game Menu

For the game project, I felt it would be prudent to have a menu that handles the control of the game engine. For this task, I have decided to use YUI Menu, because I know YUI well, and it is powerful, extendable, and easy. One of the great things about the YUI is the plethora of examples about how to use it, including the menu widget. You can also reference the JavaScript directly from the YUI site, so there is no need to maintain them yourself, or worry about versions.

Example 1: Files Needed For YUI Menu

<link rel=”stylesheet” type=”text/css” href=”http://yui.yahooapis.com/2.5.1/build/menu/assets/skins/sam/menu.css”/> <script type=”text/javascript” src=”http://yui.yahooapis.com/2.5.1/build/yahoo-dom-event/yahoo-dom-event.js”></script> <script type=”text/javascript” src=”http://yui.yahooapis.com/2.5.1/build/container/container_core-min.js”></script> <script type=”text/javascript” src=”http://yui.yahooapis.com/2.5.1/build/menu/menu-min.js”></script>

Since, YUI does such a good job documenting how to use their widgets, there isn’t a need to say much about them. The Yahoo developer site has examples showing how to create menus from markup, JavaScript, or some combination of both. I choose the last option, using markup to design the root menu, and JavaScript to build the submenus. You need to apply the class “yui-skin-sam” to the body tag and various other classes to your menu widget, depending on what type of menu you are making. I choose the “Application Menubar” styles, positioning the widget statically at the top left of the page. Give my menu a try:

Game Menu

One important thing to note, is that if you dynamically updating the menu items, as I do when checking and disabling menu items, make sure that lazy-loading is set to false, otherwise, you will find that parts of your menu are undefined.

My menu is still very basic, but does most of what I expect I will want for the game engine. You can start a new game or restart an existing one, change the resolution, or exit the game. Starting a new game will bring up an empty game board, sized 640 X 480, while restart will bring up a new, empty game board that is the same size as the existing window. I am leveraging the ‘disabled’ flag for the menu, so that certain options, such as resolution and restart are not available until the game has started. I also use the ‘checked’ flag, so that you the resolution menu shows which resolution is selected. The view -> resolution menu item allows you to resize the gameboard to the various supported sizes for the game (right now I threw in some test sizes). The exit game doesn’t do anything for now. I’m not sure what it really will do, unless I implement some type of login feature. Lastly, you can add help text to the menus, which I have used to indicate what possible shortcut keys trigger the menu items, although I haven’t wired them up yet.

posted by Matt Snider at 12:49 pm  

Thursday, April 17, 2008

News: Collection of JavaScript Tools And More

I was impressed to see that Smashing Magazine, an online designer magazine, choose to feature a collection of JavaScript resources this week. Some of them are really useful:

60 More AJAX- and JavaScript Solutions For Professional Coding

Douglas Crockford revisited global variables and decided to change his definition of best practices. The gist of which is, instead of using “var foo = ‘value’;” in the global space, you should use:

/*global foo*/ foo = {};

Find out more: Global Domination, Part Two

posted by Matt Snider at 4:42 pm  

Tuesday, April 15, 2008

Document CreateTag Method

As I worked on the GameEngine improvements, I realized that it would be nice to have a menu and several other DOM elements. Since the engine will be standalone, it is necessary to dynamically create the DOM elements required to run the game. For this task, I have use a method “document.createTag()”, which I often refactor for various projects. In its most basic form, it looks like the following:

Example 1: document.createTag

YAHOO.lang.augmentObject(document, { /** * Creates and returns an html element and adds attributes from the hash. * * @method createTag * @param tagName {String} Required. Tag name to create. * @param h {Object} Optional. The hashtable of attributes, styles, and classes; defaults is empty object. * @return {Element} The newly created element; returns null otherwise. * @static */ createTag: function(tagName, h) { var Dom = YAHOO.util.Dom, node = document.createElement(tagName), hash = isType(h, ‘object’) ? h : {}; // iterate through the possible attributes for (var k in hash) { var v = hash[k]; k = k.toLowerCase(); if (isType(v, ’string’) || (’style’ === k && isType(v, ‘object’))) { switch (k) { case ‘classname’: case ‘klass’: case ‘class’: case ‘cls’: Dom.addClass(node, v); break; case ‘cellpadding’: node.cellPadding = v; break; case ‘cellspacing’: node.cellSpacing = v; break; case ‘colspan’: node.colSpan = v; break; case ‘checked’: case ‘disabled’: node[k] = v; break; case ‘rowspan’: node.rowSpan = v; break; case ’style’: // iterate through the style object for (var t in v) { var s = v[t]; if (isType(s, ’string’) || isType(s, ‘number’)) { Dom.setStyle(node, t, s); } }; break; case ‘innerhtml’: case ‘text’: if (isType(v, ’string’) && ! v.match(/< .*?>/) && ! v.match(/&.*?;/)) { node.appendChild(document.createTextNode(v)); } else { node.innerHTML = v; } break; default: node.setAttribute(k, v); break; } } }; return node || null; } });

To use this method, simply include it in your JavaScript source files, then call “document.createTag” passing in two parameters: 1st parameter is the tag name you wish to create, and the 2nd is an Object where the keys are tag attribute names and the values are the attribute values. Using a ‘for … in’ loop we iterate on each key in the Object, evaluating only those values that are strings and numbers, or an object in the case of the style attribute. The switch statement then, normalizes the keys, so the key ‘checked’ does the same thing as ‘cHeCkEd’, because capitalization does matter.

Over the years I have added each case of the switch statement based on issues experienced in various browsers. Most attributes seem to be applied just fine, when you use the ’setAttribute’ method, so this is the default case. Some attributes such as ‘checked’ and ‘disabled’ do not work in all browsers with ’setAttribute’, so they are applied only with dot notation. Some attributes such as ‘cellPadding’ and ‘cellSpacing’ are case-sensitive in certain browsers (and capitalizing them doesn’t break the browsers that lower-case worked in), and/or can only be applied via dot notation, so we special-case each of them. The word ‘class’ is a reserved word in at least IE, so you cannot do “object.class”, instead you need to use “object.className”, and this seems to be supported by all browsers; I also support various ways of storing the classname as a key, because different projects have different naming conventions. Style is a special-case that must contain an object, where the keys are style names, and the values are what you want to set the style to (strings and integers are acceptable). Lastly, the ‘text’ or ‘innerhtml’ key will attempt to append the provided value as a text node, unless the value: isn’t a string, contains HTML elements, or contains HTML special characters; in those cases it uses innerHTML, because it will render HTML and special characters correctly, while a text node will simply print the text as is.

Now, this method probably isn’t perfect, but it works with all the browsers that I have ever needed to support. Feel free to chime in, if you know of any other special-case situations or browsers that you believe this method won’t work with.

This solution is homegrown, and there may exist better DOM node creation methods, with more exposure and support. I know the Framework Ext.js has a DOM node creation method, and I wouldn’t be surprised if Dojo or jQuery have a plugin solution as well.

posted by Matt Snider at 9:46 pm  

Monday, April 14, 2008

Sliding Puzzle Game Using Movable

So, as promised, I will be showcasing a game today that makes use of the Movable Object from last Tuesdays article. I had hoped to get this article out earlier, but my old game engine was too sloppy to use. Instead, I hacked together a new engine, but it is ‘hacked’ together and will currently only work with this game. I intend to experiment with the engine more this next week to see how abstract I can make it, or at least make each element extendable, and fire and listen for Custom Events.

The game is called Sliding Puzzle, this particular variant is called The Fifteen Puzzle. The game objective is to move 15 randomly placed tiles into and out of the one open space on a 4×4, 16-space board (there is 1 open space), until you have arranged them in order. I originally played this game on the 8-bit Nintendo Console, as The Fifteen Puzzle was a hidden, side-game in Final Fantasy One.

To make the game work, I wrote 3 new classes: GameEngine, GameBoard, and GameTile. The GameTile Object will manage the tiles, which wraps the Movable Object and needs to know its position on the board. The GameBoard manages all the tiles, handling tile movement and test for game completeness (win or lose states). The GameEngine should handle pre/post game user interaction, and initialize and manage the other objects. I also improved the Movable Object so that it can be limited to move about a DOM node or the viewport.

Unfortunately, much of the code is still hacked together and the Objects know too much about each other. I intend to work on cleaning the code up this week, but until then, here is a Fifteen Puzzle Game Demo.

posted by Matt Snider at 12:16 am  

Tuesday, April 8, 2008

Movable DOM Node Widget

One of my favorite pastimes is playing and collecting video games, which combined with another of my passions, JavaScript, drives me to figure out ways to port simple gaming engines into JavaScript. JavaScript is not the best language for writing such engines (at least not in the browser), so I do not spend much time on this. However, I had a little time and revisited an old project, replacing the ancient coding with some simple YUI calls. When I wrote this, I was thinking of the original Dragon Warrior game, where you had a character that moved around the screen.

Think of the black rectangle as the character. Using YUI animation utility and a custom Object ‘Movable’, I listen to arrow keydown events and trigger animations on Movable. Because YUI manages duplicate animations on the same style of an Element (preventing it, until the previous animation completes), this was much simpler than code I had previously written. Also, the YUI animation code allows for diagonal movement if you press two perpendicular arrow keys within the half-second animation period. Try moving the black box around the screen on the Movable Object Test Page. Here is the code for the Movable Object:

Example 1: Movable Class

Core.Widget.Movable = function(id, useAnim) { // Local Variables var F = function() {}, node = $(id), that = null, anim = null; // shortcut for viewport size var getWSize = Core.Client.getViewportSize; // Public Variables F.prototype = { /** * Move the object down. * * @method down * @public */ down: function() { var r = Dom.getRegion(node), w = r.bottom - r.top, o = r.bottom, s = getWSize(); // prevent exceeding viewport height if (s.y < o + w) {o = s.y - w;} if (useAnim) { anim = new YAHOO.util.Anim(node, {top: {to: o}}, 1, YAHOO.util.Easing.easeOut); anim.animate(); } else { Dom.setStyle(node, 'top', o + 'px'); } }, /** * Move the object left. * * @method left * @public */ left: function() { var r = Dom.getRegion(node), w = r.right - r.left, o = r.left - w; // prevent exceeding viewport width if (0 > o - w) {o = 0;} if (useAnim) { anim = new YAHOO.util.Anim(node, {left: {to: o}}, 1, YAHOO.util.Easing.easeOut); anim.animate(); } else { Dom.setStyle(node, ‘left’, o + ‘px’); } }, /** * Move the object right. * * @method right * @public */ right: function() { var r = Dom.getRegion(node), w = r.right - r.left, o = r.right, s = getWSize(); // prevent exceeding viewport width if (s.x < o + w) {o = s.x - w;} if (useAnim) { anim = new YAHOO.util.Anim(node, {left: {to: o}}, 1, YAHOO.util.Easing.easeOut); anim.animate(); } else { Dom.setStyle(node, 'left', o + 'px'); } }, /** * Move the object up. * * @method up * @public */ up: function() { var r = Dom.getRegion(node), w = r.bottom - r.top, o = r.top - w; // prevent exceeding viewport height if (0 > o - w) {o = 0;} if (useAnim) { anim = new YAHOO.util.Anim(node, {top: {to: o}}, 1, YAHOO.util.Easing.easeOut); anim.animate(); } else { Dom.setStyle(node, ‘top’, o + ‘px’); } } }; // Scoped Operations that = new F(); return that; };

The ‘Movable’ class is designed to work with any DOM node that is absolutely positioned and smaller than the viewport. Simply pass the DOM node as the first parameter and whether you want the movements to be animated as the second. There is any number of reasons that you may need an Element on a page that can move up and down, based on its size, so you needn’t only think of it as part of a gaming engine. Keep in mind that I have used shorthand notation for ‘YAHOO.util.Dom’ (Dom), and ‘YAHOO.util.Dom.get’ ($). This widget also requires that you include ‘core.js‘.

Lastly, if you want to have it animate on the page, like in my example, you will need to use YUI Event package to listen to all keydown events on the ‘document’. Here is the code that I used:

Example 2: Document Keydown Listener

Event.addListener(document, ‘keydown’, function(e) { var test = Core.Widget.Movable(obj, true); switch (Event.getCharCode(e)) { case 37: // left arrow test.left(); break; case 38: // up arrow test.up(); break; case 39: // right arrow test.right(); break; case 40: // down arrow test.down(); break; } });

Again, I have shorthanded the ‘YAHOO.util.Event’ package to just ‘Event’. This code simply listens for all keydown events, ignoring all but the arrow keys. When any key is fired, it calls the appropriate method on ‘Movable’, which then handles the movement.

Now, the next step of the engine is to have the Object move over something, such as a map or a game board, firing custom events that the engine listens to. My next article will show how the ‘Movable’ object can be used to build a simple game.

posted by Matt Snider at 10:45 pm  

Wednesday, April 2, 2008

JavaScript Gif-Like Animation

First, I like to say how much I hate spammers. I’d even start believing in the beyond again, if God would only reserve a special place in hell for spammers. 35,000 spam comments and counting… Because of this, I’d like to apologize in advanced if I accidentally delete one of your comments. Also, the first time you comment, it goes into an approval pool, so if you don’t see it right away, please give me a day or two to approve it.

I have been pretty busy prepping for a big announcement that we will be making at Mint.com this week, so I did not have as much time to prepare a blog article as I would have liked. So, I decided to have a little fun today and created a JavaScript driven GIF-Like animation tool.

The basic idea is that you take each frame that you would use in an animated GIF and instead create a separate GIF for each. The next step is to put an IMG tag on a page and set its source to the first image. Then at the end of the webpage inside a SCRIPT tag, instantiate GifAnimator, passing in the ID of the IMG tag as the first parameter, and an Array of image sources (your frames) as the second image. Then, go ahead and call the ’start’ method of your new GifAnimator Object to begin animation.

Example 1: Instantiating GifAnimator

<script type=”text/javascript”> var anim = new Core.Widget.GifAnimator(’animator’, [ ‘assets/images/animator/A.gif’, ‘assets/images/animator/B.gif’, ‘assets/images/animator/C.gif’, ‘assets/images/animator/D.gif’, ‘assets/images/animator/E.gif’, ‘assets/images/animator/F.gif’ ]); setTimeout(function() { anim.start(); }, 1000); </script>

Download GifAnimator.js and include it into your project to make Example 1 work. I have created a test page as well.

Hopefully, you will remember that I started this article by saying that I was playing. There is little reason to replace GIF animation with a JavaScript solution, as JavaScript timeouts are fairly inaccurate, and they have a tendency to pause every few seconds as the processor catches up with the browser.

posted by Matt Snider at 10:52 am  
Next Page »

Powered by WordPress