Introductie tot Popmotion Custom Animation Scrubber

In het eerste deel van de introductieserie van Popmotion hebben we geleerd hoe te gebruiken time-based animaties zoals tween en keyframes. We hebben ook geleerd hoe we deze animaties op de DOM kunnen gebruiken met behulp van de performant styler.

In deel twee hebben we geleerd hoe te gebruiken wijzer volgen en opnemen snelheid. We hebben dat vervolgens gebruikt om de -Velocity based animaties de lenteverval, en fysica.

In dit laatste deel gaan we een scrubberwidget maken en we zullen het gebruiken om een ​​scrubber-widget te schrobben keyframes animatie. We maken de widget zelf van een combinatie van pointer tracking en de lente en verval om het een meer visceraal gevoel te geven dan gewone scrubbers.

Probeer het zelf:

Ermee beginnen

markup

Blader eerst deze CodePen voor de HTML-sjabloon. Zoals eerder, omdat dit een tussentijdse zelfstudie is, zal ik niet alles doornemen.

De belangrijkste wending van de noot is dat de greep op de scrubber uit twee bestaat div elementen: .handvat en .handvat-hit-area.

.handvat is de ronde blauwe visuele indicator van waar de handgreep van de gaswasser is. We hebben het verpakt in een onzichtbaar hitgebied om het element gemakkelijker te kunnen grijpen voor gebruikers met een aanraakscherm.

Functies importeren

Gebruik boven aan uw JS-paneel alles wat we in deze zelfstudie gaan gebruiken:

const easing, keyframes, pointer, decay, spring, styler, transform, listen, value = popmotion; const pipe, clamp, conditional, linearSpring, interpolate = transform;

Selecteer elementen

We hebben drie elementen nodig in deze zelfstudie. We animeren het .doos, sleep en animeer de .handvat-hit-area, en meet de .reeks.

Laten we ook creëren stylers voor de elementen die we gaan animeren:

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

Keyframes-animatie

Voor onze scrubbare animatie gaan we het maken .doos ga van links naar rechts met keyframes. We kunnen echter net zo goed een scrubben tween of tijdlijn animatie met dezelfde methode die later in deze zelfstudie wordt beschreven.

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

Je animatie zal nu spelen. Maar dat willen we niet! Laten we het voorlopig onderbreken:

boxAnimation.pause ();

De x-as slepen

Het is tijd om te gebruiken wijzer om onze schrobberhandgreep te slepen. In de vorige zelfstudie hebben we beide gebruikt X en Y eigenschappen, maar met een gaswasser die we alleen nodig hebben X.

We geven er de voorkeur aan onze code herbruikbaar te houden en een enkele te volgen wijzer as is een vrij algemeen gebruik. Dus laten we een nieuwe functie creëren, imaginatively genaamd, pointerX.

Het zal precies zo werken wijzer behalve dat het slechts een enkel nummer als zijn argument nodig heeft en slechts één enkel getal uitvoert (X):

const pointerX = (x) => pointer (x). pipe (xy => xy.x); 

Hier kun je zien dat we een methode gebruiken van wijzer riep pijppijp is beschikbaar op alle Popmotion-acties die we tot nu toe hebben gezien, inclusief keyframes.

pijp accepteert meerdere functies. Wanneer de actie is beginAlle uitvoer wordt achtereenvolgens door elk van deze functies geleid, vóór de bijwerken functie verstrekt aan begin branden.

In dit geval is onze functie eenvoudig:

xy => xy.x

Het enige wat het doet is het nemen van de x, y object meestal uitgevoerd door wijzer en alleen het X as.

Evenement Luisteraars

We moeten weten of de gebruiker is begonnen met het indrukken van de hendel voordat we beginnen met het volgen van onze nieuwe pointerX functie.

In de laatste tutorial gebruikten we de traditionele addEventListener functie. Deze keer gaan we een andere Popmotion-functie gebruiken genaamd luisterluister biedt ook een pijp methode, evenals toegang tot alle actiemethoden, maar we gaan dit hier niet gebruiken.

luister stelt ons in staat om gebeurtenislisteners toe te voegen aan meerdere evenementen met een enkele functie, vergelijkbaar met jQuery. Dus we kunnen de vorige vier gebeurtenisluisteraars verdichten tot twee:

listen (handle, 'mousedown touchstart'). start (startDrag); luister (document, 'mouse-up touchend'). start (stopDrag);

Verplaats de hendel

We hebben de hendel x nodig snelheid later, dus laten we er een maken waarde, wat we, zoals we geleerd hebben in de laatste tutorial, ons in staat stellen om de snelheid te onderzoeken. Op de regel nadat we definiëren handleStyler, toevoegen:

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

Nu kunnen we onze toevoegen startDrag en stopDrag functies:

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

Op dit moment kan het handvat buiten de grenzen van de schuif worden geschrobd, maar daar komen we later op terug.

schrobben

Nu hebben we een visueel functionele scrubber, maar we zijn niet bezig met het schrobben van de daadwerkelijke animatie.

elk waarde heeft een abonneren methode. Dit stelt ons in staat om meerdere abonnees aan vuur te hechten wanneer het waarde veranderingen. We willen de keyframes animatie wanneer handleX updates.

Meet eerst de schuifregelaar. Op de regel nadat we definiëren reeks, toevoegen:

const rangeWidth = range.getBoundingClientRect (). width;

