How To Load And Draw Images With HTML5 Canvas
For my previous tutorials I have been drawing basic shapes like rectangles to explain concepts. For tutorials and prototypes, this is fine. If you want to create a real game, it is important that you can draw images to the screen. Before these images can be displayed, they need to be loaded first. This tutorial explains how to load images at the start of your game and how to display the loaded images afterwards in a render loop. During the loading of the images, a preloader is displayed. A working example is provided including the full source code.
Click here to go directly to the end of this article and view the demo.
Loading Images
To load a single image, we first have to create an Image object. After the object is created, we set the src property of the image to the location of the image we want to load. The image doesn’t get loaded directly, it takes some time before the image is ready to be displayed. If we want to know when the image is ready, we must add an event handler to the onload event of the image. The onload event must be set, before we set the src property, otherwise we could miss the event. The code below shows how to load a single image.
1 2 3 4 5 6 7 8 9 10 | // Create the image object var image = new Image(); // Add onload event handler image.onload = function () { // Done loading, now we can use the image }; // Set the source url of the image image.src = "image1.png"; |
Using the basic image loading code, we can create a function that takes an array of image files and loads all of our images at the same time. We could use this function at the start of a game to initialize our image resources. The function uses a couple of global variables that we can use to test if the image resources are actually loaded and ready. We use the global variables later in this tutorial to create a preloader.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | // Image loading global variables var loadcount = 0; var loadtotal = 0; var preloaded = false; // Load images function loadImages(imagefiles) { // Initialize variables loadcount = 0; loadtotal = imagefiles.length; preloaded = false; // Load the images var loadedimages = []; for (var i=0; i<imagefiles.length; i++) { // Create the image object var image = new Image(); // Add onload event handler image.onload = function () { loadcount++; if (loadcount == loadtotal) { // Done loading preloaded = true; } }; // Set the source url of the image image.src = imagefiles[i]; // Save to the image array loadedimages[i] = image; } // Return an array of images return loadedimages; } |
The function loadImages takes as input an array of filenames and returns an array of images in the same order as the input array. We can call the function like this:
1 | var images = loadImages(["sprite1.png", "sprite2.png", "sprite3.png"]); |
Draw And Scale Images
Now that we know how to load images, we want to draw them to the canvas. Drawing images is easy, if we have a context of the canvas and a loaded Image. We use the drawImage function and specify the image, dx and dy parameters to draw an image at a specified x and y position.
1 | context.drawImage(image, dx, dy) |
If you want to scale the output image, you can specify the optional parameters dWidth and dHeight as specified in the API. It is also possible to only draw a part of the source image by specifying a rectangle using the sx, sy, sWidth and sHeight parameters.
1 2 | context.drawImage(image, dx, dy, dWidth, dHeight); context.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); |
Here is a complete example, that uses a canvas with id viewport and loads and draws the image image1.png.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | window.onload = function() { // Get the canvas and context var canvas = document.getElementById("viewport"); var context = canvas.getContext("2d"); // Create the image object var image = new Image(); // Add onload event handler image.onload = function () { // Done loading, now we can use the image context.drawImage(image, 10, 10); }; // Set the source url of the image image.src = "image1.png"; }; |
A Simple Preloader
Before a game can start, all of the resources need to be loaded first. While we wait on the images to be loaded, we can show a loading screen to the player. This loading screen is called a preloader. To implement the preloader, I’m going to modify the code of the HTML5 Canvas Basic Game Framework from a previous tutorial and add the loadImages function and the preloader.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | var initialized = false; var images = []; // (...) // Initialize the game function init() { // Load images images = loadImages(["sprite1.png", "sprite2.png", "sprite3.png"]); // (...) } // Main loop function main(tframe) { // Request animation frames window.requestAnimationFrame(main); if (!initialized) { // Preloader // Clear the canvas context.clearRect(0, 0, canvas.width, canvas.height); // Draw the frame drawFrame(); // Draw a progress bar var loadpercentage = loadcount/loadtotal; context.strokeStyle = "#ff8080"; context.lineWidth=3; context.strokeRect(18.5, 0.5 + canvas.height - 51, canvas.width-37, 32); context.fillStyle = "#ff8080"; context.fillRect(18.5, 0.5 + canvas.height - 51, loadpercentage*(canvas.width-37), 32); // Draw the progress text var loadtext = "Loaded " + loadcount + "/" + loadtotal + " images"; context.fillStyle = "#000000"; context.font = "16px Verdana"; context.fillText(loadtext, 18, 0.5 + canvas.height - 63); if (preloaded) { // Add a delay for demonstration purposes setTimeout(function(){initialized = true;}, 1000); } } else { // Update and render the game update(tframe); render(); } } |
Below you can see the result of the preloader. Before the game starts, the preloader shows a progress bar which indicates the loading process of the images. During the preloader, the actual game is not being updated yet. Only after the images are loaded, the initialized variable becomes true and the normal render loop can continue.
Bouncing Images Example
To conclude this tutorial, I have created a fully working example that loads a couple of images and draws them to the screen. The images bounce around the screen, after the preloader is done loading the images. The full source code is available on GitHub.