A Look at HTML5 Canvas Interactivity

May 17, 2012 at 5:00 pm By
Download Demo

The HTML5 canvas element allows for developers to implement interactivity and drawing which was previously undoable without the use of a third party program such as flash. In this article we’re going to be tackling the problem of interactivity, and how to accomplish it using HTML5’s canvas tag. You could expand upon this information to make a basic HTML5 game.

Gaming

Games were something which until quite recently couldn’t be accomplished with just HTML and Javascript. With the canvas tag it’s become much more realistic to create a game or some sort of interactive idea with HTML5 rather than Flash which was what was traditionally considered to be the only practical way. To begin, lets take a look at keyboard input in canvas.

Keyboard Input

The canvas tag acts just like any other HTML tag. It has a width, a height and an ID. The content of the canvas tag is what the user sees should canvas be unsupported on their device. I’ve also set a function to run when the body loads, and a little div that contains data on how much you’ve moved the item about. We’re going to be making a cube which you can move around on the document with arrow keys. You could expand upon this further to add many more features.

<body onload="init();">

	<div>
	You've moved horizontally <span id="x" onload="counting(true);">0</span> and vertically <span id="y" onload="counting();">0</span>! <br />Don't leave the box to win! (Use Arrow Keys)
	</div>

	<canvas id="game" width="640" height="500">
	Oh no! Canvas isn't supported by your browser.
	
	</canvas>
	
</body>

Javascript

The Javascript is a little more difficult. In Javascript we can see what characters the user presses on their keyboard using e.keyCode. Each character on the keyboard has a predetermined number which you can check for. We’re going to be making a box which moves around, so we’ll concentrate on the arrow keys. To begin, paste this into your Javascript file. It’s just a bunch of variables we’ll be using:


var canvas, draw, width, height; // For drawing the canvas
var downcheck, upcheck, rightcheck, leftcheck; // For checking what direction is clicked

// Curent position
var up = 0;
var down = 0;
var left = 0;
var right = 0;


Next we gotta create the init() function, which will contain some basic information on what to do immediately when the document loads.

// The main function for initiating everything
function init() {

	// Get the canvas by ID
    canvas = document.getElementById('game');
    
    // Set a height and width for the canvas item
    height = canvas.height;
    width = canvas.width;
    
    // A variable we'll use to draw the actual item
    draw = canvas.getContext('2d');

	// We want to redraw every 30ms
	setInterval(redraw, 30);

	// When the user presses a key run a function, when the user stops
	// run another function. We'll get to these functions later.
	document.onkeydown = canvasMove;
	document.onkeyup = canvasStop;
	
}

Since moving rectangles on a canvas can get a little messy (the canvas will just redraw the element again and again without removing it, so you just end up with loads of rectangles), we’re going to be redrawing it every 30 milliseconds. This function is referenced in init().


// Wipe the canvas when we want to move the rectangle, then we can redraw it.
function clear(c) {
    c.clearRect(0, 0, width, height);
}

function redraw() {
	clear(draw);
	draw.fillStyle = 'rgba(0,0,0,0.5)';
	draw.fillRect(left - right , down - up, '100', '100');   
}

Next we need to add functionality to move the box around. We want two arrow keys to be able to work in tandem, so we need to do something a little more complex than just an if statement. We set the check variables to true or false depending on what the user presses so we can have two variables true at the same time. This allows us to use multiple keys at once (diagonal movement).


