|
|
@ -4,9 +4,55 @@ import mapboxgl from 'mapbox-gl' |
|
|
import mapConfig, { MAP_STYLES, MAP_OVERVIEW, MAP_VIEW } from '@/config/map' |
|
|
import mapConfig, { MAP_STYLES, MAP_OVERVIEW, MAP_VIEW } from '@/config/map' |
|
|
import commonRefs from '@/utils/commonRefs' |
|
|
import commonRefs from '@/utils/commonRefs' |
|
|
import mapHelper from '@/core/mapHelper' |
|
|
import mapHelper from '@/core/mapHelper' |
|
|
|
|
|
import { applyChineseLabels } from '@/utils/mapLabels' |
|
|
import 'mapbox-gl/dist/mapbox-gl.css' |
|
|
import 'mapbox-gl/dist/mapbox-gl.css' |
|
|
|
|
|
|
|
|
|
|
|
// 保证任意路径创建的 Map 都挂到 DOM/window,避免 HMR/异常吞错后 Monitor 丢实例 |
|
|
|
|
|
if (!mapboxgl.Map.__laicPatched) { |
|
|
|
|
|
const OriginalMap = mapboxgl.Map |
|
|
|
|
|
class LaicMap extends OriginalMap { |
|
|
|
|
|
constructor(options) { |
|
|
|
|
|
super(options) |
|
|
|
|
|
try { |
|
|
|
|
|
const el = this.getContainer?.() |
|
|
|
|
|
if (el) el.__laicMap = this |
|
|
|
|
|
if (typeof window !== 'undefined') { |
|
|
|
|
|
window.__LAIC_MAPBOX_MAP__ = this |
|
|
|
|
|
window.dispatchEvent(new CustomEvent('laic-map-ready', { detail: this })) |
|
|
|
|
|
} |
|
|
|
|
|
} catch (_) { |
|
|
|
|
|
/* ignore */ |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
LaicMap.__laicPatched = true |
|
|
|
|
|
mapboxgl.Map = LaicMap |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
let map = null |
|
|
let map = null |
|
|
|
|
|
let resizeObserver = null |
|
|
|
|
|
|
|
|
|
|
|
function resizeMap(target = map) { |
|
|
|
|
|
if (!target) return |
|
|
|
|
|
try { |
|
|
|
|
|
target.resize() |
|
|
|
|
|
} catch (_) { |
|
|
|
|
|
/* ignore */ |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function bindResizeObserver(target) { |
|
|
|
|
|
if (resizeObserver) { |
|
|
|
|
|
resizeObserver.disconnect() |
|
|
|
|
|
resizeObserver = null |
|
|
|
|
|
} |
|
|
|
|
|
const el = target?.getContainer?.() |
|
|
|
|
|
if (!el || typeof ResizeObserver === 'undefined') return |
|
|
|
|
|
resizeObserver = new ResizeObserver(() => { |
|
|
|
|
|
resizeMap(target) |
|
|
|
|
|
}) |
|
|
|
|
|
resizeObserver.observe(el) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
function ensureGlobe(target) { |
|
|
function ensureGlobe(target) { |
|
|
if (!target) return |
|
|
if (!target) return |
|
|
@ -24,6 +70,62 @@ function clearMapRef(target) { |
|
|
mapHelper.setMap(null) |
|
|
mapHelper.setMap(null) |
|
|
commonRefs.removeRef('map') |
|
|
commonRefs.removeRef('map') |
|
|
} |
|
|
} |
|
|
|
|
|
if (typeof window !== 'undefined' && window.__LAIC_MAPBOX_MAP__ === target) { |
|
|
|
|
|
delete window.__LAIC_MAPBOX_MAP__ |
|
|
|
|
|
} |
|
|
|
|
|
try { |
|
|
|
|
|
if (target.getContainer?.().__laicMap === target) delete target.getContainer().__laicMap |
|
|
|
|
|
} catch (_) { |
|
|
|
|
|
/* ignore */ |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function exposeMap(target) { |
|
|
|
|
|
if (!target) return |
|
|
|
|
|
const el = |
|
|
|
|
|
(typeof document !== 'undefined' ? document.getElementById('map') : null) || |
|
|
|
|
|
target.getContainer?.() |
|
|
|
|
|
if (el) { |
|
|
|
|
|
try { |
|
|
|
|
|
Object.defineProperty(el, '__laicMap', { value: target, writable: true, configurable: true }) |
|
|
|
|
|
} catch (_) { |
|
|
|
|
|
el.__laicMap = target |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (typeof window !== 'undefined') { |
|
|
|
|
|
try { |
|
|
|
|
|
Object.defineProperty(window, '__LAIC_MAPBOX_MAP__', { |
|
|
|
|
|
value: target, |
|
|
|
|
|
writable: true, |
|
|
|
|
|
configurable: true, |
|
|
|
|
|
}) |
|
|
|
|
|
} catch (_) { |
|
|
|
|
|
window.__LAIC_MAPBOX_MAP__ = target |
|
|
|
|
|
} |
|
|
|
|
|
window.dispatchEvent(new CustomEvent('laic-map-ready', { detail: target })) |
|
|
|
|
|
} |
|
|
|
|
|
commonRefs.setRef('map', target) |
|
|
|
|
|
mapHelper.setMap(target) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function destroyOrphanMap(container) { |
|
|
|
|
|
if (!container) return |
|
|
|
|
|
// HMR / 重复挂载时容器上常残留旧 Mapbox 实例,继续 new Map 会直接抛错 |
|
|
|
|
|
const orphan = container.__laicMap |
|
|
|
|
|
if (orphan && typeof orphan.remove === 'function') { |
|
|
|
|
|
try { |
|
|
|
|
|
orphan.remove() |
|
|
|
|
|
} catch (_) { |
|
|
|
|
|
/* ignore */ |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
delete container.__laicMap |
|
|
|
|
|
// Mapbox 会给容器加 mapboxgl-map;清掉子节点避免二次初始化失败 |
|
|
|
|
|
if (container.classList?.contains('mapboxgl-map')) { |
|
|
|
|
|
container.innerHTML = '' |
|
|
|
|
|
container.classList.remove('mapboxgl-map') |
|
|
|
|
|
container.removeAttribute('style') |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function initMap() { |
|
|
function initMap() { |
|
|
@ -35,9 +137,13 @@ function initMap() { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const container = |
|
|
|
|
|
(typeof document !== 'undefined' ? document.getElementById('map') : null) || 'map' |
|
|
|
|
|
if (typeof container !== 'string') destroyOrphanMap(container) |
|
|
|
|
|
|
|
|
mapboxgl.accessToken = tk |
|
|
mapboxgl.accessToken = tk |
|
|
map = new mapboxgl.Map({ |
|
|
map = new mapboxgl.Map({ |
|
|
container: 'map', |
|
|
|
|
|
|
|
|
container, |
|
|
style: MAP_STYLES.satellite, |
|
|
style: MAP_STYLES.satellite, |
|
|
center: MAP_OVERVIEW.center, |
|
|
center: MAP_OVERVIEW.center, |
|
|
zoom: MAP_OVERVIEW.zoom, |
|
|
zoom: MAP_OVERVIEW.zoom, |
|
|
@ -46,11 +152,29 @@ function initMap() { |
|
|
projection: 'globe', |
|
|
projection: 'globe', |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
if (map.isStyleLoaded()) ensureGlobe(map) |
|
|
|
|
|
else map.once('style.load', () => ensureGlobe(map)) |
|
|
|
|
|
|
|
|
exposeMap(map) |
|
|
|
|
|
console.info('[MapLayer] map ready', { |
|
|
|
|
|
hasDom: !!(typeof document !== 'undefined' && document.getElementById('map')?.__laicMap), |
|
|
|
|
|
hasWin: !!(typeof window !== 'undefined' && window.__LAIC_MAPBOX_MAP__), |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
if (map.isStyleLoaded()) { |
|
|
|
|
|
ensureGlobe(map) |
|
|
|
|
|
applyChineseLabels(map) |
|
|
|
|
|
} else { |
|
|
|
|
|
map.once('style.load', () => { |
|
|
|
|
|
ensureGlobe(map) |
|
|
|
|
|
applyChineseLabels(map) |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
commonRefs.setRef('map', map) |
|
|
|
|
|
mapHelper.setMap(map) |
|
|
|
|
|
|
|
|
// 布局未稳定时 Mapbox 落到错误高度(常见 ~300px),初始化后强制校正 |
|
|
|
|
|
map.once('load', () => resizeMap(map)) |
|
|
|
|
|
requestAnimationFrame(() => { |
|
|
|
|
|
resizeMap(map) |
|
|
|
|
|
requestAnimationFrame(() => resizeMap(map)) |
|
|
|
|
|
}) |
|
|
|
|
|
bindResizeObserver(map) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
onMounted(() => { |
|
|
onMounted(() => { |
|
|
@ -64,6 +188,10 @@ onMounted(() => { |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
onUnmounted(() => { |
|
|
onUnmounted(() => { |
|
|
|
|
|
if (resizeObserver) { |
|
|
|
|
|
resizeObserver.disconnect() |
|
|
|
|
|
resizeObserver = null |
|
|
|
|
|
} |
|
|
if (map) { |
|
|
if (map) { |
|
|
const dying = map |
|
|
const dying = map |
|
|
map = null |
|
|
map = null |
|
|
|