fix(map): zone 간소화를 projectionBusy 앞으로 이동
소스 데이터 간소화가 projectionBusy 가드 뒤에 있어서 globe 전환 시 원본 데이터(2100+ vertex)로 tessellation 진행 → 73,000+ vertex 폭증. setData를 가드 앞으로 이동하고 useMemo로 간소화 데이터 캐싱. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
부모
7bec1ae86d
커밋
d5700ba587
@ -1,4 +1,4 @@
|
||||
import { useEffect, type MutableRefObject } from 'react';
|
||||
import { useEffect, useMemo, type MutableRefObject } from 'react';
|
||||
import maplibregl, {
|
||||
type GeoJSONSource,
|
||||
type GeoJSONSourceSpecification,
|
||||
@ -54,6 +54,12 @@ export function useZonesLayer(
|
||||
) {
|
||||
const { zones, overlays, projection, baseMap, hoveredZoneId, mapSyncEpoch } = opts;
|
||||
|
||||
// globe용 간소화 데이터를 미리 캐싱 — ensure() 내 매번 재계산 방지
|
||||
const simplifiedZones = useMemo(
|
||||
() => (zones ? simplifyZonesForGlobe(zones) : null),
|
||||
[zones],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const map = mapRef.current;
|
||||
if (!map) return;
|
||||
@ -75,26 +81,32 @@ export function useZonesLayer(
|
||||
zoneLabelExpr.push(['coalesce', ['get', 'zoneName'], ['get', 'zoneLabel'], ['get', 'NAME'], '수역']);
|
||||
|
||||
const ensure = () => {
|
||||
if (projectionBusyRef.current) return;
|
||||
// 소스 데이터 간소화 — projectionBusy 중에도 실행해야 함
|
||||
// globe 전환 시 projectionBusy 가드 뒤에서만 실행하면 MapLibre가
|
||||
// 원본(2100+ vertex) 데이터로 globe tessellation → 73,000+ vertex → 노란 막대
|
||||
const sourceData = projection === 'globe' ? simplifiedZones : zones;
|
||||
if (sourceData) {
|
||||
try {
|
||||
const existing = map.getSource(srcId) as GeoJSONSource | undefined;
|
||||
if (existing) existing.setData(sourceData);
|
||||
} catch { /* ignore — source may not exist yet */ }
|
||||
}
|
||||
|
||||
const visibility: 'visible' | 'none' = overlays.zones ? 'visible' : 'none';
|
||||
// globe 모드에서 fill polygon은 tessellation으로 vertex 65535 초과 → 숨김
|
||||
// (해안선 디테일 2100+ vertex가 globe에서 100,000+로 폭증하여 노란 막대 아티팩트 발생)
|
||||
const fillVisibility: 'visible' | 'none' = projection === 'globe' ? 'none' : visibility;
|
||||
guardedSetVisibility(map, fillId, fillVisibility);
|
||||
guardedSetVisibility(map, lineId, visibility);
|
||||
guardedSetVisibility(map, labelId, visibility);
|
||||
|
||||
if (projectionBusyRef.current) return;
|
||||
if (!zones) return;
|
||||
if (!map.isStyleLoaded()) return;
|
||||
|
||||
try {
|
||||
// globe: 서브샘플링된 데이터로 vertex 폭증 방지, mercator: 원본 데이터
|
||||
const sourceData = projection === 'globe' ? simplifyZonesForGlobe(zones) : zones;
|
||||
const existing = map.getSource(srcId) as GeoJSONSource | undefined;
|
||||
if (existing) {
|
||||
existing.setData(sourceData);
|
||||
} else {
|
||||
map.addSource(srcId, { type: 'geojson', data: sourceData } as GeoJSONSourceSpecification);
|
||||
// 소스가 아직 없으면 생성 (setData는 위에서 이미 처리됨)
|
||||
if (!map.getSource(srcId)) {
|
||||
const data = projection === 'globe' ? simplifiedZones ?? zones : zones;
|
||||
map.addSource(srcId, { type: 'geojson', data: data! } as GeoJSONSourceSpecification);
|
||||
}
|
||||
|
||||
const style = map.getStyle();
|
||||
@ -247,5 +259,5 @@ export function useZonesLayer(
|
||||
return () => {
|
||||
stop();
|
||||
};
|
||||
}, [zones, overlays.zones, projection, baseMap, hoveredZoneId, mapSyncEpoch, reorderGlobeFeatureLayers]);
|
||||
}, [zones, simplifiedZones, overlays.zones, projection, baseMap, hoveredZoneId, mapSyncEpoch, reorderGlobeFeatureLayers]);
|
||||
}
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user