Cours 10 | Anime.js 3/3¶
SVG¶
Petit rappel sur l'anatomie d'une image svg.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path d="..." />
<polygon points="..."></polygon>
<polyline points="..." />
</svg>
On peut trouver des SVG un peu partout sur le web, dont sur https://icons.getbootstrap.com.
Morphing¶
La méthode morphTo() permer d'interpoler l'attribut d ou points dans les éléments d'un SVG.
Quelques conditions idéales
Pour que ça fonctionne bien, il faut :
- appliquer des classes aux chemins (c'est plus clair comme ça)
- cacher la forme de transition (ex:
style="opacity: 0") - s'assurer que les formes soient pleines
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-hexagon-fill" viewBox="0 0 16 16">
<path class="p1" d="M14 10a6 6 0 0 1-12 0C2 5.686 5 0 8 0s6 5.686 6 10"/>
<path class="p2" style="opacity: 0" d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2z"/>
</svg>
import { animate, svg } from 'animejs';
let p1 = document.querySelector(".p1");
let p2 = document.querySelector(".p2");
animate(p1, {
d: svg.morphTo(p2, 1),
loop: true,
alternate: true,
duration: 1500,
loopDelay: 500
});
Animation d'un tracé¶
La méthode createDrawable() créé un objet drawable ce qui permet d'animer le stroke avec la technique stroke-dasharray/stroke-dashoffset. C'est-à-dire que l'animation considère toujours la position du départ et de fin de la ligne.
<svg style="overflow: visible" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 120" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1">
<path class="p1" d="M14 10a6 6 0 0 1-12 0C2 5.686 5 0 8 0s6 5.686 6 10"/>
</svg>
import { animate, svg } from "animejs";
const drawable = svg.createDrawable(".p1");
animate(drawable, {
draw: ["0 0", "0 1", "1 1"],
loop: true,
alternate: true,
duration: 1500,
loopDelay: 500
});
Quelques conditions idéales
Pour que ça fonctionne bien, il faut probablement ajuster un peu le code du svg.
Sur la balise <svg> (ou sur le groupe <g> s'il y en a un), appliquer ces paramètres afin de configurer le stroke et retirer la couleur de fond :
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"
Je suggère également d'ajouter un style overflow: visible; au svg si les lignes ne se dessinent pas entièrement.
Suivre un chemin¶
La fonction createMotionPath() permet d'animer un élément sur le tracé d'un svg en renvoyant les coordonnées x, y et rotate d'un seul coup.
<div class="wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-egg-fill" viewBox="0 0 16 16">
<path class="ligne" d="M14 10a6 6 0 0 1-12 0C2 5.686 5 0 8 0s6 5.686 6 10" />
</svg>
<div class="car"></div>
</div>
.wrap {
position: relative;
.car {
position: absolute; /* 👈 Nécessaire */
/* Facultatif, mais utile pour la suite 👇 */
width: 10px;
height: 6px;
/* Permet de centrer l'élément */
left: -5px;
top: -3px;
}
}
import { animate, svg } from "animejs";
animate(".car", {
ease: "linear",
duration: 5000,
loop: true,
...svg.createMotionPath(".ligne")
});
... ???
La fonction createMotionPath retourne 3 paramètres d'un coup : x, y et rotate.
const { translateX, translateY, rotate } = svg.createMotionPath(path, offset);
On pourrait ensuite, prendre chacune de ces variables et les appliquer une à une dans l'animation, mais il est plus simple et propre d'utiliser la syntaxe de décomposition JavaScript avec les trois petits points.
D'ailleurs, connaissiez-vous l'affectation par décomposition ? C'est une méthode particulièrement pratique pour assigner les éléments reçus dans des variables directement.
Draggable¶
Avec la méthode createDraggable() on peut rendre n'importe quel élément d'une page déplaçable avec la souris.
import { createDraggable } from "animejs";
createDraggable(".element", {
/* paramètres */
});
Évidemment, il y a beaucoup de configurations possibles et une certaine autonomie dans celle-ci est de mise.
- snap : Lors qu'on relâche la souris, l'élément peut s'ajuster à une grille définie.
- mapTo : On peut associer le déplacement d'un élément à d'autres paramètres de modification.
- trigger : Il est possible de déplacer un élément à partir d'un autre élément.
- container : Il est possible de restreindre le déplacement dans une zone définie.
Un createDraggable par élément
S'il y a deux éléments ayant la classe .allo dans la page, je ne peux pas faire un createDraggable sur .allo en espérant que les deux soient interactifs. Il faut pour cela créer un createDraggable par élément.
Événement onScroll¶
L'événement onScroll permet de déterminer un moment précis pour déclencher une animation en fonction du scroll dans la page.
On doit dabord définir un conteneur qui fait le scroll. Probablement que dans la plupart des cas, ce sera body.
import { onScroll, animate } from "animejs";
animate(".dot", {
x: ["-10dvw", "10dvw"],
alternate: true,
loop: true,
autoplay: onScroll({
container: "body",
debug: true // À retirer éventuellement
})
});
Synchronisation¶
La synchronisation fait qu'une animation joue de façon à ce que son pourcentage de progression suit celui du scroll dans la zone prévue.
import { onScroll, animate } from "animejs";
animate(".dot", {
x: ["-10dvw", "10dvw"],
autoplay: onScroll({
container: "body",
sync: true
})
});
Différentes synchronisations :
sync: 'play pause': Valeur par défaut. Elle déclenche l'animation selon certains contexte défini par des mots cléssync: true: Synchronise l'avancement de l'animation avec l'état du scrollsync: 0.6: Synchronise l'avancement de l'animation avec l'état du scroll. La différence ici c'est qu'il y a un lissage d'appliqué lorsquesync: 'inOutCirc': L'animation suit le lissage spécifié en fonction de l'encement du scroll
Seuils du ScrollObserver¶
Les seuils enter et leave sont les points de déclenchement.
La valeur par défaut du enter est 'end start' et la valeur par défaut du leave est 'start end', mais on peut utiliser toutes sortes d'unités de mesure.
Texte¶
Les animations de texte peuvent animer les lignes de texte, les mots ou les lettres.
Ce que ça fait, c'est que ça segmente un paragraphs ou un titre en plusieurs éléments animables. Qui dit plusieurs éléments, dit Stagger !
import { animate, splitText, stagger } from 'animejs';
const { chars } = splitText('p', {
chars: { wrap: 'clip' },
});
animate(chars, {
y: ['100%', '0%'],
delay: stagger(50)
});
Propriétés de splitText() :
wrap: représente simplement l'overflowCSS. La valeurclipse comporte presque commehidden.clone: Applique un effet de répétition de lettre sur un des axes.
Timeline¶
La méthode createTimeline permet de synchroniser plusieurs animations entre elles. Pour ajouter les animations dans la timeline, on doit utiliser add().
On utilise timeline lorsqu'on a une animation à plusieurs étapes et que la séquence des animations n'est pas forcément une après l'autre.
import { createTimeline } from 'animejs';
createTimeline()
.add('.square', { x: '15rem' })
.add('.circle', { x: '15rem' })
.add('.triangle', { x: '15rem', rotate: '1turn' });
Quelques concepts à connaître :
add: La méthodeaddéquivaut àanimate. La différence est sont troisième * paramètre qui configure une position dans le temps.- Dans la fonction
createTimeline({}), on peut ajouter des paramètres commeloop: truepar exemple.- Avec
defaults, on peut aussi ajouter des paramètres par défaut pour chacune des animations.
- Avec
Responsive¶
Les animations peuvent être différentes selon les medias queries avec la notion de scope.
La méthode createScope() peut avoir quelques paramètres dont les mediasQueries.
import { animate, utils, createScope } from 'animejs';
createScope({
mediaQueries: {
isSmall: '(max-width: 200px)',
reduceMotion: '(prefers-reduced-motion)',
}
})
.add(self => {
const { isSmall, reduceMotion } = self.matches;
if (isSmall) {
utils.set('.square', { scale: .5 });
}
animate('.square', {
x: isSmall ? 0 : ['-35vw', '35vw'],
y: isSmall ? ['-40vh', '40vh'] : 0,
loop: true,
alternate: true,
duration: reduceMotion ? 0 : isSmall ? 750 : 1250
});
});
Exercices¶

Exercice - AnimeJS
Machine à écrire

Exercice - AnimeJS
Lava

Exercice - AnimeJS
Monaco

Exercice - AnimeJS
Cosmos