Sunday, May 26, 2013

Style Scope with HTML5 Canvas

When working with HTML5 Canvas, we're constantly interacting with the canvas context object, which contains an abundance of cool styling properties and drawing methods.  For a typical block of code that draws something onto the canvas, we draw a path, set a handful of context properties to style whatever it is we're drawing, and then use methods like fill() and stroke() to actually draw things onto the canvas.  Piece of cake, right?
But what happens if we're creating large, complex canvas applications, and we have lots of methods and functions that draw things onto the canvas which can be executed in any order?  We certainly don't want styles from different parts of our code base leaking into other parts of the code base.  Here's an example:

Code Editor














As you can see, we're calling drawTransparentSquare() followed by drawSquare().  Since objects can be modified by reference in JavaScript, when the first function set the global alpha property to 0.5, the style leaked over into the next function call and made the second square transparent as well.  This obviously wasn't the desired result.
So what can we do do?  Should each of our methods and functions reset the context styles like a CSS reset for each function?  Although this could be achievable by creating a resetStyles() function which loops through all of the styling properties and sets them to their default values, it seems a bit odd to constantly reset all of the style properties each time a function call is made.  Is there a better way?

Style Scope Induction


Style scope refers to the scope of styling inside of code blocks, similar to the notion of variable scoping inside of code blocks.  When writing JavaScript code, for example, it's good practice to split the code base into a collection of modular methods and functions, such that variables created within each function are scoped only to that particular function, and aren't accessible outside of it.  This is called variable scope induction.  What we need here, is a way to induce style scope within a function, or any other block of code, in such a way that the styles applied to the context don't leak over into other functions or blocks of code.

The HTML5 Canvas State Stack: A Diamond in the Rough


One of the most powerful, and probably the most overlooked features of the HTML5 canvas, is the state stack.  The state stack stores snapshots of styles and transformations in a stack data structure via the save() method of the canvas context.  What's even more important is that we can also use the state stack to restore snapshots of styles and transformations with the restore() method.
So how can we use the state stack to induce style scope?  If we use the save() method at the beginning of a function definition, we can save the state of the canvas context in the state stack.  Once the state is saved, we can apply several context styles, draw things, and then restore the state stack back to the initial state with the restore() method.  Viola, we've just induced style scope.

No comments:

Post a Comment