1/5/1404
This commit is contained in:
+19
@@ -0,0 +1,19 @@
|
||||
function decay({ velocity = 0, from = 0, power = 0.8, timeConstant = 350, restDelta = 0.5, modifyTarget, }) {
|
||||
const state = { done: false, value: from };
|
||||
let amplitude = power * velocity;
|
||||
const ideal = from + amplitude;
|
||||
const target = modifyTarget === undefined ? ideal : modifyTarget(ideal);
|
||||
if (target !== ideal)
|
||||
amplitude = target - from;
|
||||
return {
|
||||
next: (t) => {
|
||||
const delta = -amplitude * Math.exp(-t / timeConstant);
|
||||
state.done = !(delta > restDelta || delta < -restDelta);
|
||||
state.value = state.done ? target : target + delta;
|
||||
return state;
|
||||
},
|
||||
flipTarget: () => { },
|
||||
};
|
||||
}
|
||||
|
||||
export { decay };
|
||||
Generated
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
import { interpolate } from '../../utils/interpolate.mjs';
|
||||
import { easeInOut } from '../../easing/index.mjs';
|
||||
|
||||
function defaultEasing(values, easing) {
|
||||
return values.map(() => easing || easeInOut).splice(0, values.length - 1);
|
||||
}
|
||||
function defaultOffset(values) {
|
||||
const numValues = values.length;
|
||||
return values.map((_value, i) => i !== 0 ? i / (numValues - 1) : 0);
|
||||
}
|
||||
function convertOffsetToTimes(offset, duration) {
|
||||
return offset.map((o) => o * duration);
|
||||
}
|
||||
function keyframes({ from = 0, to = 1, ease, offset, duration = 300, }) {
|
||||
const state = { done: false, value: from };
|
||||
const values = Array.isArray(to) ? to : [from, to];
|
||||
const times = convertOffsetToTimes(offset && offset.length === values.length
|
||||
? offset
|
||||
: defaultOffset(values), duration);
|
||||
function createInterpolator() {
|
||||
return interpolate(times, values, {
|
||||
ease: Array.isArray(ease) ? ease : defaultEasing(values, ease),
|
||||
});
|
||||
}
|
||||
let interpolator = createInterpolator();
|
||||
return {
|
||||
next: (t) => {
|
||||
state.value = interpolator(t);
|
||||
state.done = t >= duration;
|
||||
return state;
|
||||
},
|
||||
flipTarget: () => {
|
||||
values.reverse();
|
||||
interpolator = createInterpolator();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export { convertOffsetToTimes, defaultEasing, defaultOffset, keyframes };
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
import { __rest } from 'tslib';
|
||||
import { findSpring, calcAngularFreq } from '../utils/find-spring.mjs';
|
||||
|
||||
const durationKeys = ["duration", "bounce"];
|
||||
const physicsKeys = ["stiffness", "damping", "mass"];
|
||||
function isSpringType(options, keys) {
|
||||
return keys.some((key) => options[key] !== undefined);
|
||||
}
|
||||
function getSpringOptions(options) {
|
||||
let springOptions = Object.assign({ velocity: 0.0, stiffness: 100, damping: 10, mass: 1.0, isResolvedFromDuration: false }, options);
|
||||
if (!isSpringType(options, physicsKeys) &&
|
||||
isSpringType(options, durationKeys)) {
|
||||
const derived = findSpring(options);
|
||||
springOptions = Object.assign(Object.assign(Object.assign({}, springOptions), derived), { velocity: 0.0, mass: 1.0 });
|
||||
springOptions.isResolvedFromDuration = true;
|
||||
}
|
||||
return springOptions;
|
||||
}
|
||||
function spring(_a) {
|
||||
var { from = 0.0, to = 1.0, restSpeed = 2, restDelta } = _a, options = __rest(_a, ["from", "to", "restSpeed", "restDelta"]);
|
||||
const state = { done: false, value: from };
|
||||
let { stiffness, damping, mass, velocity, duration, isResolvedFromDuration, } = getSpringOptions(options);
|
||||
let resolveSpring = zero;
|
||||
let resolveVelocity = zero;
|
||||
function createSpring() {
|
||||
const initialVelocity = velocity ? -(velocity / 1000) : 0.0;
|
||||
const initialDelta = to - from;
|
||||
const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
|
||||
const undampedAngularFreq = Math.sqrt(stiffness / mass) / 1000;
|
||||
if (restDelta === undefined) {
|
||||
restDelta = Math.min(Math.abs(to - from) / 100, 0.4);
|
||||
}
|
||||
if (dampingRatio < 1) {
|
||||
const angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio);
|
||||
resolveSpring = (t) => {
|
||||
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
||||
return (to -
|
||||
envelope *
|
||||
(((initialVelocity +
|
||||
dampingRatio * undampedAngularFreq * initialDelta) /
|
||||
angularFreq) *
|
||||
Math.sin(angularFreq * t) +
|
||||
initialDelta * Math.cos(angularFreq * t)));
|
||||
};
|
||||
resolveVelocity = (t) => {
|
||||
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
||||
return (dampingRatio *
|
||||
undampedAngularFreq *
|
||||
envelope *
|
||||
((Math.sin(angularFreq * t) *
|
||||
(initialVelocity +
|
||||
dampingRatio *
|
||||
undampedAngularFreq *
|
||||
initialDelta)) /
|
||||
angularFreq +
|
||||
initialDelta * Math.cos(angularFreq * t)) -
|
||||
envelope *
|
||||
(Math.cos(angularFreq * t) *
|
||||
(initialVelocity +
|
||||
dampingRatio *
|
||||
undampedAngularFreq *
|
||||
initialDelta) -
|
||||
angularFreq *
|
||||
initialDelta *
|
||||
Math.sin(angularFreq * t)));
|
||||
};
|
||||
}
|
||||
else if (dampingRatio === 1) {
|
||||
resolveSpring = (t) => to -
|
||||
Math.exp(-undampedAngularFreq * t) *
|
||||
(initialDelta +
|
||||
(initialVelocity + undampedAngularFreq * initialDelta) *
|
||||
t);
|
||||
}
|
||||
else {
|
||||
const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);
|
||||
resolveSpring = (t) => {
|
||||
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
||||
const freqForT = Math.min(dampedAngularFreq * t, 300);
|
||||
return (to -
|
||||
(envelope *
|
||||
((initialVelocity +
|
||||
dampingRatio * undampedAngularFreq * initialDelta) *
|
||||
Math.sinh(freqForT) +
|
||||
dampedAngularFreq *
|
||||
initialDelta *
|
||||
Math.cosh(freqForT))) /
|
||||
dampedAngularFreq);
|
||||
};
|
||||
}
|
||||
}
|
||||
createSpring();
|
||||
return {
|
||||
next: (t) => {
|
||||
const current = resolveSpring(t);
|
||||
if (!isResolvedFromDuration) {
|
||||
const currentVelocity = resolveVelocity(t) * 1000;
|
||||
const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;
|
||||
const isBelowDisplacementThreshold = Math.abs(to - current) <= restDelta;
|
||||
state.done =
|
||||
isBelowVelocityThreshold && isBelowDisplacementThreshold;
|
||||
}
|
||||
else {
|
||||
state.done = t >= duration;
|
||||
}
|
||||
state.value = state.done ? to : current;
|
||||
return state;
|
||||
},
|
||||
flipTarget: () => {
|
||||
velocity = -velocity;
|
||||
[from, to] = [to, from];
|
||||
createSpring();
|
||||
},
|
||||
};
|
||||
}
|
||||
spring.needsInterpolation = (a, b) => typeof a === "string" || typeof b === "string";
|
||||
const zero = (_t) => 0;
|
||||
|
||||
export { spring };
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
import { __rest } from 'tslib';
|
||||
import { detectAnimationFromOptions } from './utils/detect-animation-from-options.mjs';
|
||||
import sync, { cancelSync } from 'framesync';
|
||||
import { interpolate } from '../utils/interpolate.mjs';
|
||||
import { hasRepeatDelayElapsed, reverseElapsed, loopElapsed } from './utils/elapsed.mjs';
|
||||
|
||||
const framesync = (update) => {
|
||||
const passTimestamp = ({ delta }) => update(delta);
|
||||
return {
|
||||
start: () => sync.update(passTimestamp, true),
|
||||
stop: () => cancelSync.update(passTimestamp),
|
||||
};
|
||||
};
|
||||
function animate(_a) {
|
||||
var _b, _c;
|
||||
var { from, autoplay = true, driver = framesync, elapsed = 0, repeat: repeatMax = 0, repeatType = "loop", repeatDelay = 0, onPlay, onStop, onComplete, onRepeat, onUpdate } = _a, options = __rest(_a, ["from", "autoplay", "driver", "elapsed", "repeat", "repeatType", "repeatDelay", "onPlay", "onStop", "onComplete", "onRepeat", "onUpdate"]);
|
||||
let { to } = options;
|
||||
let driverControls;
|
||||
let repeatCount = 0;
|
||||
let computedDuration = options.duration;
|
||||
let latest;
|
||||
let isComplete = false;
|
||||
let isForwardPlayback = true;
|
||||
let interpolateFromNumber;
|
||||
const animator = detectAnimationFromOptions(options);
|
||||
if ((_c = (_b = animator).needsInterpolation) === null || _c === void 0 ? void 0 : _c.call(_b, from, to)) {
|
||||
interpolateFromNumber = interpolate([0, 100], [from, to], {
|
||||
clamp: false,
|
||||
});
|
||||
from = 0;
|
||||
to = 100;
|
||||
}
|
||||
const animation = animator(Object.assign(Object.assign({}, options), { from, to }));
|
||||
function repeat() {
|
||||
repeatCount++;
|
||||
if (repeatType === "reverse") {
|
||||
isForwardPlayback = repeatCount % 2 === 0;
|
||||
elapsed = reverseElapsed(elapsed, computedDuration, repeatDelay, isForwardPlayback);
|
||||
}
|
||||
else {
|
||||
elapsed = loopElapsed(elapsed, computedDuration, repeatDelay);
|
||||
if (repeatType === "mirror")
|
||||
animation.flipTarget();
|
||||
}
|
||||
isComplete = false;
|
||||
onRepeat && onRepeat();
|
||||
}
|
||||
function complete() {
|
||||
driverControls.stop();
|
||||
onComplete && onComplete();
|
||||
}
|
||||
function update(delta) {
|
||||
if (!isForwardPlayback)
|
||||
delta = -delta;
|
||||
elapsed += delta;
|
||||
if (!isComplete) {
|
||||
const state = animation.next(Math.max(0, elapsed));
|
||||
latest = state.value;
|
||||
if (interpolateFromNumber)
|
||||
latest = interpolateFromNumber(latest);
|
||||
isComplete = isForwardPlayback ? state.done : elapsed <= 0;
|
||||
}
|
||||
onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(latest);
|
||||
if (isComplete) {
|
||||
if (repeatCount === 0)
|
||||
computedDuration !== null && computedDuration !== void 0 ? computedDuration : (computedDuration = elapsed);
|
||||
if (repeatCount < repeatMax) {
|
||||
hasRepeatDelayElapsed(elapsed, computedDuration, repeatDelay, isForwardPlayback) && repeat();
|
||||
}
|
||||
else {
|
||||
complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
function play() {
|
||||
onPlay === null || onPlay === void 0 ? void 0 : onPlay();
|
||||
driverControls = driver(update);
|
||||
driverControls.start();
|
||||
}
|
||||
autoplay && play();
|
||||
return {
|
||||
stop: () => {
|
||||
onStop === null || onStop === void 0 ? void 0 : onStop();
|
||||
driverControls.stop();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export { animate };
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
import { animate } from './index.mjs';
|
||||
import { velocityPerSecond } from '../utils/velocity-per-second.mjs';
|
||||
import { getFrameData } from 'framesync';
|
||||
|
||||
function inertia({ from = 0, velocity = 0, min, max, power = 0.8, timeConstant = 750, bounceStiffness = 500, bounceDamping = 10, restDelta = 1, modifyTarget, driver, onUpdate, onComplete, onStop, }) {
|
||||
let currentAnimation;
|
||||
function isOutOfBounds(v) {
|
||||
return (min !== undefined && v < min) || (max !== undefined && v > max);
|
||||
}
|
||||
function boundaryNearest(v) {
|
||||
if (min === undefined)
|
||||
return max;
|
||||
if (max === undefined)
|
||||
return min;
|
||||
return Math.abs(min - v) < Math.abs(max - v) ? min : max;
|
||||
}
|
||||
function startAnimation(options) {
|
||||
currentAnimation === null || currentAnimation === void 0 ? void 0 : currentAnimation.stop();
|
||||
currentAnimation = animate(Object.assign(Object.assign({}, options), { driver, onUpdate: (v) => {
|
||||
var _a;
|
||||
onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(v);
|
||||
(_a = options.onUpdate) === null || _a === void 0 ? void 0 : _a.call(options, v);
|
||||
}, onComplete,
|
||||
onStop }));
|
||||
}
|
||||
function startSpring(options) {
|
||||
startAnimation(Object.assign({ type: "spring", stiffness: bounceStiffness, damping: bounceDamping, restDelta }, options));
|
||||
}
|
||||
if (isOutOfBounds(from)) {
|
||||
startSpring({ from, velocity, to: boundaryNearest(from) });
|
||||
}
|
||||
else {
|
||||
let target = power * velocity + from;
|
||||
if (typeof modifyTarget !== "undefined")
|
||||
target = modifyTarget(target);
|
||||
const boundary = boundaryNearest(target);
|
||||
const heading = boundary === min ? -1 : 1;
|
||||
let prev;
|
||||
let current;
|
||||
const checkBoundary = (v) => {
|
||||
prev = current;
|
||||
current = v;
|
||||
velocity = velocityPerSecond(v - prev, getFrameData().delta);
|
||||
if ((heading === 1 && v > boundary) ||
|
||||
(heading === -1 && v < boundary)) {
|
||||
startSpring({ from: v, to: boundary, velocity });
|
||||
}
|
||||
};
|
||||
startAnimation({
|
||||
type: "decay",
|
||||
from,
|
||||
velocity,
|
||||
timeConstant,
|
||||
power,
|
||||
restDelta,
|
||||
modifyTarget,
|
||||
onUpdate: isOutOfBounds(target) ? checkBoundary : undefined,
|
||||
});
|
||||
}
|
||||
return {
|
||||
stop: () => currentAnimation === null || currentAnimation === void 0 ? void 0 : currentAnimation.stop(),
|
||||
};
|
||||
}
|
||||
|
||||
export { inertia };
|
||||
Generated
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
import { spring } from '../generators/spring.mjs';
|
||||
import { keyframes } from '../generators/keyframes.mjs';
|
||||
import { decay } from '../generators/decay.mjs';
|
||||
|
||||
const types = { keyframes, spring, decay };
|
||||
function detectAnimationFromOptions(config) {
|
||||
if (Array.isArray(config.to)) {
|
||||
return keyframes;
|
||||
}
|
||||
else if (types[config.type]) {
|
||||
return types[config.type];
|
||||
}
|
||||
const keys = new Set(Object.keys(config));
|
||||
if (keys.has("ease") ||
|
||||
(keys.has("duration") && !keys.has("dampingRatio"))) {
|
||||
return keyframes;
|
||||
}
|
||||
else if (keys.has("dampingRatio") ||
|
||||
keys.has("stiffness") ||
|
||||
keys.has("mass") ||
|
||||
keys.has("damping") ||
|
||||
keys.has("restSpeed") ||
|
||||
keys.has("restDelta")) {
|
||||
return spring;
|
||||
}
|
||||
return keyframes;
|
||||
}
|
||||
|
||||
export { detectAnimationFromOptions };
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
function loopElapsed(elapsed, duration, delay = 0) {
|
||||
return elapsed - duration - delay;
|
||||
}
|
||||
function reverseElapsed(elapsed, duration, delay = 0, isForwardPlayback = true) {
|
||||
return isForwardPlayback
|
||||
? loopElapsed(duration + -elapsed, duration, delay)
|
||||
: duration - (elapsed - duration) + delay;
|
||||
}
|
||||
function hasRepeatDelayElapsed(elapsed, duration, delay, isForwardPlayback) {
|
||||
return isForwardPlayback ? elapsed >= duration + delay : elapsed <= -delay;
|
||||
}
|
||||
|
||||
export { hasRepeatDelayElapsed, loopElapsed, reverseElapsed };
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
import { warning } from 'hey-listen';
|
||||
import { clamp } from '../../utils/clamp.mjs';
|
||||
|
||||
const safeMin = 0.001;
|
||||
const minDuration = 0.01;
|
||||
const maxDuration = 10.0;
|
||||
const minDamping = 0.05;
|
||||
const maxDamping = 1;
|
||||
function findSpring({ duration = 800, bounce = 0.25, velocity = 0, mass = 1, }) {
|
||||
let envelope;
|
||||
let derivative;
|
||||
warning(duration <= maxDuration * 1000, "Spring duration must be 10 seconds or less");
|
||||
let dampingRatio = 1 - bounce;
|
||||
dampingRatio = clamp(minDamping, maxDamping, dampingRatio);
|
||||
duration = clamp(minDuration, maxDuration, duration / 1000);
|
||||
if (dampingRatio < 1) {
|
||||
envelope = (undampedFreq) => {
|
||||
const exponentialDecay = undampedFreq * dampingRatio;
|
||||
const delta = exponentialDecay * duration;
|
||||
const a = exponentialDecay - velocity;
|
||||
const b = calcAngularFreq(undampedFreq, dampingRatio);
|
||||
const c = Math.exp(-delta);
|
||||
return safeMin - (a / b) * c;
|
||||
};
|
||||
derivative = (undampedFreq) => {
|
||||
const exponentialDecay = undampedFreq * dampingRatio;
|
||||
const delta = exponentialDecay * duration;
|
||||
const d = delta * velocity + velocity;
|
||||
const e = Math.pow(dampingRatio, 2) * Math.pow(undampedFreq, 2) * duration;
|
||||
const f = Math.exp(-delta);
|
||||
const g = calcAngularFreq(Math.pow(undampedFreq, 2), dampingRatio);
|
||||
const factor = -envelope(undampedFreq) + safeMin > 0 ? -1 : 1;
|
||||
return (factor * ((d - e) * f)) / g;
|
||||
};
|
||||
}
|
||||
else {
|
||||
envelope = (undampedFreq) => {
|
||||
const a = Math.exp(-undampedFreq * duration);
|
||||
const b = (undampedFreq - velocity) * duration + 1;
|
||||
return -safeMin + a * b;
|
||||
};
|
||||
derivative = (undampedFreq) => {
|
||||
const a = Math.exp(-undampedFreq * duration);
|
||||
const b = (velocity - undampedFreq) * (duration * duration);
|
||||
return a * b;
|
||||
};
|
||||
}
|
||||
const initialGuess = 5 / duration;
|
||||
const undampedFreq = approximateRoot(envelope, derivative, initialGuess);
|
||||
duration = duration * 1000;
|
||||
if (isNaN(undampedFreq)) {
|
||||
return {
|
||||
stiffness: 100,
|
||||
damping: 10,
|
||||
duration,
|
||||
};
|
||||
}
|
||||
else {
|
||||
const stiffness = Math.pow(undampedFreq, 2) * mass;
|
||||
return {
|
||||
stiffness,
|
||||
damping: dampingRatio * 2 * Math.sqrt(mass * stiffness),
|
||||
duration,
|
||||
};
|
||||
}
|
||||
}
|
||||
const rootIterations = 12;
|
||||
function approximateRoot(envelope, derivative, initialGuess) {
|
||||
let result = initialGuess;
|
||||
for (let i = 1; i < rootIterations; i++) {
|
||||
result = result - envelope(result) / derivative(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function calcAngularFreq(undampedFreq, dampingRatio) {
|
||||
return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
|
||||
}
|
||||
|
||||
export { calcAngularFreq, findSpring, maxDamping, maxDuration, minDamping, minDuration };
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
import { linear } from './index.mjs';
|
||||
|
||||
const a = (a1, a2) => 1.0 - 3.0 * a2 + 3.0 * a1;
|
||||
const b = (a1, a2) => 3.0 * a2 - 6.0 * a1;
|
||||
const c = (a1) => 3.0 * a1;
|
||||
const calcBezier = (t, a1, a2) => ((a(a1, a2) * t + b(a1, a2)) * t + c(a1)) * t;
|
||||
const getSlope = (t, a1, a2) => 3.0 * a(a1, a2) * t * t + 2.0 * b(a1, a2) * t + c(a1);
|
||||
const subdivisionPrecision = 0.0000001;
|
||||
const subdivisionMaxIterations = 10;
|
||||
function binarySubdivide(aX, aA, aB, mX1, mX2) {
|
||||
let currentX;
|
||||
let currentT;
|
||||
let i = 0;
|
||||
do {
|
||||
currentT = aA + (aB - aA) / 2.0;
|
||||
currentX = calcBezier(currentT, mX1, mX2) - aX;
|
||||
if (currentX > 0.0) {
|
||||
aB = currentT;
|
||||
}
|
||||
else {
|
||||
aA = currentT;
|
||||
}
|
||||
} while (Math.abs(currentX) > subdivisionPrecision &&
|
||||
++i < subdivisionMaxIterations);
|
||||
return currentT;
|
||||
}
|
||||
const newtonIterations = 8;
|
||||
const newtonMinSlope = 0.001;
|
||||
function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {
|
||||
for (let i = 0; i < newtonIterations; ++i) {
|
||||
const currentSlope = getSlope(aGuessT, mX1, mX2);
|
||||
if (currentSlope === 0.0) {
|
||||
return aGuessT;
|
||||
}
|
||||
const currentX = calcBezier(aGuessT, mX1, mX2) - aX;
|
||||
aGuessT -= currentX / currentSlope;
|
||||
}
|
||||
return aGuessT;
|
||||
}
|
||||
const kSplineTableSize = 11;
|
||||
const kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
|
||||
function cubicBezier(mX1, mY1, mX2, mY2) {
|
||||
if (mX1 === mY1 && mX2 === mY2)
|
||||
return linear;
|
||||
const sampleValues = new Float32Array(kSplineTableSize);
|
||||
for (let i = 0; i < kSplineTableSize; ++i) {
|
||||
sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
|
||||
}
|
||||
function getTForX(aX) {
|
||||
let intervalStart = 0.0;
|
||||
let currentSample = 1;
|
||||
const lastSample = kSplineTableSize - 1;
|
||||
for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
|
||||
intervalStart += kSampleStepSize;
|
||||
}
|
||||
--currentSample;
|
||||
const dist = (aX - sampleValues[currentSample]) /
|
||||
(sampleValues[currentSample + 1] - sampleValues[currentSample]);
|
||||
const guessForT = intervalStart + dist * kSampleStepSize;
|
||||
const initialSlope = getSlope(guessForT, mX1, mX2);
|
||||
if (initialSlope >= newtonMinSlope) {
|
||||
return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
|
||||
}
|
||||
else if (initialSlope === 0.0) {
|
||||
return guessForT;
|
||||
}
|
||||
else {
|
||||
return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
|
||||
}
|
||||
}
|
||||
return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);
|
||||
}
|
||||
|
||||
export { cubicBezier };
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import { createExpoIn, reverseEasing, mirrorEasing, createBackIn, createAnticipate } from './utils.mjs';
|
||||
|
||||
const DEFAULT_OVERSHOOT_STRENGTH = 1.525;
|
||||
const BOUNCE_FIRST_THRESHOLD = 4.0 / 11.0;
|
||||
const BOUNCE_SECOND_THRESHOLD = 8.0 / 11.0;
|
||||
const BOUNCE_THIRD_THRESHOLD = 9.0 / 10.0;
|
||||
const linear = p => p;
|
||||
const easeIn = createExpoIn(2);
|
||||
const easeOut = reverseEasing(easeIn);
|
||||
const easeInOut = mirrorEasing(easeIn);
|
||||
const circIn = p => 1 - Math.sin(Math.acos(p));
|
||||
const circOut = reverseEasing(circIn);
|
||||
const circInOut = mirrorEasing(circOut);
|
||||
const backIn = createBackIn(DEFAULT_OVERSHOOT_STRENGTH);
|
||||
const backOut = reverseEasing(backIn);
|
||||
const backInOut = mirrorEasing(backIn);
|
||||
const anticipate = createAnticipate(DEFAULT_OVERSHOOT_STRENGTH);
|
||||
const ca = 4356.0 / 361.0;
|
||||
const cb = 35442.0 / 1805.0;
|
||||
const cc = 16061.0 / 1805.0;
|
||||
const bounceOut = (p) => {
|
||||
if (p === 1 || p === 0)
|
||||
return p;
|
||||
const p2 = p * p;
|
||||
return p < BOUNCE_FIRST_THRESHOLD
|
||||
? 7.5625 * p2
|
||||
: p < BOUNCE_SECOND_THRESHOLD
|
||||
? 9.075 * p2 - 9.9 * p + 3.4
|
||||
: p < BOUNCE_THIRD_THRESHOLD
|
||||
? ca * p2 - cb * p + cc
|
||||
: 10.8 * p * p - 20.52 * p + 10.72;
|
||||
};
|
||||
const bounceIn = reverseEasing(bounceOut);
|
||||
const bounceInOut = (p) => p < 0.5
|
||||
? 0.5 * (1.0 - bounceOut(1.0 - p * 2.0))
|
||||
: 0.5 * bounceOut(p * 2.0 - 1.0) + 0.5;
|
||||
|
||||
export { anticipate, backIn, backInOut, backOut, bounceIn, bounceInOut, bounceOut, circIn, circInOut, circOut, easeIn, easeInOut, easeOut, linear };
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { clamp } from '../utils/clamp.mjs';
|
||||
|
||||
const steps = (steps, direction = 'end') => (progress) => {
|
||||
progress =
|
||||
direction === 'end' ? Math.min(progress, 0.999) : Math.max(progress, 0.001);
|
||||
const expanded = progress * steps;
|
||||
const rounded = direction === 'end' ? Math.floor(expanded) : Math.ceil(expanded);
|
||||
return clamp(0, 1, rounded / steps);
|
||||
};
|
||||
|
||||
export { steps };
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
const reverseEasing = easing => p => 1 - easing(1 - p);
|
||||
const mirrorEasing = easing => p => p <= 0.5 ? easing(2 * p) / 2 : (2 - easing(2 * (1 - p))) / 2;
|
||||
const createExpoIn = (power) => p => Math.pow(p, power);
|
||||
const createBackIn = (power) => p => p * p * ((power + 1) * p - power);
|
||||
const createAnticipate = (power) => {
|
||||
const backEasing = createBackIn(power);
|
||||
return p => (p *= 2) < 1
|
||||
? 0.5 * backEasing(p)
|
||||
: 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
|
||||
};
|
||||
|
||||
export { createAnticipate, createBackIn, createExpoIn, mirrorEasing, reverseEasing };
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
export { animate } from './animations/index.mjs';
|
||||
export { inertia } from './animations/inertia.mjs';
|
||||
export { decay } from './animations/generators/decay.mjs';
|
||||
export { spring } from './animations/generators/spring.mjs';
|
||||
export { keyframes } from './animations/generators/keyframes.mjs';
|
||||
export { angle } from './utils/angle.mjs';
|
||||
export { applyOffset } from './utils/apply-offset.mjs';
|
||||
export { attract, attractExpo, createAttractor } from './utils/attract.mjs';
|
||||
export { clamp } from './utils/clamp.mjs';
|
||||
export { degreesToRadians } from './utils/degrees-to-radians.mjs';
|
||||
export { distance } from './utils/distance.mjs';
|
||||
export { interpolate } from './utils/interpolate.mjs';
|
||||
export { isPoint3D } from './utils/is-point-3d.mjs';
|
||||
export { isPoint } from './utils/is-point.mjs';
|
||||
export { mixColor } from './utils/mix-color.mjs';
|
||||
export { mixComplex } from './utils/mix-complex.mjs';
|
||||
export { mix } from './utils/mix.mjs';
|
||||
export { pipe } from './utils/pipe.mjs';
|
||||
export { pointFromVector } from './utils/point-from-vector.mjs';
|
||||
export { progress } from './utils/progress.mjs';
|
||||
export { radiansToDegrees } from './utils/radians-to-degrees.mjs';
|
||||
export { smoothFrame } from './utils/smooth-frame.mjs';
|
||||
export { smooth } from './utils/smooth.mjs';
|
||||
export { snap } from './utils/snap.mjs';
|
||||
export { toDecimal } from './utils/to-decimal.mjs';
|
||||
export { velocityPerFrame } from './utils/velocity-per-frame.mjs';
|
||||
export { velocityPerSecond } from './utils/velocity-per-second.mjs';
|
||||
export { wrap } from './utils/wrap.mjs';
|
||||
export { anticipate, backIn, backInOut, backOut, bounceIn, bounceInOut, bounceOut, circIn, circInOut, circOut, easeIn, easeInOut, easeOut, linear } from './easing/index.mjs';
|
||||
export { cubicBezier } from './easing/cubic-bezier.mjs';
|
||||
export { steps } from './easing/steps.mjs';
|
||||
export { createAnticipate, createBackIn, createExpoIn, mirrorEasing, reverseEasing } from './easing/utils.mjs';
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { radiansToDegrees } from './radians-to-degrees.mjs';
|
||||
import { zeroPoint } from './inc.mjs';
|
||||
|
||||
const angle = (a, b = zeroPoint) => radiansToDegrees(Math.atan2(b.y - a.y, b.x - a.x));
|
||||
|
||||
export { angle };
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
const applyOffset = (from, to) => {
|
||||
let hasReceivedFrom = true;
|
||||
if (to === undefined) {
|
||||
to = from;
|
||||
hasReceivedFrom = false;
|
||||
}
|
||||
return (v) => {
|
||||
if (hasReceivedFrom) {
|
||||
return v - from + to;
|
||||
}
|
||||
else {
|
||||
from = v;
|
||||
hasReceivedFrom = true;
|
||||
return to;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export { applyOffset };
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
const identity = (v) => v;
|
||||
const createAttractor = (alterDisplacement = identity) => (constant, origin, v) => {
|
||||
const displacement = origin - v;
|
||||
const springModifiedDisplacement = -(0 - constant + 1) * (0 - alterDisplacement(Math.abs(displacement)));
|
||||
return displacement <= 0
|
||||
? origin + springModifiedDisplacement
|
||||
: origin - springModifiedDisplacement;
|
||||
};
|
||||
const attract = createAttractor();
|
||||
const attractExpo = createAttractor(Math.sqrt);
|
||||
|
||||
export { attract, attractExpo, createAttractor };
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
const clamp = (min, max, v) => Math.min(Math.max(v, min), max);
|
||||
|
||||
export { clamp };
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
const degreesToRadians = (degrees) => (degrees * Math.PI) / 180;
|
||||
|
||||
export { degreesToRadians };
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
import { isPoint } from './is-point.mjs';
|
||||
import { isPoint3D } from './is-point-3d.mjs';
|
||||
import { isNum } from './inc.mjs';
|
||||
|
||||
const distance1D = (a, b) => Math.abs(a - b);
|
||||
function distance(a, b) {
|
||||
if (isNum(a) && isNum(b)) {
|
||||
return distance1D(a, b);
|
||||
}
|
||||
else if (isPoint(a) && isPoint(b)) {
|
||||
const xDelta = distance1D(a.x, b.x);
|
||||
const yDelta = distance1D(a.y, b.y);
|
||||
const zDelta = isPoint3D(a) && isPoint3D(b) ? distance1D(a.z, b.z) : 0;
|
||||
return Math.sqrt(Math.pow(xDelta, 2) + Math.pow(yDelta, 2) + Math.pow(zDelta, 2));
|
||||
}
|
||||
}
|
||||
|
||||
export { distance };
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
function hueToRgb(p, q, t) {
|
||||
if (t < 0)
|
||||
t += 1;
|
||||
if (t > 1)
|
||||
t -= 1;
|
||||
if (t < 1 / 6)
|
||||
return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2)
|
||||
return q;
|
||||
if (t < 2 / 3)
|
||||
return p + (q - p) * (2 / 3 - t) * 6;
|
||||
return p;
|
||||
}
|
||||
function hslaToRgba({ hue, saturation, lightness, alpha }) {
|
||||
hue /= 360;
|
||||
saturation /= 100;
|
||||
lightness /= 100;
|
||||
let red = 0;
|
||||
let green = 0;
|
||||
let blue = 0;
|
||||
if (!saturation) {
|
||||
red = green = blue = lightness;
|
||||
}
|
||||
else {
|
||||
const q = lightness < 0.5
|
||||
? lightness * (1 + saturation)
|
||||
: lightness + saturation - lightness * saturation;
|
||||
const p = 2 * lightness - q;
|
||||
red = hueToRgb(p, q, hue + 1 / 3);
|
||||
green = hueToRgb(p, q, hue);
|
||||
blue = hueToRgb(p, q, hue - 1 / 3);
|
||||
}
|
||||
return {
|
||||
red: Math.round(red * 255),
|
||||
green: Math.round(green * 255),
|
||||
blue: Math.round(blue * 255),
|
||||
alpha,
|
||||
};
|
||||
}
|
||||
|
||||
export { hslaToRgba };
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
const zeroPoint = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
const isNum = (v) => typeof v === 'number';
|
||||
|
||||
export { isNum, zeroPoint };
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
import { progress } from './progress.mjs';
|
||||
import { mix } from './mix.mjs';
|
||||
import { mixColor } from './mix-color.mjs';
|
||||
import { mixComplex, mixArray, mixObject } from './mix-complex.mjs';
|
||||
import { color } from 'style-value-types';
|
||||
import { clamp } from './clamp.mjs';
|
||||
import { pipe } from './pipe.mjs';
|
||||
import { invariant } from 'hey-listen';
|
||||
|
||||
const mixNumber = (from, to) => (p) => mix(from, to, p);
|
||||
function detectMixerFactory(v) {
|
||||
if (typeof v === 'number') {
|
||||
return mixNumber;
|
||||
}
|
||||
else if (typeof v === 'string') {
|
||||
if (color.test(v)) {
|
||||
return mixColor;
|
||||
}
|
||||
else {
|
||||
return mixComplex;
|
||||
}
|
||||
}
|
||||
else if (Array.isArray(v)) {
|
||||
return mixArray;
|
||||
}
|
||||
else if (typeof v === 'object') {
|
||||
return mixObject;
|
||||
}
|
||||
}
|
||||
function createMixers(output, ease, customMixer) {
|
||||
const mixers = [];
|
||||
const mixerFactory = customMixer || detectMixerFactory(output[0]);
|
||||
const numMixers = output.length - 1;
|
||||
for (let i = 0; i < numMixers; i++) {
|
||||
let mixer = mixerFactory(output[i], output[i + 1]);
|
||||
if (ease) {
|
||||
const easingFunction = Array.isArray(ease) ? ease[i] : ease;
|
||||
mixer = pipe(easingFunction, mixer);
|
||||
}
|
||||
mixers.push(mixer);
|
||||
}
|
||||
return mixers;
|
||||
}
|
||||
function fastInterpolate([from, to], [mixer]) {
|
||||
return (v) => mixer(progress(from, to, v));
|
||||
}
|
||||
function slowInterpolate(input, mixers) {
|
||||
const inputLength = input.length;
|
||||
const lastInputIndex = inputLength - 1;
|
||||
return (v) => {
|
||||
let mixerIndex = 0;
|
||||
let foundMixerIndex = false;
|
||||
if (v <= input[0]) {
|
||||
foundMixerIndex = true;
|
||||
}
|
||||
else if (v >= input[lastInputIndex]) {
|
||||
mixerIndex = lastInputIndex - 1;
|
||||
foundMixerIndex = true;
|
||||
}
|
||||
if (!foundMixerIndex) {
|
||||
let i = 1;
|
||||
for (; i < inputLength; i++) {
|
||||
if (input[i] > v || i === lastInputIndex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
mixerIndex = i - 1;
|
||||
}
|
||||
const progressInRange = progress(input[mixerIndex], input[mixerIndex + 1], v);
|
||||
return mixers[mixerIndex](progressInRange);
|
||||
};
|
||||
}
|
||||
function interpolate(input, output, { clamp: isClamp = true, ease, mixer } = {}) {
|
||||
const inputLength = input.length;
|
||||
invariant(inputLength === output.length, 'Both input and output ranges must be the same length');
|
||||
invariant(!ease || !Array.isArray(ease) || ease.length === inputLength - 1, 'Array of easing functions must be of length `input.length - 1`, as it applies to the transitions **between** the defined values.');
|
||||
if (input[0] > input[inputLength - 1]) {
|
||||
input = [].concat(input);
|
||||
output = [].concat(output);
|
||||
input.reverse();
|
||||
output.reverse();
|
||||
}
|
||||
const mixers = createMixers(output, ease, mixer);
|
||||
const interpolator = inputLength === 2
|
||||
? fastInterpolate(input, mixers)
|
||||
: slowInterpolate(input, mixers);
|
||||
return isClamp
|
||||
? (v) => interpolator(clamp(input[0], input[inputLength - 1], v))
|
||||
: interpolator;
|
||||
}
|
||||
|
||||
export { interpolate };
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import { isPoint } from './is-point.mjs';
|
||||
|
||||
const isPoint3D = (point) => isPoint(point) && point.hasOwnProperty('z');
|
||||
|
||||
export { isPoint3D };
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
const isPoint = (point) => point.hasOwnProperty('x') && point.hasOwnProperty('y');
|
||||
|
||||
export { isPoint };
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import { mix } from './mix.mjs';
|
||||
import { hsla, rgba, hex } from 'style-value-types';
|
||||
import { invariant } from 'hey-listen';
|
||||
import { hslaToRgba } from './hsla-to-rgba.mjs';
|
||||
|
||||
const mixLinearColor = (from, to, v) => {
|
||||
const fromExpo = from * from;
|
||||
const toExpo = to * to;
|
||||
return Math.sqrt(Math.max(0, v * (toExpo - fromExpo) + fromExpo));
|
||||
};
|
||||
const colorTypes = [hex, rgba, hsla];
|
||||
const getColorType = (v) => colorTypes.find((type) => type.test(v));
|
||||
const notAnimatable = (color) => `'${color}' is not an animatable color. Use the equivalent color code instead.`;
|
||||
const mixColor = (from, to) => {
|
||||
let fromColorType = getColorType(from);
|
||||
let toColorType = getColorType(to);
|
||||
invariant(!!fromColorType, notAnimatable(from));
|
||||
invariant(!!toColorType, notAnimatable(to));
|
||||
let fromColor = fromColorType.parse(from);
|
||||
let toColor = toColorType.parse(to);
|
||||
if (fromColorType === hsla) {
|
||||
fromColor = hslaToRgba(fromColor);
|
||||
fromColorType = rgba;
|
||||
}
|
||||
if (toColorType === hsla) {
|
||||
toColor = hslaToRgba(toColor);
|
||||
toColorType = rgba;
|
||||
}
|
||||
const blended = Object.assign({}, fromColor);
|
||||
return (v) => {
|
||||
for (const key in blended) {
|
||||
if (key !== "alpha") {
|
||||
blended[key] = mixLinearColor(fromColor[key], toColor[key], v);
|
||||
}
|
||||
}
|
||||
blended.alpha = mix(fromColor.alpha, toColor.alpha, v);
|
||||
return fromColorType.transform(blended);
|
||||
};
|
||||
};
|
||||
|
||||
export { mixColor, mixLinearColor };
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
import { complex, color } from 'style-value-types';
|
||||
import { mix } from './mix.mjs';
|
||||
import { mixColor } from './mix-color.mjs';
|
||||
import { isNum } from './inc.mjs';
|
||||
import { pipe } from './pipe.mjs';
|
||||
import { warning } from 'hey-listen';
|
||||
|
||||
function getMixer(origin, target) {
|
||||
if (isNum(origin)) {
|
||||
return (v) => mix(origin, target, v);
|
||||
}
|
||||
else if (color.test(origin)) {
|
||||
return mixColor(origin, target);
|
||||
}
|
||||
else {
|
||||
return mixComplex(origin, target);
|
||||
}
|
||||
}
|
||||
const mixArray = (from, to) => {
|
||||
const output = [...from];
|
||||
const numValues = output.length;
|
||||
const blendValue = from.map((fromThis, i) => getMixer(fromThis, to[i]));
|
||||
return (v) => {
|
||||
for (let i = 0; i < numValues; i++) {
|
||||
output[i] = blendValue[i](v);
|
||||
}
|
||||
return output;
|
||||
};
|
||||
};
|
||||
const mixObject = (origin, target) => {
|
||||
const output = Object.assign(Object.assign({}, origin), target);
|
||||
const blendValue = {};
|
||||
for (const key in output) {
|
||||
if (origin[key] !== undefined && target[key] !== undefined) {
|
||||
blendValue[key] = getMixer(origin[key], target[key]);
|
||||
}
|
||||
}
|
||||
return (v) => {
|
||||
for (const key in blendValue) {
|
||||
output[key] = blendValue[key](v);
|
||||
}
|
||||
return output;
|
||||
};
|
||||
};
|
||||
function analyse(value) {
|
||||
const parsed = complex.parse(value);
|
||||
const numValues = parsed.length;
|
||||
let numNumbers = 0;
|
||||
let numRGB = 0;
|
||||
let numHSL = 0;
|
||||
for (let i = 0; i < numValues; i++) {
|
||||
if (numNumbers || typeof parsed[i] === "number") {
|
||||
numNumbers++;
|
||||
}
|
||||
else {
|
||||
if (parsed[i].hue !== undefined) {
|
||||
numHSL++;
|
||||
}
|
||||
else {
|
||||
numRGB++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return { parsed, numNumbers, numRGB, numHSL };
|
||||
}
|
||||
const mixComplex = (origin, target) => {
|
||||
const template = complex.createTransformer(target);
|
||||
const originStats = analyse(origin);
|
||||
const targetStats = analyse(target);
|
||||
const canInterpolate = originStats.numHSL === targetStats.numHSL &&
|
||||
originStats.numRGB === targetStats.numRGB &&
|
||||
originStats.numNumbers >= targetStats.numNumbers;
|
||||
if (canInterpolate) {
|
||||
return pipe(mixArray(originStats.parsed, targetStats.parsed), template);
|
||||
}
|
||||
else {
|
||||
warning(true, `Complex values '${origin}' and '${target}' too different to mix. Ensure all colors are of the same type, and that each contains the same quantity of number and color values. Falling back to instant transition.`);
|
||||
return (p) => `${p > 0 ? target : origin}`;
|
||||
}
|
||||
};
|
||||
|
||||
export { mixArray, mixComplex, mixObject };
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
const mix = (from, to, progress) => -progress * from + progress * to + from;
|
||||
|
||||
export { mix };
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
const combineFunctions = (a, b) => (v) => b(a(v));
|
||||
const pipe = (...transformers) => transformers.reduce(combineFunctions);
|
||||
|
||||
export { pipe };
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { degreesToRadians } from './degrees-to-radians.mjs';
|
||||
|
||||
const pointFromVector = (origin, angle, distance) => {
|
||||
angle = degreesToRadians(angle);
|
||||
return {
|
||||
x: distance * Math.cos(angle) + origin.x,
|
||||
y: distance * Math.sin(angle) + origin.y
|
||||
};
|
||||
};
|
||||
|
||||
export { pointFromVector };
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
const progress = (from, to, value) => {
|
||||
const toFromDifference = to - from;
|
||||
return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;
|
||||
};
|
||||
|
||||
export { progress };
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
const radiansToDegrees = (radians) => (radians * 180) / Math.PI;
|
||||
|
||||
export { radiansToDegrees };
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { toDecimal } from './to-decimal.mjs';
|
||||
|
||||
const smoothFrame = (prevValue, nextValue, duration, smoothing = 0) => toDecimal(prevValue +
|
||||
(duration * (nextValue - prevValue)) / Math.max(smoothing, duration));
|
||||
|
||||
export { smoothFrame };
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { smoothFrame } from './smooth-frame.mjs';
|
||||
import { getFrameData } from 'framesync';
|
||||
|
||||
const smooth = (strength = 50) => {
|
||||
let previousValue = 0;
|
||||
let lastUpdated = 0;
|
||||
return (v) => {
|
||||
const currentFramestamp = getFrameData().timestamp;
|
||||
const timeDelta = currentFramestamp !== lastUpdated ? currentFramestamp - lastUpdated : 0;
|
||||
const newValue = timeDelta
|
||||
? smoothFrame(previousValue, v, timeDelta, strength)
|
||||
: previousValue;
|
||||
lastUpdated = currentFramestamp;
|
||||
previousValue = newValue;
|
||||
return newValue;
|
||||
};
|
||||
};
|
||||
|
||||
export { smooth };
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
const snap = (points) => {
|
||||
if (typeof points === 'number') {
|
||||
return (v) => Math.round(v / points) * points;
|
||||
}
|
||||
else {
|
||||
let i = 0;
|
||||
const numPoints = points.length;
|
||||
return (v) => {
|
||||
let lastDistance = Math.abs(points[0] - v);
|
||||
for (i = 1; i < numPoints; i++) {
|
||||
const point = points[i];
|
||||
const distance = Math.abs(point - v);
|
||||
if (distance === 0)
|
||||
return point;
|
||||
if (distance > lastDistance)
|
||||
return points[i - 1];
|
||||
if (i === numPoints - 1)
|
||||
return point;
|
||||
lastDistance = distance;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export { snap };
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
const toDecimal = (num, precision = 2) => {
|
||||
precision = Math.pow(10, precision);
|
||||
return Math.round(num * precision) / precision;
|
||||
};
|
||||
|
||||
export { toDecimal };
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
function velocityPerFrame(xps, frameDuration) {
|
||||
return xps / (1000 / frameDuration);
|
||||
}
|
||||
|
||||
export { velocityPerFrame };
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
function velocityPerSecond(velocity, frameDuration) {
|
||||
return frameDuration ? velocity * (1000 / frameDuration) : 0;
|
||||
}
|
||||
|
||||
export { velocityPerSecond };
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
const wrap = (min, max, v) => {
|
||||
const rangeSize = max - min;
|
||||
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
|
||||
};
|
||||
|
||||
export { wrap };
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"name": "popmotion",
|
||||
"version": "11.0.5",
|
||||
"description": "The animator's toolbox",
|
||||
"author": "Matt Perry",
|
||||
"homepage": "https://popmotion.io",
|
||||
"main": "dist/popmotion.cjs.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"module": "dist/es/index.mjs",
|
||||
"jsnext:main": "dist/es/index.mjs",
|
||||
"unpkg": "./dist/popmotion.min.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./lib/index.d.ts",
|
||||
"import": "./dist/es/index.mjs",
|
||||
"require": "./dist/popmotion.cjs.js",
|
||||
"default": "./dist/popmotion.cjs.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Popmotion/popmotion/tree/master/packages/popmotion"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Popmotion/popmotion/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"animation",
|
||||
"ux",
|
||||
"ui",
|
||||
"popmotion",
|
||||
"canvas animation",
|
||||
"dom animation",
|
||||
"dom",
|
||||
"pointer tracking",
|
||||
"mouse",
|
||||
"mouse tracking",
|
||||
"touch",
|
||||
"touch tracking",
|
||||
"physics",
|
||||
"interaction",
|
||||
"interface",
|
||||
"svg"
|
||||
],
|
||||
"analyze": true,
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "tsc -p . && rollup -c && yarn measure",
|
||||
"postbuild": "yarn babel $npm_package_module --out-file $npm_package_module --no-babelrc --plugins annotate-pure-calls",
|
||||
"dev": "rollup -c -w",
|
||||
"prepublishOnly": "yarn test && yarn build",
|
||||
"measure": "gzip -c $npm_package_unpkg | wc -c",
|
||||
"test": "jest --coverage --maxWorkers=2",
|
||||
"publish-beta": "npm publish --tag beta"
|
||||
},
|
||||
"dependencies": {
|
||||
"framesync": "6.1.2",
|
||||
"hey-listen": "^1.0.8",
|
||||
"style-value-types": "5.1.2",
|
||||
"tslib": "2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^11.0.1",
|
||||
"tslint-circular-dependencies": "^0.1.0",
|
||||
"typescript": "^4.2.3"
|
||||
},
|
||||
"prettier": {
|
||||
"printWidth": 80,
|
||||
"tabWidth": 4,
|
||||
"semi": false,
|
||||
"trailingComma": "es5"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"js"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"style-value-types": "<rootDir>/../../style-value-types/src",
|
||||
"framesync": "<rootDir>/../../framesync/src"
|
||||
},
|
||||
"transform": {
|
||||
"\\.(ts)$": "../../../node_modules/ts-jest/preprocessor.js"
|
||||
},
|
||||
"testRegex": "/__tests__/.*\\.test.(ts|js)$",
|
||||
"rootDir": "src",
|
||||
"collectCoverageFrom": [
|
||||
"**/*.{js,jsx,ts,tsx}",
|
||||
"!**/node_modules/**",
|
||||
"!**/__tests__/**",
|
||||
"!**/worklet/**"
|
||||
],
|
||||
"coverageDirectory": "<rootDir>/../coverage"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user