function canvasMove(e) {
  	
  	// Check if the up arrow is pressed
  	if(e.keyCode == '38') upcheck = true
  	// else check if the left arrow is pressed and the up arrow is also true
  	else if(e.keyCode == '37' &amp;amp;&amp;amp; upcheck == true) leftcheck = true; // Then set the left arrow to true
  	// else check if the right arrow is true, repeat.
  	else if(e.keyCode == '39' &amp;amp;&amp;amp; upcheck == true) rightcheck = true;
  	// otherwise the up arrow is not being pressed, so it is false
	else upcheck = false; 
  	
  	// Repeat for every arrow direction
  	if(e.keyCode == '40') downcheck = true; 
  	else if(e.keyCode == '37' &amp;amp;&amp;amp; downcheck == true) leftcheck = true;
  	else if(e.keyCode == '39' &amp;amp;&amp;amp; downcheck == true) rightcheck = true;
  	else downcheck = false;
  	
  	
 	if(e.keyCode == '37') leftcheck = true;
 	else if(e.keyCode == '40' &amp;amp;&amp;amp; leftcheck == true) downcheck = true; 
 	else if(e.keyCode == '38' &amp;amp;&amp;amp; leftcheck == true) upcheck = true;
 	else leftcheck = false;
 	
  	
  	if(e.keyCode == &amp;quot;39&amp;quot;) rightcheck = true; 
  	else if(e.keyCode == '40' &amp;amp;&amp;amp; rightcheck == true) downcheck = true; 
  	else if(e.keyCode == '38' &amp;amp;&amp;amp; rightcheck == true) upcheck = true; 
  	else rightcheck = false;
  	
	// If the variables are true, increase the left and right movement accordingly. 
	// We also run the counting function, to keep track of total movement. 
  	if(rightcheck == true) { left += 10; counting() };
  	if(leftcheck == true) { right += 10; counting() };
  	if(upcheck == true) { up += 10; counting(true) };
  	if(downcheck == true) { down += 10; counting(true) };

}

Next we need to check when the user stops pressing the arrows and set the corresponding key checks to false


// When the user stops pressing a key, check which key it is and set it to false
function canvasStop(e) {
	
	if(e.keyCode == '38') {
		upcheck = false;
	}
	if(e.keyCode == '40') {
		downcheck = false;
	}
	if(e.keyCode == '37') {
		leftcheck = false;
	}
	if(e.keyCode == '39') {
		rightcheck = false;
	}

}

And finally, we have a little function which will do all the counting.


function counting(y) {
	
	if(y == true) { 
		document.getElementById('y').innerHTML = parseInt(document.getElementById('y').innerHTML) + 1;
	}
	
	else { 
		document.getElementById('x').innerHTML = parseInt(document.getElementById('x').innerHTML) + 1;
	}
}

And that’s it! Check out the demo page if you want to see it in action, or download the whole thing. Lets take a look at mouse interactivity first.

Mouse Input

So we’re going to be making a simple drawing application, and it’s surprisingly easy with canvas. As usual, we’ll start by doing some HTML.

<body onload="init();">
<div id="drawingcontainer">
	<div class="text">
		Draw below!
	</div>
	<div id="options">
		<input type="submit" value="1px" onclick="changeSize(1);" />
		<input type="submit" value="2px" onclick="changeSize(2);" />
		<input type="submit" value="3px" onclick="changeSize(3);" />
		<input type="submit" value="5px" onclick="changeSize(5);" />
		<input type="submit" value="10px" onclick="changeSize(10);" />
		<input type="submit" value="15px" onclick="changeSize(20);" />
		
		<input type="submit" onclick="changeColor('#871de0');" class="purple" value="" />
		<input type="submit" onclick="changeColor('#eb159d');" class="pink" value="" />
		<input type="submit" onclick="changeColor('#c92626');" class="red" value="" />
		<input type="submit" onclick="changeColor('#db551b');" class="orange" value="" />
		<input type="submit" onclick="changeColor('#ddc41e');" class="yellow" value="" />
		<input type="submit" onclick="changeColor('#76b80f');" class="green" value="" />
		<input type="submit" onclick="changeColor('#1974b4');" class="blue" value="" />
		<input type="submit" onclick="changeColor('#000');" class="black" value="" />
		<input type="submit" onclick="changeColor('#FFF');" class="white" value="" />
	</div>
	
	<canvas width="690" height="500" id="drawing">
	Your browser doesn't support canvas
	</canvas>
</div>

</body>

Next lets define some simple variables, and run the initial init() function.

var canvas, draw;

var started = false;
var x, y;