keyframes.seek accepteert een voortgangswaarde zoals uitgedrukt vanaf 0 naar 1, terwijl onze handleX is ingesteld met pixelwaarden van 0 naar rangeWidth.

We kunnen converteren van de pixelmeting naar een 0 naar 1 bereik door de huidige pixelmeting te delen door rangeWidth. Op de regel erna boxAnimation.pause (), voeg deze abonnemethode toe:

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

Als je nu met de scrubber speelt, scant de animatie met succes!

De extra mijl

Springgrenzen

De gaswasser kan nog steeds buiten de grenzen van het volledige bereik worden getrokken. Om dit op te lossen, wij kon gebruik gewoon een klem functie om ervoor te zorgen dat we geen waarden buiten uitvoeren 0, rangeWidth.

In plaats daarvan gaan we de extra stap uitvoeren en veren aan het einde van onze schuif bevestigen. Wanneer een gebruiker de hendel voorbij het toegestane bereik trekt, wordt deze teruggetrokken. Als de gebruiker het handvat loslaat terwijl het buiten het bereik valt, kunnen we een de lente animatie om het terug te klikken.

We zullen dit proces een enkele functie maken die we kunnen bieden aan de pointerX pijp methode. Door een enkele, herbruikbare functie te creëren, kunnen we dit stuk code opnieuw gebruiken met elke Popmotion-animatie, met instelbare reeksen en veerkracht.

Laten we eerst een veer op de meest linkse grens aanbrengen. We gebruiken twee transformatoren, voorwaardelijk en linearSpring.

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

voorwaardelijk heeft twee functies, een bewering en een transformator. De bewering ontvangt de geleverde waarde en komt ook terug waar of vals. Als het terugkeert waar, de tweede functie krijgt de waarde om te transformeren en terug te keren.

In dit geval zegt de bewering: "Als de geleverde waarde kleiner is dan min, geef deze waarde door via linearSpring transformator linearSpring is een eenvoudige veerfunctie die, in tegenstelling tot de fysica of de lente animaties, heeft geen idee van tijd. Geef het een sterkte en een doelwit, en het zal een functie creëren die elke gegeven waarde naar het doel met de gedefinieerde sterkte "aantrekt".

Vervang onze startDrag functie hiermee:

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

We geven nu de aanwijzer door X gecompenseerd door onze springRange functie, dus als u de greep langs de meest linkse zijde sleept, merkt u dat deze terugtrekt.

Hetzelfde toepassen aan de meest rechtse kant is een kwestie van een seconde samenstellen voorwaardelijk waarbij de eerste stand-alone gebruikt pijp functie:

const springRange = (min, max, strength) => pipe (voorwaardelijk (v => v < min, linearSpring(strength, min) ), conditional( v => v> max, linearSpring (sterkte, max)));

Een ander voordeel van het samenstellen van een functie zoals springRange is dat het erg testbaar wordt. De functie die het teruggeeft is, net als alle transformatoren, een pure functie die één waarde aanneemt. Je kunt deze functie testen om te zien of deze door waarden gaat die erin liggen min en max ongewijzigd, en als het veren toepast op waarden die buiten liggen.

Als u de hendel loslaat terwijl deze buiten het bereik ligt, moet deze nu terugkeren naar binnen bereik. Daarvoor moeten we de. Aanpassen stopDrag functie om een ​​te vuren de lente animatie:

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

Onze snapHandleToEnd functie ziet er als volgt uit:

const snapHandleToEnd = (x) => veer (van: x, velocity: handleX.getVelocity (), to: x < 0 ? 0 : rangeWidth, damping: 30, stiffness: 5000 ).start(handleX);

Je kan dat zien naar is ingesteld als 0 of rangeWidth afhankelijk van aan welke kant van de slider de hendel momenteel zit. Door mee te spelen demping en stijfheid, je kunt spelen met een reeks verschillende voorjaarsgevoelens.

Momentum scrollen

Een leuk detail van de iOS-scrubber die ik altijd op prijs stelde, was dat als je de hendel gooide, deze geleidelijk langzamer ging draaien dan stil te liggen. We kunnen dat eenvoudig repliceren met behulp van de verval animatie.

In stopDrag, vervangen handleX.stop () met momentumScroll (x).

Vervolgens, op de regel na de snapHandleToEnd functie, voeg een nieuwe functie toe genaamd momentumScroll:

const momentumScroll = (x) => verval (van: x, velocity: handleX.getVelocity ()). start (handleX);

Als u nu het handvat gooit, komt het geleidelijk tot stilstand. Het wordt ook buiten het bereik van de schuifregelaar animeren. We kunnen dit stoppen door de klem transformator naar de decay.pipe methode:

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

Conclusie

Door een combinatie van verschillende Popmotion-functies te gebruiken, kunnen we een scrubber creëren die een beetje meer leven en speelsheid heeft dan de gebruikelijke.

Door het gebruiken van pijp, we stellen eenvoudige pure functies samen tot meer complex gedrag, terwijl we de samengestelde stukken testbaar en herbruikbaar laten.

Volgende stappen

Hoe zit het met het proberen van deze uitdagingen:

  • Laat het momentum scrollen eindigen met een bounce als de hendel aan beide uiteinden van de scrubber komt.
  • Laat de greep animeren naar elk punt op de scrubber wanneer een gebruiker op een ander deel van de bereikbalk klikt.
  • Voeg volledige afspeelknoppen toe, zoals een afspeel- / pauzeknop. Werk de positie van de schrobberhandgreep bij naarmate de animatie vordert.