May 2nd, 2009 Comments Off
Tags: ,

Category: News

Dojo’s Industrial-Strength Grid Widget (Linux Journal, Jun 09)

The latest, greatest copy of Linux Journal features a great primer I put together on Dojo’s really fab grid widget! The content was written a couple of months before the 1.3 release, but the code examples still work just fine with the latest version of 1.2. I start out by briefly introducing some dojo.data fundamentals and then show how the grid leverages these data APIs to do a lot of nifty things.

In early July, I’ll be allowed to reprint the article’s full content here under the terms of a free documentation license, and when that time comes, I’ll make sure it’s updated to work with the latest version of 1.3. In the meanwhile, I hope you enjoy the June edition of Linux Journal and make some time to get up close and personal with the grid widget.

April 21st, 2009 Comments Off
Tags: ,

Category: News

3 Hour Dojo Tutorial at OSCON in San Jose

If you’re coming out to OSCON this summer, be sure to drop in for my 3 hour Dojo tutorial that will add bit of kick to your web dev skills. I’ll lightly cover as much breadth as possible so that you have an appreciation for just how much is packed away in the toolkit, but we’ll certainly dig headfirst into especially interesting and fundamental areas of interest as well so that you have a firm grasp on those things you won’t want to live without.

If there are topics you’d like to see covered in particular, feel free to leave comments below, and I’ll do my best to make sure that they aren’t missed. Hope to see you there.

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

March 5th, 2009 Comments Off
Tags:

Category: News

For You Twitterers Out There

This is just a quick note for you twitterers out there: you can now follow dojotdg if that’s a more convenient way to keep up with new happenings than keeping an eye on your feed reader.

While we’re talking about Twitter, I might also add that you should take a moment to follow dojotoolkit if you’re not already doing so. Whereas dojotdg is who you’d follow for specific content that’s somehow related to my book and posted here on this blog, dojotoolkit is who you’d follow for “all things Dojo”. There’s potentially some overlap there, so follow both of us, and call it good.

March 5th, 2009 Comments Off
Tags: ,

Category: News

JavaScript/Ajax Bootcamp at the Big Nerd Ranch in May

Join me at the Big Nerd Ranch the first week of May for JavaScript/Ajax Bootcamp. Sure, there will be plenty of Dojo to go around, but we’ll also look at other technologies and toolkits throughout the course, so bring hard questions and interesting projects along with you. I’ll make sure you’re not disappointed and that you go back home with the knowledge you need to take care of business.

I’ve totally blocked off my schedule for the week I’m out at the ranch, so I’ll be completely available outside of the core teaching hours. Let’s get ready to do some serious immersion, work on interesting things after class, and have a great time.

If you’re attending the course, feel free let me know if there’s anything in particular that you’re especially interested in; given a little bit of lead time, I’ll do whatever I can to tweak the course content as long as we’re not getting too far out of scope.

February 18th, 2009 6 Comments »
Tags: ,

Category: Tips

Inspecting JSON APIs with afterOnLoad

On page 22 of my book, I provided a sidebar called “Injecting Dojo” in which I provided a hack for inserting Dojo into the page after onload (or equivalent) handlers have fired via dynamic SCRIPT tag insertion. The problem was that as of version 1.1, there wasn’t a good way to fire an addOnLoad handler after Dojo was ready, so the possibilities were a bit limited.

As of version 1.2, however, Dojo added full support for a configuration switch called afterOnLoad as well as the ability to pass in an addOnLoad handler right into djConfig. In combination, you get a nice, clean way to get Dojo running in the page after it’s already been loaded, whether it is via a bookmarklet or some other scenarios such as lazy-loading.

To demonstrate the utility of these features with a simple illustration, consider a scenario in which you’re debugging or inspecting a JSON API, and you’d like to reformat the output that appears in the browsers to be pretty-printed instead of all one one long line, so that it’s easier to read. You could install this snippet as a bookmarklet (by dragging and dropping that link into your browser’s toolbar for most browsers, or right clicking and saving it in IE) to get the job done:

