Einfache Streichen Mit Vanilla-JavaScript

0
59

Ich glaube Implementierung von swipe-gesten werden mussten, sehr schwierig, aber ich habe vor kurzem fand ich mich in einer situation, wo ich musste es tun und entdeckt die Wirklichkeit ist bei weitem nicht so düster wie ich es mir vorgestellt hatte.

Dieser Artikel wird Ihnen Schritt für Schritt, durch die Umsetzung mit dem geringsten code die ich gefunden habe. Also, lassen Sie uns springen rechts in!

Die HTML-Struktur

Beginnen wir mit einer .container, der ein paar Bilder von innen:

<div class=’container’>
<img src=’img1.jpg” alt= “image description”/>

</div>

Basic Styles

Wir verwenden display: flex, um sicherzustellen, dass Bilder gehen nebeneinander ohne Leerzeichen dazwischen. align-items: center middle richtet Sie senkrecht. Wir machen beide Bilder und die container nehmen die Breite des Containers parent (der Körper in unserem Fall).

.container {
display: flex;
align-items: center;
width: 100%;

img {
min-width: 100%; /* notwendig, damit Firefox nicht machen img schrumpfen zu fit */
width: 100%; /* kann nicht nehmen Sie dieses heraus, entweder, wie es bricht, Chrome */
}
}

Die Tatsache, dass sowohl die .container und seine untergeordneten Bilder haben die gleiche Breite macht diese Bilder spill auf der rechten Seite (markiert durch rote Umrandung) erstellen Sie eine horizontale Bildlaufleiste, aber das ist genau das, was wir wollen:

Das erste layout (siehe live-demo).

Da nicht alle Bilder haben die gleichen Abmessungen und das Seitenverhältnis, wir haben ein bisschen für den Leerraum oberhalb und unterhalb einige von Ihnen. Also, wir gehen zu trimmen, indem Sie die .container eine explizite Höhe, die sollte ziemlich viel Arbeit für den durchschnittlichen Seitenverhältnis von diesen Bildern und Einstellung overflow-y auf hidden:

.container {
/* das gleiche wie vorher */
overflow-y: hidden;
Höhe: 50vw;
max-height: 100vh;
}

Das Ergebnis kann unten gesehen werden, mit allen Bilder getrimmt werden, um die gleiche Höhe und keine leeren Räume mehr:

Das Ergebnis nach Bilder sind beschnitten overflow-y auf der .container (siehe live-demo).

Okay, aber jetzt haben wir eine horizontale Bildlaufleiste auf der .container selbst. Naja, das ist eigentlich eine gute Sache, für die keine JavaScript-Fall.

Ansonsten erzeugen wir eine CSS-variable –n für die Anzahl der Bilder und wir nutzen dieses zu machen .container breit genug für alle sein Bild Kinder, die noch die gleiche Breite wie Ihre Muttergesellschaft (der Körper, in diesem Fall):

.container {
–n: 1;
width: 100%;
width: calc(var(–n)*100%);

img {
min-width: 100%;
width: 100%;
width: calc(100%/var(–n));
}
}

Beachten Sie, dass wir behalten die Vorherige Breite Erklärungen als ersatzoption. Die calc () – Werte nicht ändern, eine Sache, bis wir set –n-aus der JavaScript-Code nach dem bekommen unserer .container und die Anzahl der untergeordneten Bilder, die er hält:

const _C = document.querySelector(‘.container’),
N = _C.Kinder.Länge;

_C.Stil.setProperty (“–n”, N)

Jetzt unsere .container erweitert, um alle passen die Bilder von innen:

Layout mit erweiterten container (live-demo).

Wechseln Bilder

Als Nächstes Holen wir uns entfernen Sie die horizontale Bildlaufleiste durch die Einstellung overflow-x: hidden auf unsere container parent (der Körper in unserem Fall) und wir erstellen eine weitere CSS-variable speichert den index des aktuell ausgewählten Bildes (–i). Wir verwenden diese, um richtig zu positionieren .container mit Bezug auf den viewport über eine übersetzung (denken Sie daran, dass % – Werte innerhalb translate () – Funktionen sind relativ zu den Abmessungen des Elements setzen wir diese Transformation auf):

body { overflow-x: hidden }

.container {
/* gleichen Stile wie zuvor */
transform: translate(calc(var(–i, 0)/var(–n)*-100%));
}

Ändern Sie die –ich um einen anderen ganzzahligen Wert größer oder gleich null ist, aber kleiner als –n, bringt ein anderes Bild, in der Ansicht, wie dargestellt durch die interaktive demo an, unten (wo der Wert der –ich wird gesteuert durch eine Reihe von input):

Finden Sie den Stift, indem Sie thebabydino (@thebabydino) auf CodePen.

Okay, aber wir wollen nicht auf einen Schieberegler verwenden, um dies zu tun.

Die grundlegende Idee ist, dass wir gehen, um die Erkennung der Richtung der Bewegung zwischen dem “touchstart” (oder “mousedown” Ereignis und “touchend” (oder “mouseup”) und dann update –ich dementsprechend den container verschieben, so dass das nächste Bild (wenn es eine ist) in die gewünschte Richtung bewegt, in den viewport.

Funktion lock(e) {};

die Funktion bewegen(e) {};

_C.addEventListener(‘mousedown’, lock, false);
_C.addEventListener(‘touchstart’, lock, false);

_C.addEventListener(‘mouseup’, bewegen, false);
_C.addEventListener(‘touchend’, bewegen, false);

Beachten Sie, dass dies nur funktionieren wird, für die Maus, wenn man den pointer-events: none auf den Bildern.

.container {
/* gleichen Stile wie zuvor */

img {
/* gleichen Stile wie zuvor */
pointer-events: none;
}
}

Auch Edge haben muss, um touch-events aktiviert von about:flags , da diese option standardmäßig deaktiviert ist:

Aktivieren der touch-events in Rand.

Bevor wir füllen die lock() und move () – Funktionen, die wir vereinheitlichen Sie die Note und klicken Sie auf die Fälle:

die Funktion unify(e) { return e.changedTouches ? e.changedTouches[0] : e };

Sperren auf “touchstart” (oder “mousedown”) bedeutet, dass das abrufen und speichern der x-Koordinate in einer ersten Koordinate variable x0:

let x0 = null;

Funktion lock(e) { x0 = unify(e).clientX };

Um zu sehen, wie um unseren .container (oder wenn wir selbst das tun, weil wir nicht wollen, weiter zu bewegen, wenn wir das Ende erreicht haben), wir überprüfen, ob wir durchgeführt haben, die lock () – Aktion, und wenn wir haben, wir Lesen die aktuelle x-Koordinate berechnen Sie die Differenz zwischen der it und x0 und beheben, was zu tun ist, der aus seinem Schild und der aktuelle index:

let i = 0;

die Funktion bewegen(e) {
wenn(x0 || x0 === 0) {
lassen dx = unify(e).clientX – x0, s = Math.sign(dx);

if((i > 0 || s < 0) && (i < N – 1 || s > 0))
_C.Stil.setProperty(‘–i’ i -= s);

x0 = null
}
};

Das Ergebnis auf ziehen nach Links/ rechts können unten gesehen werden:

Das Umschalten zwischen den Bildern auf streichen (live-demo). Versuche zu bewegen, um das Recht auf das erste Bild, oder Links auf dem letzten nichts zu tun, da haben wir kein anderes Bild vor oder nach, jeweils.

Das oben ist das erwartete Ergebnis und das Ergebnis bekommen wir in Chrom für ein wenig ziehen und Firefox. Jedoch, Edge navigiert rückwärts und vorwärts, wenn wir ziehen Sie ihn nach Links oder rechts, das ist etwas, dass Chrome auch nicht auf ein bisschen mehr ziehen.

Edge Navigation auf der angezeigten Seite rückwärts oder vorwärts, Links oder rechts wischen.

Um diese Einstellung außer Kraft setzen, müssen wir hinzufügen, “touchmove” Ereignis-listener:

_C.addEventListener(‘touchmove’, e => {e.preventDefault()}, false)

Okay, wir haben jetzt etwas funktioniert in allen Browsern, aber es sieht nicht aus wie das, was wir wirklich nach… noch!

Smooth Motion

Die einfachste Art, sich zu bewegen in Richtung zu bekommen, was wir wollen, ist, indem ein übergang:

.container {
/* gleichen Stile wie zuvor */
transition: transform .5s ease-outl
}

Und hier ist es, eine sehr einfache swipe-Effekt, die in über 25 Linien von JavaScript und über 25 Zeilen CSS:

Arbeiten swipe-Effekt (live-demo).

Leider, es gibt eine Kante Fehler, die macht jeder übergang zu einer CSS-Variablen-je calc() übersetzung scheitern. Ugh, ich denke, wir müssen vergessen, über die Edge-für jetzt.

Verfeinern das Ganze

Mit all den coolen swipe-Effekte gibt, haben wir bisher nicht ganz schneiden Sie es, so let ‘ s sehen, welche Verbesserungen vorgenommen werden können.

Bessere Visuelle Cues Beim Bewegen

First off, es passiert nichts, während wir ziehen die ganze Aktion folgt die “touchend” (oder “mouseup”) – Ereignis. So, während wir schleppen, wir haben keinen Hinweis darauf, was als Nächstes passiert. Gibt es einen nächsten Bild zu wechseln, um in die gewünschte Richtung? Oder haben wir erreicht das Ende der Zeile und nichts passiert?

Zu kümmern, dass wir zwicken die übersetzung Betrag ein wenig durch das hinzufügen einer CSS-Variablen-tx, ursprünglich 0px:

transform: translate(calc(var(–i, 0)/var(–n)*-100% + var(–tx, 0px)))

Wir verwenden zwei weitere Ereignis-Listener angelegt: einer für “touchmove” und eine für “mousemove”. Beachten Sie, dass wir bereits verhindern, vorwärts und rückwärts navigation in Chrome mit dem “touchmove” listener:

function drag(e) { e.preventDefault() };

_C.addEventListener(‘mousemove’, ziehen, false);
_C.addEventListener(‘touchmove’, ziehen, false);

Lassen Sie uns nun Auffüllen der ziehen () – Funktion! Wenn wir durchgeführt haben, die lock () – Aktion wir Lesen die aktuelle x-Koordinate berechnen Sie die Differenz dx zwischen diesem Koordinatensystem und den Initialen x0 und set-tx auf diesen Wert (was ist ein pixel-Wert).

function drag(e) {
e.preventDefault();

wenn(x0 || x0 === 0)
_C.Stil.setProperty(‘–tx’, `${Math.Runde(unify(e).clientX – x0)}px`)
};

Wir müssen auch sicherstellen, dass das zurücksetzen –tx 0px am Ende und entfernen Sie den übergang für die Dauer des ziehen. Um dies zu erleichtern, ziehen wir den übergang Erklärung auf einem .glatte Klasse:

.glatte { transition: transform .5s ease-out; }

In der lock () – Funktion, entfernen wir diese Klasse von der .container (wir ‘ ll fügen Sie es am Ende wieder auf “touchend” und “mouseup”) und auch einen gesperrt Boolesche variable, so haben wir nicht zu halten, die Durchführung der x0 || x0 === 0 prüfen. Wir verwenden dann die gesperrt-variable für die Prüfungen statt:

lassen locked = false;

Funktion lock(e) {
x0 = unify(e).clientX;
_C.classList.toggle(‘glatt’, !(locked = true))
};

function drag(e) {
e.preventDefault();
wenn(gesperrt) { /* same as before */ }
};

die Funktion bewegen(e) {
wenn(gesperrt) {
lassen dx = unify(e).clientX – x0, s = Math.sign(dx);

if((i > 0 || s < 0) && (i < N – 1 || s > 0))
_C.Stil.setProperty(‘–i’ i -= s);
_C.Stil.setProperty(‘–tx’, ‘0px’);
_C.classList.toggle(‘glatt’, !(locked = false));
x0 = null
}
};

Das Ergebnis kann unten gesehen werden. Wir sind zwar noch ziehen, wir haben jetzt einen visuellen Hinweis darauf, was als Nächstes geschehen wird:

Streichen Sie mit visuellen hinweisen während des Ziehens (live-demo).

Fix die transition-duration

An dieser Stelle, wir sind immer mit der gleichen übergangs-Dauer keine Rolle, wie viel von einem Bild, die Breite, die wir noch übersetzen müssen nach dem ziehen. Wir lösen können, dass in einem ziemlich einfache Art und Weise durch die Einführung eines Faktors f, die wir auch als CSS-Variablen, um uns zu helfen berechnen die eigentliche animation Dauer:

.glatte { transition: transform calc(var (- f, 1)*.5s), ease-out; }

In der JavaScript-bekommen wir ein Bild, Breite (aktualisiert auf “Größe ändern”) und berechnen Sie für das, was Bruchteil davon haben wir gezogen, horizontal:

lassen w;

Funktion size() { w = window.innerWidth };

die Funktion bewegen(e) {
wenn(gesperrt) {
lassen dx = unify(e).clientX – x0, s = Math.sign(dx),
f = +(s*dx/w).toFixed(2);

if((i > 0 || s < 0) && (i < N – 1 || s > 0)) {
_C.Stil.setProperty(‘–i’ i -= s);
f = 1 – f
}

_C.Stil.setProperty(‘–tx’, ‘0px’);
_C.Stil.setProperty(‘–f’, f);
_C.classList.toggle(‘glatt’, !(locked = false));
x0 = null
}
};

size();

addEventListener(‘resize’, size, false);

Dies nun gibt uns ein besseres Ergebnis.

Gehen Sie zurück, wenn nicht genügend ziehen

Lassen Sie uns sagen, dass wir nicht wollen, gehen Sie zum nächsten Bild, wenn wir nur ziehen, ein wenig unterhalb einer bestimmten Schwelle liegen. Denn jetzt, eine 1px Unterschied bei der drag bedeutet, dass wir Voraus auf das nächste Bild und das fühlt sich etwas unnatürlich.

Um dies zu beheben, setzen wir eine Schwelle, bei sagen wir mal 20% von einem Bild Breite:

die Funktion bewegen(e) {
wenn(gesperrt) {
lassen dx = unify(e).clientX – x0, s = Math.sign(dx),
f = +(s*dx/w).toFixed(2);

if((i > 0 || s < 0) && (i < N – 1 || s > 0) && f > .2) {
/* das gleiche wie vorher */
}

/* das gleiche wie vorher */
}
};

Das Ergebnis kann unten gesehen werden:

Wir nur Voraus, um das nächste Bild, wenn wir ziehen genug (live-demo).

Vielleicht einen Bounce?

Dies ist etwas, das ich nicht sicher bin, ob es eine gute Idee war, aber ich war Juckreiz, um zu versuchen, wie dem auch sei: ändern Sie die timing-Funktion, so dass wir die Einführung eines bounce. Nach ein bisschen ziehen an den Griffen auf cubic-bezier.com ich kam mit einem Ergebnis, das schien vielversprechend:

Was unsere gewählten kubischen Bézier-timing-Funktion aussieht im Vergleich zu einer Ebene ease-out.

transition: transform calc(var (- f)*.5s) cubic-bezier(1, 1.59, .61, .74);

Mit einer benutzerdefinierten CSS-timing-Funktion, um die Einführung eines bounce (live-demo).

Wie Über den JavaScript-Weg, Dann?

Wir könnten um so ein besseres Maß an Kontrolle über mehr Natürliche-Gefühl und komplexere Sprünge indem Sie die JavaScript-route für den übergang. Dies würde uns auch Edge-Unterstützung.

Wir beginnen, indem Sie loszuwerden, den übergang und die –tx und –f CSS-Variablen. Dies reduziert unsere Transformation zu dem, was es anfangs war:

transform: translate(calc(var(–i, 0)/var(–n)*-100%));

Der obige code bedeutet auch, –ich nicht unbedingt eine ganze Zahl sein, nicht mehr. Es bleibt zwar noch eine ganze Zahl, während wir ein einzelnes image haben, voll in den Blick, dass das nicht mehr der Fall, während wir ziehen während der Bewegung nach dem auslösen der “touchend” oder “mouseup” – events.

Während wir zum Beispiel haben das erste Bild vollständig anzeigen, –i 0 ist. Wir haben zwar die zweite voll im Blick-ich ist 1. Wenn wir in der Mitte zwischen der ersten und der zweiten, –i ist .5. Wenn wir ein Quartal der ersten drei Quartale des zweiten in Sicht, – ich ist .75.

Wir aktualisieren dann die JavaScript zu ersetzen, die code-Teile, wo waren wir aktualisieren diese CSS-Variablen. Zuerst kümmern wir uns um die lock() Funktion, wo wir Graben ein-und ausschalten der .glatte Klasse und der ziehen () – Funktion, wo wir ersetzen die Aktualisierung der –tx-variable, die wir haben hingeschmissen mit der Aktualisierung-ich, die, wie bereits erwähnt, muss nicht ganzzahlig sein, nicht mehr:

Funktion lock(e) {
x0 = unify(e).clientX;
locked = true
};

function drag(e) {
e.preventDefault();

wenn(gesperrt) {
lassen dx = unify(e).clientX – x0,
f = +(dx/w).toFixed(2);

_C.Stil.setProperty(‘–i’ i – f)
}
};

Bevor wir das update auch die move () – Funktion, führen wir zwei neue Variablen, ini -, und fin. Diese stellen die Initiale Wert legen wir-ich an den Anfang der animation und den letzten Wert setzen wir die gleichen Variablen am Ende der animation. Außerdem erstellen wir eine animation function ani():

lassen Sie ini, fin;

function ani() {};

die Funktion bewegen(e) {
wenn(gesperrt) {
lassen dx = unify(e).clientX – x0,
s = Math.sign(dx),
f = +(s*dx/w).toFixed(2);

ini = i – s*f;

if((i > 0 || s < 0) && (i < N – 1 || s > 0) && f > .2) {
i -= s;
f = 1 – f
}

fin = i;
ani();
x0 = null;
locked = false;
}
};

Dies ist nicht viel anders als der code, den wir vorher hatten. Was sich geändert hat, ist, dass wir nicht die Einstellung irgendein CSS-Variablen in dieser Funktion mehr, sondern stattdessen stellen Sie die ini-und die fin JavaScript-Variablen und rufen Sie die animation ani () – Funktion.

ini ist der erste Wert, den wir-ich, um an den Anfang der animation, dass der “touchend”/ “mouseup” – Ereignis auslöst. Dies wird durch die aktuelle position, die wir haben, wenn eines dieser beiden Ereignisse feuert.

fin ist der Letzte Wert, den wir-ich, um am Ende die gleiche animation. Dies ist immer ein integer-Wert, da wir am Ende immer mit einem Bild voll in Sichtweite, so fin –und ich sind der index des Bildes. Dies ist das nächste Bild in die gewünschte Richtung, wenn wir schleppen genug (f > .2) und wenn es ein Nächstes Bild in die gewünschte Richtung ((i > 0 || s < 0) && (i < N – 1 || s > 0)). In diesem Fall werden wir das update auch die JavaScript-variable speichern die aktuelle image-index (i) und den relativen Abstand (f). Ansonsten ist es das gleiche Bild, so dass ich und f müssen nicht aktualisiert werden.

Nun, lassen Sie uns bewegen auf der ani () – Funktion. Wir beginnen mit einer vereinfachten linearen version, lässt sich die Richtung ändert.

const NF = 30;

lassen rID = null;

Funktion stopAni() {
cancelAnimationFrame(rID);
rID = null
};

Funktion ani(cf = 0) {
_C.Stil.setProperty(‘–i’ ini + (fin – ini)*cf – /NF);

if(vgl === NF) {
stopAni();
zurück
}

rID = requestAnimationFrame(ani.bind(this, ++cf))
};

Der main Idee ist hier, dass der übergang zwischen den ursprünglichen Wert, ini-und die Finale fin geschieht über eine Gesamtzahl von frames NF. Jedes mal, wenn wir rufen die ani () – Funktion, berechnen wir den Fortschritt als das Verhältnis zwischen dem aktuellen frame index cf und die Gesamtanzahl der frames NF. Dies ist immer eine Zahl zwischen 0 und 1 (oder Sie können es nehmen, wie ein Prozentsatz von 0% bis 100%). Wir verwenden dann diese progress-Wert um den aktuellen Wert –ich, und legen Sie es in das style-Attribut unserer container _C. Wenn wir haben, um den letzten Zustand (der aktuelle frame index cf gleich der Gesamtzahl der frames NF, verlassen wir die Schleife animation). Ansonsten können wir nur erhöhen Sie den aktuellen frame index cf-und Anruf-ani() wieder.

An dieser Stelle haben wir eine funktionierende demo mit einem linearen JavaScript-übergang:

Version mit linearen JavaScript-übergang (live-demo).

Dies hat jedoch das problem, das wir anfangs hatten, in der CSS-Fall: unabhängig von der Entfernung, haben wir die reibungslose Umsetzung unserer element über auf release (“touchend” / “mouseup”) und die Dauer ist immer die gleiche, weil wir immer animieren, über die gleiche Anzahl von frames NF.

Wir korrigieren!

Um dies zu tun, führen wir eine weitere variable anf, wo speichern wir die tatsächliche Anzahl der Bilder, die wir verwenden, und deren Wert berechnen wir in der move () – Funktion vor dem Aufruf der animation function ani():

die Funktion bewegen(e) {
wenn(gesperrt) {
lassen dx = unify(e).clientX – x0,
s = Math.sign(dx),
f = +(s*dx/w).toFixed(2);

/* das gleiche wie vorher */

anf = Math.round(f*NF);
ani();

/* das gleiche wie vorher */
}
};

Wir müssen auch ersetzen NF mit anf in der animation function ani():

Funktion ani(cf = 0) {
_C.Stil.setProperty(‘–i’ ini + (fin – ini)*cf/anf);

if(vgl === anf) { /* same as before */ }

/* das gleiche wie vorher */
};

Mit diesen haben wir behoben das Problem mit dem timing!

Version mit linearen JavaScript-übergang bei konstanter Geschwindigkeit (live-demo).

Okay, aber eine lineare timing-Funktion ist nicht allzu spannend.

Wir könnten versuchen, die JavaScript-äquivalenten CSS-timing-Funktionen, wie ease-in, ease-out oder ease-in-out und sehen, wie Sie vergleichen. Ich habe bereits erklärt im detail, wie man diese in den zuvor verlinkten Artikel, so werde ich nicht zu gehen durch diese wieder und legen Sie einfach das Objekt mit allen von Ihnen in den code:

const TFN = {
‘linear’: function(k) { return k },
“ease-in”: Funktion(k, e = 1.675) {
return Math.pow(k, e)
},
“ease-out”: function(k, e = 1.675) {
1 zurück – Math.pow(1 – k, e)
},
“ease-in-out’: function(k) {
zurück .5*(Math.sin((k – .5)*Math.PI) + 1)
}
};

Der k-Wert ist der Fortschritt, das heißt das Verhältnis zwischen dem aktuellen frame index cf und die tatsächliche Anzahl der frames, die der übergang geschieht über anf. Das heißt, wir ändern die ani () – Funktion ein bisschen, wenn wir wollen die Leichtigkeit-out-option, zum Beispiel:

Funktion ani(cf = 0) {
_C.Stil.setProperty(‘–i’ ini + (fin – ini)*TFN [“ease-out”)] (cf/anf));

/* das gleiche wie vorher */
};

