fix(map): 라벨 사라짐 + easing 경고 + vertex 경고 수정
- guardedSetVisibility 도입: 현재 값과 동일하면 setLayoutProperty 호출 생략하여 style._changed 트리거 방지 → symbol 재배치로 인한 text-allow-overlap:false 라벨 사라짐 현상 해결 - useGlobeShips 기존 레이어 else 블록의 중복 expression 재설정 제거 (data-driven 표현식은 addLayer 시 1회 설정으로 충분) - _render 래퍼에서 globe scrollZoom easing 경고 억제 - fleet-circles-ml-fill 레이어 완전 제거 (vertex 65535 초과 원인) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
부모
91df90b528
커밋
95d9ea8aef
@ -118,7 +118,7 @@ export function useGlobeInteraction(
|
||||
});
|
||||
}
|
||||
|
||||
if (layerId === 'fleet-circles-ml' || layerId === 'fleet-circles-ml-fill') {
|
||||
if (layerId === 'fleet-circles-ml') {
|
||||
return getFleetCircleTooltipHtml({
|
||||
ownerKey: String(props.ownerKey ?? ''),
|
||||
ownerLabel: String(props.ownerLabel ?? props.ownerKey ?? ''),
|
||||
@ -186,7 +186,7 @@ export function useGlobeInteraction(
|
||||
candidateLayerIds = [
|
||||
'ships-globe', 'ships-globe-halo', 'ships-globe-outline',
|
||||
'pair-lines-ml', 'fc-lines-ml',
|
||||
'fleet-circles-ml', 'fleet-circles-ml-fill',
|
||||
'fleet-circles-ml',
|
||||
'pair-range-ml',
|
||||
'zones-fill', 'zones-line', 'zones-label',
|
||||
].filter((id) => map.getLayer(id));
|
||||
@ -213,7 +213,7 @@ export function useGlobeInteraction(
|
||||
const priority = [
|
||||
'ships-globe', 'ships-globe-halo', 'ships-globe-outline',
|
||||
'pair-lines-ml', 'fc-lines-ml', 'pair-range-ml',
|
||||
'fleet-circles-ml-fill', 'fleet-circles-ml',
|
||||
'fleet-circles-ml',
|
||||
'zones-fill', 'zones-line', 'zones-label',
|
||||
];
|
||||
|
||||
@ -232,7 +232,7 @@ export function useGlobeInteraction(
|
||||
const isShipLayer = layerId === 'ships-globe' || layerId === 'ships-globe-halo' || layerId === 'ships-globe-outline';
|
||||
const isPairLayer = layerId === 'pair-lines-ml' || layerId === 'pair-range-ml';
|
||||
const isFcLayer = layerId === 'fc-lines-ml';
|
||||
const isFleetLayer = layerId === 'fleet-circles-ml' || layerId === 'fleet-circles-ml-fill';
|
||||
const isFleetLayer = layerId === 'fleet-circles-ml';
|
||||
const isZoneLayer = layerId === 'zones-fill' || layerId === 'zones-line' || layerId === 'zones-label';
|
||||
|
||||
if (isShipLayer) {
|
||||
|
||||
@ -11,7 +11,6 @@ import {
|
||||
PAIR_RANGE_NORMAL_ML_HL, PAIR_RANGE_WARN_ML_HL,
|
||||
FC_LINE_NORMAL_ML, FC_LINE_SUSPICIOUS_ML,
|
||||
FC_LINE_NORMAL_ML_HL, FC_LINE_SUSPICIOUS_ML_HL,
|
||||
FLEET_FILL_ML, FLEET_FILL_ML_HL,
|
||||
FLEET_LINE_ML, FLEET_LINE_ML_HL,
|
||||
} from '../constants';
|
||||
import { makeUniqueSorted } from '../lib/setUtils';
|
||||
@ -28,6 +27,7 @@ import {
|
||||
} from '../lib/mlExpressions';
|
||||
import { kickRepaint, onMapStyleReady } from '../lib/mapCore';
|
||||
import { circleRingLngLat } from '../lib/geometry';
|
||||
import { guardedSetVisibility } from '../lib/layerHelpers';
|
||||
import { dashifyLine } from '../lib/dashifyLine';
|
||||
|
||||
export function useGlobeOverlays(
|
||||
@ -60,11 +60,7 @@ export function useGlobeOverlays(
|
||||
const layerId = 'pair-lines-ml';
|
||||
|
||||
const remove = () => {
|
||||
try {
|
||||
if (map.getLayer(layerId)) map.setLayoutProperty(layerId, 'visibility', 'none');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
guardedSetVisibility(map, layerId, 'none');
|
||||
};
|
||||
|
||||
const ensure = () => {
|
||||
@ -132,11 +128,7 @@ export function useGlobeOverlays(
|
||||
console.warn('Pair lines layer add failed:', e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
map.setLayoutProperty(layerId, 'visibility', 'visible');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
guardedSetVisibility(map, layerId, 'visible');
|
||||
}
|
||||
|
||||
reorderGlobeFeatureLayers();
|
||||
@ -159,11 +151,7 @@ export function useGlobeOverlays(
|
||||
const layerId = 'fc-lines-ml';
|
||||
|
||||
const remove = () => {
|
||||
try {
|
||||
if (map.getLayer(layerId)) map.setLayoutProperty(layerId, 'visibility', 'none');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
guardedSetVisibility(map, layerId, 'none');
|
||||
};
|
||||
|
||||
const ensure = () => {
|
||||
@ -235,11 +223,7 @@ export function useGlobeOverlays(
|
||||
console.warn('FC lines layer add failed:', e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
map.setLayoutProperty(layerId, 'visibility', 'visible');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
guardedSetVisibility(map, layerId, 'visible');
|
||||
}
|
||||
|
||||
reorderGlobeFeatureLayers();
|
||||
@ -259,21 +243,13 @@ export function useGlobeOverlays(
|
||||
if (!map) return;
|
||||
|
||||
const srcId = 'fleet-circles-ml-src';
|
||||
const fillSrcId = 'fleet-circles-ml-fill-src';
|
||||
const layerId = 'fleet-circles-ml';
|
||||
const fillLayerId = 'fleet-circles-ml-fill';
|
||||
|
||||
// fill layer 제거됨 — globe tessellation에서 vertex 65535 초과 경고 원인
|
||||
// 라인만으로 fleet circle 시각화 충분
|
||||
|
||||
const remove = () => {
|
||||
try {
|
||||
if (map.getLayer(fillLayerId)) map.setLayoutProperty(fillLayerId, 'visibility', 'none');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
try {
|
||||
if (map.getLayer(layerId)) map.setLayoutProperty(layerId, 'visibility', 'none');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
guardedSetVisibility(map, layerId, 'none');
|
||||
};
|
||||
|
||||
const ensure = () => {
|
||||
@ -304,29 +280,6 @@ export function useGlobeOverlays(
|
||||
}),
|
||||
};
|
||||
|
||||
// fill 폴리곤은 globe 테셀레이션으로 vertex 수가 급격히 증가하므로
|
||||
// 스텝 수를 줄이고 (24), 반경을 500nm으로 상한 설정
|
||||
const MAX_FILL_RADIUS_M = 500 * 1852;
|
||||
const fcFill: GeoJSON.FeatureCollection<GeoJSON.Polygon> = {
|
||||
type: 'FeatureCollection',
|
||||
features: (fleetCircles || []).map((c) => {
|
||||
const ring = circleRingLngLat(c.center, Math.min(c.radiusNm * 1852, MAX_FILL_RADIUS_M), 24);
|
||||
return {
|
||||
type: 'Feature',
|
||||
id: `${makeFleetCircleFeatureId(c.ownerKey)}-fill`,
|
||||
geometry: { type: 'Polygon', coordinates: [ring] },
|
||||
properties: {
|
||||
type: 'fleet-fill',
|
||||
ownerKey: c.ownerKey,
|
||||
ownerLabel: c.ownerLabel,
|
||||
count: c.count,
|
||||
vesselMmsis: c.vesselMmsis,
|
||||
highlighted: 0,
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
try {
|
||||
const existing = map.getSource(srcId) as GeoJSONSource | undefined;
|
||||
if (existing) existing.setData(fcLine);
|
||||
@ -336,41 +289,6 @@ export function useGlobeOverlays(
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const existingFill = map.getSource(fillSrcId) as GeoJSONSource | undefined;
|
||||
if (existingFill) existingFill.setData(fcFill);
|
||||
else map.addSource(fillSrcId, { type: 'geojson', data: fcFill } as GeoJSONSourceSpecification);
|
||||
} catch (e) {
|
||||
console.warn('Fleet circles source setup failed:', e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!map.getLayer(fillLayerId)) {
|
||||
try {
|
||||
map.addLayer(
|
||||
{
|
||||
id: fillLayerId,
|
||||
type: 'fill',
|
||||
source: fillSrcId,
|
||||
layout: { visibility: 'visible' },
|
||||
paint: {
|
||||
'fill-color': ['case', ['==', ['get', 'highlighted'], 1], FLEET_FILL_ML_HL, FLEET_FILL_ML] as never,
|
||||
'fill-opacity': ['case', ['==', ['get', 'highlighted'], 1], 0.7, 0.36] as never,
|
||||
},
|
||||
} as unknown as LayerSpecification,
|
||||
undefined,
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn('Fleet circles fill layer add failed:', e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
map.setLayoutProperty(fillLayerId, 'visibility', 'visible');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (!map.getLayer(layerId)) {
|
||||
try {
|
||||
map.addLayer(
|
||||
@ -391,11 +309,7 @@ export function useGlobeOverlays(
|
||||
console.warn('Fleet circles layer add failed:', e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
map.setLayoutProperty(layerId, 'visibility', 'visible');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
guardedSetVisibility(map, layerId, 'visible');
|
||||
}
|
||||
|
||||
reorderGlobeFeatureLayers();
|
||||
@ -418,11 +332,7 @@ export function useGlobeOverlays(
|
||||
const layerId = 'pair-range-ml';
|
||||
|
||||
const remove = () => {
|
||||
try {
|
||||
if (map.getLayer(layerId)) map.setLayoutProperty(layerId, 'visibility', 'none');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
guardedSetVisibility(map, layerId, 'none');
|
||||
};
|
||||
|
||||
const ensure = () => {
|
||||
@ -506,11 +416,7 @@ export function useGlobeOverlays(
|
||||
console.warn('Pair range layer add failed:', e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
map.setLayoutProperty(layerId, 'visibility', 'visible');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
guardedSetVisibility(map, layerId, 'visible');
|
||||
}
|
||||
|
||||
kickRepaint(map);
|
||||
@ -596,10 +502,7 @@ export function useGlobeOverlays(
|
||||
}
|
||||
|
||||
try {
|
||||
if (map.getLayer('fleet-circles-ml-fill')) {
|
||||
map.setPaintProperty('fleet-circles-ml-fill', 'fill-color', ['case', fleetHighlightExpr, FLEET_FILL_ML_HL, FLEET_FILL_ML] as never);
|
||||
map.setPaintProperty('fleet-circles-ml-fill', 'fill-opacity', ['case', fleetHighlightExpr, 0.7, 0.28] as never);
|
||||
}
|
||||
// fleet-circles-ml-fill 제거됨 (vertex 65535 경고 원인)
|
||||
if (map.getLayer('fleet-circles-ml')) {
|
||||
map.setPaintProperty('fleet-circles-ml', 'line-color', ['case', fleetHighlightExpr, FLEET_LINE_ML_HL, FLEET_LINE_ML] as never);
|
||||
map.setPaintProperty('fleet-circles-ml', 'line-width', ['case', fleetHighlightExpr, 2, 1.1] as never);
|
||||
|
||||
@ -25,6 +25,7 @@ import {
|
||||
ensureFallbackShipImage,
|
||||
} from '../lib/globeShipIcon';
|
||||
import { clampNumber } from '../lib/geometry';
|
||||
import { guardedSetVisibility } from '../lib/layerHelpers';
|
||||
|
||||
export function useGlobeShips(
|
||||
mapRef: MutableRefObject<maplibregl.Map | null>,
|
||||
@ -273,11 +274,10 @@ export function useGlobeShips(
|
||||
const labelId = 'ships-globe-label';
|
||||
|
||||
// 레이어를 제거하지 않고 visibility만 'none'으로 설정
|
||||
// guardedSetVisibility로 현재 값과 동일하면 호출 생략 (style._changed 방지)
|
||||
const hide = () => {
|
||||
for (const id of [labelId, symbolId, outlineId, haloId]) {
|
||||
try {
|
||||
if (map.getLayer(id)) map.setLayoutProperty(id, 'visibility', 'none');
|
||||
} catch { /* ignore */ }
|
||||
guardedSetVisibility(map, id, 'none');
|
||||
}
|
||||
};
|
||||
|
||||
@ -296,15 +296,19 @@ export function useGlobeShips(
|
||||
}
|
||||
|
||||
// 빠른 visibility 토글 — projectionBusy 중에도 실행
|
||||
// 이미 생성된 레이어의 표시 상태만 즉시 전환하여 projection 전환 체감 속도 개선
|
||||
const visibility = projection === 'globe' ? 'visible' : 'none';
|
||||
const labelVisibility = projection === 'globe' && overlays.shipLabels ? 'visible' : 'none';
|
||||
// guardedSetVisibility로 값이 실제로 바뀔 때만 setLayoutProperty 호출
|
||||
// → style._changed 방지 → 불필요한 symbol placement 재계산 방지 → 라벨 사라짐 방지
|
||||
const visibility: 'visible' | 'none' = projection === 'globe' ? 'visible' : 'none';
|
||||
const labelVisibility: 'visible' | 'none' = projection === 'globe' && overlays.shipLabels ? 'visible' : 'none';
|
||||
if (map.getLayer(symbolId)) {
|
||||
for (const id of [haloId, outlineId, symbolId]) {
|
||||
try { map.setLayoutProperty(id, 'visibility', visibility); } catch { /* ignore */ }
|
||||
const changed = map.getLayoutProperty(symbolId, 'visibility') !== visibility;
|
||||
if (changed) {
|
||||
for (const id of [haloId, outlineId, symbolId]) {
|
||||
guardedSetVisibility(map, id, visibility);
|
||||
}
|
||||
if (projection === 'globe') kickRepaint(map);
|
||||
}
|
||||
try { map.setLayoutProperty(labelId, 'visibility', labelVisibility); } catch { /* ignore */ }
|
||||
if (projection === 'globe') kickRepaint(map);
|
||||
guardedSetVisibility(map, labelId, labelVisibility);
|
||||
}
|
||||
|
||||
// 데이터 업데이트는 projectionBusy 중에는 차단
|
||||
@ -374,35 +378,8 @@ export function useGlobeShips(
|
||||
} catch (e) {
|
||||
console.warn('Ship halo layer add failed:', e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
map.setLayoutProperty(haloId, 'visibility', visibility);
|
||||
map.setLayoutProperty(haloId, 'circle-sort-key', [
|
||||
'case',
|
||||
['all', ['==', ['get', 'selected'], 1], ['==', ['get', 'permitted'], 1]], 120,
|
||||
['all', ['==', ['get', 'highlighted'], 1], ['==', ['get', 'permitted'], 1]], 115,
|
||||
['==', ['get', 'permitted'], 1], 110,
|
||||
['==', ['get', 'selected'], 1], 60,
|
||||
['==', ['get', 'highlighted'], 1], 55,
|
||||
20,
|
||||
] as never);
|
||||
map.setPaintProperty(haloId, 'circle-color', [
|
||||
'case',
|
||||
['==', ['get', 'selected'], 1], 'rgba(14,234,255,1)',
|
||||
['==', ['get', 'highlighted'], 1], 'rgba(245,158,11,1)',
|
||||
['coalesce', ['get', 'shipColor'], '#64748b'],
|
||||
] as never);
|
||||
map.setPaintProperty(haloId, 'circle-opacity', [
|
||||
'case',
|
||||
['==', ['get', 'selected'], 1], 0.38,
|
||||
['==', ['get', 'highlighted'], 1], 0.34,
|
||||
0.16,
|
||||
] as never);
|
||||
map.setPaintProperty(haloId, 'circle-radius', GLOBE_SHIP_CIRCLE_RADIUS_EXPR);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
// halo: data-driven expressions are static — visibility handled by fast toggle above
|
||||
|
||||
if (!map.getLayer(outlineId)) {
|
||||
try {
|
||||
@ -448,36 +425,8 @@ export function useGlobeShips(
|
||||
} catch (e) {
|
||||
console.warn('Ship outline layer add failed:', e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
map.setLayoutProperty(outlineId, 'visibility', visibility);
|
||||
map.setLayoutProperty(outlineId, 'circle-sort-key', [
|
||||
'case',
|
||||
['all', ['==', ['get', 'selected'], 1], ['==', ['get', 'permitted'], 1]], 130,
|
||||
['all', ['==', ['get', 'highlighted'], 1], ['==', ['get', 'permitted'], 1]], 125,
|
||||
['==', ['get', 'permitted'], 1], 120,
|
||||
['==', ['get', 'selected'], 1], 70,
|
||||
['==', ['get', 'highlighted'], 1], 65,
|
||||
30,
|
||||
] as never);
|
||||
map.setPaintProperty(outlineId, 'circle-stroke-color', [
|
||||
'case',
|
||||
['==', ['get', 'selected'], 1], 'rgba(14,234,255,0.95)',
|
||||
['==', ['get', 'highlighted'], 1], 'rgba(245,158,11,0.95)',
|
||||
['==', ['get', 'permitted'], 1], GLOBE_OUTLINE_PERMITTED,
|
||||
GLOBE_OUTLINE_OTHER,
|
||||
] as never);
|
||||
map.setPaintProperty(outlineId, 'circle-stroke-width', [
|
||||
'case',
|
||||
['==', ['get', 'selected'], 1], 3.4,
|
||||
['==', ['get', 'highlighted'], 1], 2.7,
|
||||
['==', ['get', 'permitted'], 1], 1.8,
|
||||
0.7,
|
||||
] as never);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
// outline: data-driven expressions are static — visibility handled by fast toggle
|
||||
|
||||
if (!map.getLayer(symbolId)) {
|
||||
try {
|
||||
@ -538,29 +487,8 @@ export function useGlobeShips(
|
||||
} catch (e) {
|
||||
console.warn('Ship symbol layer add failed:', e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
map.setLayoutProperty(symbolId, 'visibility', visibility);
|
||||
map.setLayoutProperty(symbolId, 'symbol-sort-key', [
|
||||
'case',
|
||||
['all', ['==', ['get', 'selected'], 1], ['==', ['get', 'permitted'], 1]], 140,
|
||||
['all', ['==', ['get', 'highlighted'], 1], ['==', ['get', 'permitted'], 1]], 135,
|
||||
['==', ['get', 'permitted'], 1], 130,
|
||||
['==', ['get', 'selected'], 1], 80,
|
||||
['==', ['get', 'highlighted'], 1], 75,
|
||||
45,
|
||||
] as never);
|
||||
map.setPaintProperty(symbolId, 'icon-opacity', [
|
||||
'case',
|
||||
['==', ['get', 'permitted'], 1], 1,
|
||||
['==', ['get', 'selected'], 1], 0.86,
|
||||
['==', ['get', 'highlighted'], 1], 0.82,
|
||||
0.66,
|
||||
] as never);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
// symbol: data-driven expressions are static — visibility handled by fast toggle
|
||||
|
||||
const labelFilter = [
|
||||
'all',
|
||||
@ -611,15 +539,8 @@ export function useGlobeShips(
|
||||
} catch (e) {
|
||||
console.warn('Ship label layer add failed:', e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
map.setLayoutProperty(labelId, 'visibility', labelVisibility);
|
||||
map.setFilter(labelId, labelFilter as never);
|
||||
map.setLayoutProperty(labelId, 'text-field', ['get', 'labelName'] as never);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
// label: filter/text-field are static — visibility handled by fast toggle
|
||||
|
||||
// 레이어가 준비되었음을 알림 (projection과 무관 — 토글 버튼 활성화용)
|
||||
onGlobeShipsReady?.(true);
|
||||
@ -658,9 +579,7 @@ export function useGlobeShips(
|
||||
|
||||
const hideHover = () => {
|
||||
for (const id of [symbolId, outlineId, haloId]) {
|
||||
try {
|
||||
if (map.getLayer(id)) map.setLayoutProperty(id, 'visibility', 'none');
|
||||
} catch { /* ignore */ }
|
||||
guardedSetVisibility(map, id, 'none');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -93,11 +93,19 @@ export function useMapInit(
|
||||
map.addControl(new maplibregl.NavigationControl({ showZoom: true, showCompass: true }), 'top-left');
|
||||
map.addControl(new maplibregl.ScaleControl({ maxWidth: 120, unit: 'metric' }), 'bottom-left');
|
||||
|
||||
// MapLibre 내부 placement TypeError 방어
|
||||
// MapLibre 내부 placement TypeError 방어 + globe easing 경고 억제
|
||||
// symbol layer 추가/제거와 render cycle 간 타이밍 이슈로 발생하는 에러 억제
|
||||
// globe projection에서 scrollZoom이 easeTo(around)를 호출하면 경고 발생 → 구조적 한계로 억제
|
||||
{
|
||||
const origRender = (map as unknown as { _render: (arg?: number) => void })._render;
|
||||
const origWarn = console.warn;
|
||||
(map as unknown as { _render: (arg?: number) => void })._render = function (arg?: number) {
|
||||
// globe 모드에서 scrollZoom의 easeTo around 경고 억제
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn = function (...args: unknown[]) {
|
||||
if (typeof args[0] === 'string' && (args[0] as string).includes('Easing around a point')) return;
|
||||
origWarn.apply(console, args as [unknown, ...unknown[]]);
|
||||
};
|
||||
try {
|
||||
origRender.call(this, arg);
|
||||
} catch (e) {
|
||||
@ -105,6 +113,9 @@ export function useMapInit(
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
} finally {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn = origWarn;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -111,7 +111,6 @@ export function useProjectionToggle(
|
||||
'pair-lines-ml',
|
||||
'fc-lines-ml',
|
||||
'pair-range-ml',
|
||||
'fleet-circles-ml-fill',
|
||||
'fleet-circles-ml',
|
||||
];
|
||||
|
||||
|
||||
@ -28,7 +28,6 @@ export function removeSourceIfExists(map: maplibregl.Map, sourceId: string) {
|
||||
const GLOBE_NATIVE_LAYER_IDS = [
|
||||
'pair-lines-ml',
|
||||
'fc-lines-ml',
|
||||
'fleet-circles-ml-fill',
|
||||
'fleet-circles-ml',
|
||||
'pair-range-ml',
|
||||
'subcables-hitarea',
|
||||
@ -44,7 +43,6 @@ const GLOBE_NATIVE_SOURCE_IDS = [
|
||||
'pair-lines-ml-src',
|
||||
'fc-lines-ml-src',
|
||||
'fleet-circles-ml-src',
|
||||
'fleet-circles-ml-fill-src',
|
||||
'pair-range-ml-src',
|
||||
'subcables-src',
|
||||
'subcables-pts-src',
|
||||
@ -96,6 +94,22 @@ export function setLayerVisibility(map: maplibregl.Map, layerId: string, visible
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setLayoutProperty('visibility') wrapper — 현재 값과 동일하면 호출 생략.
|
||||
* MapLibre는 setLayoutProperty 호출 시 항상 style._changed = true를 설정하여
|
||||
* 모든 symbol layer의 placement를 재계산시킴. text-allow-overlap:false 라벨이
|
||||
* 충돌 검사에 의해 사라지는 문제를 방지하기 위해, 값이 실제로 바뀔 때만 호출.
|
||||
*/
|
||||
export function guardedSetVisibility(map: maplibregl.Map, layerId: string, target: 'visible' | 'none') {
|
||||
if (!map.getLayer(layerId)) return;
|
||||
try {
|
||||
if (map.getLayoutProperty(layerId, 'visibility') === target) return;
|
||||
map.setLayoutProperty(layerId, 'visibility', target);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
export function cleanupLayers(
|
||||
map: maplibregl.Map,
|
||||
layerIds: string[],
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user