[JS] Créer une barre de progression
Nous allons voir ici comment créer un rendu de chargement d’une génération de fichier. Dans mon cas, j’ai créé ce petit script au sein d’un générateur de site, dont un module permet l’import et l’export d’application (permettant de passer les applys du serveur de test au serveur de prod).
Le principe est assez simple,
1- On crée 20 <img /> qui feront office d’ étapes de la barre de chargement ainsi que les emplacements pour afficher le temps restant.
2- On récupère une variable passée dans un formulaire ou n’importe quoi, tant qu’on peut la récupérer en javascript, qui contient en seconde le temps nécessaire à la génération du fichier (Je ne montre pas mon script ici, je ne parlerai que du rendu).
3- On crée la fonction javascript permettant de mettre à jour le temps restant et d’afficher progressivement les étapes de la barre de chargement.
1) Créer le HTML
<div id="loader_staging">
<strong>Temps restant : </strong><div style="display:inline;" id="comptarebour">Chargement ...</div>
<table id="loader_table_staging">
<tr>
<td><div class="loader_hidden" id="loader_stage_1"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_2"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_3"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_4"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_5"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_6"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_7"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_8"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_9"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_10"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_11"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_12"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_13"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_14"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_15"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_16"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_17"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_18"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_19"><img src="./public/images/loader_stage.png" alt="" /></div></td>
<td><div class="loader_hidden" id="loader_stage_20"><img src="./public/images/loader_stage.png" alt="" /></div></td>
</tr>
</table>
</div>
Comme vous le voyez, j’ai mis ça dans un tableau et c’est vraiment dégueulasse ! (Punissez-moi !)
Mais bon, j’avais un peu la flemme et vu que le projet sur lequel je travaille en ce moment et bah y’a des tableaux partout, je me suis pas fait chier. (En plus les utilisateurs sont sous IE6 oO).
Donc voilà, une image par étape du Staged Loader et un emplacement (où il est écrit “Chargement…”) pour afficher le décompte.
Maintenant, voyons le javascript.
2) Créer le Javascript
1-> On crée en tant que variable globale un tableau regroupant les id de nos étapes de la barre de chargement.
var Parcelles = new Array(); var Loaders = new Array(); Loaders[1]="loader_stage_20"; Loaders[2]="loader_stage_19"; Loaders[3]="loader_stage_18"; Loaders[4]="loader_stage_17"; Loaders[5]="loader_stage_16"; Loaders[6]="loader_stage_15"; Loaders[7]="loader_stage_14"; Loaders[8]="loader_stage_13"; Loaders[9]="loader_stage_12"; Loaders[10]="loader_stage_11"; Loaders[11]="loader_stage_10"; Loaders[12]="loader_stage_9"; Loaders[13]="loader_stage_8"; Loaders[14]="loader_stage_7"; Loaders[15]="loader_stage_6"; Loaders[16]="loader_stage_5"; Loaders[17]="loader_stage_4"; Loaders[18]="loader_stage_3"; Loaders[19]="loader_stage_2"; Loaders[20]="loader_stage_1";
2-> On crée une fonction qui sera appelée par un lien genre “lancer la génération”. C’est elle qui récupère l’estimation calculée en PHP (je l’ai stocké dans un hidden d’un formulaire). Elle récupère le timestamp actuel et fait la différence avec l’estimation pour pouvoir lancer mon compte à rebour. Finalement elle lance l’execution de la génération (ici faite par la validation d’un formulaire caché permettant la navigation au sein du site).
function runExport()
{
/*récupération du temps de chargement*/
document.getElementById("loader_staging").style.display="block";
now = new Date;
TNow = now.getTime();
/*calcul du temps*/
TempFuture = TNow + Math.floor(document.CmdDocMgrForm.estimation.value * 1000);
EspaceTemps = (TempFuture - TNow)/1000;
Parcelle = (EspaceTemps / 19) * 1000;
/*Association à chaque parcelle le "temps" à partir duquel elle peut être révélée*/
for($i=1;$i<20;$i++){
Parcelles[$i]=Parcelle*$i;
}
Parcelles[20]=EspaceTemps * 1000;
/*Lancement de mon compte à rebour qui gère également l'affichage des parcelles*/
Rebour(TempFuture);
/*Lancement de la génération via mon formulaire de navigation*/
document.CmdDocMgrForm.module.value = "ExportManager";
document.CmdDocMgrForm.mode.value = "export";
document.CmdDocMgrForm.submit();
}
3-> Il ne reste plus qu’à créer la fonction compte à rebour qui boucle sur elle-même et modifie le rendu à l’écran.
function Rebour(TempFuture)
{
Maintenant = new Date;
TempMaintenant = Maintenant.getTime();
DinaHeure = (TempFuture-TempMaintenant)/1000;
DinaHeure = "" + DinaHeure;
/*si le temps est écoulé, j'affiche "Finalisation..." c'est quand même plus top que " 0 secondes" ^^*/
/*J'affiche également toutes les parcelles vu que c'est fini*/
if (DinaHeure < 0){
DinaHeure = "Finalisation...";
for($i=20;$i>0;$i--){
document.getElementById(Loaders[$i]).style.display="block";
}
/*Si le temps n'est pas fini*/
}else{
/*Je décompose le temps restant en Heures, Minutes et Secondes*/
Heures = Math.floor(DinaHeure / 60 / 60);
Minutes = Math.floor((DinaHeure - (Heures * 60 * 60)) / 60);
Secondes = Math.floor(DinaHeure - (Heures * 60 * 60) - (Minutes * 60));
/*J'affiche les valeurs si elles sont positives*/
if(Heures>0)
Heures +=" H ";
else
Heures = "";
if(Minutes>0)
Minutes +=" min ";
else
Minutes = "";
if(Secondes>0)
Secondes +=" sec";
else
Secondes = "";
/*Plus haut, nous avons défini l'espace temps à partir duquel chaque parcelle doit être affichée*/
/*Je boucle ici sur mon tableau de parcelle et les affiche ou non en fonction du temps restant*/
for($i=20;$i>0;$i--){
if( (DinaHeure * 1000 ) <= Parcelles[$i] ){
document.getElementById(Loaders[$i]).style.display="block";
}
}
DinaHeure = Heures + Minutes + Secondes ;
}
/*J'affiche l'estimation du temps restant*/
document.getElementById("comptarebour").innerHTML=DinaHeure;
/*et je relance mon compte à retour avec le temps restant*/
temporebour = setTimeout("Rebour("+TempFuture+")", 1000);
}
Et voilà !
Bon, ça ne sert pas à grand chose, juste à meubler le décors plutôt que de voir la barre de chargement du navigateur stagner et ne pas savoir si ça a planté ou si c’est en cours d’exécution.
Edit : Si je ne montre pas le script PHP permettant de calculer le temps nécessaire, c’est tout simplement car cela dépend de ce qui va être généré ^^ Moi il s’agissait d’export de templates, de génération d’export SQL de 2 bases de données. A chacun de faire son truc.

Merci pour ce tuto ! :D
Ou es tu passé ? On attend des news depuis 6 mois nous =/ Le lien du form de contact est mort http://www.nanane.fr/contact/
Je reviendrai ! ^^
Non bah en fait j’ai été très pris ces 4 derniers mois, mais là je viens justement de relancer mes collègues sur Twitter pour que le Blog reparte de nouveau :p
Je vais bientôt vous pondre un truc de la mort qui tue vous allez voir :D