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 lente
, verval
, 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:
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.
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;
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 styler
s 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');
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 ();
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 pijp
. pijp
is beschikbaar op alle Popmotion-acties die we tot nu toe hebben gezien, inclusief keyframes
.
pijp
accepteert meerdere functies. Wanneer de actie is begin
Alle 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.
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 luister
. luister
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);
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.
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 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.
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);
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.
Hoe zit het met het proberen van deze uitdagingen: