You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
234 lines
6.3 KiB
234 lines
6.3 KiB
|
3 weeks ago
|
/**
|
||
|
|
* 弹窗 center 入场曲线:冲击弹出 → 微回弹 → 落锁 → 等比轻弹收尾(仅 bounce)
|
||
|
|
*/
|
||
|
|
|
||
|
|
const JELLY_DUR = 0.64;
|
||
|
|
const SEG1 = 0.26;
|
||
|
|
const SEG2 = 0.1;
|
||
|
|
const SEG3 = 0.13;
|
||
|
|
const SEG4 = 0.15;
|
||
|
|
|
||
|
|
/** @deprecated 由 adaptivePopDuration 替代 */
|
||
|
|
export const POP_OVERSHOOT_DUR = 0.11;
|
||
|
|
/** @deprecated */
|
||
|
|
export const POP_SETTLE_BACK_DUR = 0.09;
|
||
|
|
/** @deprecated */
|
||
|
|
export const POP_JELLY_SETTLE_DUR = 0.22;
|
||
|
|
/** @deprecated */
|
||
|
|
export const POP_CENTER_POP_IN_DUR = POP_OVERSHOOT_DUR + POP_SETTLE_BACK_DUR;
|
||
|
|
/** @deprecated */
|
||
|
|
export const POP_JELLY_DURATION = POP_CENTER_POP_IN_DUR + POP_JELLY_SETTLE_DUR;
|
||
|
|
/** @deprecated */
|
||
|
|
export const POP_OVERSHOOT_SCALE = 1.09;
|
||
|
|
/** @deprecated */
|
||
|
|
export const POP_JELLY_PANEL_AMP = 0.275;
|
||
|
|
|
||
|
|
/** 内部子项 reveal 与 center 弹入重叠启动 */
|
||
|
|
export const POP_REVEAL_START_DELAY = 0.04;
|
||
|
|
|
||
|
|
/** 阶段1:0 → 峰值,爆发式弹出 */
|
||
|
|
export function popImpactLaunch(t: number, peak: number): number {
|
||
|
|
return peak * easeOutExpo(clamp01(t));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 阶段1 Y 轴:高处砸落 */
|
||
|
|
export function popImpactDropY(t: number, lift: number): number {
|
||
|
|
return lift * (1 - easeOutCubic(clamp01(t)));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 阶段2:峰值 → 微欠冲(撞击回弹感) */
|
||
|
|
export function popImpactRecoil(t: number, peak: number, undershoot: number): number {
|
||
|
|
return lerp(peak, undershoot, easeInQuad(clamp01(t)));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 阶段3:欠冲 → 1,落锁 */
|
||
|
|
export function popImpactLock(t: number, undershoot: number): number {
|
||
|
|
return lerp(undershoot, 1, easeOutCubic(clamp01(t)));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 阶段4:等比轻弹收尾(衰减正弦,不压扁变形) */
|
||
|
|
export function popImpactTailBounce(t: number, amp: number): { scale: number; yOff: number } {
|
||
|
|
const phase = clamp01(t);
|
||
|
|
const fade = Math.pow(1 - phase, 0.65);
|
||
|
|
const wave = Math.sin(phase * Math.PI);
|
||
|
|
const bump = wave * fade;
|
||
|
|
return {
|
||
|
|
scale: 1 + amp * 0.06 * bump,
|
||
|
|
yOff: -amp * 4 * bump,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @deprecated 使用 popImpactTailBounce */
|
||
|
|
export function popImpactJelly(t: number, amp: number): { sx: number; sy: number } {
|
||
|
|
const { scale } = popImpactTailBounce(t, amp);
|
||
|
|
return { sx: scale, sy: scale };
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 弹出透明度闪光 */
|
||
|
|
export function popImpactOpacity(t: number, start: number): number {
|
||
|
|
const eased = easeOutQuad(clamp01(t));
|
||
|
|
return lerp(start, 255, eased);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @deprecated */
|
||
|
|
export function popCenterOvershootUniform(t: number, peak = 1.09): number {
|
||
|
|
return popImpactLaunch(t, peak);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @deprecated */
|
||
|
|
export function popCenterSettleUniform(t: number, peak = 1.09): number {
|
||
|
|
return popImpactRecoil(t, peak, 0.98);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @deprecated */
|
||
|
|
export function popJellySettle(t: number, amp = 0.275): { sx: number; sy: number } {
|
||
|
|
return popImpactJelly(t, amp);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @deprecated */
|
||
|
|
export function popCenterPopInYOffset(t: number, lift = 10): number {
|
||
|
|
return popImpactDropY(t, lift);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @deprecated */
|
||
|
|
export function popCenterPopInScale(t: number): number {
|
||
|
|
return popImpactLaunch(t, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 子节点错峰:等比缩放 */
|
||
|
|
export function popItemStaggerScale(t: number, overshoot = 1.9): number {
|
||
|
|
const eased = easeOutBack(clamp01(t), overshoot);
|
||
|
|
return Math.min(eased, 1.08);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function popItemRevealScale(t: number): number {
|
||
|
|
return popItemStaggerScale(t, 1.9);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function popItemCelebrateScale(t: number): number {
|
||
|
|
return popItemStaggerScale(t, 2.1);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function popJellySquash(t: number, amp = 1): { sx: number; sy: number } {
|
||
|
|
const phase = clamp01(t) * JELLY_DUR;
|
||
|
|
let sx: number;
|
||
|
|
let sy: number;
|
||
|
|
|
||
|
|
if (phase <= SEG1) {
|
||
|
|
const p = quadIn(phase / SEG1);
|
||
|
|
sx = lerp(0.2, 0.75, p);
|
||
|
|
sy = lerp(0.2, 1.4, p);
|
||
|
|
} else if (phase <= SEG1 + SEG2) {
|
||
|
|
const p = quadOut((phase - SEG1) / SEG2);
|
||
|
|
sx = lerp(0.75, 1.6, p);
|
||
|
|
sy = lerp(1.4, 0.4, p);
|
||
|
|
} else if (phase <= SEG1 + SEG2 + SEG3) {
|
||
|
|
const p = easeOutBack((phase - SEG1 - SEG2) / SEG3, 1.7);
|
||
|
|
sx = lerp(1.6, 0.8, p);
|
||
|
|
sy = lerp(0.4, 1.38, p);
|
||
|
|
} else {
|
||
|
|
const p = sineOut((phase - SEG1 - SEG2 - SEG3) / SEG4);
|
||
|
|
sx = lerp(0.8, 1, p);
|
||
|
|
sy = lerp(1.38, 1, p);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (amp === 1) return { sx, sy };
|
||
|
|
return { sx: 1 + (sx - 1) * amp, sy: 1 + (sy - 1) * amp };
|
||
|
|
}
|
||
|
|
|
||
|
|
export function popJellyLift(t: number, lift = 44): number {
|
||
|
|
const phase = clamp01(t) * JELLY_DUR;
|
||
|
|
if (phase <= SEG1) return lift * (1 - quadIn(phase / SEG1));
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @deprecated */
|
||
|
|
export function popBounceSquash(t: number, amp = 0.275): { sx: number; sy: number } {
|
||
|
|
return popJellySquash(t, amp);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @deprecated */
|
||
|
|
export function popCenterScale(t: number, overshoot = 1.75): number {
|
||
|
|
const { sx, sy } = popJellySquash(t, 0.35);
|
||
|
|
return (sx + sy) * 0.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @deprecated */
|
||
|
|
export function popBounceAngleDeg(_t: number): number {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function popEnterYOffset(t: number, lift = 14): number {
|
||
|
|
return popJellyLift(t, lift);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function popCelebrateYOffset(t: number): number {
|
||
|
|
return popJellyLift(t, 20);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @deprecated */
|
||
|
|
export function popEnterScale(t: number): number {
|
||
|
|
return popCenterScale(t);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @deprecated */
|
||
|
|
export function popCelebrateScale(t: number): number {
|
||
|
|
return popCenterScale(t);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function popExitScale(t: number): number {
|
||
|
|
return 1 - easeInBack(clamp01(t), 2.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function popExitYOffset(t: number): number {
|
||
|
|
return 8 * easeInBack(clamp01(t), 1.6);
|
||
|
|
}
|
||
|
|
|
||
|
|
function lerp(a: number, b: number, t: number): number {
|
||
|
|
return a + (b - a) * t;
|
||
|
|
}
|
||
|
|
|
||
|
|
function clamp01(t: number): number {
|
||
|
|
if (t <= 0) return 0;
|
||
|
|
if (t >= 1) return 1;
|
||
|
|
return t;
|
||
|
|
}
|
||
|
|
|
||
|
|
function quadIn(t: number): number {
|
||
|
|
return t * t;
|
||
|
|
}
|
||
|
|
|
||
|
|
function quadOut(t: number): number {
|
||
|
|
return 1 - (1 - t) * (1 - t);
|
||
|
|
}
|
||
|
|
|
||
|
|
function easeInQuad(t: number): number {
|
||
|
|
return t * t;
|
||
|
|
}
|
||
|
|
|
||
|
|
function easeOutQuad(t: number): number {
|
||
|
|
return 1 - (1 - t) * (1 - t);
|
||
|
|
}
|
||
|
|
|
||
|
|
function sineOut(t: number): number {
|
||
|
|
return Math.sin(t * Math.PI / 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
function easeOutCubic(t: number): number {
|
||
|
|
return 1 - Math.pow(1 - t, 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
function easeOutExpo(t: number): number {
|
||
|
|
return t >= 1 ? 1 : 1 - Math.pow(2, -10 * t);
|
||
|
|
}
|
||
|
|
|
||
|
|
function easeOutBack(t: number, overshoot: number): number {
|
||
|
|
const c = overshoot + 1;
|
||
|
|
return 1 + c * Math.pow(t - 1, 3) + overshoot * Math.pow(t - 1, 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
function easeInBack(t: number, overshoot: number): number {
|
||
|
|
const c = overshoot + 1;
|
||
|
|
return c * t * t * t - overshoot * t * t;
|
||
|
|
}
|