Tell me why with this code:

<html> <body> <canvas id = 'c01' style = "width: 800; border: 1px solid black;"></canvas> <script> var canvas = document.getElementById("c01"); var ctx = canvas.getContext("2d"); var image = new Image(); image.onload = function() { canvas.width = image.naturalWidth; canvas.height = image.naturalHeight; ctx.beginPath(); ctx.drawImage(image, 0, 0); ctx.lineWidth = "6"; ctx.strokeStyle = "red"; ctx.rect(canvas.width / 4, canvas.height / 4, canvas.width / 2, canvas.height / 2); ctx.stroke(); }; image.src = "https://icdn.lenta.ru/images/2019/03/31/13/20190331135912200/pic_5bfd003894e22bb0d70b775286b96a4f.jpg"; </script> </body> </html> 

the image is displayed and a rectangle is on top of it - ALL OK

And with this:

 <script> var canvas = document.getElementById("c01"); var ctx = canvas.getContext("2d"); var image = new Image(); image.onload = function() { canvas.width = image.naturalWidth; canvas.height = image.naturalHeight; }; image.src = "https://icdn.lenta.ru/images/2019/03/31/13/20190331135912200/pic_5bfd003894e22bb0d70b775286b96a4f.jpg"; ctx.beginPath(); ctx.drawImage(image, 0, 0); ctx.lineWidth = "6"; ctx.strokeStyle = "red"; ctx.rect(canvas.width / 4, canvas.height / 4, canvas.width / 2, canvas.height / 2); ctx.stroke(); </script> 

the canvas is constructed in the right size (with the image), but the image itself is not drawn, and the rectangle flashes for a second and disappears

Is this due to the fact that the image does not have time to load (asynchronous image.src)?

and how to do everything correctly?

if there are several images, then onload will hardly have to

    1 answer 1

    You can wait until everything is loaded, and only then draw:

     let imagesCanvas = document.querySelector('canvas'); let imgCtx = imagesCanvas.getContext('2d'); let images = ['keyboard.jpg', 'star.jpg','leaves.jpg' ] let loaded = []; load();// Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠΈ function load() { let name = images.shift(); let img = new Image(); img.crossOrigin = "anonymous"; // Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠΈ, ΠΏΠΎΠΊΠ° ΠΎΠ½ΠΈ всС Π½Π΅ Π±ΡƒΠ΄ΡƒΡ‚ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Ρ‹, // Ρ‚ΡƒΡ‚ Π½Π°Π΄ΠΎ ΠΏΡ€Π΅Π΄ΡƒΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ onerror, ΠΈ отрисовку, ΠΊΠΎΠ³Π΄Π° ΠΎΠ½ΠΈ всС загрузятся img.onload = () => add() | images.length ? load() : requestAnimationFrame(draw); img.src = `https://webglfundamentals.org/webgl/resources/${name}` // добавляСм ΠΈΠ½Ρ„ΠΎ ΠΎ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ΅ Π² массив function add() { loaded.push({ name: name, img: img, x: 50+loaded.length*120, y: 5+30*loaded.length, w: img.width/2, h: img.height/2 }); } } function draw(){ loaded.forEach((img, i) => { // рисуСм ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠΈ Π½Π° ΠΊΠ°Π½Π²Π΅ imgCtx.drawImage(img.img, img.x , img.y, img.w, img.h); })} 
     body{margin:0} 
     <canvas width="600" height="170"></canvas> 

    You can also cause the entire frame ( draw() ) to be redrawn in each onload, not optimally, but the code will be easier:

     let imagesCanvas = document.querySelector('canvas'); let imgCtx = imagesCanvas.getContext('2d'); let images = ['keyboard.jpg', 'star.jpg','leaves.jpg' ] let loaded = []; images.forEach(name => { let img = new Image(); img.crossOrigin = "anonymous"; img.src = `https://webglfundamentals.org/webgl/resources/${name}` img.onload = () => { loaded.push({ img: img, x: 50 + loaded.length*120, y: 5 + 30*loaded.length, w: img.width/2, h: img.height/2 }); draw(); }; }) function draw() { loaded.forEach(i => imgCtx.drawImage(i.img, ix , iy, iw, ih)); } 
     body{margin:0} 
     <canvas width="600" height="170"></canvas>