Archive for the ‘Articles’ Category

March 9th, 2010 Comments Off
Tags: , , ,

Category: Articles

USAID Data Charted with Dojo

Dojo’s charting infrastructure has come quite a long way since I’ve looked at it several months ago, and since the first edition of Dojo: TDG didn’t include coverage of charting, I thought it might be fun to pick up an interesting data set from data.gov and wire together a modest demo. (And yes, the next edition of the book will definitely include coverage of charting and many other subprojects in DojoX.)

Click to view the demo

Click to view the demo

The data set I settled on is what appears to be a simple csv file of all USAID distributions. Since the spreadsheet was quite large, I coded up a small Python program to slice and dice the numbers in order to get familiar with the data. One of the first things I noticed is that the dollar figures all appear to be in “raw” form — meaning, that if there was a distribution in 1946 for $1,000 that figure is obviously not adjusted for inflation; it’s in “1946 dollars.” So, I harvested some CPI data from the Bureau of Labor Statistics and attempted to create a minimal inflation calculator so that I could get a better sense of the overall trends.

You can download my PyDev project if you are interesting in hacking on the data a little bit yourself. The one thing I’ll warn you about if you use the PyDev project in Eclipse is that you’ll probably need to change the project properties to point to your own modules, which may be installed into different locations. If you’re not familiar with PyDev, you may be better off just using easy_install to pick up any missing modules and run from the command line.

After I was satisfied that I understood the data reasonably well, I added a couple of functions to emit the CPI and USAID data as JSON for easy consumption by the ComboBox widgets that drive the chart.

It turns out that most of the demo is related to getting the proper data structures hacked out and managing the events that reload the chart. The code snippet to actually build the chart is pretty self-explanatory:

// create and configure the chart
chart = new dojox.charting.Chart2D("chart");
chart.setTheme(dojox.charting.themes.Minty);
chart.addAxis("x", {
    natural: true,
    includeZero: true,
    fixUpper: "minor",
    labelFunc : function(o) {
        return parseInt(o) + usaid.getMinYear()-1;
    }
});
chart.addAxis("y", {
    vertical: true,
    natural: true,
    includeZero: true,
    fixUpper: "minor",
    labelFunc : function(o) {
        return dojo.currency.format(o, {currency : "USD", places : 0});
    }
});
chart.addPlot("default", {type: "Columns", gap: 2});
//chart.addPlot("grid", {type: "Grid", hMinorLines: true, vMinorLines: true});
legend = new dojox.charting.widget.Legend({chart: chart}, "legend");

// add some nice action for the chart when you hover over columns
new dojox.charting.action2d.Highlight(chart, "default", {
    highlight: "green"
});
new dojox.charting.action2d.Tooltip(chart, "default", {
    text : function(o) {
        return ("FY" + (parseInt(o.x)+usaid.getMinYear()) + " : " +
               dojo.currency.format(o.y, {currency : "USD", places : 0}));
    }
});

The event-driven logic demo simply uses a couple of additional functions to remove and load a series into the chart though the Chart2D’s addSeries and removeSeries functions like so:

/* Add a series to the chart */
chart.addSeries("Afghanistan/Title II" 10000, {stroke: {color: "black", width: 1}});

/* Remove a series from the chart */
chart.removeSeries("Afghanistan/Title II");

The rest is of the work in putting this together really is just non-charting-related-book-keeping-cruft.

On a data related note, the one thing that kept coming to mind as I hacked this out is that it would be nice if there were a way to annotate the data.gov catalog with links to projects that slice and dice the data, transform the data into more useful forms, provide visualization tools for the data, etc. After all, the next logical step once you have the data is actually building stuff with the data. For example, if you wanted to hack on the USAID data too, you would probably benefit from the work I’ve already done in converting it to a useful JSON format, coding up an inflation calculator (that is driven by the CPI data I had to go find), and you might even want to improve upon the interactive chart that plots it all out.

If there is interest, I’m considering a series of follow-on posts where I’ll add some improvements to the chart like plotting multiple series, viewing normalized dollar totals by country, etc.

July 21st, 2009 Comments Off
Tags: , ,

Category: Articles, News, Tips

OSCON 2009 Materials Now Available

As promised this morning, I’ve made all of my materials for the 3 hour tutorial available under liberal licensing. All ~160 slides of them and accompanying code samples.

Also as promised, I removed the PHP dependencies for some of the server stuff and replaced it with a simple python server that uses cherrypy. You should hopefully have no problems getting the sample server to run. You should have no problems finding stuff on the net to help you get that setup if you have problems, but feel free to comment here as well. Additionally be sure to skim the README in there.

You can get the materials here.

Thanks again to everyone who attended. I hope that you were exposed to some of the great tools that Dojo can bring to the user experiences you are creating and that these slides are sufficiently succinct that they are a help to you. While they don’t cover everything in my book, they really do cover a lot of it…more than enough to get you pretty darn proficient.

Finally, remember that we’re having the dojo.beer() tomorrow here in San Jose at 7pm. Please don’t miss it.

July 20th, 2009 Comments Off
Tags: ,

Category: Articles, Vetted Links

Dojo’s Industrial-Strength Grid Widget (Linux Journal Reprint)

As I was finishing up my slides for the 3 hour Dojo tutorial at OSCON tomorrow, I remembered that I hadn’t posted the source for the Linux Journal article on Dojo’s fab DataGrid that ran in the June 2009 issue. Fortunately for me, Linux Journal posted the source online for this one, so I’ll just go ahead and point you there instead of reproducing that work. It’s laid out nicely, so I hope you enjoy.

If you’re at OSCON, please come out to the dojo.beer() on Wednesday at 7pm and hang out with some of us. I’m here all week, so feel free to look me up if you want to chat about anything.

June 19th, 2009 Comments Off
Tags: , ,

Category: Articles, News, Tips, Vetted Links

Dojo Tips and Tricks

Many months ago, I wrote an article for InsideRIA that provided a topical look at some of the more useful things that Dojo provides you entitled Dojo Tips and Tricks. I’d actually forgotten that I even wrote the article so it was a surprise when a colleague wrote me earlier this morning and mentioned it.

It’s a bit more diverse than some drive-by-tutorials in that it digs into DojoX just a little bit and mentions the build system, so even if you’ve been using some of the core tools for a while now, you may still learn a few things from a quick read.

In between the time when the article was finished and now, Dojo has since updated to version 1.3 so you’ll unfortunately see a few CDN URLs that point to version 1.2; however, upgrading the URLs shouldn’t break anything. The latest and greatest is usually a great place to start, so I always encourage folks to stay up to date.

If you’re coming to OSCON this summer, be sure to drop by my 3 hour tutorial for a closer look at many of the great tools that Dojo provides.

March 20th, 2009 6 Comments »
Tags: , ,

Category: Articles

Dojo, Now With Drawing Tools (Linux Journal Reprint)

This post is a “reprint” of a feature article I wrote for the February 2009 edition of Linux Journal, entitled “Dojo, Now With Drawing Tools.” The article text was minimally adapted from the printed form, so no extensive hyperlinking or web layout has been done. Per my contract with Linux Journal, the article must be published under a FSF Free Documentation License if I reproduce it, so I hereby republish it under the BSD Documentation License. (*Strikes Gavel*) Enjoy.

Internalizing Dojo’s “write once, deploy anywhere” philosophy, Dojo’s gfx (pronounced “g-f-x” or sometimes “graphics”) library packs a powerful 2-D drawing API that’s capable of plugging in to an arbitrary renderer. Out of the box, it works with Canvas, Silverlight, SVG and VML, so regardless of which browser your application is ultimately viewed within, gfx has you covered.

