Spring easing functions

pull/5579/head
Adam Rackis 5 years ago
parent 65104e8b2a
commit 216ba82e8a

@ -1,3 +1,5 @@
import { springFrames } from "svelte/motion";
/* /*
Adapted from https://github.com/mattdesl Adapted from https://github.com/mattdesl
Distributed under MIT License https://github.com/mattdesl/eases/blob/master/LICENSE.md Distributed under MIT License https://github.com/mattdesl/eases/blob/master/LICENSE.md
@ -169,3 +171,35 @@ export function sineIn(t: number) {
export function sineOut(t: number) { export function sineOut(t: number) {
return Math.sin((t * Math.PI) / 2); return Math.sin((t * Math.PI) / 2);
} }
const springEasing = (frames, inDirection = true) => t => {
t = inDirection ? t : 1 - t;
const indexPrecise = t * frames.length;
const indexExcess = indexPrecise % 1;
const a = frames[indexPrecise - indexExcess];
let b = frames[indexPrecise - indexExcess + 1];
if (b == null) {
b = a;
}
return indexExcess ? a + (b - a) * indexExcess : a;
};
export function springEnter(from, to, opts) {
const frames = springFrames(from, to, opts);
return {
duration: (frames.length * 1000) / 60,
easing: springEasing(frames)
};
}
export function springLeave(from, to, opts) {
const frames = springFrames(from, to, opts);
return {
duration: (frames.length * 1000) / 60,
easing: springEasing(frames, false)
};
}

@ -2,14 +2,41 @@ import { Readable, writable } from 'svelte/store';
import { loop, now, Task } from 'svelte/internal'; import { loop, now, Task } from 'svelte/internal';
import { is_date } from './utils'; import { is_date } from './utils';
interface TickContext<T> { interface TickContext {
inv_mass: number; inv_mass: number;
dt: number; dt: number;
opts: Spring<T>; opts: SpringOpts;
settled: boolean; settled: boolean;
} }
function tick_spring<T>(ctx: TickContext<T>, last_value: T, current_value: T, target_value: T): T { export function springFrames(from, to, opts: SpringOpts) {
Object.assign(opts, { stiffness: 0.15, damping: 0.8, precision: 0.01 });
let value = from;
let last_val = from;
let dt = 0.25; //WTF???
const values = [from];
let ctx: TickContext;
do {
ctx = {
inv_mass: 1,
opts,
settled: true,
dt,
};
const next_value = tick_spring(ctx, last_val, value, to);
values.push(next_value);
last_val = value;
value = next_value;
dt = 1;
} while (!ctx.settled);
return values;
}
function tick_spring<T>(ctx: TickContext, last_value: T, current_value: T, target_value: T): T {
if (typeof current_value === 'number' || is_date(current_value)) { if (typeof current_value === 'number' || is_date(current_value)) {
// @ts-ignore // @ts-ignore
const delta = target_value - current_value; const delta = target_value - current_value;
@ -109,7 +136,7 @@ export function spring<T=any>(value?: T, opts: SpringOpts = {}): Spring<T> {
inv_mass = Math.min(inv_mass + inv_mass_recovery_rate, 1); inv_mass = Math.min(inv_mass + inv_mass_recovery_rate, 1);
const ctx: TickContext<T> = { const ctx: TickContext = {
inv_mass, inv_mass,
opts: spring, opts: spring,
settled: true, // tick_spring may signal false settled: true, // tick_spring may signal false

Loading…
Cancel
Save