Version mit Leichtigkeit-out-JavaScript-übergang (live-demo).

Könnten wir auch machen, die Dinge noch interessanter, indem Sie mit der Art der springenden timing-Funktion, die CSS nicht geben uns. Zum Beispiel etwas wie die illustrierte von der demo unten (klicken zum auslösen einer transition):

Finden Sie den Stift, indem Sie thebabydino (@thebabydino) auf CodePen.

Die Grafik für diesen wäre etwas ähnlich, dass der easeOutBounce timing-Funktion aus easings.net.

Grafische Darstellung des timing-Funktion.

Der Prozess für das erhalten dieser Art von timing-Funktion ist ähnlich der für immer die JavaScript-version der CSS-Leichtigkeit-in-out (auch beschrieben in dem vorher verlinkten Artikel auf die Emulation CSS-timing-Funktionen mit JavaScript).

Wir beginnen mit der Cosinus-Funktion auf [0, 90°] – Intervall (oder [0, π/2] im Bogenmaß), kein bounce, [0, 270°] ([0, 3·π/2]) für 1 bounce, [0, 450°] ([0, 5·π/2]) für 2 springt und so weiter… im Allgemeinen, es ist [0, (n + ½)·180°] – Intervall ([0, (n + ½)·π]) für n springt.

Finden Sie den Stift, indem Sie thebabydino (@thebabydino) auf CodePen.

