From 0a4850d3f4101592a8a34decaa1f9214b649bb96 Mon Sep 17 00:00:00 2001 From: htlee Date: Tue, 31 Mar 2026 14:56:38 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat(map):=20AIS=20=EB=A1=9C=EB=94=A9=20?= =?UTF-8?q?=EC=9D=B8=EB=94=94=EC=BC=80=EC=9D=B4=ED=84=B0=20=EB=B0=8F=20UX?= =?UTF-8?q?=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 선박 신호 수신 중 지도 오버레이 + 스피너 인디케이터 표시 - 초기 뷰포트를 대한민국 전역 중심(127.8, 35.5, zoom 7)으로 변경 - deck.gl 툴팁 배경색을 흰색 계통으로 변경하여 가독성 개선 Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/wing-gis-web/src/App.css | 8 ++++---- .../src/components/map/MapViewML.tsx | 16 ++++++++++++++++ frontend/wing-gis-web/src/hooks/useAisPolling.ts | 10 +++++++++- frontend/wing-gis-web/src/hooks/useStore.ts | 4 ++++ .../wing-gis-web/src/lib/map/mapConstants.ts | 8 ++++---- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/frontend/wing-gis-web/src/App.css b/frontend/wing-gis-web/src/App.css index 089ad60..ba4a6a0 100644 --- a/frontend/wing-gis-web/src/App.css +++ b/frontend/wing-gis-web/src/App.css @@ -63,11 +63,11 @@ body { /* deck.gl tooltip */ .deck-tooltip{ - background:rgba(26,58,74,.96)!important; - color:#fff!important; - border:1px solid rgba(0,147,178,.35)!important; + background:rgba(255,255,255,.97)!important; + color:#1a2e38!important; + border:1px solid #d4dde2!important; border-radius:6px!important; - box-shadow:0 6px 20px rgba(0,0,0,.35)!important; + box-shadow:0 4px 16px rgba(0,0,0,.15)!important; padding:7px 9px!important; font-size:12px!important; line-height:1.35!important; diff --git a/frontend/wing-gis-web/src/components/map/MapViewML.tsx b/frontend/wing-gis-web/src/components/map/MapViewML.tsx index b42fed2..a03aa66 100644 --- a/frontend/wing-gis-web/src/components/map/MapViewML.tsx +++ b/frontend/wing-gis-web/src/components/map/MapViewML.tsx @@ -30,6 +30,8 @@ const MapViewML: React.FC = ({ children }) => { const [scaleText, setScaleText] = React.useState('1:50,000'); const [zoom, setZoom] = React.useState(10); + const aisLoading = useStore((s) => s.aisLoading); + const aisEmpty = useStore((s) => s.aisTargets.size === 0); const photoModal = useStore((s) => s.photoModal); const openPhotoModal = useStore((s) => s.openPhotoModal); const closePhotoModal = useStore((s) => s.closePhotoModal); @@ -97,6 +99,20 @@ const MapViewML: React.FC = ({ children }) => { {children} + + {(aisLoading || aisEmpty) && ( + <> +
+
+ + + + + 선박 신호 수신 중... +
+ + )} + {photoModal && ( diff --git a/frontend/wing-gis-web/src/hooks/useAisPolling.ts b/frontend/wing-gis-web/src/hooks/useAisPolling.ts index 5a9cdca..bc64a3d 100644 --- a/frontend/wing-gis-web/src/hooks/useAisPolling.ts +++ b/frontend/wing-gis-web/src/hooks/useAisPolling.ts @@ -10,6 +10,7 @@ const RETENTION_MS = 120 * 60 * 1000; export function useAisPolling() { const setAisTargets = useStore((s) => s.setAisTargets); + const setAisLoading = useStore((s) => s.setAisLoading); const storeRef = useRef(useStore.getState); useEffect(() => { @@ -19,6 +20,7 @@ export function useAisPolling() { useEffect(() => { const ac = new AbortController(); let timer: ReturnType | null = null; + let isInitial = true; function mergeAndPrune(incoming: AisTarget[]) { const prev = storeRef.current().aisTargets; @@ -43,12 +45,18 @@ export function useAisPolling() { async function poll(minutes: number) { try { + if (isInitial) setAisLoading(true); const targets = await fetchRecentPositions(minutes, ac.signal); mergeAndPrune(targets); } catch (err) { if ((err as Error).name !== 'AbortError') { console.warn('[AIS] Poll failed:', err); } + } finally { + if (isInitial) { + setAisLoading(false); + isInitial = false; + } } } @@ -61,5 +69,5 @@ export function useAisPolling() { ac.abort(); if (timer) clearInterval(timer); }; - }, [setAisTargets]); + }, [setAisTargets, setAisLoading]); } diff --git a/frontend/wing-gis-web/src/hooks/useStore.ts b/frontend/wing-gis-web/src/hooks/useStore.ts index 04a4a77..9da38ec 100644 --- a/frontend/wing-gis-web/src/hooks/useStore.ts +++ b/frontend/wing-gis-web/src/hooks/useStore.ts @@ -28,6 +28,8 @@ interface AppState { // AIS 실시간 데이터 aisTargets: Map; setAisTargets: (targets: Map) => void; + aisLoading: boolean; + setAisLoading: (loading: boolean) => void; // 선박 사진 모달 photoModal: { imo: number; name: string; imagePath: string; imageCount: number } | null; @@ -72,6 +74,8 @@ export const useStore = create((set) => ({ aisTargets: new Map(), setAisTargets: (targets) => set({ aisTargets: targets }), + aisLoading: true, + setAisLoading: (loading) => set({ aisLoading: loading }), photoModal: null, openPhotoModal: (info) => set({ photoModal: info }), diff --git a/frontend/wing-gis-web/src/lib/map/mapConstants.ts b/frontend/wing-gis-web/src/lib/map/mapConstants.ts index 9d2ed96..2c515fe 100644 --- a/frontend/wing-gis-web/src/lib/map/mapConstants.ts +++ b/frontend/wing-gis-web/src/lib/map/mapConstants.ts @@ -1,10 +1,10 @@ import type maplibregl from 'maplibre-gl'; -/** 인천 해역 기본 중심 좌표 [lng, lat] */ -export const DEFAULT_CENTER: [number, number] = [126.7052, 37.4563]; +/** 대한민국 전역 중심 좌표 [lng, lat] */ +export const DEFAULT_CENTER: [number, number] = [127.8, 35.5]; -/** 기본 줌 레벨 */ -export const DEFAULT_ZOOM = 10; +/** 기본 줌 레벨 (대한민국 전역 표시) */ +export const DEFAULT_ZOOM = 7; /** Martin ENC 타일 서버 프록시 경로 */ export const MARTIN_BASE_PATH = '/martin'; From 115b8a6bf236b40a1929fe2bcfa9d2f0e1695b35 Mon Sep 17 00:00:00 2001 From: htlee Date: Tue, 31 Mar 2026 15:31:17 +0900 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20=EB=A6=B4=EB=A6=AC=EC=A6=88=20?= =?UTF-8?q?=EB=85=B8=ED=8A=B8=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/RELEASE-NOTES.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/RELEASE-NOTES.md b/docs/RELEASE-NOTES.md index 2033dd3..11ccec3 100644 --- a/docs/RELEASE-NOTES.md +++ b/docs/RELEASE-NOTES.md @@ -4,6 +4,13 @@ ## [Unreleased] +### 추가 +- 선박 신호 수신 중 지도 오버레이 + 스피너 로딩 인디케이터 표시 + +### 변경 +- 초기 뷰포트를 대한민국 전역 중심(zoom 7)으로 변경 +- deck.gl 선박 툴팁 배경색을 흰색 계통으로 변경하여 가독성 개선 + ## [2026-03-31] ### 수정