Get up to 80 % extra points for free! More info:

Lesson 13 - Images and drawing on canvas using JavaScript

In the previous exercise, Solved tasks for JavaScript lessons 8-12, we've practiced our knowledge from previous lessons.

Welcome to another lesson about creating web applications in JavaScript. In the previous lesson, Solved tasks for JavaScript lessons 8-12, we finished a table editor. In today's JavaScript tutorial, we're going to work with images.

There're two types of images on the web - static and dynamic. You already know static images and we can hardly do any magic with them. They're just ordinary images (the <img> tag) with which we can perform just a few basic operations. We mostly manipulate them only as DOM elements. Dynamic images can be represented in an HTML document by 2 tags - <svg> and <canvas>. Although the first tag is not static, we won't be able to do much with it yet. The <canvas> tag is a bit more interesting and the only one whose content can't be defined by any other way than by JavaScript. Let's take a look through everything.

Static images

As I mentioned earlier in the introduction, this is a classic image, which in HTML is defined by the <img> tag. Of course, we can handle different events like clicks in the same way we did it e.g. for buttons. In JavaScript, we can create it either classically as a DOM element:

let img = document.createElement("img");

Or, we can create a new Image object, which is a shorthand for creating the DOM element:

let img = new Image();

Loading images

Loading images is a big problem (as well as loading anything in JavaScript). Before we start working with an image, it must be loaded. If we have an image in HTML and we execute the JavaScript code in the load event handler, there's no problem. The browser will ensure that the handler will be triggered not before everything (even the image) is loaded.

If we create images later in JavaScript, we have to wait till they're loaded. The load event of the image element will become handy:

let img = new Image();
img.src = "images/image1.jpg";