Die Eingabe dieser cos(k) – Funktion ist in [0, 450°] – Intervall, während dessen Ausgabe in das [-1, 1] – Intervall. Aber was wir wollen, ist eine Funktion, deren Domäne [0, 1] – Intervall und dessen codomain ist auch der [0, 1] – Intervall.

Wir beschränken die codomain [0, 1] – Intervall, indem nur der absolute Wert |cos(k)|:

Finden Sie den Stift, indem Sie thebabydino (@thebabydino) auf CodePen.

Zwar bekamen wir das Intervall wollten wir für die codomain, wollen wir den Wert dieser Funktion bei 0 zu 0 und die Wert am anderen Ende des Intervalls werden 1. Derzeit ist es anders herum, aber wir können dieses Problem beheben, wenn wir die änderung unserer Funktion 1 |cos(k)|:

Finden Sie den Stift, indem Sie thebabydino (@thebabydino) auf CodePen.

Jetzt bewegen wir uns auf die Einschränkung der Domäne, aus der [0, (n + ½)·180°] Intervall [0, 1] – Intervall. Um dies zu tun, ändern wir unsere Funktion 1 – |cos(k·(n + ½)·180°)|:

Finden Sie den Stift, indem Sie thebabydino (@thebabydino) auf CodePen.

Dies gibt uns die gewünschte domain und codomain, aber wir haben immer noch einige Probleme.

