refactor: Логика координат точки на круге вынесена в отельную функцию, исправлены стили

This commit is contained in:
Ilia Mashkov
2025-11-20 16:07:18 +03:00
parent b84acfc3e7
commit c970d9c6d0
3 changed files with 34 additions and 46 deletions

View File

@@ -6,7 +6,7 @@
--color-bg: #F4F5F9;
--color-border: rgb(66 86 122 / 10%);
--color-blue: #3877EE;
--color-white: #FFFFFF;
--color-white: #FFF;
// Градиенты
--gradient-primary: linear-gradient(to right, #3877EE, #EF5DA8);

View File

@@ -1,6 +1,4 @@
.circleContainer {
$border-color: var(--color-primary);
position: absolute;
top: 50%;
left: 50%;
@@ -8,7 +6,7 @@
width: calc(var(--circle-radius, 265px) * 2);
height: calc(var(--circle-radius, 265px) * 2);
border: 1px solid rgb($border-color / 20%);
border: 1px solid rgba(#42567A, 0.2);
border-radius: 50%;
transform: translate(-50%, -50%);
@@ -17,46 +15,48 @@
.point {
position: absolute;
width: 6px;
height: 6px;
margin-top: -3px;
margin-left: -3px;
width: 56px;
height: 56px;
margin-top: -28px;
margin-left: -28px;
border: 25px solid transparent;
border-radius: 50%;
background: var(--color-text);
background-clip: content-box;
cursor: pointer;
background: var(--color-text);
border-radius: 50%;
transform-origin: center;
transition: all 0.3s ease;
transform-origin: center;
&:hover,
&.active {
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
align-items: center;
width: 56px;
height: 56px;
margin-top: -28px;
margin-left: -28px;
border: 1px solid rgb(48 62 88 / 50%);
border: 1px solid rgba(#303E58, 0.5);
background: #F4F5F9;
}
.label {
display: none;
font-size: 20px;
color: var(--color-text);
background-clip: padding-box;
}
&:hover .label,
&.active .label {
display: block;
}
.label {
display: none;
color: var(--color-text);
font-size: 20px;
}
}

View File

@@ -8,17 +8,13 @@
* Поддерживает клик по точкам для переключения периодов.
*/
import classNames from 'classnames'
import gsap from 'gsap'
import { memo, useCallback, useEffect, useMemo, useRef } from 'react'
import styles from './CircleTimeline.module.scss'
import {
ANIMATION_DURATION,
ANIMATION_EASE,
CIRCLE_RADIUS,
FULL_CIRCLE_DEGREES,
HALF_CIRCLE_DEGREES,
} from '../../model'
import { calculateCoordinates } from '../../lib/utils/calculateCoordinates/calculateCoordinates'
import { ANIMATION_DURATION, ANIMATION_EASE } from '../../model'
import type { TimePeriod } from '@/entities/TimePeriod'
@@ -90,7 +86,7 @@ export const CircleTimeline = memo(function CircleTimeline({
if (point) {
gsap.to(point, {
rotation: -rotation,
duration: ANIMATION_DURATION,
duration: 0,
ease: ANIMATION_EASE,
})
}
@@ -102,19 +98,9 @@ export const CircleTimeline = memo(function CircleTimeline({
* Пересчитывается только при изменении количества периодов
*/
const pointPositions = useMemo(() => {
return periods.map((_, index) => {
// Угол для текущей точки (в градусах)
const angle = (FULL_CIRCLE_DEGREES / periods.length) * index
// Конвертация в радианы для тригонометрических функций
const radian = (angle * Math.PI) / HALF_CIRCLE_DEGREES
// Вычисление координат на круге
const x = CIRCLE_RADIUS * Math.cos(radian)
const y = CIRCLE_RADIUS * Math.sin(radian)
return { x, y }
})
return periods.map((_, index, array) =>
calculateCoordinates(array.length, index)
)
}, [periods])
/**
@@ -139,7 +125,9 @@ export const CircleTimeline = memo(function CircleTimeline({
ref={(el) => {
pointsRef.current[index] = el
}}
className={`${styles.point} ${index === activeIndex ? styles.active : ''}`}
className={classNames(styles.point, {
[styles.active]: index === activeIndex,
})}
style={{
left: `calc(50% + ${x}px)`,
top: `calc(50% + ${y}px)`,