refactor: Переработка компонентов на использование хука useGSAP
This commit is contained in:
@@ -8,9 +8,10 @@
|
||||
* Поддерживает клик по точкам для переключения периодов.
|
||||
*/
|
||||
|
||||
import { useGSAP } from '@gsap/react'
|
||||
import classNames from 'classnames'
|
||||
import { gsap } from 'gsap'
|
||||
import { memo, useCallback, useEffect, useMemo, useRef } from 'react'
|
||||
import { memo, useCallback, useMemo, useRef } from 'react'
|
||||
|
||||
import styles from './CircleTimeline.module.scss'
|
||||
import { calculateCoordinates } from '../../lib/utils/calculateCoordinates/calculateCoordinates'
|
||||
@@ -71,52 +72,55 @@ export const CircleTimeline = memo(function CircleTimeline({
|
||||
const titlesRef = useRef<(HTMLSpanElement | null)[]>([])
|
||||
|
||||
/**
|
||||
* Эффект для анимации поворота круга и контр-поворота точек
|
||||
* Запускается при изменении rotation
|
||||
* Анимация поворота круга и контр-поворота точек
|
||||
* Использует useGSAP hook для автоматической очистки анимаций
|
||||
*/
|
||||
useEffect(() => {
|
||||
// Анимация поворота контейнера круга
|
||||
if (circleRef.current) {
|
||||
gsap.to(circleRef.current, {
|
||||
rotation,
|
||||
duration: ANIMATION_DURATION,
|
||||
ease: ANIMATION_EASE,
|
||||
})
|
||||
}
|
||||
|
||||
// Контр-поворот точек, чтобы текст оставался читаемым
|
||||
pointsRef.current.forEach((point, index) => {
|
||||
if (point) {
|
||||
gsap.to(point, {
|
||||
rotation: -rotation,
|
||||
duration: 0,
|
||||
useGSAP(
|
||||
() => {
|
||||
// Анимация поворота контейнера круга
|
||||
if (circleRef.current) {
|
||||
gsap.to(circleRef.current, {
|
||||
rotation,
|
||||
duration: ANIMATION_DURATION,
|
||||
ease: ANIMATION_EASE,
|
||||
})
|
||||
}
|
||||
|
||||
// Анимация заголовка
|
||||
const title = titlesRef.current[index]
|
||||
if (title) {
|
||||
// Сбрасываем предыдущие анимации для этого элемента
|
||||
gsap.killTweensOf(title)
|
||||
// Контр-поворот точек, чтобы текст оставался читаемым
|
||||
pointsRef.current.forEach((point, index) => {
|
||||
if (point) {
|
||||
gsap.to(point, {
|
||||
rotation: -rotation,
|
||||
duration: 0,
|
||||
ease: ANIMATION_EASE,
|
||||
})
|
||||
|
||||
if (index === activeIndex) {
|
||||
gsap.to(title, {
|
||||
opacity: 1,
|
||||
visibility: 'visible',
|
||||
duration: 0.5,
|
||||
delay: ANIMATION_DURATION, // Ждем окончания вращения
|
||||
})
|
||||
} else {
|
||||
gsap.to(title, {
|
||||
opacity: 0,
|
||||
visibility: 'hidden',
|
||||
duration: 0.2,
|
||||
})
|
||||
// Анимация заголовка
|
||||
const title = titlesRef.current[index]
|
||||
if (title) {
|
||||
// Останавливаем предыдущие анимации для предотвращения конфликтов
|
||||
gsap.killTweensOf(title)
|
||||
|
||||
if (index === activeIndex) {
|
||||
gsap.to(title, {
|
||||
opacity: 1,
|
||||
visibility: 'visible',
|
||||
duration: 0.5,
|
||||
delay: ANIMATION_DURATION, // Ждем окончания вращения
|
||||
})
|
||||
} else {
|
||||
gsap.to(title, {
|
||||
opacity: 0,
|
||||
visibility: 'hidden',
|
||||
duration: 0.2,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}, [rotation, activeIndex])
|
||||
})
|
||||
},
|
||||
{ dependencies: [rotation, activeIndex] }
|
||||
)
|
||||
|
||||
/**
|
||||
* Мемоизированный расчет позиций точек на круге
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
* Отображает список исторических событий в виде слайдера
|
||||
*/
|
||||
|
||||
import { useGSAP } from '@gsap/react'
|
||||
import classNames from 'classnames'
|
||||
import { gsap } from 'gsap'
|
||||
import { memo, useEffect, useRef, useState } from 'react'
|
||||
import { memo, useRef, useState } from 'react'
|
||||
import { Swiper, SwiperSlide } from 'swiper/react'
|
||||
|
||||
import 'swiper/css'
|
||||
@@ -45,7 +46,7 @@ export interface EventsCarouselProps {
|
||||
*
|
||||
* Использует Swiper для создания слайдера с кастомной навигацией.
|
||||
* Поддерживает адаптивное количество слайдов на разных размерах экрана.
|
||||
* Анимирует появление/исчезновение с помощью GSAP.
|
||||
* Анимирует появление/исчезновение с помощью GSAP useGSAP hook.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
@@ -62,13 +63,11 @@ export const EventsCarousel = memo(
|
||||
const [isEnd, setIsEnd] = useState(false)
|
||||
|
||||
/**
|
||||
* Эффект для анимации появления/исчезновения карусели
|
||||
* Использует GSAP для плавной анимации opacity и y-позиции
|
||||
* Анимация появления/исчезновения карусели
|
||||
* Использует useGSAP hook для автоматической очистки анимаций
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return
|
||||
|
||||
const ctx = gsap.context(() => {
|
||||
useGSAP(
|
||||
() => {
|
||||
if (visible) {
|
||||
gsap.fromTo(
|
||||
containerRef.current,
|
||||
@@ -86,10 +85,9 @@ export const EventsCarousel = memo(
|
||||
duration: HIDE_DURATION,
|
||||
})
|
||||
}
|
||||
}, containerRef)
|
||||
|
||||
return () => ctx.revert()
|
||||
}, [visible, events])
|
||||
},
|
||||
{ scope: containerRef, dependencies: [visible, events] }
|
||||
)
|
||||
|
||||
/**
|
||||
* Обработчик инициализации Swiper
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Главный компонент временной шкалы с круговой диаграммой и каруселью событий
|
||||
*/
|
||||
|
||||
import { useGSAP } from '@gsap/react'
|
||||
import classNames from 'classnames'
|
||||
import { gsap } from 'gsap'
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
@@ -21,7 +22,7 @@ import { EventsCarousel } from '../EventsCarousel/EventsCarousel'
|
||||
*
|
||||
* Отображает исторические периоды на круговой диаграмме с возможностью
|
||||
* переключения между ними. Для каждого периода показывается карусель событий.
|
||||
* Центральные даты анимируются при смене периода с помощью GSAP.
|
||||
* Центральные даты анимируются при смене периода с помощью GSAP useGSAP hook.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
@@ -66,13 +67,11 @@ export const TimeFrameSlider = memo(() => {
|
||||
}, [activePeriod, anglePerPoint])
|
||||
|
||||
/**
|
||||
* Анимация центральных дат с использованием GSAP
|
||||
* Анимация центральных дат с использованием GSAP useGSAP hook
|
||||
* Плавно изменяет числа при смене периода
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return
|
||||
|
||||
const ctx = gsap.context(() => {
|
||||
useGSAP(
|
||||
() => {
|
||||
if (startYearRef.current) {
|
||||
gsap.fromTo(
|
||||
startYearRef.current,
|
||||
@@ -109,10 +108,12 @@ export const TimeFrameSlider = memo(() => {
|
||||
{ opacity: 1, visibility: 'visible', duration: 1 }
|
||||
)
|
||||
}
|
||||
}, containerRef)
|
||||
|
||||
return () => ctx.revert()
|
||||
}, [currentPeriod.yearFrom, currentPeriod.yearTo])
|
||||
},
|
||||
{
|
||||
scope: containerRef,
|
||||
dependencies: [currentPeriod.yearFrom, currentPeriod.yearTo],
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Переключение на предыдущий период
|
||||
|
||||
Reference in New Issue
Block a user