import { useMemo, useState } from 'react'; import { Marker, Popup } from 'react-map-gl/maplibre'; import type { PowerFacility } from '../services/infra'; // SVG Wind Turbine Icon function WindTurbineIcon({ color, size = 14 }: { color: string; size?: number }) { return ( {/* Tower */} {/* Hub */} {/* Blade 1 - top */} {/* Blade 2 - bottom-right */} {/* Blade 3 - bottom-left */} {/* Base */} ); } interface Props { facilities: PowerFacility[]; } // Source → icon & color const SOURCE_STYLE: Record = { nuclear: { icon: '☢️', color: '#e040fb', label: '원자력' }, coal: { icon: '🏭', color: '#795548', label: '석탄' }, gas: { icon: '🔥', color: '#ff9800', label: 'LNG' }, oil: { icon: '🛢️', color: '#5d4037', label: '석유' }, hydro: { icon: '💧', color: '#2196f3', label: '수력' }, solar: { icon: '☀️', color: '#ffc107', label: '태양광' }, wind: { icon: '🌀', color: '#00bcd4', label: '풍력' }, biomass: { icon: '🌿', color: '#4caf50', label: '바이오' }, }; const SUBSTATION_STYLE = { icon: '⚡', color: '#ffeb3b', label: '변전소' }; function getStyle(f: PowerFacility) { if (f.type === 'substation') return SUBSTATION_STYLE; return SOURCE_STYLE[f.source || ''] || { icon: '⚡', color: '#9e9e9e', label: '발전소' }; } function formatVoltage(v?: string): string { if (!v) return ''; const kv = parseInt(v) / 1000; if (isNaN(kv)) return v; return `${kv}kV`; } export function InfraLayer({ facilities }: Props) { const [selectedId, setSelectedId] = useState(null); const plants = useMemo(() => facilities.filter(f => f.type === 'plant'), [facilities]); const substations = useMemo(() => facilities.filter(f => f.type === 'substation'), [facilities]); const selected = selectedId ? facilities.find(f => f.id === selectedId) ?? null : null; return ( <> {/* Substations — smaller, show at higher zoom */} {substations.map(f => { const s = getStyle(f); return ( { e.originalEvent.stopPropagation(); setSelectedId(f.id); }}>
{s.icon}
); })} {/* Power plants — larger, always visible */} {plants.map(f => { const s = getStyle(f); const isWind = f.source === 'wind'; return ( { e.originalEvent.stopPropagation(); setSelectedId(f.id); }}>
{isWind ? ( ) : (
{s.icon}
)}
{f.name.length > 10 ? f.name.slice(0, 10) + '..' : f.name}
); })} {/* Popup */} {selected && ( setSelectedId(null)} closeOnClick={false} anchor="bottom" maxWidth="280px" className="gl-popup">
{getStyle(selected).icon} {selected.name}
{getStyle(selected).label} {selected.type === 'plant' ? '발전소' : '변전소'}
{selected.output && (
출력: {selected.output}
)} {selected.voltage && (
전압: {formatVoltage(selected.voltage)}
)} {selected.operator && (
운영: {selected.operator}
)} {selected.source && (
연료: {selected.source}
)}
{selected.lat.toFixed(4)}°N, {selected.lng.toFixed(4)}°E
)} ); }