Home > Back-end >  How do I draw multiple images onto the canvas at once?
How do I draw multiple images onto the canvas at once?

Time:08-12

Right now the code is as follows:

const one = new Image(); 
one.src = "img/one.png";
const two = new Image();
two.src = "img/two.png";

function imgs(ctx) {
    one.onload = function () {
        ctx.drawImage(one, 50, 50);
    };
    two.onload = function () {
        ctx.drawImage(two, 100, 100);
    };
}

Can I wait for 'all' of the images to be loaded first, and than draw them all at the same time on the canvas? Currently it'll draw an image once it's been loaded, and than another once that is loaded, etc.

CodePudding user response:

You could keep a counter of the number of images loaded, and wait to act until all are loaded:

const one = new Image(); 
one.src = "img/one.png";
const two = new Image();
two.src = "img/two.png";

let numToLoad = 2;
let numLoaded = 0;

function imgs(ctx) {
    function incLoaded() {
        numLoaded  ;
        if(numLoaded == numToLoad){
            ctx.drawImage(one, 50, 50);
            ctx.drawImage(two, 100, 100);
        }
    }
    one.onload = incLoaded;
    two.onload = incLoaded;
}

CodePudding user response:

You can use create an image loader Promise, and then pass all three to Promise.all to await their load calls.

The use of Promise and async/await is preferred over a separate counter variable.

const ctx = document.querySelector('#draw').getContext('2d');

const loadImage = (url) => new Promise((resolve, reject) => {
  const img = new Image();
  img.addEventListener('load', () => resolve(img));
  img.addEventListener('error', (err) => reject(err));
  img.src = url;
});

const imageUrls = [
  'https://via.placeholder.com/100/FF7777/FFFFFF?text=A',
  'https://via.placeholder.com/100/77FF77/FFFFFF?text=B',
  'https://via.placeholder.com/100/7777FF/FFFFFF?text=C'
];

Promise
  .all(imageUrls.map(loadImage))
  .then(([one, two, three]) => {
    console.log('Drawing all three images...');
    ctx.drawImage(one, 0, 0);
    ctx.drawImage(two, 100, 0);
    ctx.drawImage(three, 200, 0);
  });
<canvas id="draw" width="300" height="100"></canvas>


Beginner help

Selectors

The document.querySelector method is preferred over the document.getElementById and document.getElementsByClassName because it it easier to work with and supports attribute selectors.

This: document.querySelector('#draw') is preferred over document.getElementById('draw') or window.draw.

Note: There is also a multi-element selector function called document.querySelectorAll

Iterators

The Array.prototype.map method returns a new array (iterates through the array) and returns a new value for each value visited. In the example above, each string is transformed into a Promise. The same code can be written more verbosely:

Promise.all(imageUrls.map(function(imageUrl) {
  return loadImage(imageUrl); // returns a Promise
}));
  • Related