Enkelt Sveip Med Vanilje JavaScript

0
13

Jeg pleide å tenke at implementering av dra-bevegelser måtte være veldig vanskelig, men jeg har nylig funnet meg selv i en situasjon hvor jeg måtte gjøre det og oppdaget at virkeligheten er ikke på langt nær så dyster som jeg hadde forestilt meg.

Denne artikkelen kommer til å ta deg, trinn for trinn, ved å gjennomføre med minst mengden av kode som jeg kan komme opp med. Så, la oss hoppe rett inn i det!

HTML-Strukturen

Vi starter med en .beholderen har en haug av bilder innvendig:

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

</div>

Grunnleggende Stiler

Vi bruker vise: flex-å sørge for at bilder går ved siden av hverandre uten mellomrom i mellom. juster-elementer: senter midt-justerer dem vertikalt. Vi gjør både bilder og beholderen ta bredden av beholderen morselskap (kroppen i vårt tilfelle).

.beholder {
skjerm: flex;
juster-elementer: center;
bredde: 100%;

img {
min-width: 100%; /* nødvendig, slik at Firefox ikke gjøre img krympe for å passe */
bredde: 100%; /* kan ikke ta dette ut, enten som det bryter Krom */
}
}

Det faktum at både den .container og sine barn bildene har samme bredde som gjør disse bildene trekkjer ut på høyre side (som markert med rødt omriss) opprette en vannrette rullefeltet, men dette er nettopp hva vi ønsker:

Den opprinnelige layout (se live-demo).

Gitt at ikke alle bilder som har samme dimensjoner og aspekt ratio, vi har litt hvitt plass over og under noen av dem. Så, vi kommer til å trimme at ved å gi .beholder en eksplisitt høyde for at det skal ganske mye arbeid for den gjennomsnittlige sideforhold på disse bildene og sette overflow-y for å skjult:

.beholder {
/* samme som før */
overflow-y: hidden;
høyde: 50vw;
maks høyde: 100vh;
}

Resultatet kan sees nedenfor, med alle bildene som er justert til samme høyde og ingen tomme områder lenger:

Resultatet etter bildene er beskåret av overflow-y på .beholder (se live-demo).

Ok, men nå har vi en vannrette rullefeltet på .beholder selv. Vel, det er faktisk en god ting for ingen JavaScript tilfelle.

Ellers kan vi lage et CSS-variabel –n for antall bilder, og vi bruker dette for å gjøre .beholder bredt nok til å holde alle sine bildet barn som fortsatt har samme bredde som sin overordnede (kroppen i dette tilfellet):

