You are previewing HTML5 Canvas.

HTML5 Canvas

Cover of HTML5 Canvas by Steve Fulton... Published by O'Reilly Media, Inc.
  1. HTML5 Canvas
    1. SPECIAL OFFER: Upgrade this ebook with O’Reilly
    2. A Note Regarding Supplemental Files
    3. Preface
      1. Running the Examples in the Book
      2. What You Need to Know
      3. How This Book Is Organized
      4. Conventions Used in This Book
      5. Using Code Examples
      6. We’d Like to Hear from You
      7. Safari® Books Online
      8. Acknowledgments
    4. 1. Introduction to HTML5 Canvas
      1. The Basic HTML Page
      2. Basic HTML We Will Use in This Book
      3. The Document Object Model (DOM) and Canvas
      4. JavaScript and Canvas
      5. HTML5 Canvas “Hello World!”
      6. Debugging with Console.log
      7. The 2D Context and the Current State
      8. The HTML5 Canvas Object
      9. Another Example: Guess The Letter
      10. What’s Next
    5. 2. Drawing on the Canvas
      1. The Basic File Setup for This Chapter
      2. The Basic Rectangle Shape
      3. The Canvas State
      4. Using Paths to Create Lines
      5. Advanced Path Methods
      6. Compositing on the Canvas
      7. Simple Canvas Transformations
      8. Filling Objects with Colors and Gradients
      9. Filling Shapes with Patterns
      10. Creating Shadows on Canvas Shapes
      11. What’s Next
    6. 3. The HTML5 Canvas Text API
      1. Displaying Basic Text
      2. Setting the Text Font
      3. Text and the Canvas Context
      4. Text with Gradients and Patterns
      5. Width, Height, Scale, and toDataURL() Revisited
      6. Final Version of Text Arranger
      7. What’s Next
    7. 4. Images on the Canvas
      1. The Basic File Setup for This Chapter
      2. Image Basics
      3. Simple Cell-Based Sprite Animation
      4. Advanced Cell-Based Animation
      5. Applying Rotation Transformations to an Image
      6. Creating a Grid of Tiles
      7. Zooming and Panning an Image
      8. Pixel Manipulation
      9. Copying from One Canvas to Another
      10. What’s Next
    8. 5. Math, Physics, and Animation
      1. Moving in a Straight Line
      2. Bouncing Off Walls
      3. Curve and Circular Movement
      4. Simple Gravity, Elasticity, and Friction
      5. Easing
      6. What’s Next?
    9. 6. Mixing HTML5 Video and Canvas
      1. HTML5 Video Support
      2. Converting Video Formats
      3. Basic HTML5 Video Implementation
      4. Preloading Video in JavaScript
      5. Video and the Canvas
      6. Video on the Canvas Examples
      7. Animation Revisited: Moving Videos
      8. What’s Next?
    10. 7. Working with Audio
      1. The Basic <audio> Tag
      2. Audio Formats
      3. Audio Tag Properties, Functions, and Events
      4. Playing a Sound with No Audio Tag
      5. Creating a Canvas Audio Player
      6. Case Study in Audio: Space Raiders Game
      7. What’s Next
    11. 8. Canvas Game Essentials
      1. Why Games in HTML5?
      2. Our Basic Game HTML5 File
      3. Our Game’s Design
      4. Game Graphics: Drawing with Paths
      5. Animating on the Canvas
      6. Applying Transformations to Game Graphics
      7. Game Graphic Transformations
      8. Game Object Physics and Animation
      9. A Basic Game Framework
      10. Putting It All Together
      11. The player Object
      12. Geo Blaster Game Algorithms
      13. The Geo Blaster Basic Full Source
      14. Rock Object Prototype
      15. What’s Next
    12. 9. Combining Bitmaps and Sound
      1. Geo Blaster Extended
      2. Creating a Dynamic Tile Sheet at Runtime
      3. A Simple Tile-Based Game
      4. What’s Next
    13. 10. Mobilizing Games with PhoneGap
      1. Going Mobile!
      2. Creating the iOS Application with PhoneGap
      3. Beyond the Canvas
      4. What’s Next
    14. 11. Further Explorations
      1. 3D with WebGL
      2. Multiplayer Applications with ElectroServer 5
      3. Conclusion
    15. Index
    16. About the Authors
    17. Colophon
    18. SPECIAL OFFER: Upgrade this ebook with O’Reilly
