diff --git a/apps/sn/app/(map-layout)/map/components/fldngHstry/FldngHstryFeatureClick.tsx b/apps/sn/app/(map-layout)/map/components/fldngHstry/FldngHstryFeatureClick.tsx index a379b5e40..8c717a2f9 100644 --- a/apps/sn/app/(map-layout)/map/components/fldngHstry/FldngHstryFeatureClick.tsx +++ b/apps/sn/app/(map-layout)/map/components/fldngHstry/FldngHstryFeatureClick.tsx @@ -5,6 +5,7 @@ "use client"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import type { RefObject } from "react"; import GisApp from "@common/business_components/ui/map/lib/gis.core"; import type Feature from "ol/Feature.js"; import VectorSource from "ol/source/Vector.js"; @@ -29,6 +30,96 @@ type FldngHstryGisLayer = { ) => void | Promise; }; +type FldngHstryScrollButtonProps = { + targetRef: RefObject; + direction: -1 | 1; + label: string; + children: string; +}; + +const FLDNG_HSTRY_SCROLL_CLICK_DISTANCE = 120; +const FLDNG_HSTRY_SCROLL_HOLD_DELAY = 300; +const FLDNG_HSTRY_SCROLL_HOLD_SPEED = 4; + +/** 짧게 누르면 한 칸, 길게 누르면 목록을 해당 방향으로 계속 이동한다. */ +const FldngHstryScrollButton = ({ + targetRef, + direction, + label, + children, +}: FldngHstryScrollButtonProps) => { + const holdTimerRef = useRef | null>(null); + const animationFrameRef = useRef(null); + const pointerClickHandledRef = useRef(false); + + const stopContinuousScroll = useCallback(() => { + if (holdTimerRef.current !== null) { + clearTimeout(holdTimerRef.current); + holdTimerRef.current = null; + } + if (animationFrameRef.current !== null) { + cancelAnimationFrame(animationFrameRef.current); + animationFrameRef.current = null; + } + }, []); + + const scrollOnce = useCallback(() => { + targetRef.current?.scrollBy({ + left: direction * FLDNG_HSTRY_SCROLL_CLICK_DISTANCE, + behavior: "smooth", + }); + }, [direction, targetRef]); + + const startContinuousScroll = useCallback(() => { + const scroll = () => { + const target = targetRef.current; + if (!target) { + stopContinuousScroll(); + return; + } + target.scrollLeft += direction * FLDNG_HSTRY_SCROLL_HOLD_SPEED; + animationFrameRef.current = requestAnimationFrame(scroll); + }; + animationFrameRef.current = requestAnimationFrame(scroll); + }, [direction, stopContinuousScroll, targetRef]); + + useEffect(() => stopContinuousScroll, [stopContinuousScroll]); + + return ( + + ); +}; + const cloneFldngHstryFeature = (feature: Feature) => { const clonedFeature = feature.clone(); const featureId = feature.getId(); @@ -171,19 +262,13 @@ export const useFldngHstryFeatureClick = () => { 심선 - +
{ ); })}
- + )} {fldngHstryWtlvRows.length > 0 && ( @@ -251,19 +330,13 @@ export const useFldngHstryFeatureClick = () => { 위선 - +
{ ); })}
- + )} diff --git a/packages/common/business_components/src/ui/map/lib/css/gis.common.css b/packages/common/business_components/src/ui/map/lib/css/gis.common.css index c7436fcab..c28560482 100644 --- a/packages/common/business_components/src/ui/map/lib/css/gis.common.css +++ b/packages/common/business_components/src/ui/map/lib/css/gis.common.css @@ -292,9 +292,14 @@ cursor: pointer; } +.zoom-level-panel .zoom-level-btn:first-child { + border-radius: 3px 3px 0 0; +} + .zoom-level-panel .zoom-level-btn:last-child { border-top: 1px solid #eeeeee; border-bottom: 0 none; + border-radius: 0 0 3px 3px; } .zoom-level-btn:hover {