Как загрузить другой html-холст после рисования на нем?

#javascript #reactjs #canvas #async-await #html5-canvas

Вопрос:

Я работаю над приложением nft-art-generator, приложение генерирует несколько и разных HTML-холстов (в виде изображения). Каждый холст представляет собой комбинацию из 3 изображений, другими словами, на каждом холсте должно быть нарисовано 3 изображения, и после рисования на холсте я загружаю его.

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

Я думаю, это произошло потому, что что-то в моем коде работает асинхронно.

Вот мой React.js Код

 const generateCollection = async()=>{

//In this exemple i want to generate 2 canvas only!!
  for(var k = 1; k <= 2; k  ){
    drawLayer(data, k)
   }
  
}
  
const drawLayer = (data, index)=>{
  var canvas = document.getElementById('myCanvas');
  var context = canvas.getContext('2d')
  let sources = {};
  //Get some random images url
  const objURLs = getImagesURLs(data, index);
  
  objURLs.forEach((url,i)=>{
    const key = `image${i 1}`;
    Object.assign(sources, {[key]: url})
  })
  
  loadImages(sources, function(images) {
    objURLs.forEach((url,i)=>{
      if (Boolean(url)) {
        context.drawImage(images[`image${i 1}`], 0, 0, 230, 230)
      }
    })
  });
  
  setTimeout(()=> download(canvas.current, index), 1000);
  
}

const loadImages = (sources, callback)=> {
  var images = {};
  var loadedImages = 0;
  var numImages = 0;
  // get num of sources
  for(var src in sources) {
    numImages  ;
  }
  for(var src in sources) {
    images[src] = new Image();
    images[src].onload = function() {
      if(  loadedImages >= numImages) {
        console.log("!!  ", images )
          callback(images);
      }
    };
    images[src].src = sources[src];
  }
}

const download = (canvas, index)=>{
  console.log("Download: ", canvas)
  var url = canvas.toDataURL("image/png");
  var link = document.createElement('a');
  link.download = `img_${index}.png`;
  link.href = url;
  link.click();
} 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<canvas 
  id="myCanvas"
  ref={canvas}
  width={230}
  height={230}
/>

<Button onClick={()=>generateCollection()} ><Button> 

Вот живой демонстрационный код, основанный на

https://jsfiddle.net/vprdhomf/1/

 I will appreciate any help, or suggestion!!
 

Комментарии:

1. (1) загрузка изображений происходит асинхронно, поэтому callback вызывается асинхронно. (2) если все комбинации canvas были завершены менее чем за секунду, setTimeout вызов download только видит холст в его конечном состоянии — либо дождитесь каждой загрузки перед созданием следующей загрузки, либо используйте несколько элементов canvas. (3) Если изображения загружаются через домены, а сервер не разрешает междоменные запросы , canvas.toDataURL генерирует исключение. Из-за этого исправление скрипки кажется невозможным.

2. Большое вам спасибо, ваш ответ был ясным и очень полезным !!. То, что я сделал, это ожидание каждой загрузки перед созданием следующей загрузки. Функция setTimeout в этом случае была бесполезной.

Ответ №1:

Снять с вопроса комментарий:

  1. Загрузка изображений происходит асинхронно, поэтому callback называется асинхронной.
  2. Если все комбинации холстов (из разных наборов нескольких изображений) были завершены менее чем за секунду, setTimeout вызов download только видит холст в его конечном состоянии. Чтобы решить эту проблему, вы можете либо
    • Дождитесь начала каждой загрузки, прежде чем создавать следующую загрузку, или
    • Используйте несколько элементов canvas или, возможно,
    • Храните URL-адреса данных в массиве для каждой комбинации canvas для последующей загрузки.
  3. Если изображения загружаются через домены, а сервер не разрешает междоменные запросы, canvas.toDataURL генерируется исключение безопасности. Из-за этого исправление скрипки с использованием приведенных в ней URL-адресов стало невозможным.