perf: 렌더링 성능 최적화 + 환적 Python 이관 + 중국어선감시 통합 #158
@ -189,7 +189,8 @@ export function KoreaMap({ ships, allShips, aircraft, satellites, layers, osintF
|
||||
);
|
||||
}, []);
|
||||
|
||||
// 줌 레벨별 아이콘/심볼 스케일 배율 — z4=1.0x 기준, 2단계씩 상향
|
||||
const anyKoreaFilterOn = koreaFilters.illegalFishing || koreaFilters.illegalTransship || koreaFilters.darkVessel || koreaFilters.cableWatch || koreaFilters.dokdoWatch || koreaFilters.ferryWatch;
|
||||
|
||||
// 줌 레벨별 아이콘/심볼 스케일 배율 — z4=0.8x, z6=1.0x 시작, 2단계씩 상향
|
||||
const zoomScale = useMemo(() => {
|
||||
if (zoomLevel <= 4) return 0.8;
|
||||
@ -568,7 +569,13 @@ export function KoreaMap({ ships, allShips, aircraft, satellites, layers, osintF
|
||||
/>
|
||||
</Source>
|
||||
|
||||
{layers.ships && <ShipLayer ships={allShips ?? ships} militaryOnly={layers.militaryOnly} analysisMap={vesselAnalysis?.analysisMap} hiddenShipCategories={hiddenShipCategories} hiddenNationalities={hiddenNationalities} />}
|
||||
{layers.ships && <ShipLayer
|
||||
ships={anyKoreaFilterOn ? ships : (allShips ?? ships)}
|
||||
militaryOnly={layers.militaryOnly}
|
||||
analysisMap={vesselAnalysis?.analysisMap}
|
||||
hiddenShipCategories={hiddenShipCategories}
|
||||
hiddenNationalities={hiddenNationalities}
|
||||
/>}
|
||||
{/* Transship suspect labels — Marker DOM, inline styles kept for dynamic border color */}
|
||||
{transshipSuspects.size > 0 && ships.filter(s => transshipSuspects.has(s.mmsi)).map(s => (
|
||||
<Marker key={`ts-${s.mmsi}`} longitude={s.lng} latitude={s.lat} anchor="bottom">
|
||||
@ -671,14 +678,29 @@ export function KoreaMap({ ships, allShips, aircraft, satellites, layers, osintF
|
||||
{layers.osint && <OsintMapLayer osintFeed={osintFeed} currentTime={currentTime} />}
|
||||
{layers.eez && <EezLayer />}
|
||||
|
||||
{/* Filter Status Banner */}
|
||||
{/* Filter Status Banner — 필터별 개별 탐지 카운트 */}
|
||||
{(() => {
|
||||
const active = (Object.keys(koreaFilters) as (keyof KoreaFiltersState)[]).filter(k => koreaFilters[k]);
|
||||
if (active.length === 0) return null;
|
||||
const filterCount: Record<string, number> = {
|
||||
illegalFishing: (allShips ?? ships).filter(s => {
|
||||
if (s.mtCategory !== 'fishing' || s.flag === 'KR') return false;
|
||||
return classifyFishingZone(s.lat, s.lng).zone !== 'OUTSIDE';
|
||||
}).length,
|
||||
illegalTransship: transshipSuspects.size,
|
||||
darkVessel: ships.filter(s => {
|
||||
const dto = vesselAnalysis?.analysisMap.get(s.mmsi);
|
||||
return dto?.algorithms.darkVessel.isDark || (s.lastSeen && currentTime - s.lastSeen > 3600000);
|
||||
}).length,
|
||||
cableWatch: cableWatchSuspects.size,
|
||||
dokdoWatch: dokdoWatchSuspects.size,
|
||||
ferryWatch: (allShips ?? ships).filter(s => s.mtCategory === 'passenger').length,
|
||||
};
|
||||
return (
|
||||
<div className="absolute top-2.5 left-1/2 -translate-x-1/2 z-20 flex gap-1.5 backdrop-blur-lg">
|
||||
{active.map(k => {
|
||||
const color = FILTER_COLOR[k];
|
||||
const count = filterCount[k] ?? 0;
|
||||
return (
|
||||
<div
|
||||
key={k}
|
||||
@ -690,12 +712,10 @@ export function KoreaMap({ ships, allShips, aircraft, satellites, layers, osintF
|
||||
>
|
||||
<span className="text-[13px]">{FILTER_ICON[k]}</span>
|
||||
{t(FILTER_I18N_KEY[k])}
|
||||
<span className="ml-0.5 text-white/80">{count}척</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<div className="rounded-lg px-3 py-1.5 font-mono text-xs font-bold flex items-center bg-kcg-glass border border-kcg-border-light text-white">
|
||||
{t('korea.detected', { count: ships.length })}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user