aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
274 lines (272 loc) • 9.74 kB
JavaScript
class InterpolationUtils {
/**
* Linear interpolation between two points
*/
static lerp(a, b, t) {
return a + (b - a) * t;
}
/**
* Linear interpolation for 2D points
*/
static lerp2D(p1, p2, t) {
return {
x: this.lerp(p1.x, p2.x, t),
y: this.lerp(p1.y, p2.y, t)
};
}
/**
* Cubic interpolation using Catmull-Rom spline
*/
static catmullRom(p0, p1, p2, p3, t, alpha = 0.5) {
// Centripetal Catmull-Rom
const t0 = 0;
const t1 = this.getT(t0, p0, p1, alpha);
const t2 = this.getT(t1, p1, p2, alpha);
const t3 = this.getT(t2, p2, p3, alpha);
const tNormalized = t1 + (t2 - t1) * t;
const a1x = (t1 - tNormalized) / (t1 - t0) * p0.x + (tNormalized - t0) / (t1 - t0) * p1.x;
const a1y = (t1 - tNormalized) / (t1 - t0) * p0.y + (tNormalized - t0) / (t1 - t0) * p1.y;
const a2x = (t2 - tNormalized) / (t2 - t1) * p1.x + (tNormalized - t1) / (t2 - t1) * p2.x;
const a2y = (t2 - tNormalized) / (t2 - t1) * p1.y + (tNormalized - t1) / (t2 - t1) * p2.y;
const a3x = (t3 - tNormalized) / (t3 - t2) * p2.x + (tNormalized - t2) / (t3 - t2) * p3.x;
const a3y = (t3 - tNormalized) / (t3 - t2) * p2.y + (tNormalized - t2) / (t3 - t2) * p3.y;
const b1x = (t2 - tNormalized) / (t2 - t0) * a1x + (tNormalized - t0) / (t2 - t0) * a2x;
const b1y = (t2 - tNormalized) / (t2 - t0) * a1y + (tNormalized - t0) / (t2 - t0) * a2y;
const b2x = (t3 - tNormalized) / (t3 - t1) * a2x + (tNormalized - t1) / (t3 - t1) * a3x;
const b2y = (t3 - tNormalized) / (t3 - t1) * a2y + (tNormalized - t1) / (t3 - t1) * a3y;
const cx = (t2 - tNormalized) / (t2 - t1) * b1x + (tNormalized - t1) / (t2 - t1) * b2x;
const cy = (t2 - tNormalized) / (t2 - t1) * b1y + (tNormalized - t1) / (t2 - t1) * b2y;
return {
x: cx,
y: cy
};
}
static getT(t, p0, p1, alpha) {
const dx = p1.x - p0.x;
const dy = p1.y - p0.y;
const distance = Math.sqrt(dx * dx + dy * dy);
return t + Math.pow(distance, alpha);
}
/**
* Hermite interpolation
*/
static hermite(p0, p1, m0, m1, t) {
const t2 = t * t;
const t3 = t2 * t;
const h00 = 2 * t3 - 3 * t2 + 1;
const h10 = t3 - 2 * t2 + t;
const h01 = -2 * t3 + 3 * t2;
const h11 = t3 - t2;
return {
x: h00 * p0.x + h10 * m0.x + h01 * p1.x + h11 * m1.x,
y: h00 * p0.y + h10 * m0.y + h01 * p1.y + h11 * m1.y
};
}
/**
* Cubic Bezier interpolation
*/
static bezier(p0, p1, p2, p3, t) {
const u = 1 - t;
const tt = t * t;
const uu = u * u;
const uuu = uu * u;
const ttt = tt * t;
return {
x: uuu * p0.x + 3 * uu * t * p1.x + 3 * u * tt * p2.x + ttt * p3.x,
y: uuu * p0.y + 3 * uu * t * p1.y + 3 * u * tt * p2.y + ttt * p3.y
};
}
/**
* B-spline interpolation
*/
static bSpline(points, t, degree = 3) {
const n = points.length - 1;
const k = Math.floor(t * (n - degree + 1));
const u = t * (n - degree + 1) - k;
let x = 0;
let y = 0;
for (let i = 0; i <= degree; i++) {
const weight = this.bSplineBasis(i, degree, u);
x += weight * points[k + i].x;
y += weight * points[k + i].y;
}
return {
x,
y
};
}
static bSplineBasis(i, p, u) {
if (p === 0) {
return u >= 0 && u <= 1 ? 1 : 0;
}
const left = (u - i) / p * this.bSplineBasis(i, p - 1, u);
const right = (i + p + 1 - u) / p * this.bSplineBasis(i + 1, p - 1, u);
return left + right;
}
/**
* Smooth step interpolation
*/
static smoothStep(edge0, edge1, x) {
const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));
return t * t * (3 - 2 * t);
}
/**
* Smoother step interpolation
*/
static smootherStep(edge0, edge1, x) {
const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));
return t * t * t * (t * (t * 6 - 15) + 10);
}
/**
* Interpolate along a path defined by points
*/
static interpolatePath(points, config, t) {
if (points.length === 0) return {
x: 0,
y: 0
};
if (points.length === 1) return {
x: points[0].x,
y: points[0].y
};
if (points.length === 2) return this.lerp2D(points[0], points[1], t);
switch (config.type) {
case 'linear':
return this.interpolateLinear(points, t);
case 'cubic':
return this.interpolateCubic(points, t, config.alpha);
case 'hermite':
return this.interpolateHermite(points, t, config.tension, config.bias, config.continuity);
case 'bezier':
return this.interpolateBezier(points, t);
case 'spline':
return this.bSpline(points, t);
default:
return this.interpolateLinear(points, t);
}
}
static interpolateLinear(points, t) {
const totalSegments = points.length - 1;
const segmentIndex = Math.floor(t * totalSegments);
const segmentT = t * totalSegments % 1;
if (segmentIndex >= totalSegments) {
return {
x: points[points.length - 1].x,
y: points[points.length - 1].y
};
}
return this.lerp2D(points[segmentIndex], points[segmentIndex + 1], segmentT);
}
static interpolateCubic(points, t, alpha = 0.5) {
const n = points.length - 1;
const i = Math.floor(t * n);
const u = t * n % 1;
if (i === 0) {
return this.catmullRom(points[0], points[0], points[1], points[2], u, alpha);
} else if (i === n) {
return this.catmullRom(points[n - 2], points[n - 1], points[n], points[n], u, alpha);
} else {
return this.catmullRom(points[i - 1], points[i], points[i + 1], points[i + 2], u, alpha);
}
}
static interpolateHermite(points, t, tension = 0, bias = 0, continuity = 0) {
const n = points.length - 1;
const i = Math.floor(t * n);
const u = t * n % 1;
if (i === 0) {
this.calculateTangent(points[0], points[1], points[2], tension, bias, continuity);
const m2 = this.calculateTangent(points[1], points[0], points[2], tension, bias, continuity);
return this.hermite(points[0], points[1], {
x: 0,
y: 0
}, m2, u);
} else if (i === n) {
const m1 = this.calculateTangent(points[n - 1], points[n - 2], points[n], tension, bias, continuity);
this.calculateTangent(points[n], points[n - 1], points[n - 1], tension, bias, continuity);
return this.hermite(points[n - 1], points[n], m1, {
x: 0,
y: 0
}, u);
} else {
const m1 = this.calculateTangent(points[i], points[i - 1], points[i + 1], tension, bias, continuity);
const m2 = this.calculateTangent(points[i + 1], points[i], points[i + 2], tension, bias, continuity);
return this.hermite(points[i], points[i + 1], m1, m2, u);
}
}
static calculateTangent(p, prev, next, tension, bias, continuity) {
const dPrev = {
x: p.x - prev.x,
y: p.y - prev.y
};
const dNext = {
x: next.x - p.x,
y: next.y - p.y
};
const dPrevLength = Math.sqrt(dPrev.x * dPrev.x + dPrev.y * dPrev.y);
const dNextLength = Math.sqrt(dNext.x * dNext.x + dNext.y * dNext.y);
if (dPrevLength === 0 || dNextLength === 0) {
return {
x: 0,
y: 0
};
}
const tensionFactor = (1 - tension) * 0.5;
const biasFactor = 1 + bias;
const continuityFactor = 1 - continuity;
return {
x: tensionFactor * (dPrev.x / dPrevLength * biasFactor + dNext.x / dNextLength * (2 - biasFactor)) * continuityFactor,
y: tensionFactor * (dPrev.y / dPrevLength * biasFactor + dNext.y / dNextLength * (2 - biasFactor)) * continuityFactor
};
}
static interpolateBezier(points, t) {
// For Bezier, we need control points. This is a simplified implementation.
// In practice, you'd need to specify control points separately.
const n = points.length - 1;
const i = Math.floor(t * n);
const u = t * n % 1;
if (i === 0) {
return this.bezier(points[0], points[0], points[1], points[2], u);
} else if (i === n) {
return this.bezier(points[n - 2], points[n - 1], points[n], points[n], u);
} else {
return this.bezier(points[i - 1], points[i], points[i + 1], points[i + 2], u);
}
}
}
// Utility functions for common interpolation patterns
const interpolate = {
linear: (a, b, t) => InterpolationUtils.lerp(a, b, t),
smooth: (a, b, t) => InterpolationUtils.smoothStep(a, b, t),
smoother: (a, b, t) => InterpolationUtils.smootherStep(a, b, t),
// Color interpolation
color: (color1, color2, t) => {
// Parse hex colors
const c1 = color1.replace('#', '');
const c2 = color2.replace('#', '');
const r1 = parseInt(c1.substr(0, 2), 16);
const g1 = parseInt(c1.substr(2, 2), 16);
const b1 = parseInt(c1.substr(4, 2), 16);
const r2 = parseInt(c2.substr(0, 2), 16);
const g2 = parseInt(c2.substr(2, 2), 16);
const b2 = parseInt(c2.substr(4, 2), 16);
const r = Math.round(InterpolationUtils.lerp(r1, r2, t));
const g = Math.round(InterpolationUtils.lerp(g1, g2, t));
const b = Math.round(InterpolationUtils.lerp(b1, b2, t));
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
},
// Path interpolation
path: (points, config, t) => InterpolationUtils.interpolatePath(points, config, t),
// Array interpolation
array: (arr1, arr2, t) => {
const result = [];
const maxLength = Math.max(arr1.length, arr2.length);
for (let i = 0; i < maxLength; i++) {
const val1 = arr1[i] || 0;
const val2 = arr2[i] || 0;
result.push(InterpolationUtils.lerp(val1, val2, t));
}
return result;
}
};
export { InterpolationUtils, interpolate };
//# sourceMappingURL=interpolation.js.map