Canvas Events

It is possible to detect mouse and keyboard events for a canvas (or any other HTML element).

Mouse Events

There are seven mouse events:

click
The event occurs when the mouse is clicked on the canvas.
dblclick
The event occurs when the mouse is double-clicked on the canvas.
mousemove
The event occurs when the mouse is moved while it is over the canvas.
mouseover
The event occurs when the mouse is moved onto the canvas.
mouseout
The event occurs when the mouse is moved out of the canvas.
mousedown
The event occurs when any mouse button is pressed over the canvas.
mouseup
The event occurs when any mouse button is released over the canvas.

We need to insert two pieces of code in order to use a mouse event.

Firstly, we need to associate the event function with the canvas. This is done by adding an event listener to the canvas.

canvas.addEventListener('click', clickHandler);

Secondly, we need to write the code that will be called when the event happens. This is just a javascript function, as shown below.

function clickHandler(e) 
{
   /* Do something */
}

The variable, 'e' is provided by the system. It provides access to the x and y location of the screen pixel that was clicked. To get the canvas pixel location, we need to subtract the canvas top left corner x and y value from the screen x and y. The example below gets the correct canvas x and y location.

Example showing how to get the canvas x and y position (Run Example)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Worked example from lecture notes</title>
<style>
#keyboardCanvas
{
    border:1px solid black;
    margin-left: 100px;
    width:500px;
    height:500px;
    cursor:default;	
}

#loadingMessage
{
    position:absolute;
    top:100px;
    left:100px;
    z-index:100;
    font-size:50px;
}
</style>

<script>
const CANVAS_WIDTH = 500;
const CANVAS_HEIGHT = 500;

let imageWidth = 100;
let imageHeight = 100;

let canvas = null;
let ctx = null;
let mouseX = 0;
let mouseY = 0;


window.onload = onAllAssetsLoaded;
document.write("<div id='loadingMessage'>Loading...</div>");
function onAllAssetsLoaded()
{
    // hide the webpage loading message
    document.getElementById('loadingMessage').style.visibility = "hidden";

    canvas = document.getElementById("keyboardCanvas");
    ctx = canvas.getContext("2d");
    canvas.width = CANVAS_WIDTH;
    canvas.height = CANVAS_HEIGHT;

    canvas.addEventListener('click', clickHandler);
}


function clickHandler(e)
{
    if (e.which === 1)
    {
        let canvasBoundingRectangle = canvas.getBoundingClientRect();
        mouseX = e.clientX - canvasBoundingRectangle.left;
        mouseY = e.clientY - canvasBoundingRectangle.top;

        alert("x:" + mouseX + "    y:" + mouseY);
    }
}
</script>
</head>

<body>
<canvas id = "keyboardCanvas" tabindex="1">
Your browser does not support the HTML5 'Canvas' tag.
</canvas>
<p>Click the mouse on the canvas to get the current x,y position within the canvas.<br>
The coordinates will still work after the browser has been resize. Try resizing the browser to test this.<br>
Note that this canvas is 500 by 500 pixels.</p>
</body>
</html>

 

In the example below, a rectangle is drawn at the location of a mouse click.

Example of a mouse click event (Run Example)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Worked example from lecture notes</title>
<style>
#keyboardCanvas
{
    border:1px solid black;
    width:500px;
    height:500px;
    cursor:default;	
}

#loadingMessage
{
    position:absolute;
    top:100px;
    left:100px;
    z-index:100;
    font-size:50px;
}
</style>

<script>
const CANVAS_WIDTH = 500;
const CANVAS_HEIGHT = 500;

let imageWidth = 100;
let imageHeight = 100;

let canvas = null;
let ctx = null;
let mouseX = 0;
let mouseY = 0;


window.onload = onAllAssetsLoaded;
document.write("<div id='loadingMessage'>Loading...</div>");
function onAllAssetsLoaded()
{
    // hide the webpage loading message
    document.getElementById('loadingMessage').style.visibility = "hidden";

    canvas = document.getElementById("keyboardCanvas");
    ctx = canvas.getContext("2d");
    canvas.width = CANVAS_WIDTH;
    canvas.height = CANVAS_HEIGHT;

    renderCanvas();

    canvas.addEventListener('click', clickHandler);
}


function renderCanvas()
{
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillRect(mouseX, mouseY, imageWidth, imageHeight);
}


function clickHandler(e)
{
    if (e.which === 1)
    {
        let canvasBoundingRectangle = canvas.getBoundingClientRect();
        mouseX = e.clientX - canvasBoundingRectangle.left - (imageWidth / 2);
        mouseY = e.clientY - canvasBoundingRectangle.top - (imageHeight / 2);

        renderCanvas();
    }
}
</script>
</head>

