Indicateur de progression de scrollbar
Pour la réalisation de l'indicateur de progression figurant sur les pages du site, je me suis inspiré de l'article how-to-build-a-page-scroll-progress-indicator-with-jquery-and-svg.
Les fichiers
<div class="progress-indicator"> <svg width="100" height="100"> <g> <circle cx="0" cy="0" r="38" class="animated-circle" transform="translate(50,50) rotate(-90)" /> </g> <g> <circle cx="0" cy="0" r="38" transform="translate(50,50)" /> <circle cx="0" cy="0" r="20" class="progress-count-circle" transform="translate(50,50)" /> </g> </svg> <div class="progress-count"> /* modifié par le script */ </div> </div>
.progress-indicator { position: fixed; top: 5%; right: 21%; width: 100px; height: 100px; } .progress-count { position: absolute; top: 0; left: 0; width: 100%; height: 100%; text-align: center; line-height: 100px; color: #0082FF; } svg { position: absolute; } circle { fill: rgb(235, 249, 198); } svg .animated-circle { fill: transparent; stroke-width: 4px; stroke: #0A74DA; stroke-dasharray: 238; /* longueur du cercle : donc dépend du rayon du cercle à animer */ stroke-dashoffset: 238; /* modifié par le script */ } svg .progress-count-circle { fill: white; }
var $w = $(window); var $circ = $('.animated-circle'); var $progCount = $('.progress-count'); var wh = $w.height(); var h = $('body').height(); var sHeight = h - wh; $w.on('scroll', function(){ var perc = Math.max(0, Math.min(1, $w.scrollTop()/sHeight)); updateProgress(perc); }); $progCount.html("0%"); function updateProgress(perc){ var circle_offset = 238 * perc; $circ.css({ "stroke-dashoffset" : 238 - circle_offset }); $progCount.html(Math.round(perc * 100) + "%"); }
Le code HTML
Le coeur du code présenté s'appuie sur 3 balises SVG (Scalable Vector Graphics). Ce langage est à la présentation d'images dans une page Web, ce qu'est HTML à l'organisation du texte dans une page. En savoir plus sur SVG en cliquant ICI.
<svg> : encadre le code SVG figurant dans le code HTML ;
<svg width="100" height="100"> crée un élément SVG d'une taille de 100px par 100px
<g> : regroupe des éléments SVG à l'image des balises <div> du langage HTML ;
<circle> : dessine un cercle ;
<circle x y r > ;
x définit, en pixel, l'abscisse du centre ;
y définit, en pixel, l'ordonnée du centre ;
r définit, en pixel, le rayon du cercle.
transform liste les fonctions de transformation de la représentation de l'élément SVG :
translate (x, y) déplace l'élément SVG de x pixels sur l'axe des abscisses et de y pixels sur l'axe des ordonnées (la transformation est une translation) ;
rotate (nb) effectue une rotation de l'élément SVG de nb degré (dans le sens trigonométrique (aiguille d'une montre) si nb est positif).
le code :
<circle cx="0" cy="0" r="38" class="animated-circle" transform= "translate(50,50) rotate(-90)" />
dessine donc un cercle de rayon 38 px dont le centre se trouve finalement aux coordonnées (50,50) relativement à la position de son objet conteneur : la div de classe "progress-indicateur". Celle-ci étant positionnée au point de coordonnées (5%, 79%) (voir le fichier CSS).
L'animation est réalisée par le script JS qui modifie en temps réel l'attribut "stroke-dashoffset" de la classe "animate-circle" de ce cercle (voir le fichier JS)
Le code CSS
Les attributs "position", "top", "right" placent l'élément div de classe "progress-indicateur" qui contient notre élément.
Les attributs de la classe "animated-circle" sont relatif au codage SVG :
fill : attribut spécifiant le remplissage de la forme SVG ;
stroke : le remplissage de la bordure de la forme SVG ;
stroke-width : l'épaisseur de la bordure de la forme SVG ;
stroke-dasharray : contrôle la suite de segments et de vides (l'espacement entre les segments) utilisés pour tracer la bordure de la forme SVG ;
stroke-dashoffset : décale la position de départ du "blanc" du pointillé sur la bordure de la forme SVG.
Notre forme étant <circle> :
<fill> fait référence au disque ;
<stroke> fait référence au cercle (qui est la "bordure" du disque) ;
La valeur de l'attribut "stroke-dasharray" dépend évidemment du rayon R du cercle (ici c'est 2ΠR soit 2x3.14x38=238 pour tracer un cercle complet)
"stroke-dasharray" = 238 crée un pointillé formé de segments de 238 pixels séparés par des vides de 238 pixels. Ce pointillé ayant la forme de la bordure de l'objet SVG donc dans notre cas, c'est un cercle, Ce cercle sera "mangé" en fonction de la valeur de l'attribut "stroke-dashoffset" qui positionne le début de l'espace inter-pointillé.
Cette attribut est modifié en temps réel par le script JS pour offrir l'animation. Cette position du début de l'espace inter-pointillé est modifiée à chaque "scroll" sur la page et donne l'animation du cercle.
Quelques valeurs pour le point de départ de "l'espace inter-pointillé" (stroke-dashoffset) :
0 : cercle entier (l'espace inter-pointillé n'existe pas, la forme est fermée) ;
238 / 4 ou 58 : 3/4 cercle (le cercle est mangé d'un 1/4) ;
238 / 2 ou 119 : 1/2 cercle ;
(238 / 4) x 3 ou 177 : 1/4 cercle.
Le code JS
Le code JS s'appuie sur la bibliothèque JQuery. Une (re)lecture de l'article 'introcuction à JQuery' peut être utile pour comprendre la suite de ce billet.
L1 à 3 : les références aux objets JQuery "Window" (la fenêtre du navigateur exposant la page), ".animated-circle" (la classe "animated-circle") et ".progress-count" (la classe progress-count) sont stockées respectivement dans les variables $w,$circ et $progCount ;
L4 : $wh reçoit comme valeur la hauteur de la fenêtre du navigateur exposant la page ;
L5 : $h reçoit comme valeur la hauteur (complète) de la page ;
L6 : A chaque évément "scroll" (déplacement du scrollbar par l'utilisateur), on appelle la fonction updateProgress() ;
L7 : calcul de la valeur de la variable "perc" qui exprime en pourcent, la position du haut de la barre de scroll relativement à la quantité totale à afficher ($w.scrollTop() /sHeight) ;
L8 : remplacement du contenu HTML de la section <div class="progCount"> <div> par "O%"> ;
L9 : déclaration de la fonction updateProgress() ;
L10 : modification de la valeur du paramètre "stroke-dashoffset" de la classe "animated-circle". C'est cette opération qui produit l'animation.
L11 : remplacement du contenu HTML de la section <div class="progCount"> <div> par "le pourcentage" calculé en L7>.
1. var $w = $(window);
2. var $circ = $('.animated-circle');
3. var $progCount = $('.progress-count');
4. var wh = $w.height();
5. var h = $('body').height();
var sHeight = h - wh;
6. $w.on('scroll', function(){
7. var perc = Math.max(0, Math.min(1, $w.scrollTop()/sHeight));
updateProgress(perc);
});
8. $progCount.html("0%");
9. function updateProgress(perc){
var circle_offset = 238 * perc;
10. $circ.css({
"stroke-dashoffset" : 238 - circle_offset
});
11. $progCount.html(Math.round(perc * 100) + "%") ;