Company logo
  • Jobs
  • Bootcamp
  • About Us
  • For professionals
    • Home
    • Jobs
    • Courses and challenges
    • Questions
    • Teachers
    • Bootcamp
  • For business
    • Home
    • Our process
    • Plans
    • Assessments
    • Payroll
    • Blog
    • Sales
    • Calculator

0

51
Views
How to retain order of array using each and image.onload

I'm trying to use image.onload function but async issue is occuring. I'm passing the data through array but it is not executing according to array order in the image.onload function. How can I fix this issue?

Object.entries(data).forEach(element => {
    const brushtype = element[0]['brush']
    const img = new Image();
      img.onload = () => {
        brushctx.drawImage(img, 0, 0);
      }
    img.src = brushtype;
   }
5 months ago · Juan Pablo Isaza
2 answers
Answer question

0

The problem is the way you're requesting those images.

By doing

Object.entries(data).forEach(element => {
   }

it's happening at the same time virtually. Whatever image finished loading will be drawn right-after.

If you want your images to be drawn in a specific order - e.g. the order it's listed in the array - you need to request a new one after the previous finished loading.

Here's an example:

let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');

let myImages = ['https://picsum.photos/id/1/50/50', 'https://picsum.photos/id/22/50/50', 'https://picsum.photos/id/83/50/50', 'https://picsum.photos/id/64/50/50'];

function loadImages(index) {
  let image = new Image();
  image.onload = function(e) {
    context.drawImage(e.target, index % 2 * 50, parseInt(index / 2) * 50);
    if (index + 1 < myImages.length) {
      loadImages(index + 1);
    }
  }
  image.src = myImages[index];
}

loadImages(0);
<canvas id='canvas' width='200' height='200'></canvas>

5 months ago · Juan Pablo Isaza Report

0

To draw images in order of request you either need to wait until all images have loaded and then draw them only when the earlier image have been draw. This answer gives an example of both approaches.

Note That if there are any load errors none of the images may be drawn. In the second method an error will mean none to all but one are drawn.

Load first then draw

The snippet bellow loads first then draws. It stores the images in an array images and keeps a count of images loading. Counting up for each new image, and when an image load it counts down.

When the counter is zero when know all images have loaded and can then draw them all

var imgCount = 0;
const images = [];
Object.entries(data).forEach(element => {
    const img = new Image;
    img.src = element[0]['brush'];
    images.push(img);
    imgCount ++;
    img.onload = () => {
       imgCount --;
       if (!imgCount) {
          for(const img of images) {  brushctx.drawImage(img, 0, 0) }
       }
    }
}

Draw only when first or previous loaded.

The alternative is to again create an array to hold all the images. But this time we track what has been drawn. Each time an image is loaded, we check if any of the images in the array before it have loaded, then we draw all images until we find a empty image slot.

var drawnCount = 0;
const images = [];
Object.entries(data).forEach(element => {
    const img = new Image;
    const imgIdx = images.length;
    img.src = element[0]['brush'];
    img.onload = () => {
       images[imgIdx] = img;
       while (images[drawnCount]) { brushctx.drawImage(images[drawnCount++], 0, 0) }
    }
    images.push(null);
}
5 months ago · Juan Pablo Isaza Report
Answer question
Find remote jobs