Work CaseRoulette

This commit is contained in:
2025-12-07 03:26:54 +05:00
parent 39f8ec875b
commit bbd0dd11b0

View File

@ -20,6 +20,9 @@ const CENTER_INDEX = Math.floor(VISIBLE_ITEMS / 2);
const CONTAINER_WIDTH = 800; const CONTAINER_WIDTH = 800;
const LINE_X = CONTAINER_WIDTH / 2; const LINE_X = CONTAINER_WIDTH / 2;
const ANIMATION_DURATION = 10; // секунды
const ANIMATION_DURATION_MS = ANIMATION_DURATION * 1000;
function getRarityByWeight(weight?: number): Rarity { function getRarityByWeight(weight?: number): Rarity {
if (weight === undefined || weight === null) return 'common'; if (weight === undefined || weight === null) return 'common';
if (weight <= 5) return 'legendary'; if (weight <= 5) return 'legendary';
@ -105,50 +108,61 @@ export default function CaseRoulette({
const startAnimation = () => { const startAnimation = () => {
const widths = measureItemWidths(); const widths = measureItemWidths();
const winPosition = Math.floor(sequence.length / 2);
// Сколько "оборотов" хотим сделать до остановки
const EXTRA_SPINS = 3;
const averageItemWidth = ITEM_WIDTH + ITEM_GAP;
const extraDistance = EXTRA_SPINS * VISIBLE_ITEMS * averageItemWidth;
// fallback, если не смогли корректно измерить ширины
if (widths.length === 0 || widths.length !== sequence.length) { if (widths.length === 0 || widths.length !== sequence.length) {
// Если не удалось измерить, используем базовую ширину
const winPosition = Math.floor(sequence.length / 2);
const centerItemCenter = const centerItemCenter =
winPosition * (ITEM_WIDTH + ITEM_GAP) + ITEM_WIDTH / 2; winPosition * (ITEM_WIDTH + ITEM_GAP) + ITEM_WIDTH / 2;
const initialOffset = centerItemCenter - CONTAINER_WIDTH;
const finalOffset = centerItemCenter - LINE_X;
const finalOffset = centerItemCenter - LINE_X;
// стартовая позиция чуть левее финальной (едем вправо к ней)
const initialOffset = Math.max(finalOffset - extraDistance, 0);
// ставим ленту далеко "слева", чтобы она много проехала
setOffset(initialOffset); setOffset(initialOffset);
animationTimeoutRef.current = setTimeout(() => { animationTimeoutRef.current = setTimeout(() => {
setAnimating(true); setAnimating(true);
setOffset(finalOffset); setOffset(finalOffset);
}, 200); }, 50);
// 7 секунд анимации + небольшой запас
finishTimeoutRef.current = setTimeout(() => { finishTimeoutRef.current = setTimeout(() => {
setAnimationFinished(true); setAnimationFinished(true);
}, 7000); }, ANIMATION_DURATION_MS + 200);
return; return;
} }
const winPosition = Math.floor(sequence.length / 2); // вариант с реальными ширинами
let cumulativeOffset = 0; let cumulativeOffset = 0;
for (let i = 0; i < winPosition; i++) { for (let i = 0; i < winPosition; i++) {
cumulativeOffset += widths[i] + ITEM_GAP; cumulativeOffset += widths[i] + ITEM_GAP;
} }
const centerItemCenter = cumulativeOffset + widths[winPosition] / 2; const centerItemCenter = cumulativeOffset + widths[winPosition] / 2;
const initialOffset = centerItemCenter - CONTAINER_WIDTH;
const finalOffset = centerItemCenter - LINE_X; const finalOffset = centerItemCenter - LINE_X;
// стартовая позиция чуть левее финальной (едем вправо к ней)
const initialOffset = Math.max(finalOffset - extraDistance, 0);
setOffset(initialOffset); setOffset(initialOffset);
animationTimeoutRef.current = setTimeout(() => { animationTimeoutRef.current = setTimeout(() => {
setAnimating(true); setAnimating(true);
setOffset(finalOffset); setOffset(finalOffset);
}, 100); }, 50);
finishTimeoutRef.current = setTimeout(() => { finishTimeoutRef.current = setTimeout(() => {
setAnimationFinished(true); setAnimationFinished(true);
}, 3100); }, ANIMATION_DURATION_MS + 200);
}; };
// Даем время на рендер элементов
const renderTimeout = setTimeout(startAnimation, 100); const renderTimeout = setTimeout(startAnimation, 100);
return () => { return () => {
@ -230,7 +244,7 @@ export default function CaseRoulette({
transform: `translateX(-${offset}px)`, transform: `translateX(-${offset}px)`,
willChange: 'transform', willChange: 'transform',
transition: animating transition: animating
? 'transform 7s cubic-bezier(0.1, 0.8, 0.2, 1)' ? `transform ${ANIMATION_DURATION}s cubic-bezier(0.15, 0.85, 0.25, 1)`
: 'none', : 'none',
}} }}
> >