Introduction à Popmotion épurateur d'animation personnalisé

Dans la première partie de la série introductive Popmotion, nous avons appris à utiliser basé sur le temps des animations comme interpolation et images clés. Nous avons également appris à utiliser ces animations sur le DOM en utilisant le logiciel performant. styler.

Dans la deuxième partie, nous avons appris à utiliser aiguille suivi et enregistrement rapidité. Nous avons ensuite utilisé cela pour alimenter le basé sur la vitesse des animations printempspourriture, et la physique.

Dans cette dernière partie, nous allons créer un widget de nettoyage, et nous allons l’utiliser pour nettoyer un images clés animation. Nous allons faire le widget lui-même à partir d'une combinaison de suivi de pointeur, ainsi que printemps et pourriture pour lui donner une sensation plus viscérale que les laveurs ordinaires.

Essayez vous-même:

Commencer

Balisage

Commencez par créer ce CodePen pour le modèle HTML. Comme auparavant, comme il s'agit d'un tutoriel intermédiaire, je ne vais pas tout passer en revue..

La principale chose à noter est que la poignée de l’autolaveuse est composée de deux div éléments: .manipuler et .zone de frappe.

.manipuler est l’indicateur visuel rond et bleu de l’emplacement de la poignée de l’épurateur. Nous l'avons intégré à un élément invisible de la zone d'accès afin de faciliter la capture de l'élément aux utilisateurs d'écran tactile..

Fonctions d'importation

En haut de votre panneau JS, importez tout ce que nous allons utiliser dans ce tutoriel:

const assouplissement, images clés, pointeur, décroissance, ressort, styler, transformer, écouter, valeur = popmotion; const pipe, clamp, conditionnel, linearSpring, interpolate = transformer;

Sélectionner des éléments

Nous allons avoir besoin de trois éléments dans ce tutoriel. Nous animerons le .boîte, faites glisser et animer le .zone de frappe, et mesurer le .intervalle.

Créons aussi stylers pour les éléments que nous allons animer:

const box = document.querySelector ('. box'); const boxStyler = styler (box); const handle = document.querySelector ('. handle-hit-area'); const handleStyler = styler (handle); const range = document.querySelector ('. range');

Animation d'images clés

Pour notre animation scrubbable, nous allons faire la .boîte se déplacer de gauche à droite avec images clés. Cependant, nous pourrions tout aussi facilement frotter un interpolation ou chronologie animation utilisant la même méthode que celle décrite plus loin dans ce tutoriel.

const boxAnimation = keyframes (valeurs: [0, -150, 150, 0], easings: [easing.backOut, easing.backOut, easing.easeOut], durée: 2000). start (boxStyler.set ('x' ));

Votre animation va maintenant jouer. Mais nous ne voulons pas ça! Faisons une pause pour le moment:

boxAnimation.pause ();

Faire glisser l'axe des x

Il est temps d'utiliser aiguille faire glisser notre manche de récureur. Dans le tutoriel précédent, nous avons utilisé à la fois X et y propriétés, mais avec un laveur nous avons seulement besoin X.

Nous préférons garder notre code réutilisable et suivre un seul aiguille L'axe est un cas d'utilisation assez commun. Créons donc une nouvelle fonction appelée avec imagination, pointeurX.

Cela fonctionnera exactement comme aiguille sauf que cela ne prendra qu'un seul nombre comme argument et ne produira qu'un seul nombre (X):

const pointeurX = (x) => pointeur (x). pipe (xy => xy.x); 

Ici, vous pouvez voir que nous utilisons une méthode de aiguille appelé tuyautuyau est disponible sur toutes les actions Popmotion que nous avons vues jusqu'à présent, y compris images clés.

tuyau accepte plusieurs fonctions. Quand l'action est débuttoutes les sorties passeront successivement par chacune de ces fonctions, avant la mettre à jour fonction fournie à début les feux.

Dans ce cas, notre fonction est simplement:

xy => xy.x

Tout ce qu'il fait est de prendre la x, y objet généralement produit par aiguille et en retournant juste le X axe.

