Introduction
Creating a Canvas
HTML5 Canvas is used to draw graphics on a webpage via scripting in JavaScript. It can be used to draw graphs and animations.
To create a canvas we just use the <canvas> element as shown below:
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<!-- Create a fixed-size drawing surface -->
<canvas id="c" width="200", height="200" style="border:1px solid #000;">
Description of content
</canvas>
</body>
</html>
It's always a good idea to provide fallback content for browsers that do not support canvas. In the example above we have provided a text description of the canvas content but we could have also provided a static image of the dynamically rendered content.
Result
To use the canvas we have to access it via JavaScript as shown below:
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Access the rendering context
var context = canvas.getContext("2d");
}
</script>
To display something on the canvas, we first need to access the rendering context. In this tutorial, we focus on the 2D rendering context but there are other contexts available. An if
statement is included to check support programmatically.
The 2d rendering context in canvas uses a Cartesian coordinate system, with the origin point (0, 0) at the top left:
Draw images onto Canvas
Example 1
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<!-- Create a fixed-size drawing surface -->
<canvas id="c" width="200", height="200" style="border:1px solid #000;">
Draw images
</canvas>
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Access the rendering context
var context = canvas.getContext('2d');
// Create image
var img = new Image();
// Set the image source
img.src = '../images/400x400.png';
// When the resource is loaded
img.onload = function () {
console.log('Image has been loaded');
// Draw image onto canvas
context.drawImage(img, 0, 0, canvas.width, canvas.height);
}
}
</script>
</body>
</html>
Result
Example 2
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<!-- Create a fixed-size drawing surface -->
<canvas id="c" width="200", height="200" style="border:1px solid #000;">
Draw images
</canvas>
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Access the rendering context
var context = canvas.getContext('2d');
// Create image
var img = new Image();
// Set the image source
img.src = '../images/400x400.png';
// When the resource is loaded
img.onload = function () {
console.log('Image has been loaded');
// Draw images onto canvas
context.drawImage(img, 0, 0, canvas.width/2, canvas.height/2);
context.drawImage(img, canvas.width/2, 0, canvas.width/2, canvas.height/2);
context.drawImage(img, 0, canvas.height/2, canvas.width/2, canvas.height/2);
context.drawImage(img, canvas.width/2, canvas.height/2, canvas.width/2, canvas.height/2);
}
}
</script>
</body>
</html>
Result
Drawing rectangles
fillRect(x, y, width, height)
- Draw a filled rectangle.
strokeRect(x, y, width, height)
- Draw a rectangular outline.
clearRect(x, y, width, height)
- Clear the specified rectangular area, making it fully transparent.
context.fillStyle = color;
context.fillStyle = gradient;
context.fillStyle = pattern;
- Specify the color or style to use inside shapes.
context.strokeStyle = color;
context.strokeStyle = gradient;
context.strokeStyle = pattern;
- Specify the color or style to use for the lines around shapes.
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="c" width="200", height="200" style="border:1px solid #000;">
Rectangles using fillRect() & strokeRect()
</canvas>
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Access the rendering context
var context = canvas.getContext('2d');
// Specify the color or style to use inside shapes
context.fillStyle = "#007f7f";
// Draw a filled rectangle
context.fillRect(0, 0, 200, 200);
// Clear the specified rectangular area (left eye)
context.clearRect(35, 35, 50, 50);
// Draw a rectangular outline (left eye)
context.strokeRect(45, 45, 30, 30);
// Clear the specified rectangular area (right eye)
context.clearRect(115, 35, 50, 50);
// Draw a rectangular outline (right eye)
context.strokeRect(125, 45, 30, 30);
// Clear the specified rectangular area (mouth)
context.clearRect(35, 140, 130, 30);
}
</script>
</body>
</html>
Note: To erase the entire canvas, you could call: context.clearRect(0, 0, c.width, c.height);
Result
Drawing paths
context.beginPath()
- Create a new path for future drawing commands.
context.closePath()
- Create a path from the current point back to the starting point.
context.moveTo()
- Move the starting point of a new sub-path to the (x, y) coordinates.
context.lineTo()
- Connect the last point in the sub-path to the x, y coordinates with a straight line.
context.arc(x, y, radius, startAngle, endAngle [, anticlockwise]);
- Add an arc to the path which is centered at (x, y) position with radius r starting at startAngle and ending at endAngle. Angles area measured in radians (radians = (PI/180)*degrees).
context.fill()
- Draw a solid shape by filling the path's content area.
context.stroke()
- Draw the shape by stroking its outline.
Example 1
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="c" width="200", height="200" style="border:1px solid #000;">
Rectangles using paths
</canvas>
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Access the rendering context
var context = canvas.getContext('2d');
// Specify the color or style to use inside shapes
context.fillStyle = "#007f7f";
// Create a new path
context.beginPath();
// Path
context.moveTo(10, 10);
context.lineTo(110, 10);
context.lineTo(110, 60);
context.lineTo(10, 60);
// Create a path from the current point back to the starting point from (10, 60) to (10, 10)
context.closePath();
// Draw
context.stroke();
// Create a new path
context.beginPath();
// Path
context.moveTo(10, 70);
context.lineTo(110, 70);
context.lineTo(110, 120);
context.lineTo(10, 120);
// Create a path from the current point back to the starting point from (10, 120) to (10, 70)
context.closePath();
// Draw
context.fill();
// Create a new path
context.beginPath();
// Clockwise arc (default)
context.arc(40, 160, 30, 0, Math.PI);
// Draw semicircle
context.fill();
// Anticlockwise arc
var anticlockwise = true;
context.arc(100, 160, 30, 0, Math.PI, anticlockwise);
// Draw semicircle
context.stroke();
}
</script>
</body>
</html>
Result
Example 2
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="c" width="200", height="200" style="border:1px solid #000;">
Smiley face using arc()
</canvas>
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Access the rendering context
var context = canvas.getContext('2d');
// Specify the color or style to use inside shapes
context.fillStyle = "#007f7f";
// Create a new path
context.beginPath();
// Head
context.arc(100, 100, 75, 0, Math.PI * 2);
context.moveTo(150, 100);
// Mouth
context.arc(100, 100, 50, 0, Math.PI);
context.moveTo(140, 80);
// Right eye
context.arc(130, 80, 10, 0, Math.PI * 2);
context.moveTo(80, 80);
// Left eye
context.arc(70, 80, 10, 0, Math.PI * 2);
context.stroke();
}
</script>
</body>
</html>
Result
Canvas drawing state
context.save()
- Save the entire state of the canvas.
context.restore()
- Restore the most recently saved canvas state.
Canvas drawing states are stored on a stack. A drawing state consists of translate
, rotate
, scale
, strokeStyle
, fillStyle
, globalAlpha
, lineWidth
, lineCap
, lineJoin
, miterLimit
, lineDashOffset
, shadowOffsetX
, shadowOffsetY
, shadowBlur
, shadowColor
, globalCompositeOperation
, font
, textAlign
, textBaseline
, direction
, imageSmoothingEnabled
.
Example
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="c" width="200", height="200" style="border:1px solid #000;">
save() and restore()
</canvas>
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Access the rendering context
var context = canvas.getContext('2d');
// Specify the color or style to use inside shapes.
context.fillStyle = "blue";
// Draw a filled rectangle.
context.fillRect(0,0,50,50);
// Specify the color or style to use inside shapes.
context.fillStyle = "green"
// Draw a filled rectangle.
context.fillRect(50,50,50,50);
// Specify the color or style to use inside shapes.
context.fillStyle = "blue"
// Draw a filled rectangle.
context.fillRect(100,100,50,50);
}
</script>
</body>
</html>
HTML (Save & restore state)
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="c" width="200", height="200" style="border:1px solid #000;">
save() and restore()
</canvas>
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Access the rendering context
var context = canvas.getContext('2d');
// Specify the color or style to use inside shapes.
context.fillStyle = "blue";
// Draw a filled rectangle.
context.fillRect(0,0,50,50);
// Save state with blue fill
context.save();
// Specify the color or style to use inside shapes.
context.fillStyle = "green"
// Draw a filled rectangle.
context.fillRect(50,50,50,50);
// Restore to blue fill
context.restore();
// Draw a filled rectangle.
context.fillRect(100,100,50,50);
}
</script>
</body>
</html>
Result
Transformations
context.scale(x, y)
- Scale the canvas horizontally and vertically by a given factor.
context.translate(x, y)
- Move the canvas and its origin on the grid.
context.rotate(angle)
- Rotate the canvas clockwise around the current origin by the angle number of radians.
Note: Transformations apply on all subsequent objects unless the drawing state is restored. It's a good idea to save the canvas state before doing any transformations.
Example
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="c" width="200", height="200" style="border:1px solid #000;">
Transformations
</canvas>
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Access the rendering context
var context = canvas.getContext('2d');
// Save state before doing any transformations
context.save();
// Specify the color or style to use inside shapes.
context.fillStyle = "blue";
// Scale (1 horizontal unit = 2px, 1 vertical unit = 4px)
context.scale(2, 4);
// Draw a filled rectangle: pos(20px,40px), 40px(w)x80px(h)
context.fillRect(10,10,20,20);
// Restore previous state (undo scale, undo fillStyle)
context.restore();
// Save state before doing any transformations
context.save();
// Specify the color or style to use for the lines around shapes.
context.strokeStyle = "red";
// Move: origin(100px,100px)
context.translate(100,100);
// Draw a rectangular outline: pos(0,0), 20px(w)x20px(h)
context.strokeRect(0,0,20,20);
// Restore previous state (undo translate, undo strokeStyle)
context.restore();
// Save state before doing any transformations
context.save();
// Specify the color or style to use inside shapes.
context.fillStyle = "green";
// Move: origin((150px, 150px), origin is the rotation center
context.translate(150,150);
// Rotate 45 degrees clockwise
context.rotate(Math.PI/4);
// Draw a filled rectangle: pos(150px,150px), 30px(w)x30px(h)
context.fillRect(0,0,30,30);
// Restore previous state (undo translate, undo strokeStyle)
context.restore();
// Save state before doing any transformations
context.save();
}
</script>
</body>
</html>
Result
Style & colors
Colors
context.fillStyle = color;
- Specify the color or style to use inside shapes.
context.strokeStyle = color;
- Specify the color or style to use for the lines around shapes.
Just like CSS, there are several ways to specify color:
context.fillStyle = 'blue';
context.fillStyle = '#0000ff';
context.fillStyle = 'rgb(0,0,255)';
context.fillStyle = 'rgba(0,0,255,1)'
Transparency
context.globalAlpha = transparencyValue
- Apply the specified transparency value to all future shapes drawn on the canvas. 0.0 means full transparency and 1.0 means full opacity. The default value is 1.0.
context.strokeStyle = 'rgba(255, 0, 0, 0.5)';
context.fillStyle = 'rgba(255, 0, 0, 0.5)';
- Assing transparent colors to stroke and fill style
Line styles
context.lineWidth = value
- Sets the width of lines drawn in the future.
context.lineCap = type
- Sets the appearance of the ends of lines.
Examples
Example 1
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="c" width="200", height="200" style="border:1px solid #000;">
Grid of rectangles with a random color
</canvas>
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Expected output: 0, 1, 2, ..., max-1
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
// Access the rendering context
var context = canvas.getContext('2d');
// Save state before doing any transformations
context.save();
// Grid of rectangles with a random color
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
context.fillStyle = 'rgb(' + getRandomInt(256) + ',' + getRandomInt(256) + ',' + getRandomInt(256) + ')';
context.fillRect(j*20,i*20,20,20);
}
}
}
</script>
</body>
</html>
Result
Example 2
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="c" width="200", height="200" style="border:1px solid #000;">
Shades of gray
</canvas>
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Access the rendering context
var context = canvas.getContext('2d');
// Save state before doing any transformations
context.save();
// Shades of gray
var transparencyValue = 0.1;
for (let i = 0; i < 10; i++) {
context.globalAlpha = transparencyValue;
context.fillRect(i*20,0,20,200);
transparencyValue += 0.1;
}
}
</script>
</body>
</html>
Result
Example 3
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h2><u>Crisp even-width lines</u></h2>
<canvas style="display:block;" id="c1" width="200", height="200" style="border:1px solid #000;">
Lines with increasing line widths
</canvas>
<h2><u>Crisp odd-width lines</u></h2>
<canvas style="display:block;" id="c2" width="200", height="200" style="border:1px solid #000;">
Lines with increasing line widths
</canvas>
<h2><u>Crisp lines</u></h2>
<canvas style="display:block;" id="c3" width="200", height="200" style="border:1px solid #000;">
Lines with increasing line widths
</canvas>
<script>
var canvas1 = document.getElementById('c1');
var canvas2 = document.getElementById('c2');
var canvas3 = document.getElementById('c3');
// Check for canvas support
if (canvas1.getContext) {
// Access the rendering contexts
var context1 = canvas1.getContext('2d');
var context2 = canvas2.getContext('2d');
var context3 = canvas3.getContext('2d');
// Save states before doing any transformations
context1.save();
context2.save();
context3.save();
// Draw lines with increasing line widths
for (let i = 0; i < 10; i++) {
// Set the current line thickness
context1.lineWidth = i + 1;
context2.lineWidth = i + 1;
context3.lineWidth = i + 1;
// Create a new path
context1.beginPath();
context2.beginPath();
context3.beginPath();
// Canvas 1 (only the even-width lines look crisp)
context1.moveTo(i*20+10,10);
context1.lineTo(i*20+10,190);
// Canvas 2 (only the odd-width lines look crisp)
context2.moveTo(i*20+10.5,10);
context2.lineTo(i*20+10.5,190);
// Canvas 3 (every line looks crisp)
// even-width lines
if (context3.lineWidth % 2 === 0) {
context3.moveTo(i*20+10,10);
context3.lineTo(i*20+10,190);
}
// odd-width lines
else {
context3.moveTo(i*20+10.5,10);
context3.lineTo(i*20+10.5,190);
}
// Draw
context1.stroke();
context2.stroke();
context3.stroke();
}
}
</script>
</body>
</html>
Result
Text
Drawing
context.fillText(text, x, y [, maxWidth])
- Fill the specified text at the given position.
context.strokeText(text, x, y [, maxWidth])
- Stroke the specified text at the given position.
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="c" width="200", height="200" style="border:1px solid #000;">
Drawing text
</canvas>
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Access the rendering context
var context = canvas.getContext('2d');
// Set text style
context.font = '30px sans-serif';
// Draw stroke text
context.strokeText('Hello World', 10, 30);
// Set text style
context.font = '30px serif';
// Draw fill text
context.fillText('Hello World', 10, 60);
}
</script>
</body>
</html>
Result
Styling
font = value
- Set text style.
textAlign = value
- Set text alignment. Beware that the alignment is based on the x value of the fillText() method.
textBaseline = value
- Set baseline alignment
direction = value
- Set directionality
HTML
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="c" width="260", height="450" style="border:1px solid #000;">
Styling text
</canvas>
<script>
var canvas = document.getElementById('c');
// Check for canvas support
if (canvas.getContext) {
// Access the rendering context
var context = canvas.getContext('2d');
/* TEXT STYLING EXAMPLE */
// Specify the color to use for the lines around shapes.
context.strokeStyle = '#007f7f';
// Set text style
context.font = 'italic small-caps bold 30px Arial, Helvetica, sans-serif';
// Set text alignment
context.textAlign = 'center';
// Draw stroke text
context.strokeText('Lorem ipsum', canvas.width / 2, 30);
/* TEXT ALIGNMENT EXAMPLE */
context.strokeStyle = 'red';
// Start a new path
context.beginPath();
// Move the starting point of a new sub-path to the (x, y) coordinates.
context.moveTo(canvas.width / 2, 50);
// Connect the last point in the sub-path to the x, y coordinates with a straight line.
context.lineTo(canvas.width / 2, 180);
// Draw the shape by stroking its outline.
context.stroke();
context.font = '20px Arial, Helvetica, sans-serif';
var alignments = ['left', 'center', 'right', 'start', 'end'];
var startX = canvas.width / 2;
var startY = 80;
var margin = 20;
alignments.forEach(function (alignment) {
context.textAlign = alignment;
// Draw fill text
context.fillText(alignment, startX, startY);
startY += margin;
});
/* BASELINE ALIGNMENT EXAMPLE */
// Default text alignment
context.textAlign = 'start';
var baselines = ['top', 'hanging', 'middle', 'alphabetic', 'ideographic', 'bottom'];
startX = 10;
startY = 200;
margin = 40;
baselines.forEach(function (baseline) {
// Set baseline alignment
context.textBaseline = baseline;
context.beginPath();
context.moveTo(startX, startY);
context.lineTo(canvas.width - startX, startY);
context.stroke();
context.fillText('Lorem ipsum (' + baseline + ')', startX, startY);
startY += margin;
});
/* ANOTHER STYLING EXAMPLE */
context.font = '30px Impact';
context.textAlign = 'center';
context.strokeStyle = 'black';
// Sets the width of lines drawn in the future.
context.lineWidth = 3;
context.strokeText('LOREM IPSUM', canvas.width / 2, startY);
context.fillStyle = 'white';
context.fillText('LOREM IPSUM', canvas.width / 2, startY);
}
</script>
</body>
</html>
Result