You are reading an article. Lots more of these in the archives. Rick Barraza Meet Rick Arrow

Articles

8Comment Retweet

Translating Canvas with HTML5

Oct 12, 2010 By Rick Barraza

Like most designers, I express myself, and feel most at ease, when communicating with motion and rhythm; with patterns of numbers or patterns of pixels

Design as a First Language

I didn’t start speaking till I was four. And while I have developed a reputation for running fashionably late on occasion as an adult, I’ve been told other factors were most likely at play here. It seems many of us creative types, or generally speaking, right brain dominant individuals may tend to struggle with language skills during our early development. Makes sense, language being such a classically left brain dominant activity and all.

codeMaybe that is why I’ve had such a lifelong fascination with languages — because I still view them as an outsider. I love everything about them. How they spread and mutate. How they saturate the way their speakers see the world. How learning a new language can reformat how you perceive reality. I love studying languages because, even now, verbal communication is not my primary language. Like most designers, I express myself, and feel most at ease, when communicating with motion and rhythm; with patterns of numbers or patterns of pixels. But putting this into a language, be it a spoken language or a computer language, always requires translation from the non-verbal solution we see in our heads to whatever linear medium is required to transmit it.

I spend most of my time these days developing high impact,rapid prototypes in Emerging Technologies and have several times been placed in a position that required me to learn a new programming language in a ridiculously short period of time. Actually,it would be better said, I needed to know just enough of a new language to get across whatever experience I was attempting to convey; many times forgetting the language just as quickly as I learned it once the project is done. Of course, I would always have my favorites, if the choice of language wasn’t a constraint of the project. For several years, it was Flash based ActionScript. In more recent years, it has generally been Silverlight. Both are well suited for rapidly creating visually rich interactions. But at the end of the day, they are still only the languages; still only the carriers.

Learning HTML5

Recently, I was commissioned to create a new experience in HTML5 for the IE9 Beta launch. Having looked at and rejected JavaScript as not being visually powerful enough all those years ago, it was with some reservation that I approached the assignment. Because, while I believe all computer languages are an act of translation for us as designers, in the real world, it is a lot easier to translate from some languages into others. Translating interaction techniques between Flash and Silverlight or between Processing or OpenFrameworks? Sure thing, no problem. But port it over to HTML and JavaScript? A traditionally static, Document based Object Model? Yeah, no thanks.

But then I discovered HTML5 and Canvas.

Jitterbugs!

Having only 8 weeks to go from concept creation to final deployment, the ability for me to create quickly was essential. With Canvas, JavaScript finally gave me a usable entry point to get up to speed and be productive with the language. Unlike the traditional DOM, Canvas provides a metaphor that is more in line with my solution process and techniques in whatever language I choose. I found Canvas to be very powerful, and the hardware acceleration on Internet Explorer 9 is second to none. So finally, I was able to create experiences in HTML that were on par with experiences I would create in other more graphics friendly languages. However, there were a couple hurdles early on and I hope to use the rest of this article to highlight a couple points I picked up along the way.

Animating Graphics with Canvas

No matter what visual language I need to learn, the translation process always starts the same. The very first thing I solve is “How do I put multiple visuals on a screen and animate them to fly around?” That solution will usually reveal the basics of object collection, rendering graphics, setting properties on elements, and whatever repetitive function call you can use as your animation loop. If you look at the source Ccode for the game I created, Jitterbugs, you’ll see that when I’m drawing all those bugs flying around, I initially load them in a function that looks something like this:

var Bugs = [];
function loadBugs() {
   For ( var i = 0; i < totalBugs; i++) {
             var temp = new Object;
            temp.x = Math.random()*STAGE_WIDTH;
             temp.y = Math.random() * STAGE_HEIGHT;
             temp.vx = Math.random()-Math.random();
             temp.vy = Math.random()-Math.random();
       Bugs.push(temp);
   }
}

With the exception of some basic punctuation or syntax, the above phrase is understandable and almost workable in most popular visual languages. Try it in Flash or Silverlight. With a couple tweaks you should have no problem. Same thing with JavaScript.

However, if you want to draw to the screen with Canvas in JavaScript, there is one preliminary step that you need to do first. When you initialize your application, you will need to create a drawing context for the Canvas you want draw into. So if you have a canvas in your HTML like this:

<canvas id="canvasRoot"></canvas>
<div id="imageResources" style="display:none;" tabIndex="-1">
  <img id="bugGraphic" src="ui/bug.png"/>
</div>

And you have created a reference to it in JavaScript like this:

var canvasRoot;
var bugGraphic;
[…]
canvasRoot = document.getElementById("canvasRoot");
bugGraphic = document.getElementById("bugGraphic");

You will also need to create and store a reference to the drawing context of that canvas before you actually want to paint into it on the screen. So you will need to add:

var canvasRoot;
var ctxRoot;
var bugGraphic;
[…]
canvasRoot = document.getElementById("canvasRoot");
ctxRoot = canvasRoot.getContext('2d');
document.body.appendChild(canvasRoot);
bugGraphic = document.getElementById(“bugGraphic”);

Setting up a gameLoop is just as easy as setting up an OnEnterFrame() in Flash or CompositionTarget.Rendering() in Silverlight. Something like this should do it for you:

var timer;
[…]
timer = setInterval( gameLoop, 20);

So with a collection of objects to draw, a reference to the canvas and it's drawing context, and an animation loop all setup, the actual rendering code could look as simple as this:

function gameLoop() {
  //SETTING THE WIDTH OF A CANVAS AUTOMATICALLY CLEARS IT
  canvasRoot.width = STAGE_WIDTH;
  var temp;
  for ( var i = 0; i < Bugs.length; i++) {
       temp = Bugs[i];
      temp.x += temp.vx;
      temp.y += temp.vy;
      ctxRoot.drawImage(bugGraphic, temp.x, temp.y);
    }
}

