gis 오버레이 수정
This commit is contained in:
@@ -10,8 +10,8 @@ export default function createOverlayManager(map, vectorLayer, overlayFormatter,
|
||||
const getCoordinateKey = buildCoordinateKeyFactory(coordPrecision);
|
||||
|
||||
let currentFormatter = overlayFormatter;
|
||||
const overlayMap = new Map(); // coordKey -> Overlay
|
||||
const overlayElementMap = new Map(); // coordKey -> HTMLElement
|
||||
const overlayMap = new Map(); // feature -> Overlay
|
||||
const overlayElementMap = new Map(); // feature -> HTMLElement
|
||||
const vectorSource = vectorLayer?.getSource?.();
|
||||
|
||||
const SYNC_MIN_INTERVAL = 120;
|
||||
@@ -25,22 +25,22 @@ export default function createOverlayManager(map, vectorLayer, overlayFormatter,
|
||||
|
||||
|
||||
const clearAllOverlaysAsync = (batch = 150) => {
|
||||
const keys = Array.from(overlayMap.keys());
|
||||
if (!keys.length) return;
|
||||
const features = Array.from(overlayMap.keys());
|
||||
if (!features.length) return;
|
||||
|
||||
// 재귀로 사용하는 이유 한번에 다지운는ㄴ것이아닌 150개 이상 더있을경우를 대비해서 다시 호출하기 위해(지도가 계속 멈춤)
|
||||
const step = () => {
|
||||
let iNum = 0;
|
||||
const end = Math.min(iNum + batch, keys.length);
|
||||
const end = Math.min(iNum + batch, features.length);
|
||||
for (; iNum < end; iNum++) {
|
||||
const k = keys[iNum];
|
||||
const ov = overlayMap.get(k);
|
||||
const feat = features[iNum];
|
||||
const ov = overlayMap.get(feat);
|
||||
try { if (ov) map.removeOverlay(ov); } catch {}
|
||||
overlayMap.delete(k);
|
||||
const el = overlayElementMap.get(k);
|
||||
if (el) { try { el.remove?.(); } catch {} overlayElementMap.delete(k); }
|
||||
overlayMap.delete(feat);
|
||||
const el = overlayElementMap.get(feat);
|
||||
if (el) { try { el.remove?.(); } catch {} overlayElementMap.delete(feat); }
|
||||
}
|
||||
if (iNum < keys.length) {
|
||||
if (iNum < features.length) {
|
||||
(typeof requestAnimationFrame === 'function' ? requestAnimationFrame : setTimeout)(step, 0);
|
||||
}
|
||||
};
|
||||
@@ -75,9 +75,8 @@ export default function createOverlayManager(map, vectorLayer, overlayFormatter,
|
||||
const ensureOverlay = (feature, properties) => {
|
||||
const coord = getFeatureLabelCoordinate(feature);
|
||||
if (!Array.isArray(coord)) return null;
|
||||
const key = getCoordinateKey(coord);
|
||||
|
||||
let el = overlayElementMap.get(key);
|
||||
let el = overlayElementMap.get(feature);
|
||||
if (!el) {
|
||||
if (!currentFormatter || typeof currentFormatter !== 'function') return null;
|
||||
|
||||
@@ -86,19 +85,19 @@ export default function createOverlayManager(map, vectorLayer, overlayFormatter,
|
||||
// 1) 동기 HTMLElement
|
||||
if (maybeEl && typeof maybeEl === 'object' && (maybeEl.nodeType === 1 || maybeEl.tagName)) {
|
||||
el = maybeEl;
|
||||
overlayElementMap.set(key, el);
|
||||
overlayElementMap.set(feature, el);
|
||||
}
|
||||
// 2) 비동기 Promise<HTMLDivElement|null>
|
||||
else if (maybeEl && typeof maybeEl.then === 'function') {
|
||||
maybeEl.then((resolvedEl) => {
|
||||
if (!resolvedEl || !(resolvedEl.nodeType === 1 || resolvedEl.tagName)) return;
|
||||
// 이미 다른 사이클에서 만들어졌으면 덮어쓰지 않음
|
||||
if (!overlayElementMap.has(key)) overlayElementMap.set(key, resolvedEl);
|
||||
if (!overlayElementMap.has(feature)) overlayElementMap.set(feature, resolvedEl);
|
||||
|
||||
let ov = overlayMap.get(key);
|
||||
let ov = overlayMap.get(feature);
|
||||
if (!ov) {
|
||||
ov = new Overlay({ element: resolvedEl, positioning: 'bottom-center', offset: [0, -18], stopEvent: true });
|
||||
overlayMap.set(key, ov);
|
||||
overlayMap.set(feature, ov);
|
||||
try { map.addOverlay(ov); } catch {}
|
||||
} else {
|
||||
try { ov.setElement(resolvedEl); } catch {}
|
||||
@@ -115,10 +114,10 @@ export default function createOverlayManager(map, vectorLayer, overlayFormatter,
|
||||
}
|
||||
|
||||
// 여기까지 왔으면 el은 HTMLElement
|
||||
let ov = overlayMap.get(key);
|
||||
let ov = overlayMap.get(feature);
|
||||
if (!ov) {
|
||||
ov = new Overlay({ element: el, positioning: 'bottom-center', offset: [0, -18], stopEvent: true });
|
||||
overlayMap.set(key, ov);
|
||||
overlayMap.set(feature, ov);
|
||||
map.addOverlay(ov);
|
||||
}
|
||||
ov.setPosition(coord);
|
||||
@@ -132,52 +131,35 @@ export default function createOverlayManager(map, vectorLayer, overlayFormatter,
|
||||
const size = map.getSize?.();
|
||||
const viewExtent = view && size ? view.calculateExtent(size) : null;
|
||||
|
||||
// gather features in viewport only and group by coordinate
|
||||
const groups = new Map(); // coordKey -> feature[]
|
||||
const addFeature = (f) => {
|
||||
const c = getFeatureLabelCoordinate(f);
|
||||
if (!Array.isArray(c)) return;
|
||||
const k = getCoordinateKey(c);
|
||||
const arr = groups.get(k);
|
||||
if (arr) arr.push(f); else groups.set(k, [f]);
|
||||
};
|
||||
|
||||
const features = [];
|
||||
const pushFeature = (f) => features.push(f);
|
||||
if (vectorSource?.forEachFeatureInExtent && viewExtent) {
|
||||
vectorSource.forEachFeatureInExtent(viewExtent, addFeature);
|
||||
vectorSource.forEachFeatureInExtent(viewExtent, pushFeature);
|
||||
} else {
|
||||
vectorSource?.forEachFeature(addFeature);
|
||||
vectorSource?.forEachFeature(pushFeature);
|
||||
}
|
||||
|
||||
// cap overlays per viewport with simple uniform sampling
|
||||
const keys = Array.from(groups.keys());
|
||||
let selectedKeys;
|
||||
if (!isFinite(maxOverlaysPerViewport) || keys.length <= maxOverlaysPerViewport) {
|
||||
selectedKeys = keys;
|
||||
} else {
|
||||
const step = Math.ceil(keys.length / maxOverlaysPerViewport);
|
||||
selectedKeys = [];
|
||||
for (let i = 0; i < keys.length && selectedKeys.length < maxOverlaysPerViewport; i += step) {
|
||||
selectedKeys.push(keys[i]);
|
||||
let selected = features;
|
||||
if (isFinite(maxOverlaysPerViewport) && features.length > maxOverlaysPerViewport) {
|
||||
const step = Math.ceil(features.length / maxOverlaysPerViewport);
|
||||
selected = [];
|
||||
for (let i = 0; i < features.length && selected.length < maxOverlaysPerViewport; i += step) {
|
||||
selected.push(features[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// ensure selected overlays
|
||||
for (const k of selectedKeys) {
|
||||
const featuresAtKey = groups.get(k);
|
||||
const rep = featuresAtKey[0];
|
||||
const props = rep.getProperties?.() ?? {};
|
||||
if (featuresAtKey.length > 1) props.__groupCount = featuresAtKey.length;
|
||||
ensureOverlay(rep, props);
|
||||
for (const f of selected) {
|
||||
const props = f.getProperties?.() ?? {};
|
||||
ensureOverlay(f, props);
|
||||
}
|
||||
|
||||
// remove non-selected overlays
|
||||
const keep = new Set(selectedKeys);
|
||||
for (const [k, ov] of overlayMap.entries()) {
|
||||
if (!keep.has(k)) {
|
||||
const keep = new Set(selected);
|
||||
for (const [feat, ov] of overlayMap.entries()) {
|
||||
if (!keep.has(feat)) {
|
||||
try { map.removeOverlay(ov); } catch {}
|
||||
overlayMap.delete(k);
|
||||
const el = overlayElementMap.get(k);
|
||||
if (el) { try { el.remove?.(); } catch {} overlayElementMap.delete(k); }
|
||||
overlayMap.delete(feat);
|
||||
const el = overlayElementMap.get(feat);
|
||||
if (el) { try { el.remove?.(); } catch {} overlayElementMap.delete(feat); }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user