Work CaseRoulette
This commit is contained in:
@ -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',
|
||||
}}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user