That wasn't so hard, right? In fact, you're probably starting to see that working with Canvas in JavaScript looks an awful lot like working with visuals in whatever your preferred visual language is.

An Idiom of the Language

And yet, every foreign language has something unexpected about it that may seem downright quirky at the time you're learning it. For me, when learning to speak Canvas in HTML5, it was figuring out how to handle individual rotations.

BugIn most other visual languages, whatever element you have on screen can usually have its own rotation manipulated somehow. Either through an attached RenderTransform or equivalent, or as a direct property of the element itself. But stamping rotated images into a single Canvas in JavaScript can be a little tricky, since the drawImage function doesn't have any overload methods that accepts a rotation parameter. So here is one way to solve it that worked for me.

In the example above, the canvas was stationary and the image was drawn with an x and y value that indicated the bug’s position relative to the Canvas origin at it's upper left corner. But to get rotation, you need to translate the entire origin of the Canvas, Do a global rotation of the canvas, and then draw the image at this new, modified world origin. In other words, you don't move the graphic relative to the view origin, you move and rotate the view origin and draw the graphic right there. Saying the same thing in code may be easier to understand:

for ( var i = 0; i < Bugs.length, i++) {
[…]
    ctxRoot.translate(temp.x, temp.y);
    ctxRoot.rotate(someAngleInRadians);
    ctxRoot.drawImage(bugGraphic, 0, 0);
}

There are two problems with this. First, for simplicity's sake, I used a made up variable called someAngleInRadians. Since I'm drawing a bug with a clear head and tail, I would rather use some basic trigonometry like this:

ctxRoot.rotate(Math.atan2(temp.vy, temp.vx));

to make sure the bug is always rotated to face in the direction I have him travelling. Man, I love that function in any language. But more importantly, since we're making the changes to the entire world space of the Canvas drawing context, those changes are going to be cumulative through our loop if we don't watch out. As soon as we draw the next bug, he would be starting off with the world coordinates of the canvas already manipulated and trust me, craziness ensues of the not good kind variety. We therefore need to SAVE and RESTORE the drawing context every time we want to manipulate it for an individual element.

So the final function would actually look like this:

function gameLoop() {
canvasRoot.width = STAGE_WIDTH;
ctxRoot.save();
var temp;
for ( var i = 0; i < Bugs.length; i++) {
       temp = bugs[i];
     temp.x += temp.vx;
     temp.y += temp.vy;
     temp.vx += Math.random()-Math.random();
     temp.vy += Math.random()-Math.random();
     ctxRoot.save();
     ctxRoot.translate(temp.x, temp.y);
     ctxRoot.rotate(Math.atan2(temp.vy, temp.vx));
     ctxRoot.drawImage(bugGraphic, -.5*temp.width, -5.temp.height, temp.width, temp.height);
     ctxRoot.restore();
}
ctxRoot.restore();
}

Those SAVE and RESTORE commands are essential. If it seems a little strange at first, consider it an idiom of the language. They become familiar over time.

Last point, you may have noticed that I used a more complex drawImage() function this time that took some additional parameters. That is because I wanted the point of rotation, or the origin of my bugGraphic to be in the center of the image, not the upper left corner like it would have been had I just drawn the image at 0,0 in the translated and rotated world space of Canvas. If you don’t completely get it, try playing around with the negative .5 values and you’ll see how they change where in the bugGraphic it appears to be rotating around.

In Conclusion

Hopefully, these few phrases of Javascript I’ve shared today have shown how accessible working with the new Canvas element can be. As I mentioned earlier, this dynamic graphics approach new to HTML5 coupled with the hardware acceleration muscle of Internet Explorer 9 makes this a powerful feature of the language. As with learning most languages, some aspects may seem a little quirky, some things may be pleasant surprises, but the challenges always seem to be worth the effort. If for no other reason, it gives us a chance to appreciate and become better in our own native tongue, whatever that may be.

Follow the Conversation

8 comments so far. You should leave one, too.

ItsAdam ItsAdam said on Oct 15, 2010

http://html5.cynergysystems.com/

Doesn''t work bro, getting stuck at 88% on 3 different machines using IE9 Beta.

Though open the site up in Google Chrome and it loads right away ;)

Also the site refuses to open on FireFox (PC).

Casey said on Oct 15, 2010

Uhm...why in the world would someone actually use IE or compliment it, especially a "designer?"

Andres Galindo Andres Galindo said on Oct 16, 2010

@Casey, he specified IE9 which is actually a half-decent browser. Not up to par with WebKit powered browser but it will certainly give Firefox a run for it''s money from an end-user perspective.

Matchu Matchu said on Oct 16, 2010

IE9 has hardware acceleration for the canvas element, which I think WebKit has as well, but not yet enabled by default.

Jack Bond said on Feb 13, 2011

You could do animations in assembly too!!! HTML 5 continues the tradition of HTML as being a complete and total JOKE for real development. Where is the native animation support? The committee has heard of animations haven''t they? I can''t believe the hype over HTML 5. The open source loonies (this is not directed at Rick) get one more layout container and they think they''ve discovered a cure for cancer. Can''t wait to see the hacked up solutions that HTML weenies come up with to animate their pages. Oh wait, I''d rather not.

Bryan said on Mar 3, 2011

Native animation support in HTML? I love trolls. I really do. :)

HTML Codes Dude said on May 11, 2011

Canvas is the poster boy for HTML5 and there are some great experiments out there. It''s early days but over time this will become the defacto way to create online games and animations.

lindanisbett.com » Blog Archive » Designer News for November 21 – 2011 said on Nov 21, 2011

[...] Mix Online: Translating Canvas with HTML5 [...]