Animation HTML5 de remplissage SVG avec CSS3 et JavaScript JavaScript
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.
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
.
Le .circle_svg
est un élément SVG qui englobe deux éléments
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:
-
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:
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
etstroke-dasharray: 10 5 2 3
) générera des tirets et des lacunes de différentes tailles.
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.
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);
}
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);
});
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);
}
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);
}
Le numéro est maintenant mis à jour jusqu'à la valeur de la note et effacé avec la fonction clearInterval ()
.
Source link