<body>
<canvas id = "keyboardCanvas" tabindex="1">
Your browser does not support the HTML5 'Canvas' tag.
</canvas>
<p>Click the mouse on the canvas to move the rectangle.</p>
</body>
</html>

Write code to draw an image in a new location whenever the user clicks on the canvas, as shown in this link.

Dragging an Image

Before we can drag an image, we need to be able to detect

  1. if the mouse is inside the image
  2. the mouse offset position relative to the top-left corner of the image

The code below will detect if the location (x, y) is positioned inside an image.

function mouseIsInsideImage(imageTopLeftX, imageTopLeftY, imageWidth, imageHeight, x, y)
{
if ((x > imageTopLeftX) && (y > imageTopLeftY))
{
if (x > imageTopLeftX)
{
if ((x - imageTopLeftX) > imageWidth)
{
return false; // to the right of the image
}
}
if (y > imageTopLeftY)
{
if ((y - imageTopLeftY) > imageHeight)
{
return false; // below the image
}
}
}
else // above or to the left of the image
{
return false;
}
return true; // inside image
}

 

The offset needs to be calculated when the mouse is pressed down on an image. The code below will calculate the offsetX and offsetY of the mouse within an image.

function mousedownHandler(e)
{
if (e.which === 1) // left mouse button
{
if (mouseIsInsideImage(x, y, imageWidth, imageHeight, e.x, e.y))
{
offsetX = e.x - x; offsetY = e.y - y; }
}
}

Whenever an image changes position, the offset needs to be taken into account when calculating the new image top-left x and y positions. This is done by subtracting the offset values that were calculated in the mousedownHandler(e) code above.

x = e.x - offsetX;
y = e.y - offsetY;

Example that detects if the mouse is inside an image and takes the x and y offsets into account when dragging an image (Run Example)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Worked example from lecture notes</title>
<style>
#canvas
{	
    width:500px;
    height:500px;
}

#canvas
{
    border:1px solid black;
    cursor:default;
}

#text
{
    clear:both;
}

#loadingMessage
{
    position:absolute;
    top:100px;
    left:100px;
    z-index:100;
    font-size:50px;
}
</style>

<script>
const CANVAS_WIDTH = 500;
const CANVAS_HEIGHT = 500;

let canvas = null;
let ctx = null;
let imageWidth = 100;
let imageHeight = 100;
let imageX = 250;
let imageY = 250;
let img = new Image();
img.src = "images/dkit01.png";

let offsetX = 0;
let offsetY = 0;

window.onload = onAllAssetsLoaded;
document.write("<div id='loadingMessage'>Loading...</div>");
function onAllAssetsLoaded()
{
    // hide the webpage loading message
    document.getElementById('loadingMessage').style.visibility = "hidden";

    canvas = document.getElementById("canvas");
    ctx = canvas.getContext("2d");
    canvas.width = CANVAS_WIDTH;
    canvas.height = CANVAS_HEIGHT;

    renderCanvas();

    canvas.addEventListener('mousedown', mousedownHandler);
    canvas.addEventListener('mousemove', moveHandler);
}


function renderCanvas()
{
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(img, imageX, imageY, imageWidth, imageHeight);
}


function mousedownHandler(e)
{
    if (e.which === 1)  // left mouse button
    {
        let canvasBoundingRectangle = canvas.getBoundingClientRect();
        mouseX = e.clientX - canvasBoundingRectangle.left;
        mouseY = e.clientY - canvasBoundingRectangle.top;
        if (mouseIsInsideImage(imageX, imageY, imageWidth, imageHeight, mouseX, mouseY))
        {
            offsetX = mouseX - imageX;
            offsetY = mouseY - imageY;
        }
    }
}


function moveHandler(e)
{
    if (e.which === 1)  // left mouse button
    {
        let canvasBoundingRectangle = canvas.getBoundingClientRect();
        mouseX = e.clientX - canvasBoundingRectangle.left;
        mouseY = e.clientY - canvasBoundingRectangle.top;
        if (mouseIsInsideImage(imageX, imageY, imageWidth, imageHeight, mouseX, mouseY))
        {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            imageX = mouseX - offsetX;
            imageY = mouseY - offsetY;
            renderCanvas();
        }
    }
}


function mouseIsInsideImage(imageTopLeftX, imageTopLeftY, imageWidth, imageHeight, x, y)
{
    if ((x > imageTopLeftX) && (y > imageTopLeftY))
    {
        if (x > imageTopLeftX)
        {
            if ((x - imageTopLeftX) > imageWidth)
            {
                return false; // to the right of the image
            }
        }

        if (y > imageTopLeftY)
        {
            if ((y - imageTopLeftY) > imageHeight)
            {
                return false; // below the image
            }
        }
    }
    else // above or to the left of the image
    {
        return false;
    }
    return true; // inside image
}
</script>
</head>

