Barre de progression dans un canvas html5

Je vous propose d’illustrer les CustomEvent javascript abordés dans l’article javascript : créer des événements personnalisés custom event par le biais d’une barre de progression relative au chargement des images et à leur affichage dans un canvas html5.

Prérequis

Je vous invite à lire l’article afficher une barre de progression en html5 et javascript

 

Création du projet

Créez un dossier comportant à sa racine :
– un fichier vide que vous nommez chargement.html;
– et un dossier img destiné à recevoir les images relatives à l’exemple.

 

Affichage d’une image dans un canvas html5

L’exemple consiste à :
– initialiser une image à partir d’un fichier png;
– créer un élément canvas par le biais de l’instruction;
– ajouter le canvas à la page html;
– lui donner des dimensions;
– y afficher l’image initialisée précédemment par le biais de son contexte 2d.

// Initialisation de l'image à partir du fichier image.png placé dans le dossier img
const img = new Image();
img.src = "./img/image.png";

const theCanvas = window.document.createElement("canvas");
document.body.appendChild(theCanvas);
theCanvas.width="800";
theCanvas.height="600";

theCanvas.getContext("2d").drawImage(img,20,20);

Le source html complet.

<html>
  <head>
    <title></title>
  </head>
  <body>
  </body>
<script>
const img = new Image();
img.src = "./img/image.png";
const theCanvas = window.document.createElement("canvas");
document.body.appendChild(theCanvas);
theCanvas.width="800";
theCanvas.height="600";
theCanvas.getContext("2d").drawImage(img,20,20);
</script>
</html>

Si vous affichez la page en l’état, rien ne se passe :
– sous Chrome, l’image ne s’affiche pas;
– sous Firefox, l’image s’affiche si vous la rafraîchissez avec la touche F5.

La cause est simple à comprendre : l’image ne s’affiche pas car celle-ci n’est pas encore chargée au moment de l’appel de la méthode drawImage.

Pour pallier à ce problème, il suffit d’afficher l’image que lorsque celle-ci est chargée par le biais de l’événement onload.

Le source html5 modifié.

<html>
  <head>
    <title></title>
  </head>
  <body>
  </body>
<script>
const img = new Image();
img.src = "./img/image.png";
const theCanvas = window.document.createElement("canvas");
document.body.appendChild(theCanvas);
theCanvas.width="800";
theCanvas.height="600";
img.addEventListener("load", function() {
  theCanvas.getContext("2d").drawImage(img,20,20);
});
</script>
</html>

Si vous affichez la page modifiée, que ce soit sous Chrome ou sous Firefox l’image s’affiche d’emblée.

 

Le problème posé

Si vous souhaitez ne pas avoir de soucis au niveau de l’affichage, il va falloir attendre que chaque image soit chargée et donc invoquer son affichage une première fois lorsqu’elle est chargée. A la suite de quoi, vous pourrez l’afficher comme bon vous semble.

Le problème est que votre code va vite se transformer en plat de spaghettis si vous le faites manuellement et systématique, en capturant l’événement onload sur chaque image à charger.

Il est donc préférable d’attendre le chargement de toutes les images utilisées une bonne fois pour toutes.

Vous allez donc le faire en le matérialisant par une barre de progression et en utilisant les événements personnalisés (CustomEvent).

 

Le principe

Vous allez créer un événement personnalisé auquel sera abonné la barre de progression et à partir duquel sa progression sera mise à jour.

Cet événement personnalisé sera lancé à chaque fois qu’une image sera chargée.

 

Mise en œuvre en javascript

Commencez par intégrer la barre de progression javascript nommée progressBar dans le fichier chargement.html. Comme vous allez charger 10 images qui incrémenterons de 10 la valeur de la barre de progression, donnez comme valeur max la valeur 100.

<html>
 <head>
  <title></title>
 </head>
 <body>
  <progress id="progressBar" value="0" max="100">0%</progress> 
 </body>
</html>

Puis créez un objet javascript CustomEvent que vous nommez imageLoaded comme suit.

