From bbd0dd11b00bc5cc870ba524b30c1f53b44c24dd Mon Sep 17 00:00:00 2001 From: DIKER0K Date: Sun, 7 Dec 2025 03:26:54 +0500 Subject: [PATCH] Work CaseRoulette --- src/renderer/components/CaseRoulette.tsx | 38 ++++++++++++++++-------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/renderer/components/CaseRoulette.tsx b/src/renderer/components/CaseRoulette.tsx index 14666d7..49edf36 100644 --- a/src/renderer/components/CaseRoulette.tsx +++ b/src/renderer/components/CaseRoulette.tsx @@ -20,6 +20,9 @@ const CENTER_INDEX = Math.floor(VISIBLE_ITEMS / 2); const CONTAINER_WIDTH = 800; const LINE_X = CONTAINER_WIDTH / 2; +const ANIMATION_DURATION = 10; // секунды +const ANIMATION_DURATION_MS = ANIMATION_DURATION * 1000; + function getRarityByWeight(weight?: number): Rarity { if (weight === undefined || weight === null) return 'common'; if (weight <= 5) return 'legendary'; @@ -105,50 +108,61 @@ export default function CaseRoulette({ const startAnimation = () => { 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) { - // Если не удалось измерить, используем базовую ширину - const winPosition = Math.floor(sequence.length / 2); const centerItemCenter = 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); animationTimeoutRef.current = setTimeout(() => { setAnimating(true); setOffset(finalOffset); - }, 200); + }, 50); + // 7 секунд анимации + небольшой запас finishTimeoutRef.current = setTimeout(() => { setAnimationFinished(true); - }, 7000); + }, ANIMATION_DURATION_MS + 200); return; } - const winPosition = Math.floor(sequence.length / 2); + // вариант с реальными ширинами let cumulativeOffset = 0; for (let i = 0; i < winPosition; i++) { cumulativeOffset += widths[i] + ITEM_GAP; } const centerItemCenter = cumulativeOffset + widths[winPosition] / 2; - const initialOffset = centerItemCenter - CONTAINER_WIDTH; + const finalOffset = centerItemCenter - LINE_X; + // стартовая позиция чуть левее финальной (едем вправо к ней) + const initialOffset = Math.max(finalOffset - extraDistance, 0); setOffset(initialOffset); animationTimeoutRef.current = setTimeout(() => { setAnimating(true); setOffset(finalOffset); - }, 100); + }, 50); finishTimeoutRef.current = setTimeout(() => { setAnimationFinished(true); - }, 3100); + }, ANIMATION_DURATION_MS + 200); }; - // Даем время на рендер элементов const renderTimeout = setTimeout(startAnimation, 100); return () => { @@ -230,7 +244,7 @@ export default function CaseRoulette({ transform: `translateX(-${offset}px)`, willChange: 'transform', 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', }} >