javascript canvas: изображение не выводится

185
31 декабря 2019, 16:40

Подскажите, почему при таком коде:

<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>

выводится изображение и поверх него прямоугольник - ВСЕ ок

А при таком:

<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>

канвас строется нужного размера (с изображение), но само изображение не отрисовывается, а прямоугольник мигает на секунду и исчезает

это связано с тем, что изображение ещё не успевает загрузиться (асинхронный image.src)?

и как корректно все делать?

если несколько изображений, то вряд ли onload придется несколько делать

Answer 1

Можно дождаться, пока все загрузиться, и только потом рисовать:

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>

А еще можно в каждом onload вызвать перерисовку всего кадра (draw()), не оптимально, но код проще будет:

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, i.x , i.y, i.w, i.h)); 
}
body{margin:0}
<canvas width="600" height="170"></canvas>

READ ALSO
Удаление элемента из массива javascript

Удаление элемента из массива javascript

Нужна функция removeArray(x, n), которая удаляет n из массива и извлекает полученный элементНапример:

174
Как отключить перенос строк в vscode для javascript и html

Как отключить перенос строк в vscode для javascript и html

Правлю код vuejs компонента в vscode, при этом периодически жму Alt + Shift + F для автоматического форматирования введённого кода

245
Ускоряется Setinterval

Ускоряется Setinterval

Есть слайдер с переключением слайда через определенный промежуток времениСделал так чтобы при клике на кнопку перелистывания слайда таймер,...

176
Создать переменную &#171;resultArray&#187; (массив)

Создать переменную «resultArray» (массив)

Создать переменную «resultArray» (массив)Создать переменные «first» = 1, «second» = 2, «senseOfLife» = 42

134