Im ersten Teil der Popmotion-Einführungsreihe haben wir die Verwendung gelernt zeitbasiert Animationen wie zwischen
und Keyframes
. Wir haben auch gelernt, wie man diese Animationen auf dem DOM verwendet, indem man das Performant verwendet Styler
.
Im zweiten Teil haben wir gelernt, wie man es benutzt Zeiger
Tracking und Aufzeichnung Geschwindigkeit
. Wir haben das dann benutzt, um das zu betreiben Geschwindigkeitsbasiert Animationen Frühling
, zerfallen
, und Physik
.
In diesem letzten Teil erstellen wir ein Scrubber-Widget, und wir werden es verwenden, um ein Scrubben durchzuführen Keyframes
Animation. Wir machen das Widget selbst aus einer Kombination von Zeiger-Tracking sowie Frühling
und zerfallen
um es mehr viszeraler zu machen als gewöhnliche Wäscher.
Probieren Sie es selbst aus:
Verzweigen Sie zunächst diesen CodePen für die HTML-Vorlage. Da dies ein fortgeschrittenes Tutorial ist, gehe ich nicht alles durch.
Der Hauptvorteil ist, dass der Griff des Wäschers aus zwei besteht div
Elemente: .Griff
und .Griffbereich
.
.Griff
ist der runde blaue visuelle Indikator dafür, wo sich der Griff des Wäschers befindet. Wir haben es in ein unsichtbares Element für den Trefferbereich eingepackt, um den Touchscreen-Benutzern das Erfassen des Elements zu erleichtern.
Importieren Sie oben in Ihrem JS-Bedienfeld alles, was wir in diesem Tutorial verwenden werden:
const Lockerung, Keyframes, Zeiger, Zerfall, Frühling, Styler, Transformieren, Hören, Wert = popmotion; const Pipe, Klemme, Bedingt, linearSpring, interpolieren = transform;
In diesem Tutorial werden wir drei Elemente benötigen. Wir werden die animieren .Box
, ziehen und animieren Sie die .Griffbereich
, und messen Sie das .Angebot
.
Lass uns auch schaffen Styler
s für die Elemente, die wir animieren werden:
const box = document.querySelector ('. box'); const boxStyler = Styler (Box); const handle = document.querySelector ('. handle-hit-area'); const handleStyler = Styler (Griff); const range = document.querySelector ('. range');
Für unsere scrubbable Animation machen wir die .Box
Bewegen Sie sich von links nach rechts mit Keyframes
. Wir könnten aber genauso leicht einen schrubben zwischen
oder Zeitleiste
Animation mit derselben Methode, die später in diesem Tutorial beschrieben wird.
const boxAnimation = Keyframes (Werte: [0, -150, 150, 0], Erleichterungen: [easing.backOut, easing.backOut, easing.easeOut], Dauer: 2000). start (boxStyler.set ('x') ));
Ihre Animation wird jetzt abgespielt. Aber das wollen wir nicht! Lass es für jetzt pausieren:
boxAnimation.pause ();
Es ist Zeit zu benutzen Zeiger
um unseren Wäschergriff zu ziehen. Im vorherigen Tutorial haben wir beide verwendet x
und y
Eigenschaften, aber mit einem Wäscher brauchen wir nur x
.
Wir bevorzugen es, unseren Code wiederverwendbar zu halten und einen einzelnen zu verfolgen Zeiger
Achse ist durchaus ein häufiger Anwendungsfall. Lassen Sie uns also eine neue Funktion erstellen, die imaginativ aufgerufen wird, pointerX
.
Es wird genau so funktionieren Zeiger
außer, es wird nur eine einzige Zahl als Argument verwendet und nur eine einzige Zahl ausgegeben (x
):
const pointerX = (x) => Zeiger (x). pipe (xy => xy.x);
Hier können Sie sehen, dass wir eine Methode von verwenden Zeiger
namens Rohr
. Rohr
ist für alle Popmotion-Aktionen verfügbar, die wir bisher gesehen haben, einschließlich Keyframes
.
Rohr
akzeptiert mehrere Funktionen. Wenn die Aktion ist Start
alle Ausgaben werden vor der Ausgabe der Reihe nach durch alle diese Funktionen geleitet aktualisieren
Funktion zur Verfügung gestellt Start
Feuer.
In diesem Fall ist unsere Funktion einfach:
xy => xy.x
Alles, was es tut, ist die x, y
Objekt wird normalerweise von ausgegeben Zeiger
und nur das zurückgeben x
Achse.
Wir müssen wissen, ob der Benutzer mit dem Drücken des Griffs begonnen hat, bevor wir mit dem neuen Tracking beginnen pointerX
Funktion.
Im letzten Tutorial haben wir das traditionelle verwendet addEventListener
Funktion. Dieses Mal verwenden wir eine andere Popmotion-Funktion, die aufgerufen wird Hör mal zu
. Hör mal zu
bietet auch eine Rohr
Methode sowie Zugriff auf alle Aktionsmethoden, aber wir werden das hier nicht verwenden.
Hör mal zu
ermöglicht das Hinzufügen von Ereignis-Listenern zu mehreren Ereignissen mit einer einzigen Funktion, ähnlich wie bei jQuery. So können wir die vorherigen vier Ereignis-Hörer zu zwei verdichten:
listen (handle, 'mousedown touchstart'). start (startDrag); hören (Dokument, 'mouseup touchend'). start (stopDrag);
Wir brauchen das x des Handles Geschwindigkeit
später machen wir es ein Wert
, Wie wir im letzten Tutorial gelernt haben, können wir die Geschwindigkeit abfragen. In der Zeile danach definieren wir GriffStyler
, hinzufügen:
const handleX = value (0, handleStyler.set ('x'));
Jetzt können wir unsere hinzufügen startDrag
und stopDrag
Funktionen:
const startDrag = () => pointerX (handleX.get ()) .start (handleX); const stopDrag = () => handleX.stop ();
Im Moment kann der Griff über die Grenzen des Schiebereglers hinaus schrubben, aber darauf kommen wir später zurück.
Jetzt haben wir einen visuell funktionierenden Scrubber, aber die eigentliche Animation wird nicht gelöscht.
Jeden Wert
hat ein abonnieren
Methode. Dies ermöglicht es uns, mehrere Abonnenten anzuschließen, wenn die Wert
Änderungen. Wir wollen das suchen Keyframes
Animation wann immer handleX
Aktualisierung.
Messen Sie zuerst den Schieberegler. In der Zeile danach definieren wir Angebot
, hinzufügen:
const rangeWidth = range.getBoundingClientRect (). width;
keyframes.seek
akzeptiert einen Fortschrittswert, wie von ausgedrückt 0
zu 1
, während unser handleX
wird mit Pixelwerten von gesetzt 0
zu rangeWidth
.
Wir können von der Pixelmessung in eine konvertieren 0
zu 1
Bereich durch Teilen der aktuellen Pixelmessung durch rangeWidth
. In der Zeile nach boxAnimation.pause ()
, Füge diese abonnierte Methode hinzu:
handleX.subscribe (v => boxAnimation.seek (v / rangeWidth));
Wenn Sie jetzt mit dem Scrubber spielen, wird die Animation erfolgreich scrubben!
Der Wäscher kann immer noch außerhalb der Grenzen des gesamten Bereichs gezogen werden. Um das zu lösen, haben wir könnte benutze einfach eine Klemme
Funktion, um sicherzustellen, dass wir keine Werte außerhalb von ausgeben 0, rangeWidth
.
Stattdessen gehen wir noch einen Schritt weiter und befestigen Federn am Ende unseres Schiebereglers. Wenn ein Benutzer den Griff über den zulässigen Bereich hinaus zieht, wird er zurückgezogen. Wenn der Benutzer den Griff freigibt, wenn er sich außerhalb des Bereichs befindet, können wir ein verwenden Frühling
Animation zum Zurückschnappen.
Wir machen diesen Prozess zu einer einzigen Funktion, die wir dem zur Verfügung stellen können pointerX
Rohr
Methode. Durch die Erstellung einer einzigen, wiederverwendbaren Funktion können wir diesen Code mit jeder Popmotion-Animation mit konfigurierbaren Bereichen und Federstärken wiederverwenden.
Lassen Sie uns zuerst eine Feder auf die äußerste linke Grenze anwenden. Wir verwenden zwei Transformatoren, bedingt
und linearSpring
.
const springRange = (min, max, Stärke) => bedingt (v => v < min, linearSpring(strength, min) );
bedingt
übernimmt zwei Funktionen, eine Zusicherung und einen Transformator. Die Zusicherung erhält den angegebenen Wert und kehrt entweder zurück wahr
oder falsch
. Wenn es zurückkehrt wahr
, der zweiten Funktion wird der Wert bereitgestellt, der transformiert und zurückgegeben werden soll.
In diesem Fall lautet die Aussage: "Wenn der angegebene Wert kleiner ist als Mindest
, geben Sie diesen Wert durch linearSpring
Transformator. "Die linearSpring
ist eine einfache Federfunktion, die im Gegensatz zum Physik
oder Frühling
Animationen, hat keine Vorstellung von Zeit. Gib es a Stärke
und ein Ziel
, und es wird eine Funktion erstellt, die einen beliebigen Wert mit der definierten Stärke in Richtung des Ziels "anzieht".
Ersetzen Sie unsere startDrag
Funktion mit diesem:
const startDrag = () => pointerX (handleX.get ()) .pipe (springRange (0, rangeWidth, 0.1)) .start (handleX);
Wir übergeben jetzt den Zeiger x
versetzt durch unsere springRange
Wenn Sie also den Griff an der am weitesten links liegenden Seite ziehen, werden Sie feststellen, dass er zurückgezogen wird.
Wenn Sie dasselbe auf die ganz rechte Seite anwenden, müssen Sie eine Sekunde erstellen bedingt
mit der ersten Verwendung des Stand-Alone Rohr
Funktion:
const springRange = (min, max, Stärke) => Rohr (bedingt (v => v < min, linearSpring(strength, min) ), conditional( v => v> max, linearSpring (Stärke, max)));
Ein weiterer Vorteil des Komponierens einer Funktion wie springRange
ist, dass es sehr überprüfbar wird. Die zurückgegebene Funktion ist wie alle Transformatoren eine reine Funktion, die einen einzelnen Wert annimmt. Sie können diese Funktion testen, um zu sehen, ob sie Werte durchlässt, die innerhalb liegen Mindest
und max
unverändert, und wenn es gilt, werden die Werte, die außerhalb liegen, mit Federn versehen.
Wenn Sie den Griff loslassen, während er außerhalb des Bereichs liegt, sollte er jetzt wieder in den Bereich zurückspringen. Dafür müssen wir die anpassen stopDrag
Funktion zu feuern a Frühling
Animation:
const stopDrag = () => const x = handleX.get (); (x < 0 || x > rangeWidth)? snapHandleToEnd (x): handleX.stop (); ;
Unsere snapHandleToEnd
Funktion sieht so aus:
const snapHandleToEnd = (x) => spring (von: x, Geschwindigkeit: handleX.getVelocity () bis: x < 0 ? 0 : rangeWidth, damping: 30, stiffness: 5000 ).start(handleX);
Sie können sehen, dass zu
ist entweder als gesetzt 0
oder rangeWidth
Je nachdem auf welcher Seite des Schiebereglers der Griff gerade sitzt. Indem du mit spielst Dämpfung
und Steifheit
, Sie können mit verschiedenen Federfühlen spielen.
Ein schöner Aspekt von iOS-Scrubber, den ich immer zu schätzen wusste, war, dass der Griff nach und nach verlangsamt würde und nicht zum Stillstand gekommen wäre. Wir können das einfach mit dem replizieren zerfallen
Animation.
Im stopDrag
, ersetzen handleX.stop ()
mit MomentumScroll (x)
.
Dann auf der Zeile nach dem snapHandleToEnd
Funktion, fügen Sie eine neue Funktion hinzu MomentumScroll
:
const momentumScroll = (x) => decay (from: x, Geschwindigkeit: handleX.getVelocity ()). start (handleX);
Wenn Sie jetzt den Griff werfen, wird er allmählich gestoppt. Es wird auch außerhalb des Bereichs des Schiebereglers animiert. Wir können damit aufhören, indem wir das übergeben Klemme
Transformator zum decay.pipe
Methode:
const momentumScroll = (x) => decay (von: x, Geschwindigkeit: handleX.getVelocity ()). pipe (clamp (0, rangeWidth)) .start (handleX);
Durch die Kombination verschiedener Popmotion-Funktionen können wir einen Wäscher erstellen, der ein bisschen mehr Leben und Verspieltheit bietet als üblich.
Durch die Nutzung Rohr
, Wir setzen einfache reine Funktionen zu komplexeren Verhaltensweisen zusammen und lassen die Verbundwerkstoffe überprüfbar und wiederverwendbar.
Wie wäre es mit diesen Herausforderungen?