(function() {
  djConfig={
    afterOnLoad: true,
    addOnLoad: function() {
      var _json = dojo.fromJson(dojo.body().innerHTML);
      dojo.body().innerHTML= "<html><body><pre>"+
      dojo.toJson(_json, true /* pretty print*/)+
      "</pre></body></html>";
    }
  };
  var e=document.createElement("script");
  e.type="text/javascript";
  e.src="http://o.aolcdn.com/dojo/1.2/dojo/dojo.xd.js";
  document.getElementsByTagName("head")[0].appendChild(e);
  })();

As you can well infer, the script is simply taking the body of the page and rewriting it as nicely-formatted JSON. It’s not hard to imagine baking in a little regex that scrapes off the “padding” part of a JSON-P API if you needed that kind of support.

February 9th, 2009 4 Comments »
Tags: , , ,

Category: News, Screencasts

iGoogle-like drag-and-drop for Shindig (ala Dojo)

My consulting firm has been spending a good bit of time augmenting and providing developer advice for a really interesting startup based out of Berkeley, CA called Life360; in case Life360 sounds familiar, it might be because they were one of the first place teams in Google’s Android Developer Challenge a while back. In short, the crew out in Berkeley is developing an incredible developer platform for “taking care of your family’s what-ifs”, and it’s been a lot of fun getting to be in on all of the discussions and working with the amazing talent on board there to see it happening.

One of the most recent tasks we’ve been working on is an iGoogle-like drag-and-drop container for gadgets. There’s a really nice project out there called Shindig that implements the gadget specification, but there’s little to be had in the way of a nice sophisticated container that gives you drag-and-drop operations, a custom title bar, and a maximized view. Well, after getting chunks of the new application platform wrapped up for some investment pitches in the coming weeks, we decided that it would be really cool to give some of this code back to the OSS community since we’ve benefited so much from Shindig, the LAMP stack, and a number of useful utilities here and there.

90 sec (6.4MB) QuickTime file of dnd in action across multiple browsers

4 min (13.5MB) QuickTime file of installing Shindig and using the container extensions

You can read the blog post on Life360.com for the details as well as watch some screencasts that walks you through downloading Shindig and putting the files to use, but I did want to take just a moment to make brief mention of a couple of the technical considerations that immediately come to mind:

  • When doing anything like this, you need infrastructure. For this part of the project, Dojo streamlined tons of things like setting up event handlers, styling nodes, getting coordinates on the screen, abstracting a lightweight fabric for drag-and-drop operations, and so forth. Currently, the code uses AOL’s CDN to keep things nice and simple, but you’d definitely want to use the build tools to consolidate and minify the code when it’s game time.
  • When an IFRAME is inserted into the DOM, it (re)loads. So, when you’re dragging an IFRAME all over the screen, its location in the DOM doesn’t change and it doesn’t continually reload because it’s just being positioned absolutely. It’s when the drag event ends that you’re faced with the reload event because you want to move it into its new column (versus trying to maintain the geometry of never manipulating the DOM tree and keeping track of everything in a snap-to-grid fashion.) Anyhow, that’s the approach we took. The one reload event that takes place when the gadget being drug reaches its final destination seemed more reasonable than all of that geometry. Other than the frame getting drug around, no other IFRAMES ever get removed and reinserted, so they never have to reload.
  • For security reasons, Shindig renders gadgets inside of their own individual IFRAMEs versus rendering gadgets in an element like a DIV. That may not sound like a big deal, but it does bring up a few more implementation details worth noting. The first one that comes to mind is that when you’re dragging a DIV that contains an IFRAME, it’s not uncommon for the mouse to occasionally slide ever so slightly into the IFRAME. Unfortunately, the IFRAME then captures mouse events, and then drag-and-drop starts to get choppy and wig out a bit. You can work around this by creating a transparent overlay and placing it on top of the IFRAME during drag events so that the IFRAME can never capture those mouse events. Overlays also come in handy when you popup menus on the titlebar and want them to disappear when the user clicks anywhere else on the screen (including in other IFRAMEs.) One day, hopefully, Caja will kill those IFRAMEs, which will also probably help performance a bit (especially on IE.)
  • There are a few peculiarities that arise when you remove the last element from a container like a DIV, so one way you can deal with this is to ensure it always has a minimum height and width by placing an element in there that spans the width of the column and has a minimal height so that it can accept drag events.
  • As always, there are always a few special cases, so you have to do a little extra bookkeeping here and there. Hopefully the code is commented well enough that it’s not hard to follow. All in all, it’s only about 150 lines for the drag and drop mechanics, including whitespace.