.beholder {
–n: 1;
bredde: 100%;
bredde: calc(var(–n)*100%);

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

Vær oppmerksom på at vi holder den forrige bredde erklæringer som fallbacks. Calc() verdier vil ikke endre en ting før vi setter –n fra JavaScript etter å få våre .container og antall barn bilder det holder:

const _C = – dokument.querySelector(‘.container’),
N = _C.barn.lengde;

_C.stil.setProperty(‘–n’, N)

Nå er vår .beholderen har blitt utvidet til å passe alle bildene innvendig:

Layout med utvidet container (live demo).

Bytte Bilder

Neste, vi bli kvitt den vannrette rullefeltet ved å sette overløp-x: skjult på våre container morselskap (kroppen i vårt tilfelle), og vi lager en annen CSS-variabel som holder indeksen for den valgte bildet (–). Vi bruker denne til riktig posisjon .container med hensyn til viewport via en oversettelse (husk at % – verdier inne oversette() funksjoner i forhold til dimensjonene på elementet vi har satt denne forandre på):

body { overløp-x: hidden }

.beholder {
/* samme stiler som før */
forvandle: translate(calc(var(–jeg, 0)/var(–n)*-100%));
}

Endre –jeg til et annet heltall større eller lik null, men mindre enn –n, gir et annet bilde i visningen, illustrert med interaktiv demo nedenfor (der verdien av –jeg er kontrollert av en rekke inngang):

Se Pennen av thebabydino (@thebabydino) på CodePen.

Alright, men vi ønsker ikke å bruke en glidebryter for å gjøre dette.

Den grunnleggende ideen er at vi kommer til å oppdage retning av bevegelse mellom “touchstart” (eller “mousedown”) hendelse og “touchend” (eller “mouseup”), og deretter update-jeg derfor å flytte beholderen slik at den neste bilde (bilder) (hvis det finnes) i ønsket retning beveger seg inn i vinduet.

function lock(e) {};

funksjon flytt(e) {};

_C.addEventListener(‘mousedown’, lås, false);
_C.addEventListener(‘touchstart’, lås, false);

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

Merk at dette kun vil arbeide for mus hvis vi setter pointer-aktiviteter: ingen på bilder.

.beholder {
/* samme stiler som før */

img {
/* samme stiler som før */
peker-aktiviteter: ingen;
}
}

Også, Edge behov for å ha kontakt hendelser aktivert fra om:flagg som dette alternativet er deaktivert som standard:

Aktivering trykk på hendelser i Kanten.

Før vi fylle ut låsen() og flytte() funksjoner, vi forene trykk på og klikk tilfeller:

funksjonen forene(e) { return e.changedTouches ? e.changedTouches[0] : e };

Låsing på “touchstart” (eller “mousedown”) betyr å få og lagre x-koordinaten til et innledende koordinering variabel x0:

la x0 = null;

function lock(e) { x0 = forene(e).clientX };

For å se hvordan til å flytte vår .beholder (eller hvis vi gjør det fordi vi ikke ønsker å gå videre når vi har nådd slutten), kan vi sjekke om vi har utført låsen() handling, og hvis vi har, kan vi lese gjeldende x-koordinaten, beregne forskjellen mellom det og x0 og løse hva de skal gjøre ut av dens tegn og gjeldende indeks:

la i = 0;

funksjon flytt(e) {
hvis(x0 || x0 === 0) {
la dx = forene(e).clientX – x0, s = Matematikk.logg(dx);

if((i > 0 || s < 0) && (i < N – 1 || s > 0))
_C.stil.setProperty (‘–‘, – = s);

x0 = null
}
};

Resultatet på å dra til venstre/ høyre kan sees nedenfor:

Veksling mellom bilder på sveip (live demo). Forsøk på å flytte til høyre på første bilde eller venstre på siste gjøre noe, så vi har ingen andre bilde før eller etter, henholdsvis.

Ovenfor er det forventede resultat, og resultatet får vi i Chrome for en liten bit av dra og Firefox. Imidlertid, Edge går frem og tilbake når vi drar du til venstre eller høyre, som er noe som Chrome også gjør det på en litt mer dra.

Kant navigere i sidevisning bakover eller fremover på venstre eller høyre sveip.

For å overstyre dette, må vi legge en “touchmove” event lytteren:

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

Alright, nå har vi noe funksjonell i alle nettlesere, men det ser ikke ut som det vi egentlig etter… ennå!

Jevn Bevegelse

Den enkleste måten å bevege seg mot å få det vi ønsker, er ved å legge til en overgang:

.beholder {
/* samme stiler som før */
overgang: transform .5s letthet-outl
}

Og her er det, et veldig enkelt sveip i kraft i ca 25 linjer med JavaScript og ca 25 linjer av CSS:

Arbeider sveip effekt (live demo).

Dessverre, det er en Kant bug som gjør en overgang til en CSS-variabel-avhengig calc() oversettelse mislykkes. Æsj, jeg tror vi har å glemme Kant for nå.

Raffinering Hele Greia

Med alle de kule sveip virkninger ut det, hva har vi så langt ikke helt klippe det, så la oss se på hvilke forbedringer som kan gjøres.

Bedre Visuelle Signaler Mens Du Drar

First off, skjer det ingenting, mens vi drar, all handling følger “touchend” (eller “mouseup”) event. Så, mens vi drar, vi har ingen indikasjon på hva som kommer til å skje neste. Er det en neste bilde for å slå til i ønsket retning? Eller har vi kommet til slutten av linjen, og ingenting vil skje?

For å ta vare på det, vi justere oversettelse mengden litt ved å legge til en CSS-variabel –tx-det er opprinnelig 0px:

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

Vi bruker to event lyttere: én for “touchmove” og en annen for “mousemove”. Vær oppmerksom på at vi allerede var å hindre bakover og fremover navigasjon i Chrome ved hjelp av “touchmove” listener:

funksjonen dra(e) { e.preventDefault() };

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

Nå la oss fylle dra () – funksjonen! Hvis vi har utført låsen() handling, vi lese gjeldende x-koordinaten, beregne forskjellen dx mellom denne koordinere og den første en x0 og sette –tx til denne verdien (som er en piksel-verdi).

funksjonen dra(e) {
e.preventDefault();

hvis(x0 || x0 === 0)
_C.stil.setProperty(‘–tx’, `${Math.runde(forene(e).clientX – x0)}px`)
};

Vi må også sørge for å tilbakestille –tx 0px på slutten og fjerne overgang for varigheten av dra. For å gjøre dette enklere, vi flytter overgang erklæring på en .jevn klasse:

.glatt { overgang: transform .5s letthet-ut; }

I låsen () – funksjonen, fjerner vi denne klassen fra .beholder (vi vil legge den igjen på slutten på “touchend” og “mouseup”) og også satt opp en låst boolsk variabel, slik at vi ikke trenger å holde utføre x0 || x0 === 0 sjekk. Så bruker vi den låst variabel for undersøkelsen i stedet:

la låst = false;

function lock(e) {
x0 = forene(e).clientX;
_C.classList.veksle(‘glatt’, !(låst = true))
};

funksjonen dra(e) {
e.preventDefault();
hvis(låst) { /* samme som før */ }
};

funksjon flytt(e) {
hvis(låst) {
la dx = forene(e).clientX – x0, s = Matematikk.logg(dx);

if((i > 0 || s < 0) && (i < N – 1 || s > 0))
_C.stil.setProperty (‘–‘, – = s);
_C.stil.setProperty(‘–tx’, ‘0px’);
_C.classList.veksle(‘glatt’, !(låst = false));
x0 = null
}
};

Resultatet kan sees nedenfor. Mens vi holder fortsatt på å dra, vi har nå en visuell indikasjon på hva som kommer til å skje neste:

Sveip med visuelle signaler mens du drar (live demo).

Fikse overgangen-varighet

På dette punktet, vi er alltid ved hjelp av den samme overgangen-varighet uansett hvor mye av en bildets bredde vi har fortsatt å oversette etter å dra. Vi kan fikse det på en ganske grei måte, ved å innføre en faktor f, som vi også sett som en CSS-variabelen til å hjelpe oss med å beregne den faktiske animasjon varighet:

.glatt { overgang: forvandle calc(var(–f, 1)*.5s) letthet-ut; }

I JavaScript, får vi et bilde bredde (oppdatert på “endre størrelse”) og beregne for hva brøkdel av dette har vi dratt horisontalt:

la w;

funksjonen size() { b = – vinduet.innerWidth };

funksjon flytt(e) {
hvis(låst) {
la dx = forene(e).clientX – x0, s = Matematikk.logg(dx),
f = +(s*dx/w).toFixed(2);

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

_C.stil.setProperty(‘–tx’, ‘0px’);
_C.stil.setProperty(‘–f’ f);
_C.classList.veksle(‘glatt’, !(låst = false));
x0 = null
}
};

størrelse();

addEventListener(‘resize’, størrelse, false);

Dette får vi nå et bedre resultat.

Gå tilbake hvis nok dra

La oss si at vi ikke ønsker å gå videre til neste bilde hvis vi bare dra litt under en viss terskel. Fordi nå, en 1px forskjell i løpet av de dra betyr at vi avansere til neste bilde, og det føles litt unaturlig.

For å fikse dette, har vi satt en grense på la oss si 20% av et bilde, bredde:

funksjon flytt(e) {
hvis(låst) {
la dx = forene(e).clientX – x0, s = Matematikk.logg(dx),
f = +(s*dx/w).toFixed(2);

if((i > 0 || s < 0) && (i < N – 1 || s > 0) && f > .2) {
/* samme som før */
}

/* samme som før */
}
};

Resultatet kan sees nedenfor:

Vi bare videre til neste bilde hvis vi drar nok (live demo).

Kanskje Legge til en Avvisning?

Dette er noe som jeg ikke er sikker på at var en god ide, men jeg var spent på å prøve likevel: endre timingen funksjon, slik at vi innfører en bounce. Etter en bit av å dra i håndtakene på cubic-bezier.com jeg kom opp med et resultat som virket lovende:

Hva våre utvalgte kubikk Bézier timing funksjonen ser ut som sammenlignet med en vanlig enkel ut.

overgang: forvandle calc(var(–f)*.5s) cubic-bezier – (1, 1.59, .61, .74);

Ved å bruke en egendefinert CSS timing funksjon for å innføre en bounce (live demo).

Hvordan Om JavaScript Måte, Da?

Vi kunne oppnå en bedre grad av kontroll over mer naturlig følelse og mer komplekse spretter ved å ta JavaScript rute for overgangen. Dette vil også gi oss Edge-støtte.

Vi starter med å bli kvitt overgangen og –tx og –f CSS variabler. Dette reduserer vår forvandle seg til hva det var i utgangspunktet:

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

Koden ovenfor betyr også-jeg vil ikke nødvendigvis være et problem lenger. Mens det fortsatt er et heltall, mens vi har et enkelt bilde fullt til syne, det er ikke tilfelle lenger, mens vi dra eller under bevegelse etter utløsende “touchend” eller “mouseup” hendelser.

For eksempel, selv om vi har det første bildet fullt i utsikt, –jeg er 0. Mens vi har den andre en fullt i utsikt, –jeg er 1. Når vi er midt mellom den første og den andre, –jeg er .5. Når vi har en fjerdedel av den første, og tre fjerdedeler av den andre, –jeg er .75.

Vi oppdaterer JavaScript for å erstatte den koden deler der vi var oppdatere disse CSS-variabler. Først skal vi ta vare på låsen () – funksjonen, hvor vi grøft skifte den .jevn klasse og dra () – funksjonen, der vi erstatte oppdatere –tx variable vi har ditched med å oppdatere –jeg, som, som nevnt tidligere, trenger ikke å være et problem lenger:

function lock(e) {
x0 = forene(e).clientX;
låst = true
};

funksjonen dra(e) {
e.preventDefault();

hvis(låst) {
la dx = forene(e).clientX – x0,
f = +(dx/w).toFixed(2);

_C.stil.setProperty (‘–‘, jeg – f)
}
};

Før vi også oppdatere flytte () – funksjonen, introduserer vi to nye variabler, ini og fin. Disse representerer den første verdien vi setter –jeg til på begynnelsen av animasjon og den endelige verdien vi sett den samme variabelen til på slutten av animasjonen. Vi kan også lage en animasjon funksjon ani():

la ini, fin;

funksjonen ani() {};

funksjon flytt(e) {
hvis(låst) {
la dx = forene(e).clientX – x0,
s = Matematikk.logg(dx),
f = +(s*dx/w).toFixed(2);

ini = i – s*f;

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

fin = i;
ani();
x0 = null;
låst = false;
}
};

Dette er ikke så forskjellig fra den koden vi hadde før. Hva har endret seg er at vi ikke sette noen CSS variabler i denne funksjonen lenger, men i stedet satt ini og fin JavaScript variabler og ringe animasjon ani () – funksjonen.

ini er den opprinnelige verdien vi setter –jeg til på begynnelsen av animasjon som “touchend”/ “mouseup” hendelse utløser. Denne er gitt ved den aktuelle posisjonen vi har når en av disse to hendelsene branner.

fin er den endelige verdien vi setter –jeg til på slutten av samme animasjon. Dette er alltid et heltall fordi vi alltid avslutte med et bilde fullt til syne, så fin og-jeg er indeksen for at bildet. Dette er det neste bildet i ønsket retning hvis vi dro nok (f > .2) og hvis det er det neste bildet i ønsket retning ((i > 0 || s < 0) && (i < N – 1 || s > 0)). I dette tilfellet, kan vi også oppdatere JavaScript-variabel lagre gjeldende bilde, indeks (jeg) og den relative avstanden til det (f). Ellers er det det samme bildet, så jeg og f ikke trenger å bli oppdatert.

Nå, la oss gå videre til ani () – funksjonen. Vi starter med en enkel lineær versjon som etterlater seg en endring av retning.

const NF = 30;

la rID = null;

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

funksjonen ani(jf = 0) {
_C.stil.setProperty (‘–‘, ini + (fin – ini)*cf/NF);

hvis(jf === NF) {
stopAni();
tilbake
}

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

Hovedideen her er at overgangen mellom den opprinnelige verdien ini-og endelig en fin skjer over totalt antall bilder NF. Hver gang vi kaller ani () – funksjonen, kan vi beregne den fremgang som forholdet mellom gjeldende ramme indeks cf og totalt antall bilder NF. Dette er alltid et tall mellom 0 og 1 (eller du kan ta det som en prosentandel, som går fra 0% til 100%). Vi bruker denne fremgangen verdi å få den aktuelle verdien av –jeg og sette den i stil-attributt av våre container _C. Hvis vi fikk til den endelige tilstand (gjeldende ramme indeks jf tilsvarer det totale antallet bilder som skal NF, vi avslutte animasjon loop). Ellers er vi bare tilvekst gjeldende ramme indeks cf og samtale ani() igjen.

På dette punktet, vi har en fungerende demo med en lineær JavaScript overgangen:

Versjonen med lineær JavaScript-overgang (live demo).

Dette har imidlertid problemet at vi opprinnelig hadde i CSS sak: uansett avstand, vi må ha et jevnt oversette våre element på utslipp (“touchend” / “mouseup”), og varigheten er alltid den samme, fordi vi alltid animere over samme antall rammer NF.

La oss fikse det!

For å gjøre dette, vi introdusere en annen variabel anf hvor vi lagrer den faktiske antallet bilder som vi bruker og som har en verdi som vi beregner i farten () – funksjonen, før du ringer animasjonen funksjon ani():

funksjon flytt(e) {
hvis(låst) {
la dx = forene(e).clientX – x0,
s = Matematikk.logg(dx),
f = +(s*dx/w).toFixed(2);

/* samme som før */

anf = Matematikk.runde(f*NF);
ani();

/* samme som før */
}
};

Vi trenger også å erstatte NF med anf i animasjon-funksjonen ani():

funksjonen ani(jf = 0) {
_C.stil.setProperty (‘–‘, ini + (fin – ini)*cf/anf);

hvis(jf === anf) { /* samme som før */ }

/* samme som før */
};

Med dette, vi har fast timing problemet!

Versjonen med lineær JavaScript overgang ved konstant hastighet (live demo).

Alright, men en lineær timing funksjonen er ikke så spennende.

Vi kunne prøve JavaScript-ekvivalenter av CSS timing funksjoner som lette, lette ut, eller letthet-i-ut og se hvordan de kan sammenlignes. Jeg har allerede forklart i en masse detaljer hvordan å komme disse i tidligere knyttet artikkelen, så jeg kommer ikke til å gå gjennom det igjen og bare slipp den-objekt med alle av dem inn koden:

const TFN = {
‘lineær’: function(k) { return k },
‘letthet-i’: function(k, e = 1.675) {
tilbake Matematikk.pow(k, e)
},
‘letthet-out”: function(k, e = 1.675) {
avkastning 1 – Matematikk.pow(1 – k, e)
},
‘letthet-i-ut’: function(k) {
tilbake .5*(Matematikk.synd((k – .5)*Matematikk.PI) + 1)
}
};

K-verdien er fremgang, noe som er forholdet mellom gjeldende ramme indeks cf og det faktiske antallet bilder som overgangen skjer over anf. Dette betyr at vi vil endre ani () – funksjonen litt på om vi ønsker å bruke det lette- / utsjekking tjeneste, for eksempel:

funksjonen ani(jf = 0) {
_C.stil.setProperty (‘–‘, ini + (fin – ini)*TFN[‘letthet-out’](cf/anf));

/* samme som før */
};

Versjonen med letthet-ut JavaScript-overgang (live demo).

Vi kan også gjøre ting mer interessant ved hjelp av den slags hoppende timing funksjon som CSS kan ikke gi oss. For eksempel, noe som er illustrert ved den demo nedenfor (klikk for å utløse en overgang):

Se Pennen av thebabydino (@thebabydino) på CodePen.

Grafikken for dette ville være noe som ligner på den som easeOutBounce timing funksjon fra easings.net.

Grafisk fremstilling av timing funksjon.

Prosessen for å få denne form for timing funksjonen er lik som for å få JavaScript versjon av CSS letthet-i-ut (igjen, som beskrevet i tidligere knyttet artikkelen på simulere CSS timing funksjoner med JavaScript).

Vi starter med cosinus-funksjonen på [0, 90°] – intervallet (eller [0, π/2] i radianer) for ikke sprette, [0, 270°] ([0, 3·π/2]) for 1 sprette, [0, 450°] ([0, 5·π/2]) for 2 spretter og så videre… generelt det er [0, (n + ½)·180°] – intervallet ([0, (n + ½)·π]) for n spretter.

Se Pennen av thebabydino (@thebabydino) på CodePen.

Input av dette cos(k) – funksjonen er i [0, 450°] – intervallet, mens produksjonen er i [-1, 1] – intervallet. Men det vi ønsker er en funksjon som domene er [0, 1] – intervallet og som codomain er også [0, 1] – intervallet.

Vi kan begrense codomain [0, 1] intervall ved bare å ta den absolutte verdien |cos(k)|:

Se Pennen av thebabydino (@thebabydino) på CodePen.

Mens vi fikk det intervallet vi ønsket for codomain, vi vil verdien av denne funksjonen på 0 for å være 0 og verdien i den andre enden av intervallet til å være 1. For tiden, det er den andre veien rundt, men vi kan fikse dette hvis vi endrer vår funksjon til 1 – |cos(k)|:

Se Pennen av thebabydino (@thebabydino) på CodePen.

Nå kan vi gå videre til å begrense domene fra [0, (n + ½)·180°] intervallet [0, 1] – intervallet. For å gjøre dette, endrer vi vår funksjon å være 1 – |cos(k·(n + ½)·180°)|:

Se Pennen av thebabydino (@thebabydino) på CodePen.

Dette gir oss både ønsket domene og codomain, men vi har fortsatt noen problemer.

Først av alt, for alle våre spretter har samme høyde, men vi ønsker at deres høyde for å redusere som k øker fra 0 til 1. Våre fastsette i dette tilfellet er å multiplisere cosinus med 1 – k (eller med en kraft på 1 – k for en ikke-lineær nedgang i amplitude). Interaktiv demo nedenfor viser hvordan dette amplitude endringer for ulike eksponenter en, og hvordan dette påvirker funksjonen vi har så langt:

Se Pennen av thebabydino (@thebabydino) på CodePen.

For det andre, alle spretter ta like lang tid, selv om deres amplituder holde synkende. Den første ideen her er å bruke en strøm av k inne i cosinus-funksjonen i stedet for bare k. Denne klarer å gjøre rare ting som cosinus ikke treffer 0 ved like intervaller lenger, betyr at vi ikke alltid får at f(1) = 1 lenger som er hva vi vil alltid trenger fra en timing funksjon vi faktisk kommer til å bruke. Imidlertid, for noe sånt som en = 2.75, n = 3 og b = 1.5, får vi et resultat som ser ut tilfredsstillende, så vi får la det bli med det, selv om det kan bli forskjøvet for bedre kontroll:

Timingen funksjon vi ønsker å prøve.

Dette er den funksjonen vi prøver ut i JavaScript-hvis vi ønsker noen hoppende å skje.

const TFN = {
/* den andre funksjonen vi hadde før */
‘sprette ut”: function(k, n = 3, a = 2.75, b = 1.5) {
avkastning 1 – Matematikk.pow(1 – k, a)*Matematikk.abs(Matematikk.cos(Matematikk.pow(k, b)*(n + .5)*Matematikk.PI))
}
};

Hmm, virker litt for ekstrem i praksis:

Versjon med en hoppende JavaScript-overgang (live demo).

Kanskje vi kunne gjøre n avhenger av mengden av oversettelse, trenger vi fremdeles å utføre fra det øyeblikket av utgivelsen. Vi gjør det i en variabel som vi deretter sette i farten () – funksjonen før du ringer animasjonen funksjon ani():

const TFN = {
/* den andre funksjonen vi hadde før */
‘sprette ut”: function(k, a = 2.75, b = 1.5) {
avkastning 1 – Matematikk.pow(1 – k, a)*Matematikk.abs(Matematikk.cos(Matematikk.pow(k, b)*(n + .5)*Matematikk.PI))
}
};

var n;

funksjon flytt(e) {
hvis(låst) {
la dx = forene(e).clientX – x0,
s = Matematikk.logg(dx),
f = +(s*dx/w).toFixed(2);

/* samme som før */

n = 2 + Matematikk.runde(f)
ani();
/* samme som før */
}
};

Dette gir oss det endelige resultatet:

Versjonen med den endelige hoppende JavaScript-overgang (live demo).

Det er definitivt fortsatt rom for forbedringer, men jeg kan ikke ha en følelse for hva som gjør en god animasjon, så jeg skal bare la det bli med det. Som det er, dette er nå funksjonell kryss-nettleser (uten å ha noen av Kanten problemer som den versjonen ved å bruke en CSS-overgangen har) og ganske fleksibel.