Aller au contenu principal


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.

Billet créé le :
29 nov 2020

La figure ci-dessous illustre cet indicateur de progression.

La réalisation de cet élément des pages, ainsi que les commentaires explicatifs,  figurent dans les onglets ci-dessous :

 

Les fichiers

Cliquez sur le bouton pour copier le code dans le presse papier
<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>       
Cliquez sur le bouton pour copier le code dans le presse papier
 .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;
                }  
            
Cliquez sur le bouton pour copier le code dans le presse papier
        
                    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)

information complémentaire disponible en cliquant ici

J'ai collé ce code html immédiatement entre l'instruction {{content }} et la la balise fermante </div> du fichier "region--content.html.twig"

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.

information complémentaire disponible en cliquant ici

Ce code CSS peut-être collé dans n'importe quel fichier CSS du site. Pensez à vider les caches et à régénérer les agrégations pour visualiser l'effet produit.

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) + "%") ;

 

information complémentaire disponible en cliquant ici

Ce code est à copier dans votre fichier de script entre les accolades qui limitent la définition de la fonction "attachée" (attach : function (context, settings) { le script JS est à coller ICI } ). Pour plus d'information lire la page "ajouter un script".