Life360 would love to have you go take a look at their site and rate some of their ideas, so why not head on over there, browse around, and leave some feedback on what they’re doing. Helping startups that have good intentions is the cool thing to do, right?

January 28th, 2009 9 Comments »
Tags: , ,

Category: Screencasts

Becoming More Productive With Dojo and Vim Screencast

Update: I’ve uploaded an mpeg-4 (~63MB) video of the screencast that you can access here if for some reason QuickTime’s H.264 format isn’t an option for you. I’m still a bit new at encoding video, so I’ll try to get the filesize down for next time.

I’ve been doing some reflecting this week on how I can work smarter (instead of harder), and one of the things I came up with was adding a few more tools to my Vim repertoire. I spend more than half of my engineering time in Vim (the other half usually being in a web browser), so I figured that a few minutes here and there would eventually add up in a big way.

In hopes of inspiring you to do the same, I put together a short screencast (~4mins; 14.5MB QuickTime file) that talks you through how to generate a custom tags file for Dojo’s API and the keystrokes to put it to work. Although I’m specifically using Dojo, I think this technique should probably apply to a lot of other toolkits as well assuming that they define API call in a consistent manner that can be approximated by a regex.

But like anything else with Vim, there are always multiple ways of accomplishing the very same thing, so I make no guarantees that there aren’t simpler ways of getting this done — but I can say that this way gets the job done, and is pretty easy to get working on your own system.

By the way, here are links to the generateTags.sh script and the tags file (for Core) mentioned in the screencast. I’ve slightly tweaked the tags file to remove duplicate tag names and a few things that weren’t really parts of the public API (regexes are obviously imperfect heuristics). I can’t say that the tags file may not be missing a few API calls, but tags are easy enough to add in manually if you do notice any omissions.

As time allows, I’ll try to get the Dijit API and DojoX API churned out and post back here with a consolidated tags file for the entire toolkit — that is, unless someone beats me to it, in which case I’d be happy to host or link back to the tags file you come up with if you send it over.

January 18th, 2009 Comments Off
Tags: ,

Category: Vetted Links

Navigating Source Code with ack

I’m an enthusiastic user of vim, so when you combine how much time I already spend in a terminal with the fact that it’s usually faster for me to look up something in Dojo’s source than reading the API docs, the quicker I can find what I need, the better.

Earlier this week, the O’Reilly Week In Review podcast asked me for a “tech tip”, so I thought I’d share a quick blurb about ack, a nifty little replacement for grep that has saved me tons of time in getting from vim to whatever it is I’m looking for in the source. The blurb is just a few seconds into the podcast and lasts less than two minutes, so go have a listen if you could use a better way to find things from the command line.

January 17th, 2009 Comments Off
Tags: ,

Category: News

Dojo, Now with Drawing Tools! (Linux Journal, Feb 09)

I was really excited when I got the Feb 09 issue of Linux Journal in the mail yesterday, because they did such a fantastic on laying out the article I put together on gfx, a module for cross-browser 2D drawing. It’s a fairly meaty nine page tutorial, there’s a ton of code examples in it (each with accompanying images that show you what the code examples produce) and overall, it’s clear that they really put some thought into making it look so nice in print.

Per my contracts with Linux Journal, I’m allowed to republish articles I write under an OSS license 30 days after they’ve been on newsstands, so once that time elapses, I’ll republish it here, just like I did for Using Dojo: The JavaScript Toolkit with Industrial Strength Mojo. But seriously — don’t let that dissuage you from paying the six bucks to get this February issue. It’s packed with great articles on web dev, and is one of my favorite issues in a long time.