img.onload = function () {
    // here we can be sure the image is loaded

Example: A switch

Let's create a switch. You know the ON-OFF switches for sure. Download the images below and keep their names switch0.png and switch1.png.

We'll create a page where will be a switch image with the switch id and with the switch0.png file loaded as default.

<img src="switch0.png" id="switch" alt="Switch" />

We'll create a script where we declare a mySwitch variable (since switch is a reserved keyword) and, after the page is loaded, we'll store our switch image element in it. As next, we'll create a switchIt() function and set it as an event handler for clicking the image.

let mySwitch;

function switchIt() {

window.onload = function () {
    mySwitch = document.getElementById("switch");
    mySwitch.onclick = switchIt;

Img.src vs. img.getAttribu­te("src")

Now it's just about the condition and changing src, but... The image object (in OOP, you'll discover it's called HTMLImageElement) has the src property. Therefore, it's possible to change either the value of the src HTML attribute of the <img> element or to assign the value directly to the src property of the JavaScript element. Unfortunately, these two possibilities behave a bit differently in some browsers. While the getAttribute() method returns exactly what is written in the attribute, the src property returns the absolute path. So, if we'll compare the sources, we'll mostly do it with the value in the attribute. To try it out, we'll change the image source using the src property.

function switchIt() {
    if (mySwitch .getAttribute("src") == "switch0.png") {
        mySwitch .src = "switch1.png";
    } else {
        mySwitch .src = "switch0.png";

Open and test the page, the switch should work.


Notice that we don't have to worry when the image loads, we're not interested in it at all. The user will wait anyway, but we're relieved from this as long as we don't work with the image any further.

Now, let's proceed to dynamic images.

Dynamic images

Dynamic images are drawn on canvas, which is represented by the <canvas> element. This element MUST have the width and height attributes set. If we don't specify them or set them in CSS, some browsers will not understand and the result will be blurred. However, we can't draw directly on the <canvas> element, we must get its context first. Maybe you're wondering what's it good for, getting the context? It's a difference when we draw a 3D game and a 2D tree on a canvas. 3D is currently being adopted as the WebGL standard and we won't deal with it now. We'll be interested in the 2D context only.

Getting the context

We'll get the context of a canvas using the getContext() method, passing the context type as its string parameter. In our case, the context type is "2d".

let canvas = document.getElementById("canvas");
let context = canvas.getContext("2d");

On this context we can call various method which draw on the canvas.


The basic object is a rectangle. We have two basic methods for drawing a rectangle. These are fillRect() and strokeRect(). They both have the same parameters which are x, y, width, and height. The fillRect() method will fill the rectangle, the strokeRect() will draw just its outline.

HTML part

<canvas width="320" height="200" id="canvas"></canvas>

JS part

let canvas = document.getElementById("canvas");
let context = canvas.getContext("2d");
context.fillRect(50, 50, 100, 100);
context.strokeRect(200, 50, 100, 100);


We use paths to draw lines on a canvas. We must (or should) begin the paths and then close them as well. We use the beginPath() and closePath() to do so. We'll draw the line itself using the lineTo(x, y) method. The line will be drawn from the last cursor position (which is [0;0] at the start). We can set this position by the moveTo(x, y) method. The method doesn't draw anything, just moves the canvas cursor to a given position. We'll draw the path either by the fill() method, which fills the inside of the path with color (so you can draw your own shapes, that's why you need to close the path), or the stroke() method that only draws the outline of the path. A simple example below draws a line from the point [20;20] to [40;150].

context.moveTo(20, 20);
context.lineTo(40, 150);

The results:


Circles and arcs

The other things we can draw on the canvas are circles and arcs (circle slices). This is all provided by the arc() method which syntax follows:

context.arc(x, y, radius, startAngle, endAngle, direction);

The x and` y` arguments again specify the absolute position, in this case the center of the circle. The radius argument specifies the radius of the circle, startAngle is the angle from which the circle will be drawn. We specify the angles in radians. From mathematics, we should remember that the full angle is 2 * PI and that degrees are converted to radians as (PI / 180) * degrees. The last argument is direction. It's a logical value (true/false) which indicates whether the circle will be drawn clockwise or counterclockwise. The default value is true, which indicates the clockwise direction. We've to use this method inside of a path.

We draw a circle as follows:

context.arc(100, 100, 80, 0, Math.PI * 2);

The reward for the code above will be this circle:



To make our drawings look good, we'll learn to use styles. We distinguish styles to fill and stroke. Styles can be applied to all objects from rectangles to circles. We have two basic properties that the stroke() and fill() methods work with. These are fillStyle and strokeStyle. The values of these properties are colors. We can specify them using the usual CSS hexadecimal syntax like #ffffff or rgb(255, 255, 255). We can also use rgba(255, 255, 255, 0.5), where the last value is the alpha channel (opacity), or hsl and hsla (as in CSS 3). And the last option is to specify the colors by their names if they have it (e.g. "green").

Let's style some simple objects:

// We define styles before drawing the objects (calling the fill(), stroke(), or other drawing methods such as fillRect(), strokeRect()...)

context.fillStyle = "#a8c101";
context.fillRect(10, 10, 50, 50);
Styling objects

External images

On the canvas, of course, we can also draw existing images, e.g. from files. The images have to be already loaded, otherwise they won't be drawn. We draw an image simply using the drawImage() method. It accepts the image as the first parameter, the X and Y positions of where to draw the image as the second and third parameters. There are also methods with parameters for scaling/reducing and cropping the image.


An image to test drawing images on HTML5 canvas

The result:



In addition to all the shapes, text can also be rendered on a canvas. This can be used, for example, as a watermark on photos in your gallery, labels of a chart, or completely differently, just as your imagination allows. The basic function is fillText(text, x, y). The text here represents the string we want to draw. The x and` y` arguments are the absolute position. We can render a simple text as follows:

context.fillText("", 50, 50);

However, the text will be unstyled and quite small. Therefore, there's the context.font property that we need to set before the text is rendered (smilarly as fillStyle). The values of the property are the same as the values of the CSS font property. Let's set the text size to 30 pixels, for example, and use the sans-serif font.

context.font = "30px sans-serif";
context.fillText("", 50, 50);

The result:


That would be enough for the canvas introduction. In the next lesson, 2D canvas context in JavaScript, we'll look at the canvas in more detail.


Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.


By downloading the following file, you agree to the license terms

Downloaded 12x (110.24 kB)
Application includes source codes in language JavaScript


Previous article
Solved tasks for JavaScript lessons 8-12
All articles in this section
JavaScript Basic Constructs
Skip article
(not recommended)
2D canvas context in JavaScript
Article has been written for you by Michal Zurek
User rating:
1 votes