Zuerst werden alle unsere prallt die gleiche Höhe haben, aber wir wollen, dass Ihre Höhe zu verringern, wie k steigt von 0 auf 1. Unser fix ist in diesem Fall, multiplizieren Sie den Cosinus mit 1 – k (oder mit einer power von 1 – k für eine nicht-lineare Abnahme in der amplitude). Die interaktive demo an, unten zeigt, wie dieser amplitude ändert sich für verschiedene Exponenten ein, und wie diese Einflüsse die Funktion, die wir bisher haben:

Finden Sie den Stift, indem Sie thebabydino (@thebabydino) auf CodePen.

Zweitens, werden alle unzustellbaren nehmen Sie die gleiche Menge an Zeit, auch wenn Ihre Amplituden zu halten abnimmt. Die erste Idee ist es, zu einer Kraft k im inneren der Cosinus-Funktion statt nur k. Dieser schafft es, dass Dinge seltsam, wie der Cosinus nicht auf 0, in gleichen Abständen mehr, was bedeutet, wir bekommen nicht immer, dass f(1) = 1 nicht mehr das ist, was wir eigentlich immer brauchen, von einem timing-Funktion, die wir sind eigentlich Los, um zu verwenden. Jedoch für so etwas wie a = 2.75, n = 3 und b = 1.5, so erhalten wir ein Ergebnis, das aussieht befriedigend, also werden wir es dabei belassen, dass, obwohl es könnte optimiert werden für eine bessere Kontrolle:

