- lazy + 동적 import로 DEV에서만 청크 로드 - mapRef 기반 이벤트 등록으로 KoreaMap 코드에 디버그 흔적 없음 - 이전 CoordDebugTool/useCoordDebug 삭제
91 lines
3.1 KiB
TypeScript
91 lines
3.1 KiB
TypeScript
/**
|
||
* [DEBUG] 좌표 디버그 — 자체 완결형 래퍼
|
||
* KoreaMap에서 이 컴포넌트만 동적 import하면 프로덕션 번들에서 완전 제거됨.
|
||
* import, 훅, 컴포넌트 모두 이 파일 안에서 독립적으로 존재.
|
||
*/
|
||
import { useState, useEffect } from 'react';
|
||
import { Marker, Popup } from 'react-map-gl/maplibre';
|
||
import type { MapRef } from 'react-map-gl/maplibre';
|
||
|
||
interface CoordPoint {
|
||
lat: number;
|
||
lng: number;
|
||
id: number;
|
||
}
|
||
|
||
function toDMS(dd: number, axis: 'lat' | 'lng'): string {
|
||
const dir = axis === 'lat' ? (dd >= 0 ? 'N' : 'S') : (dd >= 0 ? 'E' : 'W');
|
||
const abs = Math.abs(dd);
|
||
const d = Math.floor(abs);
|
||
const mFull = (abs - d) * 60;
|
||
const m = Math.floor(mFull);
|
||
const s = ((mFull - m) * 60).toFixed(2);
|
||
return `${d}°${String(m).padStart(2, '0')}′${String(s).padStart(5, '0')}″${dir}`;
|
||
}
|
||
|
||
interface Props {
|
||
mapRef: React.RefObject<MapRef | null>;
|
||
}
|
||
|
||
/**
|
||
* 자체 완결형 디버그 오버레이.
|
||
* mapRef를 받아서 직접 click 이벤트를 등록/해제.
|
||
* KoreaMap의 기존 코드에 어떤 것도 섞이지 않음.
|
||
*/
|
||
export default function DevCoordDebug({ mapRef }: Props) {
|
||
const [points, setPoints] = useState<CoordPoint[]>([]);
|
||
|
||
useEffect(() => {
|
||
const map = mapRef.current?.getMap();
|
||
if (!map) return;
|
||
|
||
const handler = (e: maplibregl.MapMouseEvent) => {
|
||
if (e.originalEvent.ctrlKey || e.originalEvent.metaKey) {
|
||
e.originalEvent.preventDefault();
|
||
setPoints(prev => [...prev, { lat: e.lngLat.lat, lng: e.lngLat.lng, id: Date.now() }]);
|
||
}
|
||
};
|
||
|
||
map.on('click', handler);
|
||
return () => { map.off('click', handler); };
|
||
}, [mapRef]);
|
||
|
||
return (
|
||
<>
|
||
{points.map(cp => (
|
||
<div key={cp.id}>
|
||
<Marker longitude={cp.lng} latitude={cp.lat}>
|
||
<div style={{
|
||
width: 12, height: 12, borderRadius: '50%',
|
||
background: '#f43f5e', border: '2px solid #fff',
|
||
boxShadow: '0 0 6px rgba(244,63,94,0.8)',
|
||
}} />
|
||
</Marker>
|
||
<Popup
|
||
longitude={cp.lng}
|
||
latitude={cp.lat}
|
||
onClose={() => setPoints(prev => prev.filter(p => p.id !== cp.id))}
|
||
closeButton={true}
|
||
closeOnClick={false}
|
||
anchor="bottom"
|
||
offset={[0, -10]}
|
||
style={{ zIndex: 50 }}
|
||
>
|
||
<div style={{ fontFamily: 'monospace', fontSize: 11, lineHeight: 1.8, padding: '2px 4px', color: '#fff' }}>
|
||
<div style={{ fontWeight: 700, marginBottom: 4, borderBottom: '1px solid rgba(255,255,255,0.3)', paddingBottom: 2, color: '#93c5fd' }}>
|
||
WGS84 (EPSG:4326)
|
||
</div>
|
||
<div><b>DD</b></div>
|
||
<div style={{ paddingLeft: 8 }}>{cp.lat.toFixed(6)}°N</div>
|
||
<div style={{ paddingLeft: 8 }}>{cp.lng.toFixed(6)}°E</div>
|
||
<div style={{ marginTop: 2 }}><b>DMS</b></div>
|
||
<div style={{ paddingLeft: 8 }}>{toDMS(cp.lat, 'lat')}</div>
|
||
<div style={{ paddingLeft: 8 }}>{toDMS(cp.lng, 'lng')}</div>
|
||
</div>
|
||
</Popup>
|
||
</div>
|
||
))}
|
||
</>
|
||
);
|
||
}
|