Backbone.js, HTML5 Canvas, and the 3form Tile Configuration Tool

After months of working hand-in-hand with 3form, Inc., Digital Trike is excited to announce the release of the 3form Tile Configuration Tool. The Configuration Tool comes in multiple flavors, corresponding with 3form’s Studio product lines: Ditto, Wave Wall, Wovin Wall, and Ripple Wall.

Choosing the Right Tools for the Job

Going into it, we weren’t exactly sure what we were going to use to get the job done. We knew that Flash wouldn’t cut it (as it so rarely does these days), so a Javascript web app seemed like the obvious solution. We use jQuery extensively internally, but it too seemed ill-suited for such a complex task. That’s when we discovered Backbone.js, a lightweight MVC framework for Javascript (not dissimilar to the much weightier node.js). With the added power of Coffeescript and Compass, off we went!

HTML5 Canvas

The problem of rendering the tiles for the tool quickly came into view. We had a few options – SVG, images, or the HTML5 canvas. Noting that one of the requirements was the ability to save a copy of the tile design as an image, HTML5 canvas seemed like the obvious choice. The HTML5 canvas spec includes the ability to grab the element’s data as PNG data, which was put to good use in the tool. But using the canvas was not without its downsides.

Conquering HTML5 Canvas

jQuery unfortunately does not provide any interface for dealing with canvas elements. The prospect of using the JS native canvas interface was unattractive, though not unmanageable, but we discovered a jQuery extension, jCanvas, which helped simplify using canvas quite a bit.

The biggest downside to using canvas was the fact that canvas does not utilize the concept of layers, as it follows the “painting” method of rendering. Under a painting methodology, content is drawn directly on top of the image, but content from an area cannot be unrendered without clearing the entire area being redraw (removing not just the layers you want cleared, but the whole rectangle). Due to the complexity of the tile systems we were trying to model and their tricky layering rules, we had to address this in some interesting ways – primarily by making heavy use of “masking”, which means hiding parts of an image.

One of the layers being painted onto the canvas – the material layer – is an oddly-shaped area of color or predefined material image. In order to color in only the area we wanted for a given tile, we found a small plugin called Canvas Mask that applies a mask image to an area of the canvas, hiding any part of the layer outside of the mask area.

Backbone.js

The bulk of the project was writing Backbone.js code using Coffeescript. This was definitely a learning experience. While we’re familiar with Javascript coding, we’ve never had occasion to delve deep into the object oriented side of Javascript, and what a strange world it is. We’ve created some training material in a public git repository here to help developers get up-to-speed on Backbone.js, go ahead a take a look.

From a high-level, Backbone.js is all about splitting your code into small chunks of information in an organized manner. We create models for the different tile types, models for different material types, and so on. Backbone helped us create views to manage various levels of the app, from the high level of the app itself; to the meat of the app, the grid view; all the way down to tiny views for things like the scrollers for changing the installation dimensions. Given enough time, these tiny views and tiny models eventually started to grow and to build up into something usable and totally awesome.

Backbone Regrets

As awesome as Backbone is, our path was fraught with regret. There are many things we learned along the way that we really wish we had known to begin with, looking back on how many small mistakes had to be corrected and how much code was continually refactored. Here are a few of the things we learned:

  • Don’t take shortcuts. If something is logically distinct and self-contained, code it that way in the beginning, or you’ll eventually have to go back and separate it out later – and it will be harder then.
  • Craft your views such that when any data that concerns that view is changed, the whole view can re-render itself automatically.
  • There’s no built-in memory management. When you delete a view, it doesn’t go away, and all of its children and all of their models will continue listening for events, which can cause huge memory issues or other bugs if left unmanaged. Always track the subviews and models that are created and always destroy them when destroying the parent view. Every model and view should be responsible for turning on and off their own event listeners.
  • You can make up any event name you want, and trigger it/listen for it whenever you’d like. You are not limited to the default events, and custom events can greatly simplify some processes in the code.
  • Figure out a robust testing strategy early on. Learn how to use your browser’s console and all of its features, as each will help you greatly during development.

Conclusion

Backbone.js is a light, powerful JS framework, and it helped us successfully pull off this complex project. We will definitely keep it in mind next time we’re asking to overcome a challenging JS task like this one. HTML5 canvas is a powerful recent technology, but it’s not without pitfalls. It can be a great solution for many problems, but it can also be the exact opposite if not evaluated correctly.