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

Setting the Text Font

Now that we have placed text on the canvas, it’s time to explore some of the basics of setting the context.font property. As you will see, specifying the font for displaying basic text on Canvas is really no different from doing the same thing in HTML and CSS.

Font Size, Face Weight, and Style Basics

It is very easy to style text that will be rendered on the canvas. It requires you to set the size, weight, style, and font face in a CSS-compliant text string that is applied to the context.font property. The basic format looks like this:

[font style] [font weight] [font size] [font face]

An example might be:

context.font = "italic bold 24px serif";

or:

context.font = "normal lighter 50px cursive";

Once the context.font property is set, it will apply to all text that is rendered afterward—until the context.font is set to another CSS-compliant string.

Handling Font Size and Face in Text Arranger

In Text Arranger, we have implemented only a subset of the available font options for displaying text. We have chosen these to make the application work in as many browsers as possible. Here is a short rundown of the options we will implement.

Available font styles

CSS defines the valid font styles as:

normal | italic | oblique | inherit

In Text Arranger, we have implemented all but inherit.

Here is the markup we used to create the font style <select> box in HTML. We made the id of the form control equal to fontStyle. We will use this id when we listen for a change event, which is dispatched when the user updates the value of this control. We will do this for all the controls in this version of Text Arranger:

<select id="fontStyle">
 <option value="normal">normal</option>
 <option value="italic">italic</option>
 <option value="oblique">oblique</option>
</select>

Available font weights

CSS defines the valid font weights as:

normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit | auto

We have used only normal, bold, bolder, and lighter in Text Arranger. You can add the other values as you see fit.

Here is the markup we used to create the font weight <select> box in HTML:

<select id="fontWeight">
 <option value="normal">normal</option>
 <option value="bold">bold</option>
 <option value="bolder">bolder</option>
 <option value="lighter">lighter</option>
</select>

Generic font faces

Because we cannot be sure which font will be available in the browser at any time, we have limited the font face choices in Text Arranger to those that are defined as “generic” in the CSS specification: serif, sans-serif, cursive, fantasy, and monospace.

Here is the markup we used to create the font face <select> box in HTML:

<select id="textFont">
 <option value="serif">serif</option>
 <option value="sans-serif">sans-serif</option>
 <option value="cursive">cursive</option>
 <option value="fantasy">fantasy</option>
 <option value="monospace">monospace</option>
</select>

Font size and HTML5 range control

To specify the size of the font, we have implemented the new HTML5 range form control. range is an <input> type that creates a slider on the HTML page to limit the numerical input to that specified in the range. A range is created by specifying range as the type of a form input control. range has four properties that can be set:

min

The minimum value in the range

max

The maximum value in the range

step

The number of units to step when the range slider is moved

value

The default value of the range

Here is the markup we used to specify the range in the Text Arranger HTML:

<input type="range" id="textSize"
 min="0"
 max="200"
 step="1"
 value="50"/>

If the browser does not support this range control, it will be rendered as a text box.

Note

At the time of this writing, range did not render in Firefox.

Creating the necessary variables in the canvasApp() function

In the canvasApp() container function, we need to create four variables—fontSize, fontFace, fontWeight, and fontStyle—that will hold the values set by the HTML form controls for Text Arranger. We create a default value for each so that the canvas can render text the first time the drawScreen() function is called. After that, drawScreen() will be called only when a change event is handled by one of the event handler functions we will create for each form control:

var fontSize = "50";
var fontFace = "serif";
var fontWeight = "normal";
var fontStyle = "normal";

Setting event handlers in canvasApp()

Just like we did in version 1.0 of Text Arranger, we need to create event listeners and the associated event handler functions so changes on the HTML page form controls can interact with HTML5 Canvas. All of the event listeners below listen for a change event on the form control:

formElement = document.getElementById("textSize");
formElement.addEventListener('change', textSizeChanged, false);

formElement = document.getElementById("textFont");
formElement.addEventListener('change', textFontChanged, false);

formElement = document.getElementById("fontWeight");
formElement.addEventListener('change', fontWeightChanged, false);

formElement = document.getElementById("fontStyle");
formElement.addEventListener('change', fontStyleChanged, false);

Defining event handler functions in canvasApp()

Below are the event handlers we need to create for each form control. Notice that each handler updates the variable associated with part of the valid CSS font string, and then calls drawScreen() so the new text can be painted onto the canvas:

function textSizeChanged(e) {
   var target = e.target;
   fontSize = target.value;
   drawScreen();
}

function textFontChanged(e) {
   var target = e.target;
   fontFace = target.value;
   drawScreen();
}

function fontWeightChanged(e) {
   var target = e.target;
   fontWeight = target.value;
   drawScreen();
}

function fontStyleChanged(e) {
   var target = e.target;
   fontStyle = target.value;
   drawScreen();
}

Setting the font in the drawScreen() function

Finally, in the drawScreen() function, we put all of this together to create a valid CSS font string that we apply to the context.font property:

context.font = fontWeight + " " + fontStyle + " " + fontSize + "px " + fontFace;

Figures 3-3 and 3-4 show the results.

Setting the font size and face

Figure 3-3. Setting the font size and face

Setting the font as bold and italic

Figure 3-4. Setting the font as bold and italic

Font Color

Setting the font color for text rendered on HTML5 Canvas is as simple as setting the context.fillStyle or context.strokeStyle property to a valid CSS RGB color. Use the format “#RRGGBB”, where RR is the red component hexadecimal value, GG is the green component hexadecimal value, and BB is the blue component hexadecimal value. Here are some examples:

context.fillStyle = "#FF0000";

Sets the text fill to red.

context.strokeStyle = "#FF00FF";

Sets the text stroke to purple.

context.fillStyle = "#FFFF00";

Sets the text fill to yellow.

Handling font color with JSColor

For Text Arranger, we will allow the user to select the text color. We could have made this a drop-down or a text box, but instead, we want to use the new HTML5 <input> type of color. This handy new form control works directly in the web browser, allowing users to visually choose a color from a beautifully designed color picker. At the time of this writing, only Opera has implemented the color <input> object of the HTML5 specification.

However, since we could really use a nice color picker for Text Arranger, we will implement a third-party color picker, JSColor (http://jscolor.com/). The jsColor control creates a nice color picker in JavaScript (see Figure 3-5), similar to the one that will someday grace browsers supporting HTML5.

To implement jsColor and the color picker for Text Arranger, first download the jscolor.js library and put it in the same folder as Text Arranger. Then, add this line of code in the <head> to include jsColor in the HTML page:

<script type="text/javascript" src="jscolor/jscolor.js"></script>

Then add a new <input> element to the ever-growing HTML <form> on the Text Arranger HTML page, and give it the CSS class designation color:

<input class="color" id="textFillColor" value="FF0000"/>

When you pick a color with jsColor, it creates a text value that looks like “FF0000”, representing the color value chosen. However, we already know that we need to append the pound (#) sign to the front of that value to work with HTML5 Canvas. The textFillColorChanged event handler does this by appending “#” to the value of the textFillColor form control:

function textFillColorChanged(e) {
      var target = e.target;
      textFillColor = "#" + target.value;
      drawScreen();
   }

Oh yes, and let’s not forget the event listener we must create so that we can direct and “change” events from the textFillColor <input> element to the textFillColorChanged() event handler:

formElement = document.getElementById("textFillColor");
formElement.addEventListener('change', textFillColorChanged, false);

Finally, in the canvasApp() function, we need to create the textFillColor variable:

var textFillColor = "#ff0000";

We do this so that the variable can be updated by the aforementioned event handler, and then implemented when that event handler calls the drawScreen() function:

switch(fillOrStroke) {
   case "fill":
      context.fillStyle = textFillColor;
      context.fillText (message, xPosition,yPosition);
      break;
   case "stroke":
      context.strokeStyle = textFillColor;
      context.strokeText (message, xPosition,yPosition);
      break;
   case "both":
      context.fillStyle = textFillColor;
      context.fillText (message, xPosition ,yPosition);
      context.strokeStyle = "#000000";
      context.strokeText (message, xPosition,yPosition);
      break;
 }

Notice that we needed to update the switch() statement created for Text Arranger version 1.0 so that it used textFillColor instead of hardcoded values. However, when both a stroke and a fill are chosen, we still render the stroke as black (“#000000”). We could have added an additional color picker for the strokeColor, but that is something you can do if you want to start expanding the application. Figure 3-5 illustrates what it looks like now.

Setting the font color

Figure 3-5. Setting the font color

Font Baseline and Alignment

You have options to align text on HTML5 Canvas both vertically and horizontally. These alignments affect the text in relation to Canvas itself, but only to the invisible bounding box that would surround the text’s topmost, bottommost, rightmost, and leftmost sides. This is an important distinction because it means these alignments affect the text in ways that might be unfamiliar to you.

Vertical alignment

The font baseline is the vertical alignment of the font glyphs based on predefined horizontal locations in a font’s em square (the grid used to design font outlines) in relation to font descenders. Basically, font glyphs, like lowercase p and y that traditionally extend “below the line,” have descenders. The baseline tells the canvas where to render the font based on how those descenders relate to other glyphs in the font face.

The HTML5 Canvas API online has a neat graphic that attempts to explain baseline. We could copy it here, but in reality, we think it’s easier to understand by doing, which is one of the main reasons we wrote the Text Arranger application.

The options for the context.textBaseline property are:

top

The top of the text em square and the top of the highest glyph in the font face. Selecting this baseline will push the text the farthest down (highest y position) the canvas of all the baselines.

hanging

This is a bit lower than the top baseline. It is the horizontal line from which many glyphs appear to “hang” from near the top of their face.

middle

The dead vertical center baseline. We will use middle to help us vertically center the text in Text Arranger.

alphabetic

The bottom of vertical writing script glyphs such as Arabic, Latin, and Hebrew.

ideographic

The bottom of horizontal writing script glyphs such as Han Ideographs, Katakana, Hiragana, and Hangul.

bottom

The bottom of the em square of the font glyphs. Choosing this baseline will push the font the farthest up (lowest y position) the canvas.

So, for example, if you want to place your text with a top baseline, you would use the following code:

context.textBaseline = "top";

All text displayed on the canvas afterward would have this baseline. To change the baseline, you would change the property:

context.textBaseline = "middle";

In reality, you will probably choose a single baseline for your app and stick with it, unless you are creating a word-processing or design application that requires more precise text handling.

Horizontal alignment

The context.textAlign property represents the horizontal alignment of the text based on its x position. These are the available textAlign values:

center

The dead horizontal center of the text. We can use this alignment to help center our text in Text Arranger.

start

Text is displayed directly after the text y position.

end

All text is displayed before the text y position.

left

Text is displayed starting with the y position of the text in the leftmost position (just like start).

right

Text is displayed with the y position in the rightmost position of the text (just like end).

For example, to set the text alignment to center, you would use the code:

context.textAlign = "center";

After this property is set, all text would be displayed with the y value of the text as the center point. However, this does not mean the text will be “centered” on the canvas. To do that, you need to find the center of the canvas, and use that location as the y value for the text position. We will do this in Text Arranger.

These values can also be modified by the dir attribute of the Canvas object (inherited from the DOM document object). dir changes the direction of how text is displayed; the valid values for dir are rtl (“right to left”) and ltr (“left to right”).

Handling text baseline and alignment

We are going to handle the text baseline and alignment much like we handled the other text properties in Text Arranger. First, we will add some variables to the canvasApp() function in which Text Arranger operates that will hold the alignment values. Notice that we have set the textAlign variable to center, helping us simplify centering the text on the canvas:

var textBaseline = "middle";
var textAlign = "center";

Next, we add the <select> form elements for each new attribute to the HTML portion of the page:

Text Baseline <select id="textBaseline">
  <option value="middle">middle</option>
  <option value="top">top</option>
  <option value="hanging">hanging</option>
  <option value="alphabetic">alphabetic</option>
  <option value="ideographic">ideographic</option>
  <option value="bottom">bottom</option>
  </select>
  <br>
  Text Align <select id="textAlign">
  <option value="center">center</option>
  <option value="start">start</option>
  <option value="end">end</option>
  <option value="left">left</option>
  <option value="right">right</option>

  </select>

We then add event listeners and event handler functions so we can connect the user interaction with the HTML form elements to the canvas display. We register the event listeners in the canvasApp() function:

formElement = document.getElementById("textBaseline");
formElement.addEventListener('change', textBaselineChanged, false);

formElement = document.getElementById("textAlign");
formElement.addEventListener('change', textAlignChanged, false);

Next, we need to create the event handler functions inside canvasApp():

function textBaselineChanged(e) {
   var target = e.target;
   textBaseline = target.value;
   drawScreen();
}

function textAlignChanged(e) {
   var target = e.target;
   textAlign = target.value;
   drawScreen();
}

We then apply the new values in the drawScreen() function:

context.textBaseline = textBaseline;
context.textAlign = textAlign;

Finally, we change the code that centers the text horizontally on the screen. Because we used the center alignment for context.textAlign, we no longer need to subtract half the width of the text that we retrieved through context.measureText() like we did previously in Text Arranger 1.0:

var metrics = context.measureText(message);
var textWidth = metrics.width;
var xPosition = (theCanvas.width/2) - (textWidth/2);

Instead, we can simply use the center point of the canvas:

var xPosition = (theCanvas.width/2);

Remember, center is only the default alignment for the text. Because you can change this with Text Arranger, the text can still be aligned in different ways while you are using the application.

Figure 3-6 shows how a font set to start alignment with a middle baseline might appear on the canvas.

Font with start alignment and middle baseline

Figure 3-6. Font with start alignment and middle baseline

Text Arranger Version 2.0

Now, try the new version of Text Arranger, shown in Example 3-2. You can see that we have added a ton of new options that did not exist in version 1.0. One of the most striking things is how fluidly the text grows and shrinks as the font size is updated. Now, imagine scripting the font size to create animations. How would you do that? Could you create an application to record the manipulations the user makes with Text Arranger, and then play them back in real time?

Also, notice how all the alignment options affect one another. Experiment with how changing the text direction affects the vertical alignment. Choose different font faces and see how they affect the baseline. Do you see how an application like Text Arranger can help you understand the complex relationships of all the text properties on HTML5 Canvas in an interactive and—dare we say—fun way?

Example 3-2. Text Arranger 2.0

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CH3EX2: Text Arranger Version 2.0</title>
<script src="modernizr-1.6.min.js"></script>
<script type="text/javascript" src="jscolor/jscolor.js"></script>
<script type="text/javascript">

window.addEventListener("load", eventWindowLoaded, false);
function eventWindowLoaded() {

   canvasApp();
}

function canvasSupport () {
     return Modernizr.canvas;
}

function eventWindowLoaded() {

   canvasApp();
}

function canvasApp() {

   var message = "your text";
   var fillOrStroke = "fill";

   var fontSize = "50";
   var fontFace = "serif";
   var textFillColor = "#ff0000";
   var textBaseline = "middle";
   var textAlign = "center";
   var fontWeight = "normal";
   var fontStyle = "normal";

   if (!canvasSupport()) {
          return;
        }

   var theCanvas = document.getElementById("canvasOne");
   var context = theCanvas.getContext("2d");

   var formElement = document.getElementById("textBox");
   formElement.addEventListener('keyup', textBoxChanged, false);

   formElement = document.getElementById("fillOrStroke");
   formElement.addEventListener('change', fillOrStrokeChanged, false);

   formElement = document.getElementById("textSize");
   formElement.addEventListener('change', textSizeChanged, false);

   formElement = document.getElementById("textFillColor");
   formElement.addEventListener('change', textFillColorChanged, false);

   formElement = document.getElementById("textFont");
   formElement.addEventListener('change', textFontChanged, false);

   formElement = document.getElementById("textBaseline");
   formElement.addEventListener('change', textBaselineChanged, false);

   formElement = document.getElementById("textAlign");
   formElement.addEventListener('change', textAlignChanged, false);

   formElement = document.getElementById("fontWeight");
   formElement.addEventListener('change', fontWeightChanged, false);

   formElement = document.getElementById("fontStyle");
   formElement.addEventListener('change', fontStyleChanged, false);

   drawScreen();

   function drawScreen() {
      
      //Background
      context.fillStyle = "#ffffaa";
      context.fillRect(0, 0, theCanvas.width, theCanvas.height);
      
      //Box
      context.strokeStyle = "#000000";
      context.strokeRect(5,  5, theCanvas.width−10, theCanvas.height−10);

      //Text
      context.textBaseline = textBaseline;
      context.textAlign = textAlign;
      context.font = fontWeight + " " + fontStyle + " " + fontSize + "px " + fontFace;

      var xPosition = (theCanvas.width/2);
      var yPosition = (theCanvas.height/2);

      switch(fillOrStroke) {
         case "fill":
            context.fillStyle = textFillColor;
                context.fillText (message, xPosition,yPosition);
            break;
         case "stroke":
            context.strokeStyle = textFillColor;
            context.strokeText (message, xPosition,yPosition);
            break;
         case "both":
            context.fillStyle = textFillColor;
                context.fillText (message, xPosition ,yPosition);
            context.strokeStyle = "#000000";
            context.strokeText (message, xPosition,yPosition);
            break;
      }

   }

   function textBoxChanged(e) {
      var target = e.target;
      message = target.value;
      drawScreen();
   }

   function fillOrStrokeChanged(e) {
      var target = e.target;
      fillOrStroke = target.value;
      drawScreen();
   }

   function textSizeChanged(e) {
      var target = e.target;
      fontSize = target.value;
      drawScreen();
   }

   function textFillColorChanged(e) {
      var target = e.target;
      textFillColor = "#" + target.value;
      drawScreen();
   }

   function textFontChanged(e) {
      var target = e.target;
      fontFace = target.value;
      drawScreen();
   }

   function textBaselineChanged(e) {
      var target = e.target;
      textBaseline = target.value;
      drawScreen();
   }

   function textAlignChanged(e) {
      var target = e.target;
      textAlign = target.value;
      drawScreen();
   }

   function fontWeightChanged(e) {
      var target = e.target;
      fontWeight = target.value;
      drawScreen();
   }

   function fontStyleChanged(e) {
      var target = e.target;
      fontStyle = target.value;
      drawScreen();
   }

}

</script>
</head>
<body>
<div style="position: absolute; top: 50px; left: 50px;">
<canvas id="canvasOne" width="500" height="300">
 Your browser does not support HTML5 Canvas.
</canvas>

<form>
  Text: <input id="textBox" placeholder="your text" />
  <br>

  Fill Or Stroke :
  <select id="fillOrStroke">
  <option value="fill">fill</option>
  <option value="stroke">stroke</option>
  <option value="both">both</option>
  </select>
  <br>
  Text Font: <select id="textFont">
  <option value="serif">serif</option>
  <option value="sans-serif">sans-serif</option>
  <option value="cursive">cursive</option>
  <option value="fantasy">fantasy</option>
  <option value="monospace">monospace</option>
  </select>
  <br>
  Text Size: <input type="range" id="textSize"
       min="0"
       max="200"
       step="1"
       value="50"/>
  <br>
  Text Color: <input class="color" id="textFillColor" value="FF0000"/>
  <br>
  Font Weight:
  <select id="fontWeight">
  <option value="normal">normal</option>
  <option value="bold">bold</option>
  <option value="bolder">bolder</option>
  <option value="lighter">lighter</option>
  </select>
  <br>
  Font Style:
  <select id="fontStyle">
  <option value="normal">normal</option>
  <option value="italic">italic</option>
  <option value="oblique">oblique</option>
  </select>
  <br>
  Text Baseline <select id="textBaseline">
  <option value="middle">middle</option>
  <option value="top">top</option>
  <option value="hanging">hanging</option>
  <option value="alphabetic">alphabetic</option>
  <option value="ideographic">ideographic</option>
  <option value="bottom">bottom</option>
  </select>
  <br>
  Text Align <select id="textAlign">
  <option value="center">center</option>
  <option value="start">start</option>
  <option value="end">end</option>
  <option value="left">left</option>
  <option value="right">right</option>

  </select>

</div>
</body>
</html>

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