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
}));