My article Dojo: the JavaScript Toolkit with Industrial-Strength Mojo in the July 2008 issue of Linux Journal illustrated how Dojo significantly lowers the amount of effort it takes to develop a cross-browser Web application by normalizing so many of the yucky aspects of Web programming, such as DOM manipulation, non-uniform aspects of the JavaScript across browsers, and repetitive tasks, such as styling nodes, performing AJAX requests and so forth. With that working knowledge, let’s turn to Dojo’s gfx library—a much more specialized aspect of the toolkit that’s expressly designed to give you 2-D drawing tools that can be used to do anything from producing a cool-looking reflection of an image to creating an animated game to rendering a drag-and-drop graph.
Figure 1. An example of a slick effect gfx can produce on an image.

So that you better understand exactly where gfx fits into the larger toolkit, recall that Dojo breaks down into roughly five components: Base, Core, Dijit, DojoX and Util. Base is the tiny dojo.js file that contains hard-live-without library code for common operations; Core includes most of the programmatic machinery for the toolkit; Dijit is an assortment of turnkey widgets; DojoX provides a collection of specialized subprojects; and Util provides a testing framework and scripts for tasks, such as minifying and consolidating JavaScript and CSS files. The gfx library is one of those many specialized subprojects that lives under the DojoX umbrella.

Figure 2. A Conceptual Portrayal of Dojo’s Functional Architecture

Note: A common misunderstanding is that everything within DojoX is experimental or necessarily unstable. Although there certainly are some alpha-quality subprojects within the DojoX namespace that you wouldn’t want to rely on for long-term production scenarios, several DojoX subprojects (including gfx) are quite ready for mainstream use. In general, you should be able to check a project’s README file to determine information about its status.

A Minimal Development Template

In order to demonstrate the various drawing concepts as clearly as possible, all of the examples you’re about to see will plug right in to the following minimal HTML page. Although you’re encouraged to download the entire toolkit eventually, so you have full access to the source code whenever you need it, let’s take advantage of the version that’s hosted on AOL’s Content Delivery Network, as it’s quicker to get up and running. The latest version of Dojo at the time of this writing is 1.2, so the minimal effort to put Dojo to work is the following page, which uses a script tag to cross-domain load the toolkit:

<html>
  <head>
      <title>Minimal Development Template</title>
      <script
          type="text/javascript"
          src="http://o.aolcdn.com/dojo/1.2/dojo/dojo.xd.js">
      </script>
      <script type="text/javascript">
          dojo.addOnLoad(function() {
              /*Add Dojo-dependent logic
                here to avoid race conditions*/
          });
      </script>
  </head>
  <body>
  </body>
</html>

With the minimal template in place, it is trivial to load the gfx module and start drawing. The next section digs right in to various aspects of the API, but just so you can see where we’re heading, consider the modification to the template that instantiates a 600×600 pixel drawing surface and draws a line from the upper-left corner to the lower-right corner shown in Listing 1.

Listing 1: A Minimal Development Template

<html>
  <head>
      <title>Square with a Diagonal Line</title>
      <script
          type="text/javascript"
          src="http://o.aolcdn.com/dojo/1.2/dojo/dojo.xd.js">
      </script>
      <script type="text/javascript">
          dojo.require("dojox.gfx");
          dojo.addOnLoad(function() {
              var node = dojo.byId("surface");
              var surface = dojox.gfx.createSurface(node, 600, 600);

              surface.createLine({
                  x1 : 0,
                  y1 : 0,
                  x2 : 600,
                  y2 : 600
              })
              .setStroke("black")
              ;
          });
      </script>
  </head>
  <body>
      <div style="width:600;height:600;border:solid 1px"
       id="surface"></div>
  </body>
</html>

Figure 3. A 600×600 Drawing Surface with a Diagonal Line Drawn through It

Although quite simple, the previous example taught us that the origin of the drawing surface is the upper-left corner with positive axes extending down and to the right, and that you can place a drawing surface into an arbitrary page element. Although not directly stated, the latter implies that you can have multiple drawing surfaces on a single page.

It’s also worth noting that the style applied to the div element in no way applies to the gfx surface that is created. Internally, what happens is that the surface is created and placed inside of the div; thus, the containing div exhibits a 600×600 size with a visible border around it, and the surface that is placed into the div just so happened to be 600×600 pixels also. Without using Firebug to inspect the DOM, that may not have been obvious, so hopefully, mentioning it here avoids any confusion.

An additional aspect of this simple demonstration that’s important to note is that the browser was detected and a default drawing renderer was assigned automatically without any special intervention. In the case of a Gecko- or KHTML-based browser, like Firefox or Konqueror, SVG is used as the default renderer; Internet Explorer defaults to VML.

Figure 4. The gfx library’s flexible design provides a uniform API that supplies a uniform abstraction on top of the most common drawing engines in the mainstream. Because it internally detects the drawing engine that’s available, it works right out of the box.

Silverlight and Canvas can be configured to run on supported platforms via a gfxRenderer configuration switch supplied to djConfig via the script tag that loads Dojo into the page. For example, to instruct Firefox to use Canvas as the renderer you would provide the following script tag:

<script
    type="text/javascript"
    djConfig="gfxRenderer:'canvas'"
    src="http://o.aolcdn.com/dojo/1.2/dojo/dojo.xd.js">
</script>

All Shapes and Sizes

The gfx API exposes a number of intuitive functions for common operations, such as creating rectangles, circles, lines, polylines and paths that are loosely based on the SVG standard as well as a set of custom attributes, such as stroke, fill color, rounded corners and more. Most of the methods support “chaining syntax”, which allows you to operate on the results of the previous operation repeatedly, leading to crisp code and clean syntax, so long as you do not abuse the device (Listing 2).

Listing 2. An Assortment of Shapes

dojo.addOnLoad(function() {
    var node = dojo.byId("surface");
    var surface = dojox.gfx.createSurface(node, 600, 600);

    surface.createEllipse({
        cx : 300,
        cy : 300,
        rx  : 50,
        ry  : 100
    })
    .setFill("yellow")
    ;

    surface.createRect({
        x : 90,
        y : 90,
        width : 50,
        height : 170
    })
    .setFill([255,0,0,0.5])
    ;

    surface.createCircle({
        cx : 400,
        cy : 200,
        r  : 50
    })
    .setFill([255,0,0,0.5]);

    surface.createCircle({
        cx : 425,
        cy : 225,
        r  : 50
    })
    .setFill([0,255,0,0.5])
    ;

    surface.createCircle({
        cx : 425,
        cy : 175,
        r  : 50
    })
    .setFill([0,0,255,0.5])
    ;

    surface.createPolyline([
            100,400,
            200,300,
            350,350,
            500,350
    ])
    .setStroke({
        width : 10,
        join : "round",
        cap : "round"
    })
    ;

    surface.createCircle({
        r : 50,
        cx : 200,
        cy: 200
    })
    .setFill({
        type: "radial",
        cx : 200,
        cy: 200,
        r:50,
        colors: [
            {color:"white",offset:0},
            {color:"red",offset:1}]
    })
    ;
});

Figure 5. Dojo’s fairly intuitive gfx API makes drawing a variety of customized elements easy and fun.

Hopefully, the code mostly speaks for itself. The various types of objects that you can create are usually framed in the same way that they are presented in grade school. For example, a circle has a center point and a radius defined by cx, cy and r. Given a circle, you could set a fill color in a number of different ways: a string value, an rgb(a) tuple or even something more complex like a radial gradient with custom parameters of its own.

