I have the following JavaScript file with a function called menu
that calls the draw
function 4 different times to display 4 different images on the screen.
I need to display them in the order they are coded in, but every time I refresh I get something different. I understand that this is most likely because some of the images load faster than others.
I have looked up some other examples of this on the site and the solution seems to be drawing the images only when all of them are loaded first, however I can't get that to work.
Is there another way?
var cvs = document.getElementById("canvas");
var ctx = cvs.getContext("2d");
var audio = new Audio('sounds/sound.ogg');
cvs.addEventListener("click", function(){
audio.play();
});
var logoSound;
ctx.fillStyle= "#87ceeb";
ctx.fillRect(0,0,1330,800);
function draw(src, a, b) {
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.onload = function() {
ctx.drawImage(img, x, y);
};
img.src = src;
}
function menu() {
draw("images/clouds.png", 0, 300);
draw("images/background.png", 0, 360);
draw("images/display.png", 410, 0);
draw("images/plank.png", 405, 300);
}
menu();
Update
async function draw(src,x,y) {
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.onload = function(){
ctx.drawImage(img,x,y);
};
img.src = src;
}
// main
(async function menu (){
await draw("images/clouds.png", 0, 300);
await draw("images/background.png", 0, 360);
await draw("images/display.png", 410, 0);
await draw("images/plank.png", 405, 300);
await draw("images/info.png", 1195, 660);
}());
function cloud2(){
ctx.drawImage(cloud, speed, 0);
cvs.requestAnimationFrame(cloud);
}
menu();
You could make your draw function asynchronous. The setTimeout call is a simulation of your asynchronous on load handler.
async function draw (msg) {
return new Promise ((resolve, reject) => {
let randomDelay = Math.floor(Math.random() * 3000);
setTimeout(() => {
resolve(msg);
}, randomDelay);
});
}
(async function (){
console.log(await draw(1));
console.log(await draw(2));
console.log(await draw(3));
console.log(await draw(4));
}());
Which would guarantee the drawing order.
output is: 1 2 3 4
Drawing an image on a canvas is a synchronous operation, what is not, is to load these images.
So split your logic in 1.Loading, then 2.Drawing
The loading part will just create as many <img>
elements as you need to be drawn, operation greatly cleaned up thanks to Promises.
Once that's done, the drawing part will just iterate over the images and draw them:
const ctx = canvas.getContext('2d'); function loadImages(urls) { return Promise.all(urls.map(loadImage)); } function loadImage(url) { return new Promise((res, rej) => Object.assign((new Image()), { src: url, onload: function(e){res(this)}, onerror: rej })); } function drawImages(images) { images.forEach((img, i) => ctx.drawImage(img, i * 50, 0)); } async function begin() { // build up our array of urls const urls = Array.from({ length: 10 }, () => 'https://lorempixel.com/50/50?' + Math.random()); // load them all const images = await loadImages(urls); // draw them all drawImages(images); } begin().catch(console.error)
<canvas id="canvas" width="500" height="50"></canvas>
Note that it is the basic operations when external assets are required:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.