Copyright Derek O'Reilly, Dundalk Institute of Technology (DkIT), Dundalk, Co. Louth, Ireland.
It is possible to detect mouse and keyboard events for a canvas (or any other HTML element).
There are seven mouse events:
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>
<title>Course notes example code</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
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.clientWidth
canvas.height = canvas.clientHeight
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> <title>Course notes example code</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <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> 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.clientWidth canvas.height = canvas.clientHeight 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.
Before we can drag an image, we need to be able to detect
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> <title>Course notes example code</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <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> 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.clientWidth canvas.height = canvas.clientHeight 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.
We can use an offscreen canvas to store the scribbles. This will allow us to seperate the background image from the scribbles. Use an offscreen canvas to allow the user to change the background image without losing the scribbles, as shown here.
Amend the scribble canvas so that it includes a save button, as shown here. Hint, there is a hyperlink <a> tag 'download' property that you can use. You should make the <a> tag look like a button using CSS.
What additional features can you add to improve this drawing tool?
We can associate a function with the mouse wheel using the code below
canvas.addEventListener('wheel', 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 here. Note, that you should make sure that scaling only occurs if the mouse is over the image.
Write code to move and scale an image, as shown in here .
Expand the code above, so that the user can select between multiple images. You should highlight the currently selected image and apply the dragging and scaling to the selected image, as shown here.
Expand the code above, so that the user can also rotate any of the multiple images, as shown here. Hint: You need to use a double buffer.
Extend the code above, so that the user can also adjust the brightness and toggle greyscale on any of the multiple images, as shown here.
There are three keyboard events:
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. Use this link to get the keyCode for any key. 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> <title>Course notes example code</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <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> 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.clientWidth canvas.height = canvas.clientHeight 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:
Copyright Derek O' Reilly, Dundalk Institute of Technology (DkIT), Dundalk, Co. Louth, Ireland.