/** * 底图计划(票 29):把配置里的 `map.basemap` 翻译成「用哪一类 Cesium 影像源、什么 URL」。 * * 纯函数、**不 import cesium** —— 引擎侧(services/cesiumEngine.js)照着这份计划建 provider, * 逻辑断言脚本因此能脱浏览器把每种来源(含天地图模板拼装、缺 tk 的失败态)都测到。 * * 为什么单独一层:票 27 故意 `baseLayer: false`(底图未配置就不伪造地理配准), * 票 21 负责地形 / 3D Tiles / 倾斜摄影与地面-管线视图切换;底图影像这一层独立成票。 */ /** 底图来源(配置里 `map.basemap.source` 的取值)。 */ export const BASEMAP_SOURCE = { NONE: 'none', NATURAL_EARTH: 'natural-earth', ARCGIS_IMAGERY: 'arcgis-imagery', XYZ: 'xyz', TIANDITU: 'tianditu', } /** 底图状态(写进宿主 `data-map-basemap`,也是 getLifecycleStats().basemap 的取值)。 */ export const BASEMAP_STATE = { NOT_CONFIGURED: 'not-configured', NATURAL_EARTH: 'natural-earth', ARCGIS_IMAGERY: 'arcgis-imagery', XYZ: 'xyz', TIANDITU: 'tianditu', INVALID: 'invalid', } /** * ArcGIS 官方世界影像:免费、免 key(署名即可),模板顺序是 `{z}/{y}/{x}`。 * 注意本机实测**连不上**(外网被挡),离线环境请用 `natural-earth`。 */ export const ARCGIS_WORLD_IMAGERY_URL = 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}' /** Cesium 自带的离线影像(随 `Build/Cesium/Assets` 一起进产物,不需要账号或外网)。 */ export const NATURAL_EARTH_TMS = 'Assets/Textures/NaturalEarthII' /** 天地图子域(生产直连时用;开发走仓库里已有的 `/tianditu.map` 代理,单主机不加子域)。 */ export const TIANDITU_SUBDOMAINS = ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'] export const TIANDITU_LAYERS = { img: '影像底图', vec: '矢量底图', ter: '地形晕渲', } /** * 天地图 WMTS 瓦片模板(tk 拼在查询串里;Cesium 负责替换 `{s}`/`{z}`/`{x}`/`{y}`)。 * @param {string} base 形如 `/tianditu.map`(开发代理)或 `https://t{s}.tianditu.gov.cn`(生产) * @param {string} token 天地图 tk * @param {string} layer `img` / `vec` / `ter` */ export function tiandituTileUrl(base, token, layer = 'img') { const root = String(base || '').replace(/\/+$/, '') return `${root}/${layer}_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=${layer}&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${token}` } function basePlan(state, source, label, extra = {}) { return { state, source, label, ready: false, kind: '', url: '', subdomains: [], minimumLevel: null, maximumLevel: null, credit: '', issue: '', ...extra } } /** * 配置 → 底图计划。 * @param {object} mapConfig 归一化后的 `config.map` * @param {object} [options] * @param {boolean} [options.dev] 开发态:天地图走仓库自带的 `/tianditu.map` 代理 * @returns {{state: string, source: string, label: string, ready: boolean, kind: string, url: string, * subdomains: string[], minimumLevel: number|null, maximumLevel: number|null, credit: string, issue: string}} */ export function planBasemap(mapConfig = {}, options = {}) { const map = mapConfig || {} const basemap = map.basemap || {} const source = basemap.source || BASEMAP_SOURCE.NONE if (source === BASEMAP_SOURCE.NONE) { return basePlan(BASEMAP_STATE.NOT_CONFIGURED, source, '底图未配置') } if (source === BASEMAP_SOURCE.NATURAL_EARTH) { return basePlan(BASEMAP_STATE.NATURAL_EARTH, source, '内置离线影像 Natural Earth II', { ready: true, kind: 'tms', url: NATURAL_EARTH_TMS, }) } if (source === BASEMAP_SOURCE.ARCGIS_IMAGERY) { return basePlan(BASEMAP_STATE.ARCGIS_IMAGERY, source, 'ArcGIS 全球影像(免费免 key)', { ready: true, kind: 'xyz', url: ARCGIS_WORLD_IMAGERY_URL, credit: 'Esri, Maxar, Earthstar Geographics', }) } if (source === BASEMAP_SOURCE.XYZ) { if (!basemap.url) { return basePlan(BASEMAP_STATE.INVALID, source, '底图配置无效', { issue: 'xyz 底图缺少 url 模板' }) } return basePlan(BASEMAP_STATE.XYZ, source, '自定义瓦片(XYZ)', { ready: true, kind: 'xyz', url: basemap.url, subdomains: basemap.subdomains || [], minimumLevel: basemap.minimumLevel, maximumLevel: basemap.maximumLevel, credit: basemap.credit || '', }) } if (source === BASEMAP_SOURCE.TIANDITU) { const token = basemap.token || (map.tianditu && map.tianditu.token) || '' if (!token) { return basePlan(BASEMAP_STATE.INVALID, source, '底图配置无效', { issue: '天地图底图缺少 tk(填 map.tianditu.token)', }) } const requested = (map.tianditu && map.tianditu.layer) || basemap.layer || 'img' const layer = TIANDITU_LAYERS[requested] ? requested : 'img' const dev = options.dev === true return basePlan(BASEMAP_STATE.TIANDITU, source, `天地图${TIANDITU_LAYERS[layer]}`, { ready: true, kind: 'xyz', url: tiandituTileUrl(dev ? '/tianditu.map' : 'https://t{s}.tianditu.gov.cn', token, layer), subdomains: dev ? [] : TIANDITU_SUBDOMAINS, credit: '天地图', }) } return basePlan(BASEMAP_STATE.INVALID, source, '底图配置无效', { issue: `未知的底图来源 ${source}` }) } /** 引擎状态浮标上的底图措辞(未配置时保持票 27 的原话)。 */ export function basemapStatusText(plan) { const current = plan || planBasemap({}) if (current.ready) return `底图:${current.label}` if (current.state === BASEMAP_STATE.INVALID) return `底图配置无效(${current.issue})· 回退临时影像` return '底图未配置(正式底图见票 21)' }