From 23341b93c73e7496cda812a58bbbc627ab4adbdf Mon Sep 17 00:00:00 2001 From: ljpark Date: Tue, 8 Sep 2026 18:15:40 +0900 Subject: [PATCH] =?UTF-8?q?sn:=20=EC=B9=A8=EC=88=98=ED=9D=94=EC=A0=81?= =?UTF-8?q?=EC=8B=AC=EC=84=A0/=EC=9C=84=EC=84=A0=20=ED=99=94=EC=82=B4?= =?UTF-8?q?=ED=91=9C=20=EC=97=B0=EC=86=8D=20scroll=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fldngHstry/FldngHstryFeatureClick.tsx | 155 +++++++++++++----- .../src/ui/map/lib/css/gis.common.css | 5 + 2 files changed, 116 insertions(+), 44 deletions(-) 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 {