3×3 Matrix Transforms

Using a well-designed API with nice mnemonic devices is useful for much of the routine drawing you’ll be doing, but what about when you need to do something a lot more in depth? Although this is where a lot of JavaScript graphics libraries fall short, gfx absolutely shines here by equipping you with the ability to perform arbitrary 3×3 matrix transformations.

Just in case you don’t have a background with graphics, it may not be immediately apparent how 3×3 matrices and “all of that math” is useful. Basically, 3×3 matrices provide a compact way to express the three common operations that you do with objects all at the same time:

  • Translation: adjusting the position of an object in the x and y directions.
  • Rotation: adjusting the position of an object in the clockwise or counterclockwise directions usually (but not necessarily) around its center point.
  • Scaling: adjusting the size of an object by a scalar multiplier.

Don’t freak out quite yet if you’re not a math buff and don’t want to sink time into re-learning linear algebra just to get started with that great idea you had for a game or drawing application. Many of the common operations for manipulating shapes come with intuitive wrappers. To illustrate a trivial example, let’s assume that you want to draw a square but then rotate it around its center point so that it looks like a diamond:

dojo.addOnLoad(function() {
    var node = dojo.byId("surface");
    var surface = dojox.gfx.createSurface(node, 600, 600);

    rect1 = surface.createRect({
        x: 200,
        y: 200,
        width : 200,
        height:200
    })
    .setFill("red")
    .setTransform([dojox.gfx.matrix.rotategAt(45,300,300)])
    ;
});

With an upper-left corner at point (200,200) and a width and height of 200 pixels, the square originally was centered on the surface. Then, applying a 45-degree rotation around the square’s center point of (300,300) rotated it in place.

Figure 6. The effect of drawing a square and rotating 45 degrees around its center point.

To illustrate the effect of successively applying transformation matrices, let’s draw the very same diamond but rely on explicit translation to position it in the center of the surface before rotating it versus positioning it via the createRect function:

dojo.addOnLoad(function() {
    var node = dojo.byId("surface");
    var surface = dojox.gfx.createSurface(node, 600, 600);

    rect1 = surface.createRect({
        /* x and y default to (0,0) */
        width : 200,
        height:200
    })
    .setFill("red")
    .setTransform([
        dojox.gfx.matrix.translate(200,200),
        dojox.gfx.matrix.rotategAt(45,100,100)
    ])
    ;
});

In general, it is immensely more convenient to draw most shapes initially in a coordinate system with perpendicular x and y axes and then apply final positioning via translation and rotation. An important technicality to be aware of with successive transformations, however, is that the order in which the transforms are applied does matter, and the original position of the object is normally the point of reference. For instance, in the previous example, the shape explicitly was translated as 200 pixels in the x and y directions, but its original center point from before the translation is applied serves as the basis of rotation.

If you’re unconvinced that a shape as simple as a diamond would benefit much from the convenience of matrix transforms, just consider the extra work involved in calculating the exact coordinates for its corners, and you’ll quickly see that it’s easier to reason about “rotated squares” than it is about “native diamonds”.

Manipulating Groups

It won’t be long before you’ll find that it’s far more convenient to transform entire groups of objects instead of applying individual transforms to each object in the group. Let’s consider the task of drawing a simple arrow that is nothing more than a line with a triangle on the end of it. Although you could use a path to construct the entire arrow, take a look at how groups can be useful by combining the results from the createLine function and the createPath function (Listing 3).

Listing 3. Arrows in All Four Quadrants

dojo.addOnLoad(function() {
    var node = dojo.byId("surface");
    var surface = dojox.gfx.createSurface(node, 600, 600)

    function drawArrow(p) {
        /////////////////////////////////////////////////////
        //Create a group that can be manipulated as a whole
        /////////////////////////////////////////////////////
        var group = surface.createGroup();

        var x1 = p.start.x,
            y1=p.start.y,
            x2 = p.end.x,
            y2=p.end.y;

        var len = Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2));

        var _defaultStroke = {
            color : "black",
            style : "solid",
            width : 1
        };

        ///////////////////////////
        //Add a line to the group
        ///////////////////////////
        group.createLine({
            x1 : 0,
            y1 : 0,
            x2 : 0+len,
            y2 : 0
        })
        .setStroke(p.stroke || _defaultStroke)
        ;

        var _arrowHeight = p.arrowHeight || 5;
        var _arrowWidth = p.arrowWidth || 3;

        /////////////////////////////////////////////////////
        //Add a custom path that is a triangle to the group
        /////////////////////////////////////////////////////
        group.createPath()
        .moveTo(len-_arrowHeight,0)
        .lineTo(len-_arrowHeight,-_arrowWidth)
        .lineTo(len,0)
        .lineTo(len-_arrowHeight,_arrowWidth)
        .lineTo(len-_arrowHeight,0)
        .setStroke(p.stroke || _defaultStroke)
        .setFill(p.stroke ? p.stroke.color : "black" )
        ;

        var _rot = Math.asin((y2-y1)/len)*180/Math.PI;
        if (x2 <= x1) {_rot = 180-_rot;}

        /////////////////////////////////////////////////////////////
        //Translate and rotate the entire group as a whole
        /////////////////////////////////////////////////////////////
        group.setTransform([
            dojox.gfx.matrix.translate(x1,y1),
            dojox.gfx.matrix.rotategAt(_rot,0,0)
        ]);
    }

    //diagonals
    drawArrow({start: {x:300,y:300}, end: {x : 435, y : 435}});
    drawArrow({start: {x:300,y:300}, end: {x : 165, y : 165}});
    drawArrow({start: {x:300,y:300}, end: {x : 435, y : 165}});
    drawArrow({start: {x:300,y:300}, end: {x : 165, y : 435}});

    //up, down, left, right
    drawArrow({start: {x:300,y:300}, end: {x : 300, y : 450}});
    drawArrow({start: {x:300,y:300}, end: {x : 300, y : 150}});
    drawArrow({start: {x:300,y:300}, end: {x : 150, y : 300}});
    drawArrow({start: {x:300,y:300}, end: {x : 450, y : 300}});
});

Attempting to calculate the three points for each of the arrows without the benefit of rotation quickly demonstrates just how laborious high-school geometry really can be; perhaps putting it to work with gfx makes it at least a little more interesting.

Figure 7. It’s generally a bit easier to think in terms of objects that have been rotated than trying to determine exact coordinates for shapes that don’t fit nicely into a simple perpendicular frame of reference.

Drag-and-Droppable Dominoes

Because it’s so common to want to interact with graphics, Dojo’s gfx library has gone a long way to do most of the legwork for you in this use case as well. To wrap up some aspects of drawing, let’s put together a little demonstration that draws a domino on the screen and then add drag-and-drop capabilities to it. As you’re about to see, the laborious part of the effort is actually drawing something interesting enough that you’d actually want to drag and drop it. The actual mechanics of making it drag-and-droppable amounts to one whole line of code.

Listing 4. Drag-and-Drappable Dominoes