O'Reilly logo

Applying Rotation Transformations to an Image

In the previous section, we created an animation using tiles from a tile sheet. In this section, we will take it one step further and use the Canvas transformation matrix to rotate our image before drawing it to the canvas. This will allow us to use only a single set of animated tiles for all four (or more) rotated directions in which we would like to display our images. Before we write the code, let’s examine what it will take to rotate our tank animation from the previous section.

Note

In Chapter 2, we dove into applying basic transformations when drawing with paths. The same concepts apply to transforming images on the canvas. If you have not read the section Simple Canvas Transformations in Chapter 2, you might want to review it before reading on.

Canvas Transformation Basics

Although we covered basic Canvas transformations in detail in Chapter 2, let’s review what’s necessary to transform an individual object on the canvas. Remember, the canvas is a single immediate-mode drawing surface, so any transformations we make are applied to the entire canvas. In our example, we are drawing two objects. First, we draw a gray background rectangle, and then we copy the current tile from our tile sheet to the desired location. These are two discrete objects, but once they are on the canvas, they are both simply collections of pixels painted on the surface. Unlike Flash or other platforms that allow many separate sprites or “movie clips” to occupy the physical space, there is only one such object on Canvas: the context.

To compensate for this, we create logical display objects. Both the background and the tank are considered separate logical display objects. If we want to draw the tank but rotate it with a transformation matrix, we must separate the logical drawing operations by using the save() and restore() Canvas context functions.

Let’s look at an example where we rotate the tank 90 degrees so it is facing to the right rather than up.

Step 1: Save the current context to the stack

The save() context function will take the current contents of the canvas (in our case the gray background rectangle) and store it away for “safekeeping”:

   context.save();

Once we have transformed the tank, we will replace it with the restore() function call.

Step 2: Reset the transformation matrix to identity

The next step in transforming an object is to clear the transformation matrix by passing it values that reset it to the identity values:

context.setTransform(1,0,0,1,0,0)

Step 3: Code the transform algorithm

Each transformation will be slightly different, but usually if you are rotating an object, you will want to translate the matrix to the center point of that object. Our tank will be positioned at 50,50 on the canvas, so we will translate it to 66,66. Since our tank is a 32×32 square tile, we simply add half of 32, or 16, to both the x and y location points:

context.translate(x+16, y+16);

Next, we need to find the angle in radians for the direction we want the tank to be rotated. For this example, we will choose 90 degrees:

var rotation = 90;
var angleInRadians = rotation * Math.PI / 180;
context.rotate(angleInRadians);

Step 4: Draw the image

When we draw the image, we must remember that the drawing’s point of origin is no longer the 50,50 point from previous examples. Once the transformation matrix has been applied to translate to a new point, that point is now considered the 0,0 origin point for drawing.

This can be confusing at first, but it becomes clear with practice. To draw our image with 50,50 as the top-left coordinate, we must subtract 16 from the current position in both the x and y directions:

context.drawImage(tileSheet, sourceX, sourceY,32,32,-16,-16,32,32);

Example 4-7 adds in this rotation code to Example 4-4. When you run the example now, you will see the tank facing to the right.

Note

Notice in Example 4-7 that we remove the original call to drawScreen() from the previous examples, and replace it with a new event listener function that is called after the tileSheet has been loaded. The new function is called eventShipLoaded().

Example 4-7. Rotation transformation

var tileSheet = new Image();
tileSheet.addEventListener('load', eventShipLoaded , false);

tileSheet.src = "tanks_sheet.png";

var animationFrames = [1,2,3,4,5,6,7,8];
var frameIndex = 0;
var rotation = 90;

var x = 50;
var y = 50;

function eventShipLoaded() {
   drawScreen();
}

