Copyright Derek O'Reilly, Dundalk Institute of Technology (DkIT), Dundalk, Co. Louth, Ireland.
The HTML5 Canvas provides an rectangular area on a webpage on which graphics can be drawn. Canvas is used with javascript to provide animated graphics on a webpage.
Use the <canvas> tag to create a canvas. Every canvas needs to have an id assigned to it. This will be used in the javascript code to access the canvas.
<canvas id="simpleCanvas"> Your browser does not support the HTML5 'Canvas' tag. </canvas>
Use the javascript getElementById() function to access the canvas id within the javajcript code.
<script> let canvas = document.getElementById("simpleCanvas") </script>
The width and height of the canvas need to be declared twice: in the style and in the canvas's javascript code.
The style width and height define how much physical space the canvas occupies on the website.
Javascript is used to define the logical width and height of the canvas. It the canvas sizes do not match the style sizes, then the canvas drawing is scaled.
We can use canvas.clientWidth and canvas.clientHeight to get the canvas's physical size. We can use this information to match the canvas's logical size to its physical size, as shown below:
<style> #simpleCanvas { width:500px; height:500px; } </style> <script> let canvas = document.getElementById("simpleCanvas") canvas.width = canvas.clientWidth canvas.height = canvas.clientHeight </script>
In order to draw onto the canvas, we need to assign a graphics context to it. This is done in the javascript code using the getContext("2d") function.
<script>
let ctx = canvas.getContext("2d")
</script>
Any drawing outside of a canvas's logical area will be clipped. This is shown in the example below, where the width of the red rectangle being drawn extends beyond the logical width of the canvas.
Example of a simple canvas (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 { border:1px solid black; width:500px; height:500px; } #loadingMessage { position:absolute; top:100px; left:100px; z-index:100; font-size:50px; } </style> <script> let canvas = null let ctx = null window.onload = onAllAssetsLoaded document.write("<div id='loadingMessage'>Loading...</div>") function onAllAssetsLoaded() { // hide the webpage loading message document.getElementById('loadingMessage').style.visibility = "hidden" /* associate the javascript canvas variable to the HTML canvas element */ canvas = document.getElementById("canvas") /* Assign a graphics context to the canvas, so that we can draw on it */ ctx = canvas.getContext("2d") /* Give the canvas a width and height */ /* The width and height are in canvas logical units */ canvas.width = canvas.clientWidth canvas.height = canvas.clientHeight renderCanvas() } function renderCanvas() { /* Draw on the canvas */ ctx.fillStyle = "red" ctx.fillRect(100, 200, 600, 200) } </script> </head> <body> <canvas id = "canvas"> Your browser does not support the HTML5 'Canvas' tag. </canvas> </body> </html>
Write code to draw four coloured blocks on the canvas, as shown here.
Write code to draw a block that fades out from white to red, as shown here.
Write code to draw a set of randomly coloured blocks, as shown here.
Write code to allow the user to adjust the size of the blocks from the previous question, as shown here.
Write code to generate a piece of block art, as shown here. Note that the user should be able to specify how many blocks they would like to have.
Example of various paths (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> #pathsCanvas { border:1px solid black; width:500px; height:500px; } #loadingMessage { position:absolute; top:100px; left:100px; z-index:100; font-size:50px; } </style> <script> let canvas = null let ctx = null 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("pathsCanvas") ctx = canvas.getContext("2d") canvas.width = canvas.clientWidth canvas.height = canvas.clientHeight renderCanvas() } function renderCanvas() { /* draw a square */ ctx.beginPath() ctx.strokeStyle = "blue" /* stroke colour */ ctx.moveTo(100, 100) ctx.lineTo(200, 100) ctx.lineTo(200, 200) ctx.lineTo(100, 200) ctx.lineTo(100, 100) ctx.stroke() ctx.closePath() /* draw a triangle */ ctx.beginPath() ctx.strokeStyle = "red" /* stroke colour */ ctx.lineWidth = "10" ctx.lineCap = "bevel" ctx.moveTo(350, 100) ctx.lineTo(400, 200) ctx.lineTo(300, 200) ctx.lineTo(350, 100) ctx.lineTo(400, 200) ctx.stroke() ctx.closePath() /* draw and fill a polygon */ ctx.beginPath() ctx.lineWidth = "20" ctx.setLineDash([50, 20]) ctx.lineCap = "round" ctx.lineJoin = "round" /* Can also be miter (default) or bevel */ ctx.strokeStyle = "green" /* stroke colour */ ctx.fillStyle = "yellow" ctx.moveTo(100, 300) ctx.lineTo(50, 400) ctx.lineTo(200, 450) ctx.lineTo(450, 400) ctx.lineTo(200, 400) ctx.lineTo(100, 300) ctx.lineTo(50, 400) /* Needed to clean up wide stroke for first polygon point */ ctx.fill() ctx.stroke() ctx.closePath() } </script> </head> <body> <canvas id = "pathsCanvas"> Your browser does not support the HTML5 'Canvas' tag. </canvas> </body> </html>
In javascript, circle angles are given in radients. The table below gives the conversion between degrees and radients for various values.
Degrees | radients |
---|---|
30 | PI / 6 |
45 | PI / 4 |
60 | PI / 3 |
90 | PI / 2 |
120 | 2 * PI / 3 |
135 | 3 * PI / 4 |
150 | 5 * PI / 6 |
180 | PI |
210 | 7 * PI / 6 |
225 | 5 * PI / 4 |
240 | 4 * PI / 3 |
270 | 3 * PI / 2 |
300 | 5* PI / 3 |
315 | 7 * PI / 4 |
330 | 11* PI / 6 |
360 | 2 * PI |
The example below draws a circle, a semi-circle and two circle quadrants.
Example of a circle (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 { border:1px solid black; width:500px; height:500px; } #loadingMessage { position:absolute; top:100px; left:100px; z-index:100; font-size:50px; } </style> <script> let canvas = null let ctx = null 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() } function renderCanvas() { /* Red Circle */ ctx.beginPath() ctx.fillStyle = "red" ctx.arc(100, 100, 50, 0, Math.PI * 2) ctx.fill() ctx.closePath() /* Semi-circle and two circle quadrants */ ctx.beginPath() ctx.fillStyle = "red" ctx.arc(300, 100, 50, 0, Math.PI) ctx.fill() ctx.closePath() ctx.beginPath() ctx.fillStyle = "yellow" ctx.arc(300, 100, 50, 0, 3 * Math.PI / 2, true) ctx.lineTo(300, 100) ctx.fill() ctx.closePath() ctx.beginPath() ctx.fillStyle = "blue" ctx.arc(300, 100, 50, 3 * Math.PI / 2, Math.PI, true) ctx.lineTo(300, 100) ctx.fill() ctx.closePath() } </script> </head> <body> <canvas id = "canvas"> Your browser does not support the HTML5 'Canvas' tag. </canvas> </body> </html>
An alternative to the above is to implement a degrees function and a radients function.
// Convert from degrees to radians. Math.radians = function(degrees) { return degrees * Math.PI / 180 } // Convert from radians to degrees. Math.degrees = function(radians) { return radians * 180 / Math.PI }
The circle example above can be rewritten using the radients conversion function, as shown below.
Example of a circle using the radients() helper function (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 { border:1px solid black; width:500px; height:500px; } #loadingMessage { position:absolute; top:100px; left:100px; z-index:100; font-size:50px; } </style> <script> let canvas = null let ctx = null 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() } function renderCanvas() { /* Red Circle */ ctx.beginPath() ctx.fillStyle = "red" ctx.arc(100, 100, 50, 0, Math.radians(360)) ctx.fill() ctx.closePath() /* Semi-circle and two circle quadrants */ ctx.beginPath() ctx.fillStyle = "red" ctx.arc(300, 100, 50, 0, Math.radians(180)) ctx.fill() ctx.closePath() ctx.beginPath() ctx.fillStyle = "yellow" ctx.arc(300, 100, 50, 0, Math.radians(270), true) ctx.lineTo(300, 100) ctx.fill() ctx.closePath() ctx.beginPath() ctx.fillStyle = "blue" ctx.arc(300, 100, 50, Math.radians(270), Math.radians(180), true) ctx.lineTo(300, 100) ctx.fill() ctx.closePath() } Math.radians = function (degrees) { /* Convert from degrees to radians */ return degrees * Math.PI / 180 } </script> </head> <body> <canvas id = "canvas"> Your browser does not support the HTML5 'Canvas' tag. </canvas> </body> </html>
Write code to make a grayscale circle gradient, as shown here.
Write code to make a red circle gradient that has a slider control to set the number of shades of red, as shown here.
Examples of linear gradients (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 { border:1px solid black; width:500px; height:500px; } #loadingMessage { position:absolute; top:100px; left:100px; z-index:100; font-size:50px; } </style> <script> let canvas = null let ctx = null 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() } function renderCanvas() { let gradient = ctx.createLinearGradient(50, 50, 300, 300) gradient.addColorStop(0, "red") gradient.addColorStop(1, "blue") ctx.fillStyle = gradient ctx.fillRect(50, 50, 300, 150) /* x, y, w, h */ gradient = ctx.createLinearGradient(50, 1, 350, 1) gradient.addColorStop(0, "green") gradient.addColorStop(0.5, "yellow") gradient.addColorStop(1, "blue") ctx.fillStyle = gradient ctx.fillRect(50, 300, 300, 150) } </script> </head> <body> <canvas id = "canvas"> Your browser does not support the HTML5 'Canvas' tag. </canvas> </body> </html>
Example of a radial gradient (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
{
border:1px solid black;
width:500px;
height:500px;
}
#loadingMessage
{
position:absolute;
top:100px;
left:100px;
z-index:100;
font-size:50px;
}
</style>
<script>
let canvas = null
let ctx = null
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()
}
function renderCanvas()
{
let gradient = ctx.createRadialGradient(250, 250, 0, 250, 250, 400)
gradient.addColorStop(0, "red")
gradient.addColorStop(1, "blue")
ctx.fillStyle = gradient
ctx.fillRect(0, 0, 500, 500)
}
</script>
</head>
<body>
<canvas id = "canvas">
Your browser does not support the HTML5 'Canvas' tag.
</canvas>
</body>
</html>
Examples text fill and text stroke (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 { border:1px solid black; width:500px; height:500px; } #loadingMessage { position:absolute; top:100px; left:100px; z-index:100; font-size:50px; } </style> <script> let canvas = null let ctx = null 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() } function renderCanvas() { ctx.fillStyle = "red" ctx.font = "100px Times Roman" ctx.fillText("DkIT", 150, 150) ctx.strokeStyle = "blue" ctx.font = "200px Arial" ctx.lineWidth = 10 ctx.strokeText("DkIT", 50, 350) } </script> </head> <body> <canvas id = "canvas"> Your browser does not support the HTML5 'Canvas' tag. </canvas> </body> </html>
Write code to place the blue stroke and red fill text together, as shown here.
Example of an image and a scaled 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 { border:1px solid black; width:500px; height:500px; } #loadingMessage { position:absolute; top:100px; left:100px; z-index:100; font-size:50px; } </style> <script> let canvas = null let ctx = null let img = new Image() img.src = "images/dkit01.png" 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() } function renderCanvas() { ctx.drawImage(img, 0, 0) ctx.drawImage(img, 300, 400, 200, 100) } </script> </head> <body> <canvas id = "canvas"> Your browser does not support the HTML5 'Canvas' tag. </canvas> </body> </html>
Write code to show four equally sized images on a canvas, as shown here.
Example of an image with its colours inverted (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 { border:1px solid black; width:500px; height:500px; } #loadingMessage { position:absolute; top:100px; left:100px; z-index:100; font-size:50px; } </style> <script> let canvas = null let ctx = null let img = new Image() img.src = "images/dkit02.png" 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() } let imageData = null let data = null function renderCanvas() { ctx.drawImage(img, 0, 0, canvas.width, canvas.height) // get the pixels from the canvas // NOTE: getImageData() will only work if the image in drawImage is // on the same server as the webpage imageData = ctx.getImageData(0, 0, canvas.width, canvas.height) data = imageData.data for (let i = 0; i < data.length; i += 4) { data[i + 0] = 255 - data[i + 0] data[i + 1] = 255 - data[i + 1] data[i + 2] = 255 - data[i + 2] data[i + 3] = 255 } ctx.putImageData(imageData, 0, 0) } </script> </head> <body> <canvas id = "canvas"> Your browser does not support the HTML5 'Canvas' tag. </canvas> </body> </html>
Write code to place coloured text on a grayscale image, as shown here.
Write code to adjust the brightness of an image, as shown here.
Write code to adjust the brightness of the red, green and blue components of an image, as shown here.
A smaller rectangular area from a canvas can be manipulated, as shown in the example below
Example of a rectangular area of an image being inverted (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 { border:1px solid black; width:500px; height:500px; } #loadingMessage { position:absolute; top:100px; left:100px; z-index:100; font-size:50px; } </style> <script> let canvas = null let ctx = null let img = new Image() img.src = "images/dkit02.png" 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() } let imageData = null let data = null function renderCanvas() { ctx.drawImage(img, 0, 0, canvas.width, canvas.height) // get the pixels from the canvas // NOTE: getImageData() will only work if the image in drawImage is // on the same server as the webpage imageData = ctx.getImageData(canvas.width / 3, 0, canvas.width / 3, canvas.height) data = imageData.data // Manipulate the pixel data for (let i = 0; i < data.length; i += 4) { data[i + 0] = 255 - data[i + 0] data[i + 1] = 255 - data[i + 1] data[i + 2] = 255 - data[i + 2] data[i + 3] = 255 } ctx.putImageData(imageData, canvas.width / 3, 0) } </script> </head> <body> <canvas id = "canvas"> Your browser does not support the HTML5 'Canvas' tag. </canvas> </body> </html>
Write code to display a greyscaled image with an adjustable coloured border, as shown here.
Example of an image that is rotated by 90 degrees (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
{
border:1px solid black;
width:500px;
height:500px;
}
#loadingMessage
{
position:absolute;
top:100px;
left:100px;
z-index:100;
font-size:50px;
}
</style>
<script>
let canvas = null
let ctx = null
let img = new Image()
img.src = "images/dkit01.png"
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()
}
function renderCanvas()
{
// rotate around the centre of the canvas
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(Math.radians(90))
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
}
// Convert from degrees to radians.
Math.radians = function (degrees)
{
return degrees * Math.PI / 180
}
// Convert from radians to degrees.
Math.degrees = function (radians)
{
return radians * 180 / Math.PI
}
</script>
</head>
<body>
<canvas id = "canvas">
Your browser does not support the HTML5 'Canvas' tag.
</canvas>
</body>
</html>
Write code to include a rotated watermark on an image that appears on a webpage, as shown here.
A canvas can be reset to its state previous by wrapping graphics instructions (such as the rotation and drawing code in the example above) inside a pair of save() and restore() functions. Wrapping the above example with the pair of save() and restore() functions would give the code below.
Although it is not needed in this example, it will generally be needed if your code is writting to the canvas more than once. For example, the game at this link needs to restore the canvas after each rotation.
The example below will give the same result as the example above where the image is rotated by 90 degrees (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 { border:1px solid black; width:500px; height:500px; } #loadingMessage { position:absolute; top:100px; left:100px; z-index:100; font-size:50px; } </style> <script> let canvas = null let ctx = null let img = new Image() img.src = "images/dkit01.png" 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() } function renderCanvas() { ctx.save() // remember the state of the canvas prior to the rotation // rotate around the centre of the canvas ctx.translate(canvas.width / 2, canvas.height / 2) ctx.rotate(Math.radians(90)) ctx.translate(-canvas.width / 2, -canvas.height / 2) ctx.drawImage(img, 0, 0, canvas.width, canvas.height) ctx.restore() // restore the canvas to its state prior to the rotation } // Convert from degrees to radians. Math.radians = function (degrees) { return degrees * Math.PI / 180 } </script> </head> <body> <canvas id = "canvas"> Your browser does not support the HTML5 'Canvas' tag. </canvas> </body> </html>
Write code to allow the user to change the angle of rotation of an image, as shown here. Do not use save() and restore() in your code. Your code will not work as expected. What do you think is happening?
Change the code from the above example to include a save() and restore(), as shown here. Your code will now work as expected.
It is possible to perform a translation in 3D. Although we usually do not need to apply 3D translations, doing a single 3D translation has a useful side-effect in that it forces all of a webpage's graphics to be drawn using the GPU. This will result in all graphics being drawn faster and smoother. The visual effect of this will not be obvious in most webpages. However, in games, where a lot of images are being drawn, it can greatly enhance the speed and smoothness of renderinctx. You should only use the GPU when it is needed, as using the GPU affects the battery life on mobile devices.
Including the code below will ensure that all rendering of a webpage is done using the GPU.
<style> body
{ transform:translate3d(0,0,0);
}
</style>
Adjust the code from the previous example, so as to include a call to translate3d(), as shown here.
Copyright Derek O' Reilly, Dundalk Institute of Technology (DkIT), Dundalk, Co. Louth, Ireland.