<html>
  <head>
    <title>Dominoes!</title>
    <script type="text/javascript"
        src="http://o.aolcdn.com/dojo/1.2/dojo/dojo.xd.js">
    </script>
    <script type="text/javascript">
           dojo.require("dojox.gfx");
            dojo.require("dojox.gfx.move");

            dojo.addOnLoad(function() {
                var node = dojo.byId("surface");
                var surface = dojox.gfx.createSurface(node, 600, 300);

                /* Using some sane ratios for layout, construct a domino */
                function drawDomino(surface,x,y,num1,num2,_width) {

                    var surface = surface.createGroup();

                    var _width = _width || 200;

                    _height = 2*_width, _r = _width/20;

                    //draw an empty domino...
                    var rect1 = surface.createRect({
                        x : x,
                        y : y,
                        width : _width,
                        height : _height,
                        r : _r
                    })
                    .setStroke("black")
                    .setFill("black")
                    ;
                    var rect2 = surface.createRect({
                        x : x+ _r/2,
                        y : y+ _r/2,
                        width : _width -_r,
                        height :_height -_r,
                        r : _r
                    })
                    .setStroke({width: _r/4, color: "white"})
                    ;

                    var line = surface.createLine({
                        x1 : x + _r/2,
                        y1 : y+_height/2,
                        x2 : x+ _width - _r/2,
                        y2 : y+_height/2,
                    })
                    .setStroke({width: _r/4, color: "white"})
                    ;

                    //now, fill in the dots

                    //numbers 1,3,5 have dots in the center
                    if (num1 == 1 || num1 == 3 || num1 == 5) {
                        surface.createCircle({
                            cx : x+_width/2,
                            cy : y+_height/4,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                    }
                    if (num2 == 1 || num2 == 3 || num2 == 5) {
                        surface.createCircle({
                            cx : x+_width/2,
                            cy : y+_height/4*3,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                    }

                    //numbers >= 2 have two of the corners filled in
                    if (num1 >= 2) {
                        surface.createCircle({
                            cx : x+_width/6*5,
                            cy : y+_height/12,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                        surface.createCircle({
                            cx : x+_width/6,
                            cy : y+_height/12*5,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;

                    }
                    if (num2 >= 2) {
                        surface.createCircle({
                            cx : x+_width/6*5,
                            cy : y+_height/12*7,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                        surface.createCircle({
                            cx : x+_width/6,
                            cy : y+_height/12*11,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                    }

                    //numbers >=4 have the other two corners filled in
                    if (num1 >= 4) {
                        surface.createCircle({
                            cx : x+_width/6,
                            cy : y+_height/12,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                        surface.createCircle({
                            cx : x+_width/6*5,
                            cy : y+_height/12*5,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                    }
                    if (num2 >= 4) {
                        surface.createCircle({
                            cx : x+_width/6,
                            cy : y+_height/12*7,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                        surface.createCircle({
                            cx : x+_width/6*5,
                            cy : y+_height/12*11,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                    }

                    //number 6 has the sides filled in
                    if (num1 == 6) {
                        surface.createCircle({
                            cx : x+_width/6,
                            cy : y+_height/4,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                        surface.createCircle({
                            cx : x+_width/6*5,
                            cy : y+_height/4,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                    }
                    if (num2 == 6) {
                        surface.createCircle({
                            cx : x+_width/6,
                            cy : y+_height/4*3,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                        surface.createCircle({
                            cx : x+_width/6*5,
                            cy : y+_height/4*3,
                            r : _width/10
                        })
                        .setStroke("white")
                        .setFill("white")
                        ;
                    }

                    return surface;
                }

                var width=50,
                    padding=50;

                for (var i=0; i <= 6; i++) {
                    var d = drawDomino(
                        surface,
                        i*75+padding,
                        2*padding,
                        i,
                        Math.floor(Math.random()*7),
                        width
                    );

                    ////////////////////////////////////////////
                    //This is all it takes to make the group
                    //drag-and-droppable!
                    ////////////////////////////////////////////
                    new dojox.gfx.Moveable(d);
                }

                ////////////////////////////////////////////
                //Ensure that the last domino moved is always on top
                //by subscribing to move notifications and
                //adjusting the z-index
                ////////////////////////////////////////////
                dojo.subscribe("/gfx/move/start", function(m) {
                    m.shape.moveToFront();
                });

            });

    </script>
  </head>
  <body>
    <div id="surface"
     style="position:absolute;width:600;height:300;border:solid1px;">
    </div>
  </body>
</html>

Figure 8. With the logic to draw the drag-and-droppable dominoes in place, now all that’s left is to write some game logic. (An exercise for the most interested of readers.)

Charting: gfx on Steroids

Perhaps the ultimate test of an API is a few good examples of what you can build with it. One of the ultimate demonstrations of gfx’s flexibility and power is Dojo’s charting library, another DojoX subproject. A comprehensive introduction of the charting library would entail an article of its own, so until that time comes, you can find some great documentation on Dojo charting from the Dojo Key Links page. And, of course, you always can read over the source, which is located in the dojox.charting module of the toolkit’s source code, if you want to get an idea of how much work goes into aligning labels, drawing tick marks and so on.

In addition to equipping you with many of the basic charts you’d want to use in a Web application, charting recently got a boost with a number of cool new features, including event support so that custom tooltips and animations can occur within charts—that kind of visual flair makes all the difference. To give you an idea of just how easy the charting API is to get up and running, consider the code blurb in Listing 5 that shows how to create a chart.

Listing 5. Preview of Dojo’s Charting API

//////////////////////////////////////////////////////
// This function demonstrates the general form of
// putting Dojo's charting API built on top of
// gfx to use. Pass in a node, customize the chart,
// and let Dojo take care of the rest
//////////////////////////////////////////////////////
new dojox.charting.Chart2D(node))
    .setTheme(dojox.charting.themes.PlotKit.blue)
    .addPlot("default", {
        type: "Default",
        lines: true,
        markers: true,
        tension: 2
    })
    .addAxis("x", {
        min: 0,
        max: 6,
        majorTick: { stroke: "black", length: 3 },
        minorTick: { stroke: "gray", length: 3 }
    })
    .addAxis("y", {
        vertical: true,
        min: 0,
        max: 10,
        majorTick: { stroke: "black", length: 3 },
        minorTick: { stroke: "gray", length: 3 }
    })
    .addSeries("Series A", [
        { x: 0.5, y: 5 },
        { x: 1.5, y: 1.5 },
        { x: 2, y: 9 },
        { x: 5, y: 0.3 }
    ])
    .addSeries("Series B", [
        { x: 0.3, y: 8 },
        { x: 4, y: 6 },
        { x: 5.5, y: 2 }
    ])
    .render()
    ;

Figure 9. An example of the charts you can draw with Dojo—no Flash required!

Figure 10. Another Example Chart Drawn with Dojo

Although only a teaser, it’s worthwhile to note the charting API focus on charting—not on raw drawing operations—so you can focus on the semantics of the task at hand instead of the implementation details associated with lower-level operations. In general, you simply provide some data that says what kind of chart you’d like, how to customize the axes and pass in the series data. Setting up event handlers, legends and other related things all work much the same way.

There’s Plenty More Where That Came From

2-D drawing is an enormous topic in and of itself, and no single article could cover all the nooks and crannies adequately. This article is designed to give you an idea of just how easy Dojo makes 2-D for the Web, which hopefully motivates you to start experimenting with the examples and check out the API docs.

Resources

December 24th, 2008 1 Comment »
Tags: , , ,

Category: Articles

How debugAtAllCosts Works (Or: A Quick Primer on Dojo’s Loaders)

On pages 19-20 of my book, you’ll notice a handy table of the various configuration switches you can pass to djConfig to customize aspects of the bootstrapping process.  A sidebar I’d like to have included (and will include in a future printing or update) involves some additional explanation about how the debugAtAllCosts option works, and incidentally, explains some important nuances between the “normal” loader and the XDomain loader in the process.

At a glance, debugAtAllCosts is simply what you use to try and get some more specific debugging information when something has gone wrong and Firebug or Firebug Lite aren’t giving you much to work with. Oftentimes, a quick update to djConfig with debugAtAllCosts:true is all it takes to get that helpful information and isolate the issue.

But how does it do that?

Detour: A Primer on the Loaders
To better understand how debugAtAllCosts works, it’s critical to first understand the difference between the “normal” loader and the XDomain loader. (Recall that the XDomain loader works around the same origin policy and is used to bootstrap the toolkit from a domain that’s different from where your web page is located to bring your page to life with Dojo goodness e.g. AOL’s CDN and such things.) To illustrate, consider a simple HTML page that might have a script block in it that looks something like this:

dojo.require(“A”);
dojo.require(“B”);
dojo.require(“C”);

In the general case when the “normal” loader is being used, each of those three dependencies is evaluated synchronously such that the scripts for A, B, and C are each fetched in turn, and any dependencies are processed in a depth-first search fashion. For example, if B had dojo.require’d modules named D and E (in that order), then the overall order of requests look like A -> B -> D -> B -> E -> B -> C. Note that B is listed multiple times in that chain because B begins loading, then at some point (maybe immediately) D is processed, then E is processed, and then control returns to B one last time before C gets kicked off.

It’s worth reiterating is that the execution of D and E are “blocking” in the sense that B begins executing, then when the dojo.require(“D”) statement is reached within B, D is processed on the spot before B finishes executing; ditto for the way that E works.

With the “normal” loader, the entire process is entirely predictable every single time. You can not only count on the dojo.require dependencies being resolved properly, but you also have an implicit guarantee about the relative order of various dojo.require statements that appear sequentially in the same source file as in the previous example.

The XDomain (cross-domain) loader, however, does something different by necessity of the way it circumvents the same origin policy, which can’t be done with dojo.xhrGet. It uses information provided through other djConfig switches such as baseUrl and modulePaths, or uses information provided via the dojo.registerModulePath function to build URLs that serve as the SRC attribute for dynamically insert SCRIPT tags that get inserted into the HEAD of the page. Moving forward, realize that the dynamic insertion of SCRIPT tags is an operation that is asynchronous in nature.

One of the most significant differences to note is that while dojo.require dependencies are still preserved by the XDomain loader, the relative order in which non-dependent modules become ready (where “ready” roughly corresponds to “alive” or “fully processed”) is not necessarily preserved. In our working example, this means that while the XDomain loader guarantees that D and E will be ready before B is ready, it guarantees nothing about whether D will be ready before E or if E will be ready before D — nor does it guarantee anything about the relative order of A, B, or C becoming ready. The reason why there are no such guarantees is simply due to the nature of asynchronous requests and latency.

To make sure you fully grasped the important nuances in that paragraph, here are a few of the possible scenarios with the XDomain loader for our toy example:

D -> E -> B -> A -> C
A -> C -> D -> E -> B
A -> C -> E -> D -> B
E -> A -> D -> C -> B

Note that in all scenarios, both D and E are ready, in no particular order, before B is ready. That’s the only commonality.

If you stop to ponder for a moment, you’ll recognize that a really easy way you could not only get into trouble but also cripple yourself from trivially porting your application to take advantage of the XDomain loader would be if you constructed logic that depended on the relative order of modules loading. For example, if you were counting on module A in the working example to perform a synchronous dojo.xhrGet request to retrieve some kind of global object that gets used throughout your application and module B, C, D, or E relied on it, you’d have a race condition on your hands if you tried to go with an XDomain build because there’s no guarantee that A will finish loading before any of the other modules; maybe it will, but maybe it won’t. For XDomain loading scenarios, if you truly wanted to guarantee that A would load before every other module, you’d have to go as far as to identify A as a dependency such that everything else that needs to block on it would block on it.

Getting Back to How debugAtAllCosts Works
Getting back to debugAtAllCosts and how it does what it does — basically, it forces the XDomain loader into effect, which causes each module to be individually loaded via a dynamically inserted SCRIPT tag as opposed to building up the equivalent of what’s analogous to a deeply nested parse tree that causes the underlying JavaScript engine to “just crap out” and give you a nearly useless error message when the going gets tough. Thus, while it can often work wonders and help you find some kinds of errors in a hurry because of the way it loads individual modules in isolation, it can also complicate your situation (for reasons that should now be obvious) if you haven’t been precise in identifying dojo.require dependencies or  are relying on the relative order or modules loading.

And as Paul Harvey would say, “now you know…the rest of the story.”

September 10th, 2008 5 Comments »
Tags: ,

Category: Articles

Using Dojo: The JavaScript Toolkit with Industrial Strength Mojo (Linux Journal Reprint)

This post is a “reprint” of a feature article I wrote for the July 2008 edition of Linux Journal, entitled “Using Dojo: The JavaScript Toolkit with Industrial Strength Mojo.” The article text was minimally adpated from the printed form, so no extensive hyperlinking or web layout has been done. Per my contract with Linux Journal, the article must be published under a FSF Free Documentation License if I reproduce it, so I hereby republish it under the BSD Documentation License. (*Strikes Gavel*) Enjoy.

See the upper right corner

July 08 Cover

Featuring a rich standard library, an extensive collection of turn-key widgets, a unit-testing framework and build tools for minifying your source files, it’s no wonder that Dojo is a key part of products from industry giants, such as AOL, Sun Microsystems, BEA and others.

A number of JavaScript toolkits have emerged to automate common Web development tasks and simplify creating rich user interfaces. Of all the contenders, Dojo stands out as the industrial-strength JavaScript toolkit because of its incredible depth and breadth. It features an extensive JavaScript library, a system of rich turn-key widgets, a collection of specialized subprojects, build tools and a unit-testing harness. Regardless of what your project entails, it is almost a certainty that Dojo can simplify the development and maintenance required. This article systematically focuses almost exclusively on some of the most fundamental constructs in the toolkit’s highly optimized kernel, commonly referred to as Base.

Figure 1. Toolkit Architecture

Figure 1. Toolkit Architecture

Dojo: The JavaScript Toolkit You’ve Always Wanted

Variations among Web browsers have made developing applications for the Web really messy work. Working around subtle variations in JavaScript implementations, wrangling the Document Object Model (DOM) and normalizing content rendering across browsers can be downright tormenting at times, and unfortunately, a nontrivial portion of the investment in developing a solid Web application is spent re-inventing this kind of brittle boilerplate. Although many technologies have evolved to mitigate these kinds of issues, one you especially should be aware of the next time you decide to build a Web application is Dojo, the industrial-strength JavaScript toolkit.

In short, the Dojo toolkit is a liberally licensed client-side technology that can supplement virtually any aspect of Web development. It features a tiny but fully featured JavaScript standard library that insulates you from the bare metal of the browser, a large subsystem of widgets that snap into a page with little to no JavaScript required, and a suite of build tools for minifying and consolidating resources as well as writing unit tests. Knowing that industry giants, such as AOL, IBM, BEA and Sun Microsystems, are on board with Dojo should give you a boost of confidence if you’re leery of trying something else in an ecosystem that’s littered with half-baked inventions that don’t always come though on their promises to deliver all-encompassing solutions. This remainder of this article works through the bulk of the toolkit’s most fundamental JavaScript programming constructs that will benefit you regardless of the size or scope of your project.

Firebug

The Firebug add-on for Mozilla Firefox is a terrific tool that can benefit your Web development efforts in ways you can’t even imagine. Of particular interest is its console, which allows you to execute arbitrary JavaScript code–great advantage when learning a new technology, as you’ll commonly want to test out new ideas in an interactive fashion.

Getting Dojo To Work In Less Than One Minute

Although you could download Dojo from its official Web presence and set up a local installation, the easiest way to get started with Dojo is to use the latest version of Dojo that is hosted on AOL’s Content Delivery Network (CDN). The following page skeleton demonstrates that the minimal effort required to put Dojo to work from the CDN is a SCRIPT tag that loads Dojo into the HEAD of the page; it is especially noteworthy that the SCRIPT tag incurs the cost of one request to the Web server that delivers a gzipped payload of approximately 29kB and provides the latest 1.1.x release that is available. In Dojo parlance, the good that the SCRIPT tag provides is called Base, because it provides the base for the toolkit, and because everything you’ll use is contained in the base-level dojo.* namespace. Speaking of which, with the exception of the dojo identifier itself, the global page-level namespace is otherwise preserved:

<html>
    <head>
        <title>Putting Dojo To Work</title>

        <!-- Loading Dojo requires only one SCRIPT tag -->
        <script type="text/javascript"
            src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
        </script>

        <script type="text/javascript">
            dojo.addOnLoad(function() {
                /* safely use any code that relies on dojo.*
                   functions in here ... */
            });
        </script>
    </head>
    <body>
        <a href="http://dojotoolkit.org">Dojo</a>
    </body>
</html>

To summarize, the dojo.addOnLoad block fires once the asynchronous loading of the dojo.xd.js file and any dependencies specified via dojo.require statements (more on these in a bit) have completed, and this is necessary in order to prevent any race conditions that might occur without it. Basically, the dojo.xd.js file providing Base accomplishes feats such as normalizing DOM events and provides you with a number of useful utilities for accelerating application development.

Fetching Nodes

As a natural starting point for our discussion, consider the following snippet from a Web page:

<form name="foo" action="/bar">
  <label>A form with name="foo"</label>
</form>

<div id="foo">
  A div with id=foo
</div>

The excerpt is trivial, and it should be obvious that running a function as simple as document.getElementById("foo") would always return the DIV element as a result. As a Linux user, you even could use a Gecko-based browser, such as Firefox, or a KHTML-based browser, such as Konqueror, to test the page and verify it for yourself. However, you may be alarmed and shocked to learn that running the very same test in Internet Explorer versions 6 or 7 returns the FORM element instead of the DIV element! This particular bug arises, because the name and id attribute namespaces are merged for IE. As it turns out, the DIV would have been returned if the FORM had not appeared first in the document, so this bug is especially tricky. At any rate, Dojo provides the dojo.byId function that works just like document.getElementById–except that it accounts for this particular issue. Use it to stay safe and to save some typing.

Manipulating Arrays

Although the Array data type is one of the most commonly used, not all arrays are created equal–at least not among the various JavaScript implementations. Fortunately, Dojo’s Array facilities provide an easy-to-use abstraction, ensuring that the code you write will work anywhere, and you won’t be left scratching your head staring at a big semantic bug that’s painful to track down. Consider the following (seemingly innocent) block of code:

var a = getMetasyntacticVariables();
if (a.indexOf("foo") != -1) {
  /* do something... */
}

Although you might swear that there couldn’t possibly be anything wrong with that code, that’s because you’re probably (again) using and testing with a nice KHTML- or Gecko-based browser. The Trident-based Internet Explorer has its own notions of what an Array should and shouldn’t do, and the indexOf method isn’t one of them. In other words, you can expect for your code most likely to outright fail if you try to invoke the indexOf function on an Array when the code runs in IE. In this particular case, you could use the dojo.indexOf function to produce code safely that is portable across browsers:

var a = getMetasyntacticVariables();
if (dojo.indexOf(a, "foo") != -1) {
  /* do something... */
}

Other useful Array methods available via the dojo.* namespace include map, filter, every, some, lastIndexOf and forEach. They all work as described in the Mozilla Developer documentation.

At first glance, the forEach method may seem a bit redundant, because JavaScript provides a for loop construct, but forEach provides one particularly important feature that often escapes even many senior-level JavaScript programmers: block level scope. To illustrate, first consider the following two approaches to iterating over an Array:

// Approach 1:
var arr = getSomeArray();
for (var i in arr) {
  /* manipulate arr[i] */
}

/* The last value of i is available here because the
   for loop does not have its own block level scope.
   Ditto for any temporary variables
   defined between the braces. */

// Approach 2:
var arr = getSomeArray();
dojo.forEach(arr, function(item) {
  /* manipulate item */
});

/* Neither item nor any temporary variables are
   available here because the scope of the anonymous
   function protected this outer scope from it. */

Styling Nodes

Another function you’ll use quite often for DOM manipulation is dojo.style, which acts as a setter when you pass it a node and a map of style properties as parameters and a getter when you pass it a node and a particular style property. In addition to providing an intuitive one-stop shop for style, it protects you from a number of DOM-based browser-specific quirks that otherwise would creep up on you. Here’s how it works:

// Set some style properties..
var fooNode = dojo.byId("foo");
dojo.style(fooNode, {
    color : "red",
    background : "white",
    border : "blue"
});

/* ... Lots of interesting things
       happen in the meanwhile ... */

// Get a style property such as width...
var props = dojo.style(fooNode, "width");

On a related tangent, you can use any combination of the dojo.hasClass, dojo.addClass and dojo.removeClass functions to inspect and manipulate classes in the same intuitive manner:

var fooNode = dojo.byld("foo");
if dojo.hasClass(fooNode) {
  // do something...
  dojo.addClass(fooNode, "bar");
} else {
  //do something else...
  dojo.removeClass(fooNode, "baz");
}

Querying The DOM

The dojo.query function provides a natural segue into general-purpose DOM manipulation and is based on CSS3 selectors. For example, you might use the following logic to query the DOM for any anchor tags and temporarily highlight the background to be yellow for a mouse-over event:

dojo.query("a")
.onmouseover(function(evt) {
  dojo.style(evt.target, {background : "yellow"});
})
.onmouseout(function(evt) {
  dojo.style(evt.target, {background : ""});
});

The statement inside the dojo.addOnLoad block queries the DOM for any anchor tags using the “a” CSS3 selector and returns a collection of nodes as a specialized subclass of Array called dojo.NodeList. Each of the dojo.NodeList methods is then successively applied to the collection of nodes with the final result being returned so that it can be captured into a variable if desired. The dojo.NodeList class provides a number of useful methods, such as addClass, removeClass, style and the various Array functions that you already have seen. For example, if you are seduced by the elegant dot notation that dojo.NodeList provides, you may find yourself with an expression like the following:

// find anchors that are direct descendants of divs
var highlyManipulatedNodes = dojo.query("div > a")
.addClass("foo")
.removeClass("bar")
.onmouseover(function(evt) { /* ... you ... */})
.map(function(item) { /* ... get ... */})
.filter(function(item) { /* ... the ... */})
.forEach(function(item) { /* ... idea ... */});

It is especially noteworthy that the dojo.NodeList methods named after and triggered by DOM events, such as onmouseover or onblur, accept a single parameter that is a W3C standardized event object, so you are freed from the development and maintenance of yet another layer of subtle incompatibilities when developing a Web application. In fact, the next section investigates the very mechanism that makes this possible.

Event Chaining

It’s quite often the case that you’ll need to chain together some events arbitrarily to produce an action/reaction effect. The dojo.connect function provides a seamless interface for arbitrarily connecting events and JavaScript Objects. For example, you already know that you could hook up a handler when a user mouses over a specific node by using dojo.query and assigning a function via dojo.NodeList’s onmouseover method like so:

dojo.query("#foo") //find the node with id=foo
.onmouseover(function(evt) { /* ... */ });

An alternative implementation via dojo.connect is the following statement, which assembles the connection and returns a handle that can be disconnected later manually if the situation calls for the relationship to be torn down. For example, it’s generally a good idea to tear down the handle explicitly before destroying nodes that are involved in the connection:

var h = dojo.connect(dojo.byId("foo"), "onmouseover", function(evt) {
  /* ... use the normalized event object, evt, here ... */
});

/* Later */
dojo.disconnect(h); //tidy up things...

Although the net effect is the same for the two implementations presented, dojo.connect seamlessly allows you to provide Objects as the context. For example, the following variation illustrates how to fire off an event handler whenever a particular function is invoked:

var obj = { // a big hash of functions...
  foo : function() { /* ... */ },
  bar : function() { /* ... */ }
}

// set the handler to fire whenever obj.foo() is run
dojo.connect(obj, "foo", function() {
  /* ... a custom event handler ... */
});

obj.foo(); // the custom handler fires automatically

If you want to use a particular scope with the custom handler, you can wedge it in as a third parameter. The parameters are all normalized internally. Here’s how it would work:

var obj1 = { // a big hash of functions...
  foo : function() { /* ... */ },
  bar : function() { /* ... */ }
}

var obj2 = { // a big hash of functions...
  baz : function() { /* ... */ }
}

// fire the handler whenever obj1.foo() is run
dojo.connect(obj1, "foo", obj2, "baz");

obj1.foo(); // fire obj2.baz right after obj1.foo

Pub/Sub Communication

Although dojo.connect provides a kind of direct action/reaction style of communication, the publish/subscribe metaphor has many highly applicable use cases in loosely coupled architectures in which it’s not prudent for objects or widgets to know about one another’s existence. This metaphor is simple enough to set up. The dojo.publish function accepts a topic name and an optional Array of parameters that should be passed to any subscribers. Becoming a subscriber to a topic is done through the dojo.subscribe function, which accepts a topic name and a function that is executed in response to the published topic. Here’s a working example with a couple Function Objects:

function Foo(topic) {
  this.greet = function() {
    console.log("Hi, I'm Foo");

    /* Foo directly publishes information,
       but not to anywhere specific... */
    dojo.publish("/lj/salutation");
  }

}

function Bar(topic) {
  this.greet = function() { console.log("Hi, I'm Bar"); }

  / * Bar directly subscribes to information,
      but not from anywhere specific */
  dojo.subscribe("/lj/salutation", this, "greet");
}

var foo = new Foo();
var bar = new Bar();

foo.greet(); //Hi, I'm Foo...Hi, I'm Bar

A couple variations on the pub/sub metaphor are available, but the vanilla dojo.publish/dojo.subscribe functions relay the general idea. Any situation in which you cannot (for whatever reason) expose an API might be a prime opportunity to take advantage of pub/sub communication in your application.

Object-Oriented JavaScript

JavaScript is an object-oriented programming language, but unlike the class-based languages of Java or C++, it uses prototypal inheritance as its mechanism of choice instead of a class-based paradigm. Consequently, mixing properties into object instances as part of a “has-a” relationship is often a far more natural pattern than attempting to mimic class-based patterns that espouse an “is-a” relationship. Consider the following example that adds in a collection of properties to an object instance all at once using dojo.mixin:

var obj = {prop1 : "foo"}

/* obj gets passed around and lots of
   interesting things happen to it */

// now, we need to add in a batch of properties...
dojo.mixin(obj, {
  prop2 : "bar",
  prop3 : "baz",
  prop4 : someOtherObject
});

The dojo.extend function works much like dojo.mixin except that it manipulates a constructor function’s prototype instead of the specific object instances.

Of course, there are some design patterns that do lend themselves to inheritance hierarchies, and the dojo.declare function is your ticket to mimicking class-based inheritance if you find yourself in a predicament that calls for it. You pass it the fully qualified name of the “class” you’d like to create, any ancestors that it should inherit from, and a hash of any additional properties. The dojo.declare function provides a built-in construction function that gets run, so any parameters that are passed in can be handled as needed. Here’s a short example demonstrating a Baz class that multiply inherits from both a Foo and a Bar class:

//create an lj.Foo that doesn't have any ancestors
dojo.declare("lj.Foo", null,
{
  /* custom properties go here */
  _name : null,
  constructor : function(name) {
    this._name = name;
  },
  talk : function() {alert("I'm "+this._name);},
  customFooMethod : function() { /* ... */ }
});

//create an lj.Bar that doesn't have any ancestors
dojo.declare("lj.Bar", null,
{
  /* custom properties go here */
  _name : null,
  constructor : function(name) {
    this._name = name;
  },
  talk : function() {alert("I'm "+this._name);},
  customBarMethod : function() { /* ... */ }
});

//create an lj.Baz that multiply inherits
dojo.declare("lj.Baz", [lj.Foo, lj.Bar],
{
  /* custom properties go here */
  _name : null,
  constructor : function(name) {
    this._name = name;
  },
  talk : function() {alert("I'm "+this._name);},
  customBazMethod : function() { /* ... */ }
});

//parameters get passed into the special constructor function
bartyBaz = new lj.Baz("barty");

When each of the dojo.declare statements is encountered, internal processing leaves a function in memory that can be readily used to instantiate a specific object instance with the new operator–just like plain-old JavaScript works. In fact, the bartyBaz object is one such instantiation. It inherits the customFooMethod and customBarMethod from ancestors, but provides its own talk method. In the event that it had not provided its own talk method, the last one that was mixed in from the ancestors would have prevailed. In this particular case, the ancestors were [lj.Foo, lj.Bar], so the last mixed in ancestor would have been lj.Bar. If defined, all classes created with dojo.declare have their parameters passed a special constructor function that can be used for initialization or preprocessing.

Note

Strictly speaking, there aren’t classes in JavaScript–only objects exist. When discussing simulated inheritance situations, however, it is not uncommon to use the word “class” as though classes really do exist, provided appropriate caveats (like this one) are applied.

Server Communication

No discussion of a JavaScript toolkit would be complete without a mention of the AJAX and server-side communication facilities that are available. Dojo’s support for server-side communication via the XMLHttpRequest (XHR) object is quite rich, and the dojo.xhrGet function is the most logical starting point, because it is the most commonly used variant. As you might have suspected, it performs a GET request to the server. Unless you configure it otherwise, the request is asynchronous and the return type is interpreted as text. Here’s an example of typical usage:

dojo.xhrGet({
  url : "/foo", //returns {"foo" : "bar"}
  handleAs : "json", // interpret the response as JSON vs text
  load : function(response, ioArgs) {
    /* success! treat response.foo just like a
       normal JavaScript object */
    return response;
  },
  error : function(response, ioArgs) {
    /* be prepared to handle any errors that occur here */
    return response;
  }
});

A point wasn’t made of it, but the reason that both the load and error function returns the response type is because Dojo’s I/O subsystem uses an abstraction called a Deferred to streamline network operations. The Deferred implementation was adapted from MochiKit’s implementation (which was, in turn, inspired from Python’s Twisted networking engine). The overarching concept behind a Deferred is that it provides a uniform interface that drastically simplifies I/O by allowing you to handle asynchronous and synchronous requests the very same way. In other words, you can chain callbacks and errbacks arbitrarily onto a Deferred, regardless of whether the network I/O is in flight, threw an Error or completed successfully. Regardless, the callback or errback is handled the same way. In some situations, Deferreds almost create the illusion that you have something like a thread at your disposal.

Here’s an updated example of the previous dojo.xhrGet function call that showcases the dojo.Deferred object that is returned:

var d = dojo.xhrGet({
  url : "/foo", //returns {"foo" : "bar"}
  handleAs : "json", // interpret the response as JSON instead

  load : function(response, ioArgs) {
    /* success! treat response.foo just
       like a normal JavaScript object */
    return response; // pass into next callback
  },
  error : function(response, ioArgs) {
    /* be prepared to handle any errors that occur here */
    return response; //pass into next errback
  }
});

/* The xhrGet function just fired. We have no idea if/when
   it will complete in this case since it's asynchronous.
    The value of d, the Deferred, right now is null since it
     was an asynchronous request */

//gets called once load completes
d.addCallback(function(response) {
  /* Just chained on a callback that
     fires after the load handler with the
     same response that load returned. */
     return response;
});

d.addCallback(function(response) {
  /* Just chained on another callback that
     fires after the one we just added */
      return response;
});

d.addErrback(function(response) {
  /* Just added an errback that
     fires after the default error handler */
     return response;
});

/* You get the idea... */

Again, the beauty of a Deferred is that you treat it as somewhat of a black box. It doesn’t matter if, when or how it finishes executing. It’s all the same to you as the application programmer.

Just so you’re aware, sending data to the server with another HTTP method, such as POST or PUT, entails using the very same kind of pattern and works just as predictably with the dojo.xhrPost function. You even can provide a form node so that an entire form is POSTed to the server in one fell swoop or pass in raw data for those times when you need to transfer some information to the server as part of a RESTful (Representational State Transfer-based) architecture. The dojo.toJson function may be especially helpful in serializing JavaScript objects into a properly escaped JSON string, if the protocol is something along the lines of a JSON-RPC system in which the envelope is expected to be JSON in both directions.

Special Effects

Simple animations are generally a crowd-pleaser, and Base includes a few easy-to-use functions that make animating content a snap. For starters, consider the dojo.fadeIn and dojo.fadeOut functions:

dojo.fadeOut({node : "foo"}).play();

// then sometime later...
dojo.fadeIn({node : "foo"}).play();

Hopefully, that seemed as simple as it should be: point to a node and fade it. It won’t be long though before you’ll find the desire to do some animations that involve arbitrary CSS properties, and that’s when the dojo.animateProperty function comes into play. The basic pattern is that you pass it a node, a map of properties and a duration, and it handles the rest. Here’s a simple example that relates the pattern via the dojo.anim function by providing functions for imploding and exploding a node:

//implode a node...
dojo.anim("foo", properties : {width : 0, height : 0}, 500);
//implode over 500ms

/* ... Later ... */

//then explode it back out
dojo.anim("foo", properties : {width : 300, height : 300}, 500);
//explode back out over 500ms...

A number of other useful animation functions exist in the dojo.fx module.

Highlights From Core

Although there is a ton of functionality jam-packed into Base, there are a number of other highly useful modules that you can get from Core at the expense of a dojo.require statement, which acts like #include from C++ or an import statement from Python or Java. Before providing an overview of what’s available in Core, however, it’s worth briefly summarizing how the dojo.require statement works, because it is a staple in the toolkit.

Requiring Resources

In Dojo parlance, a dojo.require statement generally fetches an entire module or a resource that is part of a module, and a module is just a JavaScript file arranged according to a particular convention. For example, if you were to download a source distribution of Dojo and browse the contents of the dojo/io folder, you’d see that an iframe.js file and a script.js file are present. The first statement in each of these files is dojo.provide(“dojo.io.iframe”) and dojo.provide(“dojo.io.script”), respectively. In this case, you’d say that the dojo.io module provides the iframe and script resources. The basic trade-off when designing modules is the balance between minimizing HTTP requests that incur a lot of latency and not downloading more content than you actually need. (The build tools included in Util, however, can consolidate multiple resource files into a single minified JavaScript file that nearly obliterates any concern surrounding this particular issue for many cases.)

Let’s put dojo.require to work by having it retrieve the dojo.io.script resource that we’ll use to fetch some public data using Flickr’s JSON with padding (JSONP) API. Like almost everything else in the toolkit, the dojo.io.script.get function that we’ll use abstracts most of the dirty work away, so you don’t have to write or maintain any of that brittle boilerplate:

//Require what you need...
dojo.require("dojo.io.script");

//...but don't reference it outside of the dojo.addOnLoad
//block or you'll create a race condition since dojo.require
//statements are satisfied asynchronously over the CDN...
dojo.addOnLoad(function() {
  dojo.io.script.get({
     callbackParamName : "jsoncallback", //provided by Flickr
     url: "http://www.flickr.com/services/feeds/photos_public.gne",
     load : function(response, ioArgs) {
      /* response is a JSON object with data about public photos */
      return response;
    },
    error : function(response, ioArgs) {
      /* ... handle the error ... */
      return response;
    }
  });

}

More Core

Although there’s not time to gloss over Core systematically the same way we did with Base, it’s well worth the time to explore it, and you’re now equipped with enough fundamental knowledge to go do some digging on your own. A few of the resources you’ll find in Core include:

  • Internationalization facilities and functions for computing dates,times and formatting currency.
  • Additional animation capabilities.
  • The IFRAME transport (useful for uploading files to the server).
  • Functions for handling cookies.
  • Powerful data APIs that abstract cumbersome server-side I/O.
  • Drag-and-drop machinery.

More Toolkit

And even though Base and Core are two substantial components of the toolkit, there’s also Dijit, DojoX and Util, which easily could span entire articles and books of their own. In short, Dijit is a huge infrastructure of DHTML-based turn-key widgets. DojoX is a collection of specialized subprojects ranging from wrappers around Google Gears to graphics functions that can use scalable vector graphics (SVG) to draw in the browser natively. Util provides DOH, a unit-testing framework and a collection of build tools for squeezing as much performance as possible out of your JavaScript. Although not covered in this article, these topics are well worth investigating and are just as important to your development efforts as Base and Core.

Resources

The Dojo Toolkit: dojotoolkit.org

The Official Dojo API: redesign.dojotoolkit.org

Firebug: getfirebug.com

Mozilla’s Developer Documentation on Arrays:
developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array

CSS3 Selectors: www.w3.org/TR/css3-selectors/#selectors

W3C Documentation on DOM Events: www.w3.org/TR/DOM-Level-2-Events/events.html

Python’s Twisted Matrix: twistedmatrix.com

MochiKit Deferreds: www.mochikit.com/doc/html/MochiKit/Async.html#fn-deferred

REST: en.wikipedia.org/wiki/Representational_State_Transfer

JSON-RPC: json-rpc.org

JSONP: ajaxian.com/archives/jsonp-json-with-padding

Flickr API: www.flickr.com/services/api

Clean Licensing: Why You Should Care (If You Don’t Already):
alex.dojotoolkit.org/?p=654

Dojo: The Definitive Guide by Matthew Russell:
www.amazon.com/Dojo-Definitive-Guide-Matthew-Russell/dp/0596516487

Matthew Russell is a computer scientist and technologist whose latest pastime entailed authoring Dojo: The Definitive Guide. With what little time is left over from writing, hacking on Web technology and noodling on hard computer science problems, he enjoys getting as far away from technology as possible by escaping for long bike rides near his home in Franklin, Tennessee.