diff --git a/backend/package-lock.json b/backend/package-lock.json index e5e0aed..a3d5138 100755 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -558,7 +558,6 @@ "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", @@ -1992,7 +1991,6 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.19.0.tgz", "integrity": "sha512-QIcLGi508BAHkQ3pJNptsFz5WQMlpGbuBGBaIaXsWK8mel2kQ/rThYI+DbgjUvZrIr7MiuEuc9LcChJoEZK1xQ==", "license": "MIT", - "peer": true, "dependencies": { "pg-connection-string": "^2.11.0", "pg-pool": "^3.12.0", diff --git a/frontend/src/tabs/weather/components/WeatherMapControls.tsx b/frontend/src/tabs/weather/components/WeatherMapControls.tsx new file mode 100644 index 0000000..56173c6 --- /dev/null +++ b/frontend/src/tabs/weather/components/WeatherMapControls.tsx @@ -0,0 +1,48 @@ +import { useMap } from '@vis.gl/react-maplibre' + +interface WeatherMapControlsProps { + center: [number, number] + zoom: number +} + +export function WeatherMapControls({ center, zoom }: WeatherMapControlsProps) { + const { current: map } = useMap() + + const buttons = [ + { + label: '+', + tooltip: '확대', + onClick: () => map?.zoomIn(), + }, + { + label: '−', + tooltip: '축소', + onClick: () => map?.zoomOut(), + }, + { + label: '🎯', + tooltip: '한국 해역 초기화', + onClick: () => map?.flyTo({ center, zoom, duration: 1000 }), + }, + ] + + return ( +
+
+ {buttons.map(({ label, tooltip, onClick }) => ( +
+ +
+ {tooltip} +
+
+ ))} +
+
+ ) +} diff --git a/frontend/src/tabs/weather/components/WeatherView.tsx b/frontend/src/tabs/weather/components/WeatherView.tsx index c626b27..d3b9bb1 100755 --- a/frontend/src/tabs/weather/components/WeatherView.tsx +++ b/frontend/src/tabs/weather/components/WeatherView.tsx @@ -1,5 +1,5 @@ import { useState, useMemo, useCallback } from 'react' -import { Map, useControl, useMap } from '@vis.gl/react-maplibre' +import { Map, Marker, useControl } from '@vis.gl/react-maplibre' import { MapboxOverlay } from '@deck.gl/mapbox' import type { Layer } from '@deck.gl/core' import type { StyleSpecification, MapLayerMouseEvent } from 'maplibre-gl' @@ -12,6 +12,7 @@ import { useWaterTemperatureLayers } from './WaterTemperatureLayer' import { WindParticleLayer } from './WindParticleLayer' import { useWeatherData } from '../hooks/useWeatherData' import { useOceanForecast } from '../hooks/useOceanForecast' +import { WeatherMapControls } from './WeatherMapControls' type TimeOffset = '0' | '3' | '6' | '9' @@ -117,38 +118,6 @@ function DeckGLOverlay({ layers }: { layers: Layer[] }) { return null } -// 줌 컨트롤 -function WeatherMapControls() { - const { current: map } = useMap() - - return ( -
-
- - - -
-
- ) -} - /** * WeatherMapInner — Map 컴포넌트 내부 (useMap / useControl 사용 가능 영역) */ @@ -159,6 +128,9 @@ interface WeatherMapInnerProps { oceanForecastOpacity: number selectedForecast: ReturnType['selectedForecast'] onStationClick: (station: WeatherStation) => void + mapCenter: [number, number] + mapZoom: number + clickedLocation: { lat: number; lon: number } | null } function WeatherMapInner({ @@ -168,6 +140,9 @@ function WeatherMapInner({ oceanForecastOpacity, selectedForecast, onStationClick, + mapCenter, + mapZoom, + clickedLocation, }: WeatherMapInnerProps) { // deck.gl layers 조합 const weatherDeckLayers = useWeatherDeckLayers( @@ -216,8 +191,31 @@ function WeatherMapInner({ stations={weatherStations} /> + {/* 클릭 위치 마커 */} + {clickedLocation && ( + +
+ {/* 펄스 링 */} +
+
+
+
+ {/* 핀 꼬리 */} +
+ {/* 좌표 라벨 */} +
+ {clickedLocation.lat.toFixed(3)}°N {clickedLocation.lon.toFixed(3)}°E +
+
+ + )} + {/* 줌 컨트롤 */} - + ) } @@ -225,6 +223,8 @@ function WeatherMapInner({ export function WeatherView() { const { weatherStations, loading, error, lastUpdate } = useWeatherData(BASE_STATIONS) + console.log(weatherStations,'날씨'); + const { selectedForecast, availableTimes, @@ -343,12 +343,6 @@ export function WeatherView() {
- -
- -
{/* Map */} @@ -371,6 +365,9 @@ export function WeatherView() { oceanForecastOpacity={oceanForecastOpacity} selectedForecast={selectedForecast} onStationClick={handleStationClick} + mapCenter={WEATHER_MAP_CENTER} + mapZoom={WEATHER_MAP_ZOOM} + clickedLocation={selectedLocation} /> diff --git a/frontend/src/tabs/weather/hooks/useWeatherData.ts b/frontend/src/tabs/weather/hooks/useWeatherData.ts index 37eb2df..909face 100755 --- a/frontend/src/tabs/weather/hooks/useWeatherData.ts +++ b/frontend/src/tabs/weather/hooks/useWeatherData.ts @@ -87,6 +87,7 @@ export function useWeatherData(stations: WeatherStation[]) { } const obs = await getRecentObservation(obsCode) + if (obs) { const r = (n: number) => Math.round(n * 10) / 10 diff --git a/frontend/src/tabs/weather/services/khoaApi.ts b/frontend/src/tabs/weather/services/khoaApi.ts index 5a01d36..cd20ee7 100755 --- a/frontend/src/tabs/weather/services/khoaApi.ts +++ b/frontend/src/tabs/weather/services/khoaApi.ts @@ -157,6 +157,8 @@ export async function getRecentObservation(obsCode: string): Promise