Die timing-Funktion, die wir wollen, um zu versuchen.

Dies ist die Funktion, die wir versuchen in die JavaScript-wenn wir wollen, einige Prellen zu passieren.

const TFN = {
/* die andere Funktion hatten wir vor */
‘bounce-out’: function(k, n = 3, a = 2.75, b = 1.5) {
1 zurück – Math.pow(1 – k)*Math.abs(Math.cos(Math.pow(k, b)*(n + .5)*Math.PI))
}
};

Hmm, scheint ein wenig zu extrem in der Praxis:

Version mit einem hüpfenden JavaScript-übergang (live-demo).

Vielleicht könnten wir n hängt von der Menge der übersetzung, die wir noch durchführen müssen, ab dem Augenblick der Veröffentlichung. Wir machen es in eine variable, welche wir legen Sie dann in der move () – Funktion vor dem Aufruf der animation function ani():

const TFN = {
/* die andere Funktion hatten wir vor */
‘bounce-out’: function(k, a = 2.75, b = 1.5) {
1 zurück – Math.pow(1 – k)*Math.abs(Math.cos(Math.pow(k, b)*(n + .5)*Math.PI))
}
};

var n;

die Funktion bewegen(e) {
wenn(gesperrt) {
lassen dx = unify(e).clientX – x0,
s = Math.sign(dx),
f = +(s*dx/w).toFixed(2);

/* das gleiche wie vorher */

n = 2 + Math.Runde(f)
ani();
/* das gleiche wie vorher */
}
};

Dies gibt uns unser abschließendes Resultat:

Version mit dem letzten Prellen JavaScript-übergang (live-demo).

Es gibt definitiv noch Raum für Verbesserungen, aber ich habe kein Gefühl dafür, was macht eine gute animation, also werde ich es belassen. Wie es ist, ist dies nun funktionale cross-browser (ohne irgendwelche der Rand Probleme, die version mit einem CSS-übergang) und ziemlich flexibel.