Auditeurs de l'événement

Nous devons savoir si l'utilisateur a commencé à appuyer sur la poignée avant de commencer à suivre avec notre nouveau pointeurX une fonction.

Dans le dernier tutoriel, nous avons utilisé le traditionnel addEventListener une fonction. Cette fois, nous allons utiliser une autre fonction Popmotion appelée écouteécoute fournit également un tuyau méthode, ainsi que l'accès à toutes les méthodes d'action, mais on ne va pas l'utiliser ici.

écoute nous permet d'ajouter des écouteurs d'événements à plusieurs événements avec une seule fonction, similaire à jQuery. Nous pouvons donc condenser les quatre auditeurs d’événement précédents à deux:

listen (handle, 'mousedown touchstart'). start (startDrag); écouter (document, 'mouseup touchend'). start (stopDrag);

Déplacer la poignée

Nous aurons besoin de la poignée de x rapidité plus tard, alors faisons-en un valeur, comme nous l’avons appris dans le dernier tutoriel, nous permet d’interroger la vitesse. Sur la ligne après on définit poignéeStyler, ajouter:

const handleX = valeur (0, handleStyler.set ('x'));

Maintenant, nous pouvons ajouter notre startDrag et stopDrag les fonctions:

const startDrag = () => pointeurX (handleX.get ()) .start (handleX); const stopDrag = () => handleX.stop ();

Pour le moment, la poignée peut être nettoyée au-delà des limites du curseur, mais nous y reviendrons plus tard..

Lavage

Maintenant, nous avons un récureur visuellement fonctionnel, mais nous ne nettoyons pas l'animation proprement dite..

Chaque valeur a un souscrire méthode. Cela nous permet d’attacher plusieurs abonnés au feu lorsque le valeur changements. Nous voulons chercher le images clés animation chaque fois handleX mises à jour.

Commencez par mesurer le curseur. Sur la ligne après on définit intervalle, ajouter:

const rangeWidth = range.getBoundingClientRect (). width;

keyframes.seek accepte une valeur de progression telle qu'exprimée à partir de 0 à 1, alors que notre handleX est défini avec les valeurs de pixel de 0 à rangeWidth.

Nous pouvons convertir de la mesure de pixel à un 0 à 1 plage en divisant la mesure de pixel actuelle par rangeWidth. Sur la ligne après boxAnimation.pause (), ajoutez cette méthode d'abonnement:

handleX.subscribe (v => boxAnimation.seek (v / rangeWidth));

Maintenant, si vous jouez avec le scrubber, l’animation sera nettoyée avec succès!

Le mille supplémentaire

Limites de printemps

La récureuse peut toujours être tirée en dehors des limites de la plage complète. Pour résoudre cela, nous pourrait utilisez simplement un serrer fonction pour nous assurer de ne pas sortir des valeurs en dehors de 0, étendue de la largeur.

Au lieu de cela, nous allons faire un pas supplémentaire et attacher des ressorts à la fin de notre curseur. Lorsqu'un utilisateur tire la poignée au-delà de la plage autorisée, il le tirera vers elle. Si l'utilisateur relâche le handle alors qu'il se trouve en dehors de la plage, nous pouvons utiliser un printemps animation pour le ramener.

Nous ferons de ce processus une fonction unique que nous pourrons fournir au pointeurX tuyau méthode. En créant une seule fonction réutilisable, nous pouvons réutiliser ce morceau de code avec n’importe quelle animation Popmotion, avec des plages configurables et des forces de ressorts..

Tout d'abord, appliquons un ressort à la limite la plus à gauche. Nous allons utiliser deux transformateurs, conditionnel et linearSpring.

const springRange = (min, max, force) => conditionnel (v => v < min, linearSpring(strength, min) );

conditionnel prend deux fonctions, une assertion et un transformateur. L'assertion reçoit la valeur fournie et retourne soit vrai ou faux. Si cela revient vrai, la deuxième fonction sera fournie la valeur pour transformer et retourner.

