feature: vor und nachteile

This commit is contained in:
Hikyu
2026-05-31 13:54:31 +02:00
parent 552a947a1c
commit e3dad17446
23270 changed files with 3024794 additions and 200 deletions
+2
View File
@@ -0,0 +1,2 @@
import { Point } from '../types';
export declare const angle: (a: Point, b?: Point) => number;
+4
View File
@@ -0,0 +1,4 @@
import { radiansToDegrees } from './radians-to-degrees';
import { zeroPoint } from './inc';
export const angle = (a, b = zeroPoint) => radiansToDegrees(Math.atan2(b.y - a.y, b.x - a.x));
//# sourceMappingURL=angle.js.map
+1
View File
@@ -0,0 +1 @@
export declare const applyOffset: (from: number, to?: number) => (v: number) => number;
+18
View File
@@ -0,0 +1,18 @@
export 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;
}
};
};
//# sourceMappingURL=apply-offset.js.map
+3
View File
@@ -0,0 +1,3 @@
export declare const createAttractor: (alterDisplacement?: Function) => (constant: number, origin: number, v: number) => number;
export declare const attract: (constant: number, origin: number, v: number) => number;
export declare const attractExpo: (constant: number, origin: number, v: number) => number;
+11
View File
@@ -0,0 +1,11 @@
const identity = (v) => v;
export 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;
};
export const attract = createAttractor();
export const attractExpo = createAttractor(Math.sqrt);
//# sourceMappingURL=attract.js.map
+1
View File
@@ -0,0 +1 @@
export declare const clamp: (min: number, max: number, v: number) => number;
+2
View File
@@ -0,0 +1,2 @@
export const clamp = (min, max, v) => Math.min(Math.max(v, min), max);
//# sourceMappingURL=clamp.js.map
@@ -0,0 +1 @@
export declare const degreesToRadians: (degrees: number) => number;
+2
View File
@@ -0,0 +1,2 @@
export const degreesToRadians = (degrees) => (degrees * Math.PI) / 180;
//# sourceMappingURL=degrees-to-radians.js.map
+2
View File
@@ -0,0 +1,2 @@
import { Point } from "../types";
export declare function distance<P extends Point | number>(a: P, b: P): number;
+16
View File
@@ -0,0 +1,16 @@
import { isPoint } from "./is-point";
import { isPoint3D } from "./is-point-3d";
import { isNum } from "./inc";
const distance1D = (a, b) => Math.abs(a - b);
export 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));
}
}
//# sourceMappingURL=distance.js.map
+2
View File
@@ -0,0 +1,2 @@
import { HSLA, RGBA } from "style-value-types";
export declare function hslaToRgba({ hue, saturation, lightness, alpha }: HSLA): RGBA;
+40
View File
@@ -0,0 +1,40 @@
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;
}
export 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,
};
}
//# sourceMappingURL=hsla-to-rgba.js.map
+3
View File
@@ -0,0 +1,3 @@
import { Point } from '../types';
export declare const zeroPoint: Point;
export declare const isNum: (v: any) => v is number;
+7
View File
@@ -0,0 +1,7 @@
export const zeroPoint = {
x: 0,
y: 0,
z: 0
};
export const isNum = (v) => typeof v === 'number';
//# sourceMappingURL=inc.js.map
+11
View File
@@ -0,0 +1,11 @@
import { Easing } from '../easing/types';
declare type MixEasing = Easing | Easing[];
declare type InterpolateOptions<T> = {
clamp?: boolean;
ease?: MixEasing;
mixer?: MixerFactory<T>;
};
declare type Mix<T> = (v: number) => T;
export declare type MixerFactory<T> = (from: T, to: T) => Mix<T>;
export declare function interpolate<T>(input: number[], output: T[], { clamp: isClamp, ease, mixer }?: InterpolateOptions<T>): (v: number) => T;
export {};
+90
View File
@@ -0,0 +1,90 @@
import { progress } from './progress';
import { mix } from './mix';
import { mixColor } from './mix-color';
import { mixComplex, mixArray, mixObject } from './mix-complex';
import { color } from 'style-value-types';
import { clamp } from './clamp';
import { pipe } from './pipe';
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);
};
}
export 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;
}
//# sourceMappingURL=interpolate.js.map
+2
View File
@@ -0,0 +1,2 @@
import { Point, Point3D } from '../types';
export declare const isPoint3D: (point: Point) => point is Point3D;
+3
View File
@@ -0,0 +1,3 @@
import { isPoint } from './is-point';
export const isPoint3D = (point) => isPoint(point) && point.hasOwnProperty('z');
//# sourceMappingURL=is-point-3d.js.map
+2
View File
@@ -0,0 +1,2 @@
import { Point } from '../types';
export declare const isPoint: (point: Object) => point is Point;
+2
View File
@@ -0,0 +1,2 @@
export const isPoint = (point) => point.hasOwnProperty('x') && point.hasOwnProperty('y');
//# sourceMappingURL=is-point.js.map
+3
View File
@@ -0,0 +1,3 @@
import { Color } from "style-value-types";
export declare const mixLinearColor: (from: number, to: number, v: number) => number;
export declare const mixColor: (from: Color | string, to: Color | string) => (v: number) => any;
+39
View File
@@ -0,0 +1,39 @@
import { mix } from "./mix";
import { hsla, rgba, hex } from "style-value-types";
import { invariant } from "hey-listen";
import { hslaToRgba } from "./hsla-to-rgba";
export 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.`;
export 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);
};
};
//# sourceMappingURL=mix-color.js.map
+12
View File
@@ -0,0 +1,12 @@
import { RGBA, HSLA } from "style-value-types";
declare type MixComplex = (p: number) => string;
declare type BlendableArray = Array<number | RGBA | HSLA | string>;
declare type BlendableObject = {
[key: string]: string | number | RGBA | HSLA;
};
export declare const mixArray: (from: BlendableArray, to: BlendableArray) => (v: number) => (string | number | HSLA | RGBA)[];
export declare const mixObject: (origin: BlendableObject, target: BlendableObject) => (v: number) => {
[x: string]: string | number | HSLA | RGBA;
};
export declare const mixComplex: (origin: string | number, target: string | number) => MixComplex;
export {};
+80
View File
@@ -0,0 +1,80 @@
import { color, complex } from "style-value-types";
import { mix } from "./mix";
import { mixColor } from "./mix-color";
import { isNum } from "./inc";
import { pipe } from "./pipe";
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);
}
}
export 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;
};
};
export 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 };
}
export 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}`;
}
};
//# sourceMappingURL=mix-complex.js.map
+1
View File
@@ -0,0 +1 @@
export declare const mix: (from: number, to: number, progress: number) => number;
+2
View File
@@ -0,0 +1,2 @@
export const mix = (from, to, progress) => -progress * from + progress * to + from;
//# sourceMappingURL=mix.js.map
+1
View File
@@ -0,0 +1 @@
export declare const pipe: (...transformers: Function[]) => Function;
+3
View File
@@ -0,0 +1,3 @@
const combineFunctions = (a, b) => (v) => b(a(v));
export const pipe = (...transformers) => transformers.reduce(combineFunctions);
//# sourceMappingURL=pipe.js.map
@@ -0,0 +1,5 @@
import { Point2D } from '../types';
export declare const pointFromVector: (origin: Point2D, angle: number, distance: number) => {
x: number;
y: number;
};
+9
View File
@@ -0,0 +1,9 @@
import { degreesToRadians } from './degrees-to-radians';
export const pointFromVector = (origin, angle, distance) => {
angle = degreesToRadians(angle);
return {
x: distance * Math.cos(angle) + origin.x,
y: distance * Math.sin(angle) + origin.y
};
};
//# sourceMappingURL=point-from-vector.js.map
+1
View File
@@ -0,0 +1 @@
export declare const progress: (from: number, to: number, value: number) => number;
+5
View File
@@ -0,0 +1,5 @@
export const progress = (from, to, value) => {
const toFromDifference = to - from;
return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;
};
//# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
export declare const radiansToDegrees: (radians: number) => number;
+2
View File
@@ -0,0 +1,2 @@
export const radiansToDegrees = (radians) => (radians * 180) / Math.PI;
//# sourceMappingURL=radians-to-degrees.js.map
+1
View File
@@ -0,0 +1 @@
export declare const smoothFrame: (prevValue: number, nextValue: number, duration: number, smoothing?: number) => number;
+4
View File
@@ -0,0 +1,4 @@
import { toDecimal } from './to-decimal';
export const smoothFrame = (prevValue, nextValue, duration, smoothing = 0) => toDecimal(prevValue +
(duration * (nextValue - prevValue)) / Math.max(smoothing, duration));
//# sourceMappingURL=smooth-frame.js.map
+1
View File
@@ -0,0 +1 @@
export declare const smooth: (strength?: number) => (v: number) => number;
+17
View File
@@ -0,0 +1,17 @@
import { smoothFrame } from './smooth-frame';
import { getFrameData } from 'framesync';
export 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;
};
};
//# sourceMappingURL=smooth.js.map
+1
View File
@@ -0,0 +1 @@
export declare const snap: (points: number | number[]) => (v: number) => number;
+24
View File
@@ -0,0 +1,24 @@
export 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;
}
};
}
};
//# sourceMappingURL=snap.js.map
+1
View File
@@ -0,0 +1 @@
export declare const toDecimal: (num: number, precision?: number) => number;
+5
View File
@@ -0,0 +1,5 @@
export const toDecimal = (num, precision = 2) => {
precision = Math.pow(10, precision);
return Math.round(num * precision) / precision;
};
//# sourceMappingURL=to-decimal.js.map
@@ -0,0 +1 @@
export declare function velocityPerFrame(xps: number, frameDuration: number): number;
+4
View File
@@ -0,0 +1,4 @@
export function velocityPerFrame(xps, frameDuration) {
return xps / (1000 / frameDuration);
}
//# sourceMappingURL=velocity-per-frame.js.map
@@ -0,0 +1 @@
export declare function velocityPerSecond(velocity: number, frameDuration: number): number;
@@ -0,0 +1,4 @@
export function velocityPerSecond(velocity, frameDuration) {
return frameDuration ? velocity * (1000 / frameDuration) : 0;
}
//# sourceMappingURL=velocity-per-second.js.map
+1
View File
@@ -0,0 +1 @@
export declare const wrap: (min: number, max: number, v: number) => number;
+5
View File
@@ -0,0 +1,5 @@
export const wrap = (min, max, v) => {
const rangeSize = max - min;
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
};
//# sourceMappingURL=wrap.js.map