function drawScreen() {

   //draw a background so we can see the Canvas edges
   context.fillStyle = "#aaaaaa";
   context.fillRect(0,0,500,500);

   context.save();
   context.setTransform(1,0,0,1,0,0)

   context.translate(x+16, y+16);
   var angleInRadians = rotation * Math.PI / 180;
   context.rotate(angleInRadians);

   var sourceX = Math.floor(animationFrames[frameIndex] % 8) *32;
   var sourceY = Math.floor(animationFrames[frameIndex] / 8) *32;

   context.drawImage(tileSheet, sourceX, sourceY,32,32,-16,-16,32,32);

   context.restore();

}

function eventShipLoaded() {
    drawScreen();
}

Figure 4-8 shows the output for this example.

Applying a rotation transformation

Figure 4-8. Applying a rotation transformation

Let’s take this one step further by applying the animation technique from Example 4-5 and looping through the eight tiles while facing the tank at the 90-degree angle.

Animating a Transformed Image

To apply a series of image tiles to the rotated context, we simply have to add back in the frame tick loop code and increment the frameIndex variable on each frame tick. Example 4-8 has added this into the code for Example 4-7.

Example 4-8. Animation and rotation

var tileSheet = new Image();
tileSheet.addEventListener('load', eventShipLoaded , false);

tileSheet.src = "tanks_sheet.png";

var animationFrames = [1,2,3,4,5,6,7,8];
var frameIndex = 0;
var rotation = 90;
var x = 50;
var y = 50;

function eventShipLoaded() {
  startUp();
}

function drawScreen() {

  //draw a background so we can see the Canvas edges
  context.fillStyle = "#aaaaaa";
  context.fillRect(0,0,500,500);

  context.save();
  context.setTransform(1,0,0,1,0,0)
  var angleInRadians = rotation * Math.PI / 180;
  context.translate(x+16, y+16)
  context.rotate(angleInRadians);
  var sourceX = Math.floor(animationFrames[frameIndex] % 8) *32;
  var sourceY = Math.floor(animationFrames[frameIndex] / 8) *32;

  context.drawImage(tileSheet, sourceX, sourceY,32,32,-16,-16,32,32);
  context.restore();
  frameIndex++;
  if (frameIndex==animationFrames.length) {
      frameIndex=0;
  }

}

function startUp(){

  setInterval(drawScreen, 100 );
}

When you test Example 4-8, you should see that the tank has rotated 90 degrees, and the tank tracks loop through their animation frames.

As we did in Example 4-6, let’s move the tank in the direction it is facing. This time, it will move to the right until it goes off the screen. Example 4-9 has added back in the dx and dy movement vectors; notice that dx is now 1, and dy is now 0.

Example 4-9. Rotation, animation, and movement

var tileSheet = new Image();
tileSheet.addEventListener('load', eventShipLoaded , false);

tileSheet.src = "tanks_sheet.png";

var animationFrames = [1,2,3,4,5,6,7,8];
var frameIndex = 0;
var rotation = 90;
var x = 50;
var y = 50;
var dx = 1;
var dy = 0;

function eventShipLoaded() {
  startUp();
}

function drawScreen() {
   x = x+dx;
   y = y+dy;

  //draw a background so we can see the Canvas edges
  context.fillStyle = "#aaaaaa";
  context.fillRect(0,0,500,500);

  context.save();
  context.setTransform(1,0,0,1,0,0)
  var angleInRadians = rotation * Math.PI / 180;
  context.translate(x+16, y+16)
  context.rotate(angleInRadians);
  var sourceX=Math.floor(animationFrames[frameIndex] % 8) *32;
  var sourceY=Math.floor(animationFrames[frameIndex] / 8) *32;

  context.drawImage(tileSheet, sourceX, sourceY,32,32,−16,−16,32,32);
  context.restore();

  frameIndex++;
  if (frameIndex ==animationFrames.length) {
     frameIndex=0;
  }

}

function startUp(){

  setInterval(drawScreen, 100 );
}

When Example 4-9 is running, you will see the tank move slowly across the screen to the right. Its tracks animate through the series of tiles from the tile sheet on a plain gray background.

So far, we have only used tiles to simulate sprite-based animated movement. In the next section, we will examine how to use an image tile sheet to create a much more elaborate background using a series of tiles.

The best content for your career. Discover unlimited learning on demand for around $1/day.