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