Код: Выделить всё
import { FC, useEffect, useRef, useMemo, useCallback } from 'react';
import styles from './SpinningBarWheel.module.css';
import SlotItem from './spinBarHighlight/slotItem/SlotBackgroundItem';
import WheelHighlight from './spinBarHighlight/wheelHighlight/WheelHighlight';
// import { isMatchingPrize } from '../wheelDropModals/spinBarUtils';
import type { WinNotificationType, PrizedropPrizeType } from '@pp/core/src/api/fetchers/promotionsV2/types/promotions';
interface Props {
spinBarItems: { text: string; color: string; isBaseColor?: boolean; prize?: PrizedropPrizeType }[];
result: WinNotificationType;
}
const SpinningBarWheel: FC = ({ result, spinBarItems }) => {
console.log(result, "result");
const reelRef = useRef(null);
const posRef = useRef(0);
const animRef = useRef();
const winningIndexRef = useRef(null);
const rowHeight = 100;
const reelLength = spinBarItems.length * rowHeight;
const getMiddleOffset = () => window.innerHeight / 2 - rowHeight / 2;
console.log(getMiddleOffset(), 'getMiddleOffset');
// useEffect(() => {
// const handleResize = () => {
// if (winningIndexRef.current !== null && reelRef.current) {
// const loops = 10;
// const newOffset = getMiddleOffset();
// const targetPos = -((winningIndexRef.current + loops * spinBarItems.length) * rowHeight) + newOffset;
// posRef.current = targetPos;
// reelRef.current.style.transform = `translateY(${posRef.current % reelLength}px)`;
// }
// };
// window.addEventListener('resize', handleResize);
// return () => window.removeEventListener('resize', handleResize);
// }, [spinBarItems.length, reelLength, rowHeight]);
const getMiddleTextElement = useCallback(() => {
if (!reelRef.current) return null;
const rects = Array.from(reelRef.current.children) as HTMLDivElement[];
const middleY = window.innerHeight / 2;
for (const child of rects) {
const rect = child.getBoundingClientRect();
if (rect.top = middleY) {
return child.querySelector('span') as HTMLSpanElement;
}
}
return null;
}, []);
const renderedSlotItems = useMemo(() => {
const loops = 6;
return Array.from({ length: Math.ceil(loops) }).flatMap((_, i) =>
spinBarItems.map((item, j) => (
))
);
}, [spinBarItems]);
const easeOutCubic = useCallback((t: number) => 1 - Math.pow(1 - t, 3), []);
useEffect(() => {
const candidatePositions: number[] = [];
spinBarItems.forEach((item, idx) => {
if (idx === 3) {
winningIndexRef.current = idx; // Save for snapping later
console.log(idx, "idx");
for (let loop = 0; loop < 20; loop++) {
const pos = getMiddleOffset() - ((idx + loop * spinBarItems.length) * rowHeight);
console.log(pos, "pos");
candidatePositions.push(pos);
}
}
});
const target = candidatePositions[candidatePositions.length - 1];
const start = posRef.current;
const distance = target - start;
const duration = 500;
const startTime = Date.now();
console.log({ target, start, distance }, 'animation start');
const animate = () => {
const elapsed = Date.now() - startTime;
const t = Math.min(1, elapsed / duration);
const eased = easeOutCubic(t);
posRef.current = start + distance * eased;
if (reelRef.current) {
reelRef.current.style.transform = `translateY(${posRef.current % reelLength}px)`;
console.log(posRef.current % reelLength, 'current pos');
}
if (t < 1) {
animRef.current = requestAnimationFrame(animate);
} else {
const middleSpan = getMiddleTextElement();
if (middleSpan) {
middleSpan.classList.add(styles.resultScale);
setTimeout(() => middleSpan.classList.remove(styles.resultScale), 4000);
}
}
};
animRef.current = requestAnimationFrame(animate);
return () => {
if (animRef.current) {
cancelAnimationFrame(animRef.current);
}
};
}, [result, spinBarItems, reelLength, easeOutCubic, getMiddleTextElement]);
return (
{renderedSlotItems}
);
};
export default SpinningBarWheel;< /code>
Подробнее здесь: https://stackoverflow.com/questions/797 ... -bottom-to