Dojo, Now with Drawing Tools!

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.
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).

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.

3x3 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 3x3 matrix transformations.

Just in case you don't have a background with graphics, it may not be immediately apparent how 3x3 matrices and “all of that math” is useful. Basically, 3x3 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”.

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Please post missing file 10308.tgz

Anonymous's picture

When I try this link in the resources:

ftp://ftp.linuxjournal.com/pub/lj/issue178/10308.tgz

It's a bad link. I found this
ftp://ftp.linuxjournal.com/pub/lj/listings/issue178/README178

10042.tgz -- Web 2.0 Development with the Google Web Toolkit
Federico Kereki

10308.tgz -- Dojo, Now with Drawing Tools!
Matthew Russell

but this file is missing: 10308.tgz

very interesting, good for

Anonymous's picture

very interesting, good for gfx beginner just like me. thanks!

where is the download for listing 4

forestial's picture

Trying to download the code from listing 4 from the ftp link in Resources. I get a "550 Failed to change directory" error.

Tried browsing the ftp site, but there seems to be nothing there for this issue (178).

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix