Canvas GUI

In this section we will look at how to implement the HTML5 Canvas tag to create a GUI (Graphic User Interface), along with the audio tag to create full fledged applications on the browser. This opens us up to many new interesting opportunities such as making games.


The HTML5 Canvas tag is a rectangular element that we can draw on using JavaScript, with it we can make a varaity of things such as : graphs, animations, images, etc. Here is the setup:

<canvas id="myCanvas" width="100" height="100">

And our canvas is created:

As you can see the canvas is transparent, the canvas tag can have CSS applied to it like all other elements. It's very common to place a border around the canvas or center it:

CSS:

canvas{ 
   border: 1px solid black; // Place border around canvas
   display: block; // change to block-level so we can margin.
   margin: auto; // center canvas horizontally 
}


The Canvas uses a cartesian coordinate system such that (0,0) is the top left, (width, 0) is top right, (width, height) is bottom right, and (0, height) is bottom left.

Note: That applying CSS to the canvas width and height will make the canvas scale draw items to it's default size: 150x300. Mostly we don't want this behavior; be sure to apply width and height directly in the canvas HTML without using CSS or style, like the examples above.

In order to draw on the Canvas we need to get it and it's context:

var canvas = document.getElementById("myCanvas");   // The HTML canvas element
var ctx = canvas.getContext("2d");   // ctx (context) is the 2d drawing context of the canvas.

The context objects has a varaity of methods and properties to use for drawing on the canvas, here are some common ones:

  • Rectangle:
    • ctx.fillRect(x, y, width, height) - Draws a filled rectangle.
    • ctx.strokeRect(x, y, width, height) - Draws a outlined rectangle.
    • ctx.clearRect(x, y, width, height) - Clears a rectangle from the canvas.
  • Paths:
    • ctx.beginPath() - Starts a path.
    • ctx.moveTo(x, y) - Line starting point.
    • ctx.lineTo(x, y) - Line ending point.
    • ctx.arc(x, y, r, start, end) - draws a arc with raduis r, from start to end in radians.
    • ctx.closePath() - Ends a path.
    • ctx.stroke() - Draws path as an outline.
    • ctx.fill() - Fills path as a soild shape.
  • Text:
    • ctx.font = "20px Arial" - Sets the size and font-faimly of text.
    • ctx.fillText(string ,x, y) - Draw soild text
    • ctx.strokeText(string ,x, y) - Draw outlined text
  • Colors and Properties:
    • ctx.fillStyle = "#FF0000" - Sets color of filled items. (red)
    • ctx.strokeStyle = "rgb(0,0,255)" - Sets color of stroked items. (blue)
      • ... = "rgba(int, int, int, float)" - [Red 0-255, Green 0-255, Blue 0-255, Aplha 0.0-1.0]
    • ctx.lineWidth = int - Sets the width of drawn lines.
  • Images:
    • ctx.drawImage(image, x, y) - Draws an Image on the Canvas.


Code that produces Canvas drawings:

   var canvas = document.getElementById("myCanvas3"); // Canvas element
   var ctx = canvas.getContext("2d"); // Canvas context.
   
   ctx.fillRect(20,20,30,30);        // Draw filled Rect
   ctx.strokeRect(105,20,30,30);     // Draw outlined Rect
   
   ctx.beginPath();                  // Draw Lines
   ctx.moveTo(170,20);
   ctx.lineTo(200,30);
   ctx.lineTo(190,10);
   ctx.stroke();
   
   ctx.beginPath();                  // Draw lines 
   ctx.moveTo(250,20);
   ctx.lineTo(280,30);
   ctx.lineTo(270,10);
   ctx.closePath();                  // Close path
   ctx.fill();                       // Fill-in closed path 
   
   ctx.beginPath();               
   ctx.arc(370,38,20,0,Math.PI*2);   // Draw circle
   ctx.stroke();

   ctx.font = "28px Arial";          // Set font to 28px
   ctx.fillText("Hello",10,100)      // Draw filled text "Hello"
   ctx.strokeText("Hello",90,100)    // Draw outlined text "Hello"
   
   ctx.font = "8px Arial";
   ctx.fillText('A',177,90);         // Draw text 'A' with 8px size 
   ctx.font = "30px Arial";
   ctx.fillText('A',170,120);        // Draw text 'A' with 30px size

   ctx.fillStyle = "#FF0000";        // Set fills to be red 
   ctx.fillRect(280,80,30,30);       // Draw red rect
   
   var crate = new Image();          // Create Image
   crate.src = 'crate.png';          // Set Image source 
   crate.onload = function(){        // Draw Image when it loads 
      ctx.drawImage(crate, 348, 70, 45, 45);
   }; 

A static canvas is nice, although often we will want to make it more dynamic. For animation we will want a way to update the canvas, we will look into how to redraw to the canvas and using timers and events to do so. Now lets look exactly what is going on by updating the canvas.

Here is a common process on how we do this:

  1. Draw items to canvas
  2. Wait a small amount of time (ex: timer)
  3. Update items (ex: positions)
  4. Clear the canvas
  5. Draw our updated items to the canvas
  6. Wait a small amount of time
  7. Update items
  8. And so on ...

Here is a basic example of a moving box. While simple we will be doing the same thing for all our programs, so be sure you understand this example well:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";

var myBox = new Box(10,10,30); // x = 10  y = 50  size = 30

function main()
{
    // * Clear the Canvas
    ctx.clearRect(0,0,canvas.width,canvas.height);
    
    // * Update Items
    
    // If our box hits the sides of the canvas reverse it's direction.
    if(myBox.x > canvas.width - myBox.size || myBox.x < 0)
        myBox.vel = -myBox.vel;
    
    myBox.moveX();
    
    // * Draw Items
    myBox.draw();
}

function Box(x, y, size)
{
    this.x = x;
    this.y = y;
    this.size = size;
    this.vel = 3; // speed and direction for our box
    
    this.moveX = function() {
         this.x += this.vel; 
    }
    this.draw = function() {
         ctx.fillRect(this.x, this.y, this.size, this.size); 
    }
}


setInterval(function(){main()}, 30); // Call main every 30 milliseconds
          

Feel free to experiment and see what you can do with this, perhaps make it move and reflex in with the X and Y directions. HERE is the code.

In this program we are first creating a Box object. We give it: x and y for it's position, size for how big it is, and vel for how fast it moves. The two methods this Box object has is draw(), which draws the box to the canvas, and moveX(), which changes our x position base on our vel. For the main() function we are performing 3 steps: clearing, updating, and drawing. For clearing we simply paint the screen white. Next for updating we are first checking if our box is past the canvas side edges, if it is then we change the direction of our box. Then we move our box by vel(3) pixels. Finally for drawing we simple draw the box to the canvas. Note if we had more then one box we would need to go though them and draw each one (we could for example use an aray for that).

For this section we will be looking into how to utilize keyboard and mouse input to be used as user input for the canvas. First let me introduce a few new event handlers:

Keyboard Input

  • keydown: A key is pressed down
  • keyup: A key is released
  • keypress: A character key is pressed

We will be adding an event listener to our document, even listeners are basically things that listen to events. Such that if we have a keyboard event a keyboard listener would fire whenever we have some type of keyboard input. Here is an example for keydown:

document.addEventListener("keydown", function(e) { 
   // Do stuff
});

The parameter given in the function is an object about the key information, I've given it the name e short for event, while there are a few properties I will only talk about the most commonly used ones: e.keyCode and e.charCode.

  • keyCode: Scan code of keyboard input, given by your keyboard driver itself for the physical keys themselves. For example "a" and "A" are the same.
  • charCode: The key input based on it's ASCII value.

Here is a basic example of printing the keyCode text to the canvas, press a key on your keyboard and it will show the keyCode on the canvas below:

var canvas = document.getElementById("keyCanvas");
var ctx = canvas.getContext("2d");
ctx.font = "20px Arial";
ctx.fillText("keyCode = ",5,40);
ctx.font = "30px Arial";

document.addEventListener("keydown", function(e) { 
    ctx.clearRect(100,0,canvas.width,canvas.height);
    ctx.fillText(e.keyCode,110,40);
});

HERE is the fiddle example.



Mouse Input

When we have mouse event listeners the e argument (event), from it we can get our X and Y mouse coordinates of the window by using e.clientX and e.clientY. The only problem to this is these are repect to the window and not the canvas, we want (0,0) to be the top left corner of the canvas. To solve this we first get the coordinates (in the form of a rectangle object) of the canvas with respect to the client window by using canvas.getBoundingClientRect(), then we subract the window positions(clientX, clientY) from the canvas positions(left, top):

var canvas = document.getElementById("mouseCanvas");
var ctx = canvas.getContext("2d");
ctx.font = "20px Arial";

canvas.addEventListener("mousemove", function(e) 
{ 
    var cRect = canvas.getBoundingClientRect();
    var canvasX = e.clientX - cRect.left;
    var canvasY = e.clientY - cRect.top;
    ctx.clearRect(0,0,canvas.width,canvas.height);
    ctx.fillText("X: "+canvasX+", Y: "+canvasY, 10, 30);
});

Move your mouse over the canvas and it will show your mouse positions:


Note: Sometimes you may need to slightly manipulate the calculated X and Y positions. If we have a complex webpage sometimes the margins may not be whole numbers, this can cause decimals on the numbers. We can fix this be either using Math.round(), Math.floor(), and Math.ceil() as we see fit. In my case canvasX and canvasY have round() applied to it.

Along with a GUI, we would also like sound in our applications. I will give you a short introduction to the HTML5 Audio tag, we will be using this for our music and sound:

<audio controls>
  <source src="fileName.mp3" type="audio/mp3">
  Your browser does not support the audio tag.
</audio>

The audio tag supports 3 formats: mp3, wav, and ogg. To have it not show an interface simply remove the control attribute. To play it's sound we call the play() method:

var canvas = document.getElementById("soundCanvas");
var ctx = canvas.getContext("2d");
ctx.font = "20px Arial";
ctx.fillText("Click to play",20,30);

canvas.addEventListener("click", function(e) { 
    document.getElementById("audioPlayer").play();
});
  • The Canvas
    • The HTML5 Canvas tag is a rectangular element that we can draw on using JavaScript.
    • Canvas uses a cartesian coordinate system such that (0,0) is the top left.
  • Drawing to the Canvas
    • We need to get the context area of the canvas by doing: canvas.getContext("2d")
    • We can draw: Rectangles, Paths, Text, Images, and adjust properties.
  • Updating the Canvas
    • Steps to updating the Canvas are as followed, normally we use a timer if we want to always keep updating:
      • Draw items to canvas
      • Wait a small amount of time (ex: timer)
      • Update items (ex: positions)
      • Clear the canvas
      • repeat...
    • For timers we perform three steps: Clearing, Updating, then Drawing.
  • Keyboard & Mouse Input
    • For events we use Event Listeners, that check for and fire for only certain events:
    • document.addEventListener("keydown", function(e) { ... });
      • For the keyboard:
        • keydown: A key is pressed down
        • keyup: A key is released
        • keyCode: Scan code of keyboard input, given by your keyboard driver itself for the physical keys themselves
      • For the Mouse:
        • canvas.getBoundingClientRect(): Gets the Canvas as a window rectangle object.
        • e.clientX: Gets the X position of the mouse with respect to the window
        • e.clientY: Gets the Y position of the mouse with respect to the window
  • Audio
    • The audio tag is used for sound and music for an HTML5 webpage.
    • It support the following formats: mp3, wav, and ogg
    • We can use the play() method to play the sound file.
Spencer Wieczorek