Dans ce cas, l’assertion dit: "Si la valeur fournie est inférieure à min, passer cette valeur à travers le linearSpring transformateur. "Le linearSpring est une fonction de ressort simple qui, contrairement à la la physique ou printemps animations, n'a pas de notion de temps. Lui fournir un force et un cible, et il va créer une fonction qui "attire" toute valeur donnée vers la cible avec la force définie.

Remplacer notre startDrag fonctionner avec ceci:

const startDrag = () => pointerX (handleX.get ()) .pipe (springRange (0, rangeWidth, 0.1)) .start (handleX);

Nous passons maintenant le pointeur X compenser par notre SpringRange fonction, donc si vous faites glisser la poignée au-delà du côté le plus à gauche, vous remarquerez qu'il tire en arrière.

Appliquer la même chose du côté le plus à droite est une question de composition d'une seconde conditionnel avec le premier en utilisant le stand-alone tuyau une fonction:

const springRange = (min, max, résistance) => tuyau (conditionnel (v => v < min, linearSpring(strength, min) ), conditional( v => v> max, linearSpring (force, max)));

Un autre avantage de composer une fonction comme SpringRange est-ce que cela devient très testable. La fonction qu'il renvoie est, comme tous les transformateurs, une fonction pure qui prend une valeur unique. Vous pouvez tester cette fonction pour voir si elle passe par des valeurs comprises entre min et max inaltéré, et s’il applique des ressorts à des valeurs qui se trouvent sans.

Si vous lâchez la poignée alors qu'elle se trouve en dehors de la plage, elle devrait maintenant revenir à sa portée. Pour cela, nous devrons ajuster la stopDrag fonction pour tirer un printemps animation:

const stopDrag = () => const x = handleX.get (); (X < 0 || x > rangeWidth)? snapHandleToEnd (x): handleX.stop (); ;

Notre snapHandleToEnd la fonction ressemble à ceci:

const snapHandleToEnd = (x) => ressort (de: x, vélocité: handleX.getVelocity (), à: x < 0 ? 0 : rangeWidth, damping: 30, stiffness: 5000 ).start(handleX);

Tu peux voir ça à est défini comme 0 ou rangeWidth en fonction de quel côté du curseur la poignée se trouve actuellement. En jouant avec amortissement et rigidité, vous pouvez jouer avec une gamme de différents ressorts.

Défilement Momentum

J'ai toujours apprécié le nettoyage du lecteur iOS que j'ai toujours apprécié, à savoir que si vous jetiez la poignée, elle ralentirait progressivement au lieu de s'arrêter. Nous pouvons reproduire cela facilement en utilisant le pourriture animation.

Dans stopDrag, remplacer handleX.stop () avec momentumScroll (x).

Ensuite, sur la ligne après le snapHandleToEnd fonction, ajouter une nouvelle fonction appelée MomentScroll:

const momentumScroll = (x) => decay (from: x, velocity: handleX.getVelocity ()). start (handleX);

Maintenant, si vous jetez la poignée, elle s’arrêtera progressivement. Il animera également en dehors de la plage du curseur. Nous pouvons arrêter cela en passant le serrer transformateur à la decay.pipe méthode:

const momentumScroll = (x) => decay (from: x, velocity: handleX.getVelocity ()). pipe (clamp (0, rangeWidth)) .start (handleX);

Conclusion

En utilisant une combinaison de différentes fonctions Popmotion, nous pouvons créer un laveur qui a un peu plus de vie et d’amusement que la normale.

En utilisant tuyau, nous composons des fonctions pures simples en comportements plus complexes tout en laissant les pièces composites testables et réutilisables.

Prochaines étapes

Pourquoi ne pas essayer ces défis:

  • Faire rebondir la fin du mouvement avec un rebond si la poignée touche l'une des extrémités de l'épurateur.
  • Faites en sorte que la poignée s'anime en un point quelconque de la barre de défilement lorsqu'un utilisateur clique sur une autre partie de la barre de plage.
  • Ajoutez des commandes de lecture complètes, comme un bouton Lecture / Pause. Mettre à jour la position du manche de l'épurateur au fur et à mesure de l'animation.