const imageLoaded = new CustomEvent(
  "imageLoaded",
  {
    detail: {
    },
    bubbles: true,
    cancelable: true
  }
);

La propriété detail est vide puisque dans le cas présent nous n’avons besoin d’aucune propriété spécifique.

Ensuite créez une fonction loadImages dont l’objet est de charger toutes les images.

const loadImages = function() {
  for (let i=0; i<10; i++){
    const img = new Image();
    img.src = "./img/image.png";
    img.addEventListener("load",function() {
      document.getElementById("progressBar").dispatchEvent(imageLoaded);
    });
  } 
}

Enfin, vous devez incrémenter la valeur de la barre de progression à chaque fois qu’une image est chargée : lorsqu’un événement imageLoaded est lancé.

Il suffit d’abonner la barre de progression à l’événement imageLoaded et lorsque l’événement est capturé, incrémenter la valeur de la barre de progression.

document.getElementById("progressBar").addEventListener("imageLoaded", function(event) {
  document.getElementById("progressBar").value = document.getElementById("progressBar").value + 10;
});

Il ne reste plus qu’à lancer le chargement en appelant la fonction loadImages.

<html>
<head>
  <title></title>
</head>
<body>
  <progress id="progressBar" value="0" max="100">0%</progress> 
</body>
<script>
const imageLoaded = new CustomEvent(
  "imageLoaded",
  {
    detail: {
    },
    bubbles: true,
    cancelable: true
  }
);
 
document.getElementById("progressBar").addEventListener("imageLoaded", function(event) {
  document.getElementById("progressBar").value = document.getElementById("progressBar").value + 10;
});
 
const loadImages = function() {
  for (let i=0; i<10; i++){
    const img = new Image();
    img.src = "./img/image.png";
    img.addEventListener("load",function() {
      document.getElementById("progressBar").dispatchEvent(imageLoaded);
    });
  } 
}
 
loadImages();
</script>
</html>

Pour tester, cliquez ici

Et là à l’exécution, vous constatez que le chargement est quasi instantané : vous ne voyez pas la barre de chargement se remplir, ça va trop vite. Pour rendre les choses visibles, il suffit de décaler dans le temps chaque mise à jour de la barre de progression par le biais de la fonction setTimeout.

Créez une variable startTime initialisé à 1000 permettant de lancer la première mise à jour de la barre de progression avec un décalage de 1s (1000ms).

let startTime = 1000;

Incrémentez la de 100 avant chaque modification de la valeur de la barre de progression.

startTime += 100;

Enfin lancez la mise à jour de la barre de progression par le biais de la fonction setTimeout avec le décalage startTime.

document.getElementById("progressBar").addEventListener("imageLoaded", function(event) {
  startTime += 100;
  setTimeout( function() {
    document.getElementById("progressBar").value = document.getElementById("progressBar").value + 10;
  }, startTime);
});

Le code source.

<html>
<head>
  <title></title>
</head>
<body>
  <progress id="progressBar" value="0" max="100">0%</progress> 
</body>
<script>
let startTime = 1000;
const imageLoaded = new CustomEvent(
  "imageLoaded",
  {
    detail: {
    },
    bubbles: true,
    cancelable: true
  }
);
 
document.getElementById("progressBar").addEventListener("imageLoaded", function(event) {
  startTime += 100;
  setTimeout( function() {
    document.getElementById("progressBar").value = document.getElementById("progressBar").value + 10;
  }, startTime);
});
 
const loadImages = function() {
  for (let i=0; i<10; i++){
    const img = new Image();
    img.src = "./img/image.png";
    img.addEventListener("load",function() {
    document.getElementById("progressBar").dispatchEvent(imageLoaded);
   });
  } 
}
 
loadImages();
</script>
</html>

Pour tester, cliquez ici.

Explore l'univers de la création de jeux vidéo

Saisis ton prénom et ton e-mail pour recevoir ton livre GRATUIT et commence ton voyage ludique dès maintenant.

Bravo, jette un œil à ta boite mail pour télécharger ton guide.