function init() {

	// Get the drawing canvas
	canvas = document.getElementById('drawing');
	context = canvas.getContext('2d');
    
	// Add some event listeners so we can figure out what's happening
	// and run a few functions when they are executed.
	canvas.addEventListener('mousemove', mousemovement, false);
	canvas.addEventListener('mousedown', mouseclick, false);
	canvas.addEventListener('mouseup', mouseunclick, false);

}

Next we run some simple functions that will happen when the user clicks, moves while clicking, and unclicks. All they do is track the mouse position and draw a line where appropriate.

function mouseclick() {
	// When the mouse is clicked. Change started to true and move
	// the initial position to the position of the mouse
	context.beginPath();
	context.moveTo(x, y);
	started = true;
	
}
// For getting the mouse position, basically. This gets the position
// of the canvas element, so we can use it to calculate the mouse 
// position on the canvas
function getOffset(e) {
    var cx = 0;
    var cy = 0;
    
    while(e &amp;&amp; !isNaN(e.offsetLeft) &amp;&amp; !isNaN(e.offsetTop)) {
        cx += e.offsetLeft - e.scrollLeft;
        cy += e.offsetTop - e.scrollTop;
        e = e.offsetParent;
    }
    return { top: cy, left: cx };
}

function mousemovement(e) {
	
	// Get mouse position
	
	if(e.offsetX || e.offsetY) {
		x = e.pageX - getOffset(document.getElementById('drawing')).left - window.pageXOffset;
		y = e.pageY - getOffset(document.getElementById('drawing')).top - window.pageYOffset;
	}
	else if(e.layerX || e.layerY) {
		x = (e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft)
		- getOffset(document.getElementById('drawing')).left - window.pageXOffset;
		y = (e.clientY + document.body.scrollTop + document.documentElement.scrollTop)
		- getOffset(document.getElementById('drawing')).top;
	}	
		
	// If started is true, then draw a line
	if(started) {
		context.lineTo(x, y);
		context.stroke();
	
	}
	
}


function mouseunclick() {
	// Change started to false when the user unclicks the mouse
	if(started) {
		started = false;	
	}

}

Finally we just have to run two extra functions for changing the colour and size of the line.

// Change size
function changeSize(s) {
	context.lineWidth = s;
}

// Change color
function changeColor(c) {
	context.strokeStyle = c;
}

And that’s it! To finish off lets just add a little CSS:

body {
	margin: 0;
	padding:  0;
	background: url('background.gif');
	font-family: Arial, Helvetica, sans-serif;
}

canvas {
	box-shadow: 0px 0px 30px rgba(0,0,0,0.3);
	float: left;
	border-radius: 6px;
	display: block;
}

div {
	font-family: 'Droid Sans', Helvetica, Arial, sans-serif;
	font-size: 30px;
	padding: 15px;
	line-height: 30px;
}

#options {
	float: left;
}

h3 {
	float: left;
	margin: 0;
}

div span {
	float: left;
	text-transform: uppercase;
	padding: 0 20px 20px 20px; 
	font-size: 14px;
	font-weight: bold;
}

div input {
	float: left;
	display: inline;
}

div input[type=range] {
	position: relative;
	top: 6px;
}

#options input[type=submit] {
	border: 0;
	border-radius: 4px;
	margin-right: 10px;
	width: 35px;
	box-shadow: inset 0px 0px 10px rgba(0,0,0,0.2);
	height: 35px;
	position: relative;
	cursor: pointer;
}

#options input[type=submit]:hover {
	box-shadow: inset 0px 0px 10px rgba(0,0,0,0.5);
}

#options input[type=submit]:active {
	top: 2px;
}

.purple { background: #871de0; }
.pink { background: #eb159d; }
.red { background: #c92626; }
.orange { background: #db551b; }
.yellow { background: #ddc41e; }
.green { background: #76b80f; }
.blue { background: #1974b4; }
.black { background: #000; }
.white { background: #fff; }

#drawingcontainer {
	width: 710px;
	margin: 0px auto;
}


I’ve set up a demo page to try out both of these things. Check out the demo below, or download if you want to play around with the script directly.