Fermer

janvier 4, 2019

Animation HTML5 de remplissage SVG avec CSS3 et JavaScript JavaScript


À propos de l'auteur

Marina Ferreira est une ingénieure en logiciel de São Paulo, au Brésil. Elle est passionnée par le développement, la conception, l'écriture, les langues étrangères, les…
Plus d'informations sur Marina

Dans cet article, vous pouvez apprendre à créer l'affichage des notes animées à partir du site Web Awwwards . Il traite de l'élément de cercle HTML5 SVG, de ses propriétés de trait et de la manière de les animer à l'aide de variables CSS et de code JavaScript Vanilla.

SVG signifie S calable V ector G raphics et constitue un langage de balisage standard basé sur XML pour les graphiques vectoriels. Il vous permet de tracer des tracés, des courbes et des formes en déterminant un ensemble de points dans le plan 2D. De plus, vous pouvez ajouter des propriétés de torsion sur ces chemins (par exemple, trait, couleur, épaisseur, remplissage, etc.) afin de générer des animations.

Depuis avril 2017, Module de remplissage et de carottage de niveau 3 en CSS permet de définir les couleurs et les motifs de remplissage SVG à partir d'une feuille de style externe, au lieu de définir des attributs pour chaque élément. Dans ce didacticiel, nous allons utiliser une couleur hexadécimale simple, mais les propriétés de remplissage et de contour acceptent également les motifs, les dégradés et les images.

Note : Lors de la visite du site Web, l'affichage des notes animées ne peut être visualisé qu'avec une largeur de navigateur définie à 1024 px ou plus.

 Démo du projet d'affichage de notes
Une démo du résultat final ( Grand aperçu .) [19659009] Smashing Cat, juste en train de faire quelque chose de magique. "Width =" 310 "height =" 400 « />

Structure des fichiers

Commençons par créer les fichiers dans le terminal:

 mkdir note-display
? cd note display
? touchez index.html styles.css scripts.js

HTML

Voici le modèle initial qui relie les fichiers css et js :



  

   Affichage de la note 

    

Chaque élément de la note est constitué d'un élément de la liste: li comportant le cercle la valeur la note et son étiquette .


 Élément de liste et enfants directs
élément de l'élément et ses enfants directs: .circle .percent et .label . ( Grand aperçu )

Le .circle_svg est un élément SVG qui englobe deux éléments . Le premier est le chemin à remplir tandis que le second est le remplissage qui sera animé.


 Eléments SVG
Eléments SVG. SVG wrapper et étiquettes de cercle. ( Grand aperçu )

