Dependency Versions
This post was built with Ember.js 1.0.0RC1, handlebars RC3, and jQuery 1.9.1
Understand The Goal
What will we explore?
Our goal is to use Ember’s ContainerView class to wrap up multiple HTML5 canvas elements into a single, layered display. This pattern is extremely common for effective use of canvas elements and Ember offers an elegant solution for encapsulating them as a “unit”.
Show me the end product before I listen…
Feel free to check out this Completed Fiddle or build your own fiddle as we go.
Separating Signals and Noise
This project, and many that follow require some “support” code to achieve the end goal. Often times that code is not germane to the point the article is trying to make about Ember.js.
Signals
Use of Container/Canvas Views
Dynamic styling using computed properties
Initial Canvas drawing and re-rendering
Noise
Buttons to change linecount and supporting behavior validation
Local variable setup
Methods for drawing to canvas (these are worth exploring but don’t directly convey our purpose here)
Ember setup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | |
What is all this…stuff?
The ApplicationController is the context for all our views in this system. It will eventually also house a few basic methods to support some html buttons.
The CompositeView is an instance of Ember’s ContainerView and is used to hold the two canvases (which contain the bulk of the program’s code)
The Canvas Views are setup to wrap HTML5 canvas elements (see previous blogpost for details). We instantiate two of them as we intend to build a layered display.
Add a template and give our views some style
1 2 3 4 | |
This template is our application template (Ember automatically assigns this if no data-template-name is declared in the script tag). We add a line to confirm our app is rendering this template and we add a handlebars tag to create an instance of our view and bind its content to the applicationController’s appVars attribute.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
This View is now complete and will not change for the rest of this post. We have added a computed property called “style” to the view which constructs a string of
in-line styles to be added onto the view’s element, “div”, via the attributeBindings attribute. Read
Ember’s View API for more information on how these attributes work.
NOTE: This is not the only way to style an element but it showcases a method that will allow us to dynamically re-size our view if the view’s content.height or content.width are changed by our application.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
We have again added an attributeBindings method to our view but, critically, we have utilized it differently. In the CompositeView we used in-line style to set
our view’s height and width. Here, we must use the html attributes “height” and “width” to give dimensions to a canvas element. This is an important
distinction.
Attributes height and width are implemented as computed properties that simply reflect content.height and content.width. This again allows us
to re-size our canvases elsewhere in our application should we want to do so.
1 2 3 4 5 6 7 | |
Setting position:absolute on the canvas means they will draw directly on top of our div element rather than in normal html block format. The results of this aren’t yet apparent but they will be shortly. We set opacity so that our layers are partially transparent.
Canvas drawing code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | |
This class is now finished and will not change for the rest of this post.
This code looks a little dense but its purpose is very simple. It draws horizontal or vertical stripes onto our canvases using the low-level canvas API’s methods. It is easy to google these methods so I will not explain them here. The rest of the lines are dedicated to calculating x,y,height, and width based on our view’s content (which is inherited from applicationController.appVars). Feel free to tweet, email, or comment below if any of this is unclear.
NOTE: Be sure to remove the “return” we had listed in the fill method initially. It was only there as filler.
Finally, we also implement an Ember observer called layoutChanged which fires any time content.lineCount, content.height, or content.width change. We use this to signal to our canvas that it must re-draw itself. We don’t need to clear the canvas in this particular app because our draw process completely re-draws the whole canvas. This may not always be the case!
Dynamically re-draw our canvas by changing lineCount!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
These new methods on the applicationController change the lineCount attribute on appVars within the range 1->10. We will call these methods from our template as shown below.
1 2 3 4 5 6 7 | |
We have added buttons that utilize Ember’s action handlebars tag to call the new methods on applicationController. We now have a way for users to change the lineCount which creates such dreamy, dreamy patterns…
Conclusion and future work
Once again, here is a Completed Fiddle showcasing this application.
This post has highlighted a pattern that we intend to elaborate on with examples of UI widgets, editable objects, and more advanced canvas APIs. If you understand what is going on in this post and in the previous canvas post you will be prepared to do some truly useful things in Ember.js! Who doesn’t love being useful? Cats…that’s who.
/golfclap
/bow