분석레포트 타임라인 표시

This commit is contained in:
Macbook
2026-06-10 16:53:03 +09:00
parent 55b1c75226
commit bf5554d375
12 changed files with 2032 additions and 28 deletions
@@ -0,0 +1,43 @@
import { useLayoutEffect, type RefObject } from 'react';
/** 봉 시간축 — 시간 레일이 스크롤 영역 중앙(세로·가로)에 오도록 조정 */
export function useCenterAxisTimelineScroll(
scrollRef: RefObject<HTMLElement | null>,
trackRef: RefObject<HTMLElement | null>,
enabled: boolean,
deps: unknown[] = [],
): void {
useLayoutEffect(() => {
if (!enabled) return;
const scroll = scrollRef.current;
const track = trackRef.current;
if (!scroll || !track) return;
const center = () => {
const rail = track.querySelector('.arp-timeline-axis-rail') as HTMLElement | null;
if (rail) {
const scrollRect = scroll.getBoundingClientRect();
const railRect = rail.getBoundingClientRect();
const railMidInContent =
scroll.scrollTop + (railRect.top - scrollRect.top) + railRect.height / 2;
const targetTop = railMidInContent - scroll.clientHeight / 2;
scroll.scrollTop = Math.max(0, Math.min(
targetTop,
scroll.scrollHeight - scroll.clientHeight,
));
}
const targetLeft = (scroll.scrollWidth - scroll.clientWidth) / 2;
scroll.scrollLeft = Math.max(0, targetLeft);
};
center();
requestAnimationFrame(center);
const ro = new ResizeObserver(() => center());
ro.observe(scroll);
ro.observe(track);
return () => ro.disconnect();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [enabled, scrollRef, trackRef, ...deps]);
}
@@ -0,0 +1,29 @@
import { useEffect, type RefObject } from 'react';
/** 가로 overflow 컨테이너 — 세로 휠을 좌우 스크롤로 변환 */
export function useHorizontalWheelScroll(
ref: RefObject<HTMLElement | null>,
enabled = true,
): void {
useEffect(() => {
if (!enabled) return;
const el = ref.current;
if (!el) return;
const onWheel = (e: WheelEvent) => {
if (el.scrollWidth <= el.clientWidth + 1) return;
const delta = Math.abs(e.deltaX) > Math.abs(e.deltaY) ? e.deltaX : e.deltaY;
if (delta === 0) return;
const prev = el.scrollLeft;
el.scrollLeft += delta;
if (el.scrollLeft !== prev) {
e.preventDefault();
}
};
el.addEventListener('wheel', onWheel, { passive: false });
return () => el.removeEventListener('wheel', onWheel);
}, [enabled, ref]);
}