La note est séparée en nombre entier et en décimales afin que différentes tailles de police puissent leur être appliquées. Le label est un simple . Donc, tout cela se présente comme suit:

  • 0. 00
    Transparent
  • Les attributs cx et cy définissent l'axe des x du cercle. et le point central de l’axe des y. L'attribut r définit son rayon.

    Vous avez probablement remarqué le motif de soulignement / tiret dans les noms de classes. C'est BEM qui signifie bloc élément et modificateur . C'est une méthodologie qui rend votre élément de nommage plus structuré, organisé et sémantique.

    Lecture recommandée : Une explication de BEM et pourquoi vous en avez besoin

    À Pour terminer les structures de modèle, enveloppons les quatre éléments de la liste dans un élément de liste non ordonnée:


     Enveloppe de liste non ordonnée
    Une enveloppe de liste non ordonnée contient quatre li enfants ( Grand aperçu )
    • 0. 00
      Transparent
    • 0. 00
      Raisonnable
    • 0. 00
      Utilisable
    • 0. 00
      . ] Exemple

    Vous devez vous demander ce que sont les étiquettes Transparent Reasonable Utilisable et Exemple moyen . Plus vous maîtriserez la programmation, vous vous rendrez compte que l'écriture de code ne consiste pas seulement à rendre l'application fonctionnelle, mais également à assurer sa maintenance et son évolutivité à long terme. Cela ne peut être réalisé que si votre code est facile à modifier.

    "L'acronyme TRUE devrait vous aider à décider si le code que vous écrivez sera en mesure de prendre en compte les modifications à venir ou non."

    , la prochaine fois, demandez-vous:

    • Transparent : Les conséquences des modifications de code sont-elles claires?
    • Raisonnable : Le rapport coût-avantages en vaut-il la peine?
    • Utilisable : Pourrai-je le réutiliser? dans des scénarios inattendus?
    • Exemple : Existe-t-il un code de haute qualité comme exemple futur?

    Note : Conception pratique orientée objet en rubis ” par Sandi Metz explique TRUE ainsi que d’autres principes et explique comment les réaliser par le biais de modèles de conception. Si vous n'avez pas encore pris le temps d'étudier les modèles de conception, pensez à ajouter ce livre à votre lecture.

    CSS

    Importons les polices et appliquons une réinitialisation à tous les éléments:

    
     @import url (' https://fonts.googleapis.com/css?family=Nixie+One|Raleway:200 ');
    
    * {
      rembourrage: 0;
      marge: 0;
      taille de la boîte: boîte-frontière;
    }
    

    La propriété box-sizing: border-box inclut les valeurs de remplissage et de bordure dans la largeur et la hauteur totales d'un élément, ce qui facilite le calcul de ses dimensions.

    Note : Pour une explication visuelle de la taille de la boîte veuillez lire « Facilitez-vous la vie avec la taille de la boîte CSS ."

     body {
      hauteur: 100vh;
      couleur: #fff;
      affichage: flex;
      arrière-plan: # 3E423A;
      famille de polices: 'Nixie One', cursive;
    }
    
    .display-container {
      marge: auto;
      affichage: flex;
    }
    

    En combinant les règles affichez: flex dans le corps et margin-auto dans le .display-container il est possible pour centrer l'élément enfant à la fois verticalement et horizontalement. L'élément .display-container sera également un flex-container ; ainsi, ses enfants seront placés dans la même rangée le long de l'axe principal.

    L'élément de liste .note-display sera également un conteneur flexible . Comme il y a beaucoup d’enfants à centrer, passons aux propriétés motivées et align-items . Tous les éléments flexibles seront centrés le long des axes croisé et principal . Si vous n’êtes pas sûr de ce qu’ils sont, consultez la section relative à l’alignement dans « Guide visuel des fondamentaux de la Flexbox CSS ."

     .note-display {
      affichage: flex;
      direction de flexion: colonne;
      align-items: centre;
      marge: 0 25 px;
    }
    

    Appliquons un trait aux cercles en définissant les règles trait-largeur trait-opacité et trait-épaissi-crayon tout à fait le style le coup en direct se termine. Ensuite, ajoutons une couleur à chaque cercle:

     .circle__progress {
      remplissage: aucun;
      largeur de trait: 3;
      trait-opacité: 0,3;
      AVC-linecap: rond;
    }
    
    .note-display: nth-child (1) .circle__progress {stroke: # AAFF00; }
    .note-display: nth-child (2) .circle__progress {stroke: # FF00AA; }
    .note-display: nth-child (3) .circle__progress {stroke: # AA00FF; }
    .note-display: nth-child (4) .circle__progress {stroke: # 00AAFF; }
    

    Pour positionner l’élément pour cent de façon absolue, il est nécessaire de savoir absolument à quoi. L'élément .circle devrait être la référence, ajoutons donc position: relative .

    Note : Pour une explication visuelle plus profonde sur le positionnement absolu, veuillez vous reporter à « Comment comprendre la position CSS une fois pour toutes ».

    Une autre façon de centrer les éléments consiste à combiner en haut: 50% left: 50% et transforment: translate (-50%, -50%); qui positionne le centre de l'élément au centre de son parent.

     .circle {
      position: relative;
    }
    
    .percent {
      largeur: 100%;
      en haut: 50%;
      à gauche: 50%;
      position: absolue;
      poids de police: gras;
      text-align: center;
      hauteur de ligne: 28px;
      transformer: traduire (-50%, -50%);
    }
    
    .percent__int {taille de la police: 28px; }
    .percent__dec {taille de la police: 12px; }
    
    .label {
      famille de polices: 'Raleway', serif;
      taille de police: 14px;
      text-transform: majuscule;
      marge supérieure: 15 px;
    }
    

    À présent, le modèle devrait ressembler à ceci:


     Modèle initial terminé
    Éléments et styles de modèles finis ( Grand aperçu )

    Transition de remplissage

    L'animation de cercle peut être créée à l'aide de deux propriétés SVG de cercle: stroke-dasharray et stroke-dashoffset .

    stroke-dasharray définit le motif de tiret dans un trait. ”

    Il peut prendre jusqu'à quatre valeurs:

    • lorsqu'il est défini sur un entier uniquement ( stroke-dasharray: 10 ), les tirets et les espaces vides ont la même taille;
    • Pour deux valeurs ( stroke-dasharray: 10 5 ), la première est appliquée aux tirets, en second lieu aux espaces vides;
    • ( stroke-dasharray: 10 5 2 et stroke-dasharray: 10 5 2 3 ) générera des tirets et des lacunes de différentes tailles.
     Les valeurs des propriétés du dasharray de l'AVC
    AVC-dasharray Valeurs de propriété ( Grand aperçu )

    L'image à gauche montre la propriété AVC-dasharray étant définie entre 0 et 23 8px, qui correspond à la longueur de la circonférence du cercle.

    La deuxième image représente la propriété stroke-dashoffset qui décale le début du tableau de tirets. Il est également défini entre 0 et la longueur du cercle.

     Propriétés de dasharray et de dashoffset de trait
    propriétés de stroke-dasharray et stroke-dashoffset ( Grand aperçu )

    Pour obtenir l'effet de remplissage, définissez le stroke-dasharray sur la longueur de la circonférence, de sorte que toute sa longueur se remplisse d'un grand tiret sans espace. Nous allons également le compenser avec la même valeur, donc il sera "caché". Ensuite, le stroke-dashoffset sera mis à jour avec la valeur de note correspondante, en remplissant le trait en fonction de la durée de la transition.

    La mise à jour des propriétés sera effectuée dans les scripts via Variables CSS . . Déclarons les variables et définissons les propriétés:

     .circle__progress - fill {
      --initialStroke: 0;
      --transitionDuration: 0;
      accident vasculaire cérébral: 1;
      stroke-dasharray: var (- initialStroke);
      stroke-dashoffset: var (- initialStroke);
      transition: stroke-dashoffset var (- transitionDuration) facilité;
    }
    

    Pour définir la valeur initiale et mettre à jour les variables, commençons par sélectionner tous les éléments .note-display à l’aide de document.querySelectorAll . La transitionDuration sera définie sur 900 millisecondes.

    Ensuite, nous parcourons le tableau des affichages, sélectionnons son .circle__progress.circle____progress - fill et extrayons l'attribut r défini dans le code HTML pour calculer la longueur de la circonférence. Avec cela, nous pouvons définir les valeurs initiales - dasharray et - dashoffset .

    L'animation se produira lorsque la variable - dashoffset sera mise à jour. par 100ms setTimeout:

     const displays = document.querySelectorAll ('. note-display');
    const transitionDuration = 900;
    
    displays.forEach (display => {
      let progress = display.querySelector ('. circle__progress - fill');
      let radius = progress.r.baseVal.value;
      laisser circonférence = 2 * Math.PI * rayon;
    
      progress.style.setProperty ('- transitionDuration', `$ {transitionDuration} ms`);
      progress.style.setProperty ('- initialStroke', circonférence);
    
      setTimeout (() => progress.style.strokeDashoffset = 50, 100);
    });
    

    Pour obtenir la transition en partant du haut, vous devez faire pivoter l'élément .circle__svg :

     .circle__svg {
      transformer: faire pivoter (-90deg);
    }
    
     Transition des propriétés de la course
    Transition des propriétés de la course ( Aperçu large )

    Calculons maintenant la valeur de dashoffset - relative à la note. La valeur de la note sera insérée dans chaque li attribut via l'attribut data - * . Le * peut être remplacé par n'importe quel nom qui convient à vos besoins. Il peut ensuite être récupéré en JavaScript dans le jeu de données de l'élément: element.dataset. * .

    Note : Vous pouvez en savoir plus sur l'attribut data- * dans MDN Web Docs .

    Notre attribut s'appellera “ data-note ”:

     
      +
    • 0. 00
      Transparent
    • +
    • 0. 00
      Raisonnable
    • +
    • 0. 00
      Utilisable [19659110] +
    • 0. 00
      Exemple

    La méthode parseFloat convertit la chaîne renvoyée par display.dataset.note en un nombre à virgule flottante. Le décalage représente le pourcentage manquant pour atteindre le score maximal. Donc, pour une note 7.50 nous aurions (10 - 7.50) / 10 = 0.25 ce qui signifie que la longueur de la circonférence doit être compensée de 25% de sa valeur:

     let note = parseFloat (display.dataset.note);
    laissez décalage = circonférence * (10 - note) / 10;
    

    Mise à jour du fichier scripts.js :

     const displays = document.querySelectorAll ('. Note-display');
    const transitionDuration = 900;
    
    displays.forEach (display => {
      let progress = display.querySelector ('. circle__progress - fill');
      let radius = progress.r.baseVal.value;
      laisser circonférence = 2 * Math.PI * rayon;
    + let note = parseFloat (display.dataset.note);
    + let offset = circonférence * (10 - note) / 10;
    
      progress.style.setProperty ('- initialStroke', circonférence);
      progress.style.setProperty ('- transitionDuration', `$ {transitionDuration} ms`);
    
    + setTimeout (() => progress.style.strokeDashoffset = offset, 100);
    });
    
     Transition des propriétés de trait jusqu'à la valeur de note
    Transition des propriétés de trait jusqu'à la valeur de note ( Grand aperçu )

    Avant de poursuivre, extrayons la transition du contour à sa propre méthode: [19659098] const displays = document.querySelectorAll ('. note-display');
    const transitionDuration = 900;

    displays.forEach (display => {
    - let progress = display.querySelector ('. circle__progress - fill');
    - let radius = progress.r.baseVal.value;
    - soit circonférence = 2 * Math.PI * rayon;
      let note = parseFloat (display.dataset.note);
    - let offset = circonférence * (10 - note) / 10;

    - progress.style.setProperty ('- initialStroke', circonférence);
    - progress.style.setProperty ('- transitionDuration', `$ {transitionDuration} ms`);

    - setTimeout (() => progress.style.strokeDashoffset = offset, 100);

    + strokeTransition (affichage, note);
    });

    + fonction strokeTransition (display, note) {
    + let progress = display.querySelector ('. circle__progress - fill');
    + let radius = progress.r.baseVal.value;
    + let circonference = 2 * Math.PI * rayon;
    + let offset = circonférence * (10 - note) / 10;

    + progress.style.setProperty ('- initialStroke', circonférence);
    + progress.style.setProperty ('- transitionDuration', `$ {transitionDuration} ms`);

    + setTimeout (() => progress.style.strokeDashoffset = offset, 100);
    +}

    Augmentation de la valeur de la note

    Il reste la transition de la note de 0.00 à la valeur de la note à construire. La première chose à faire est de séparer les valeurs entières et décimales. Nous allons utiliser la méthode string split () (il faut un argument qui détermine où la chaîne sera cassée et retourne un tableau contenant les deux chaînes cassées). Ceux-ci seront convertis en nombres et passés comme arguments à la fonction augmentationNumber () ainsi qu'à l'élément display et à un drapeau indiquant s'il s'agit d'un entier ou d'une décimale.

     displays = document.querySelectorAll ('. note-display');
    const transitionDuration = 900;
    
    displays.forEach (display => {
      let note = parseFloat (display.dataset.note);
    + let [int, dec] = display.dataset.note.split ('.');
    + [int, dec] = [Number(int), Number(dec)];
    
      strokeTransition (affichage, note);
    
    + numéroD'augmentation (display, int, 'int');
    + augmentation du nombre (display, dec, 'dec');
    });
    

    Dans la fonction augmentationNombre () nous sélectionnons l'élément .percent__int ou ou en fonction du nom de classe . et aussi si la sortie doit contenir un point décimal ou non. Nous avons réglé notre transitionDuration sur 900 ms . Maintenant, pour animer un nombre compris entre 0 et 7, par exemple, la durée doit être divisée par la note 900/7 = 128.57ms . Le résultat représente combien de temps chaque itération augmentera. Cela signifie que notre setInterval sera déclenché toutes les 128,57ms .

    Avec ces variables définies, définissons le setInterval . La variable de compteur sera ajoutée à l'élément sous forme de texte et augmentée à chaque itération:

     fonction augmentez le numéro (display, number, className) {
      let element = display.querySelector (`.percent __ $ {ClassName}`),
          decPoint = className === 'int'? '.' : '',
          intervalle = transitionDurée / nombre,
          compteur = 0;
    
      let augmentationInterval = setInterval (() => {
        element.textContent = counter + decPoint;
        counter ++;
      }, intervalle);
    }
    
     Augmentation du compteur infini
    Augmentation du compteur infini ( Grand aperçu )

    Cool! Cela augmente les valeurs, mais le fait pour toujours. Nous devons effacer le setInterval lorsque les notes atteignent la valeur souhaitée. Cela se fait avec la fonction clearInterval :

     function augmentationNuméro (nombre, type, nom de classe) {
      let element = display.querySelector (`.percent __ $ {ClassName}`),
          decPoint = className === 'int'? '.' : '',
          intervalle = transitionDurée / nombre,
          compteur = 0;
    
      let augmentationInterval = setInterval (() => {
    + if (compteur === nombre) {window.clearInterval (augmentationInterval); }
    
        element.textContent = counter + decPoint;
        counter ++;
      }, intervalle);
    }
    
     Projet d'affichage des notes finies
    Projet terminé ( Aperçu grand format )

    Le numéro est maintenant mis à jour jusqu'à la valeur de la note et effacé avec la fonction clearInterval () .




    Source link