<body>
<canvas id = "canvas">
Your browser does not support the HTML5 'Canvas' tag.
</canvas>
<div id = 'text'>
<p>Press the left mouse button on the image and drag the mouse to move the image.</p>
</div>
</body>
</html>

Write code to make a drawing tool that is similar to the one shown at this link.

Adjust the tool above, so that the user can select a colour from a colour picker, as shown here. Remember to initialise the colour picker to match the initial red colour of the brush.

Adjust the tool above, so that the user can select the brush width using a slider, as shown here. Remember to adjust the slider whenever the user presses the "thin" or "thick" button.

What additional features can you add to improve this drawing tool?

We can associate a function with the mouse wheel using the code below

window.onmousewheel = document.onmousewheel = mousewheelHandler;

The function is provided with a system variable, e. This variable contains the wheel movement in the variable e.wheelDelta. This value increments/decrements in units of 120. Therefore, we need to devide it by 120 to get a unit increment/decrement value.

function mousewheelHandler(e) 
{
unitChange = e.wheelDelta / 120; // unitChange will be equal to either +1 or -1
// code to use the unitChange value is placed below }

Write code to scale an image using the mouse wheel, as shown in this link. Note, that you should make sure that scaling only occurs if the mouse is over the image.

Write code to move, drag and scale an image, as shown in this link.

Write code to create a word jigsaw game, as shown here.

Keyboard Events

There are three keyboard events:

onkeydown
The event occurs when as soon as any key has been pressed.
onkeypress
The event occurs when any key is being pressed.
onkeyup
The event occurs when a key is being released.
 

As with the mouse event, we need to insert two pieces of code in order to use a keyboard event: a function containing the action and an event listener. Unlike the mouse event, the canvas cannot detect keyboard events. Therefore, we tie the keyboard event to the html document.

document.addEventListener('keydown', keydownHandler);

 

When using keyboard events, we need to be able to detect which key has been pressed. The code below will test if the left arrow has been pressed.

function keydownHandler(e) 
{
   if (e.keyCode == 37)  // left arrow key
   {
      x -= stepSize;
   }
}

In the example above, the variable, 'e' is provided by the system. It provides access to the keyCode of the key that has been pressed. The complete set of keyCodes can be found at this link.

 

The example below allows the user to move a rectangle around the canvas using the four arrow keys.

Example of a keyboard event (Run example)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Worked example from lecture notes</title>
<style>
#keyboardCanvas
{
    border:1px solid black;
    width:500px;
    height:500px;
}

#loadingMessage
{
    position:absolute;
    top:100px;
    left:100px;
    z-index:100;
    font-size:50px;
}
</style>

<script>
const CANVAS_WIDTH = 500;
const CANVAS_HEIGHT = 500;

let imageWidth = 100;
let imageHeight = 100;

let canvas = null;
let ctx = null;
let blackSquareX = 0;
let blackSquareY = 0;


window.onload = onAllAssetsLoaded;
document.write("<div id='loadingMessage'>Loading...</div>");
function onAllAssetsLoaded()
{
    // hide the webpage loading message
    document.getElementById('loadingMessage').style.visibility = "hidden";

    canvas = document.getElementById("keyboardCanvas");
    ctx = canvas.getContext("2d");
    canvas.width = CANVAS_WIDTH;
    canvas.height = CANVAS_HEIGHT;

    renderCanvas();

    document.addEventListener('keydown', keydownHandler);
}


function renderCanvas()
{
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillRect(blackSquareX, blackSquareY, imageWidth, imageHeight);
}


function keydownHandler(e)
{
    let stepSize = 10;

    if (e.keyCode === 37)  // left
    {
        blackSquareX -= stepSize;
    }
    else if (e.keyCode === 38) // up
    {
        blackSquareY -= stepSize;
    }
    else if (e.keyCode === 39) // right
    {
        blackSquareX += stepSize;
    }
    else if (e.keyCode === 40) // down
    {
        blackSquareY += stepSize;
    }

    renderCanvas();
}
</script>
</head>
<body>
<canvas id = "keyboardCanvas" tabindex="1">
Your browser does not support the HTML5 'Canvas' tag.
</canvas>
<p>Use the four arrow keys to move the square.</p>
</body>
</html>

Amend the above code to move an image around the screen.

Amend the above code to stop the image moving off the canvas.

Write code to animate a sprite character walking, as shown here. The sprite image is below:

Touch Events

Touch events are covered in the section on smart phones.

 
<div align="center"><a href="../../versionC/index.html" title="DKIT Lecture notes homepage for Derek O&#39; Reilly, Dundalk Institute of Technology (DKIT), Dundalk, County Louth, Ireland. Copyright Derek O&#39; Reilly, DKIT." target="_parent" style='font-size:0;color:white;background-color:white'>&nbsp;</a></div>