Nicolas
Nicolas

Reputation: 673

How to preload all images before removing loading animation?

I'm working on a image sequence animation and I came across a problem when a new user enters the site for the first time:

Once I have loaded the images from the external database the full screen loading animation removes itself from the screen but now when the user enters the animation, all the images has not been loaded yet so the animation seems buggy & broken. After few seconds all the images has loaded and the animation works just like it should.

So my question is how can I wait till all images has been loaded fully before removing the loading animation to prevent the user from using the animation while the images are still loading?

Here's the function for getting the images:

async getImages(state) {
            var images = []
            for (let i = 0; i < state.frameCount; i++) {
                var imgIndex = (i + 1).toString().padStart(4, '0')
                const img = new Image();
                img.index = Number(imgIndex)
                img.id = imgIndex
                var storageRef = this.$fire.storage.ref(`/web-2-160-final.${imgIndex}.png`);
                storageRef.getDownloadURL().then((url) => {
                    console.log('IMG URL',url)
                    var imgSrc = url
                    img.src = imgSrc;
                    img.classList.add('full-screen')
                    images.push(img);

                    function percentage(partialValue, totalValue) {
                        state.percentage = (100 * partialValue) / totalValue
                    }
                    percentage(images.length, state.frameCount)

                    if(images.length == state.frameCount) setImages()
                })
            }
            const setImages = () => {
                state.isLoaded = true
                var lowestToHighest = images.sort((a,b) => a.index - b.index)
                console.log('NEW ARRAY', lowestToHighest)
                state.images = images
                console.log(state.images)
            }
        },

Upvotes: 0

Views: 391

Answers (1)

Emiel Zuurbier
Emiel Zuurbier

Reputation: 20954

First loop over all the download URLs that you need for each image. Collect each Promise returned from every storageRef.getDownloadURL() call.

Wait for every URL to be retrieved with Promise.all(). This ensures that the code waits until every URL is retrieved and ensures that the order remains in the correct order.

Then loop over every URL and create an image for each URL. Use the onload event of the image to return the image whenever it is finished loading. Collect everything in an array of promises and await it again with Promise.all().

The result should be an array of (loaded) images in the order you provided.

async getImages(state) {
  const downloadUrls = [];

  for (let i = 0; i < state.frameCount; i++) {
    const imgIndex = (i + 1).toString().padStart(4, '0');
    const storageRef = this.$fire.storage.ref(`/web-2-160-final.${imgIndex}.png`);
    const downloadUrl = storageRef.getDownloadURL();
    downloadUrls.push(downloadUrl);
  }

  const urls = await Promise.all(downloadUrls);

  let amountOfPreloadedImages = 0;
  const images = await Promise.all(urls.map(url => 
    new Promise((resolve, reject) => {
      const image = new Image();
      image.src = url;
      image.onload = () => resolve(image);
      image.onerror = (error) => reject(error);
    }).then(image => {
      amountOfPreloadedImages++;
      state.percentage = 100 * amountOfPreloadedImages / state.frameCount;
      return image;
    })
  ));

  state.images = images;
}

Upvotes: 1

Related Questions