@uavs/3d-model-map
v0.1.8
Published
UAVS 3D map components based on Vue 3, Mars3D and Cesium.
Readme
@uavs/3d-model-map
@uavs/3d-model-map 是 UAVS 的 Vue 3 三维模型地图能力包,专门用于展示 3D Tiles 模型。组件内部负责 Mars3D/Cesium 地图初始化、三维模型加载、模型定位、模型总览、标签交互和清晰度调整;业务项目负责提供模型数据、模型文件地址和应用级 API 适配。
源码仓库:https://gitee.com/jxzhsz/packages,包目录为 packages/3d-model-map。
功能
- 基于 Vue 3、Mars3D、Cesium 展示城市、园区、小区、工厂等区域的三维模型。
- 支持从外部传入模型分组数据或模型列表数据。
- 支持从外部传入 3D Tiles
tileset.json地址解析函数。 - 支持模型定位、当前模型状态面板、模型总览切换。
- 支持模型标签 hover 状态和点击定位,不绘制模型范围框。
- 支持配置返回按钮是否显示、按钮文字和返回行为。
- 不依赖业务项目里的
@uavs/ui、BaseDialog或 Element Plus。
安装
pnpm add @uavs/3d-model-map如果 @uavs scope 发布在私有 npm 源,先配置 scope registry:
pnpm config set @uavs:registry <registry-url>然后再安装:
pnpm add @uavs/3d-model-map@uavs/3d-model-map 会随包安装 mars3d、mars3d-cesium、@turf/turf 和 Cesium 静态资源复制插件。业务项目通常只需要自己已有的 vue 和 vite。
如果业务项目还没有 Vue,再补装:
pnpm add vueVite 项目使用包内 createCesiumStaticPlugins 时,不需要单独安装 vite-plugin-static-copy,也不需要单独安装 mars3d、mars3d-cesium 或 @turf/turf。
Cesium / Mars3D 依赖
组件会按下面的顺序使用 Cesium 和 Mars3D:
- 如果业务项目已经初始化了
window.Cesium,直接复用。 - 如果没有
window.Cesium,从宿主应用的BASE_URL + lib/Cesium/Cesium.js加载 Cesium,并设置window.CESIUM_BASE_URL。 - Mars3D 会从宿主应用的
BASE_URL + lib/Mars3D/mars3d.js加载,并复用window.mars3d。
接入项目必须在 Vite 配置里调用 createCesiumStaticPlugins(),它会在开发环境提供 /lib/Cesium/* 和 /lib/Mars3D/* 静态资源,并在构建时把 Cesium 和 Mars3D 资源复制到产物目录。
如果地图配置里用到了底图预览图片,也需要在业务项目里准备:
public/img/basemaps这些底图预览图片会随 npm 包发布,并由 createCesiumStaticPlugins 在构建时复制到应用产物。业务项目需要替换底图预览图片时,可以在自己的 public/img/basemaps 中放置同名文件覆盖。
Vite 接入配置
使用 Vite 的项目建议在 vite.config.ts 中加入 Cesium/Mars3D 静态资源插件、Mars3D Cesium shim 和依赖预构建排除:
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { createCesiumStaticPlugins, createMapdataProxy } from '@uavs/3d-model-map/vite/cesium'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, import.meta.dirname)
return {
plugins: [
vue(),
...createCesiumStaticPlugins()
],
resolve: {
alias: [
{
find: /^mars3d-cesium$/,
replacement: '@uavs/3d-model-map/runtime/mars3d-cesium-shim'
}
]
},
server: {
proxy: createMapdataProxy(env)
},
optimizeDeps: {
exclude: ['mars3d', 'mars3d-cesium']
},
build: {
assetsInlineLimit: 0,
target: 'es2020'
}
}
})createCesiumStaticPlugins() 默认会从 @uavs/3d-model-map 自己的依赖里解析 mars3d-cesium/Build/Cesium 和 mars3d 静态资源。如果项目确实需要指定自定义资源目录,也可以传入实际路径:第一个参数指向 mars3d-cesium/Build/Cesium,第二个参数指向包含 mars3d.js、mars3d.css 和 img 的 Mars3D 目录。
基础用法
在页面或应用入口里导入组件和样式:
<script setup lang="ts">
import { ThreeDimensionalMap } from '@uavs/3d-model-map'
import '@uavs/3d-model-map/style.css'
import type { MaterialModelItem, ThreeDimensionalMapDataSource } from '@uavs/3d-model-map'
const dataSource: ThreeDimensionalMapDataSource = {
async getModelGroups() {
// 在业务项目里调用自己的接口,例如 /admin-api/material/threedList
return []
}
}
function resolveTilesetUrl(item: MaterialModelItem) {
if (!item.file) return ''
return `/mapdata/${String(item.file).replace(/^\/+|\/+$/g, '')}/tileset.json`
}
</script>
<template>
<div class="map-page">
<ThreeDimensionalMap
map-key="project-3d-map"
:center="{ lng: 113.732711, lat: 27.640558, alt: 18000, zoom: 14 }"
:data-source="dataSource"
:resolve-tileset-url="resolveTilesetUrl"
:show-back-button="false"
/>
</div>
</template>
<style scoped>
.map-page {
width: 100%;
height: 100vh;
}
</style>注意:地图容器必须有明确高度,否则 Cesium 容器可能无法正常显示。
数据接入
推荐在业务项目里通过 dataSource 注入数据,组件本身不绑定具体请求库,也不固定接口地址。
interface ThreeDimensionalMapDataSource {
getModelGroups?: () => Promise<MaterialModelGroup[]>
getModelItems?: () => Promise<MaterialModelItem[] | PageResult<MaterialModelItem>>
}分组数据
getModelGroups 适合接入类似 /admin-api/material/threedList 的树形数据:
const dataSource: ThreeDimensionalMapDataSource = {
async getModelGroups() {
const res = await geyThreedList()
return res.data ?? []
}
}顶层 modelType 为 2 的分组会被当作三维模型分组。因为部分接口返回的子项 modelType 不可靠,组件会按顶层分组归一化子项类型,不再依赖子项自己的 modelType 判断是否为 3D 模型。
平铺数据
getModelItems 适合接入普通模型列表接口。返回值可以是数组,也可以是带 list 字段的分页对象:
const dataSource: ThreeDimensionalMapDataSource = {
async getModelItems() {
const res = await getMaterialApi({ pageSize: 999, pageNo: 1, type: 2 })
return res.data
}
}模型数据格式
模型项至少需要包含可唯一识别的 id。如果要让定位更准确,建议同时提供经纬度。
interface MaterialModelItem {
id: number | string
file?: string
fileName?: string
name?: string
longitude?: number
latitude?: number
height?: number
}字段说明:
| 字段 | 说明 |
| --- | --- |
| id | 模型唯一标识,用于图层创建、定位和当前模型判断。 |
| file | 模型文件目录或 URL,默认会用于拼接 tileset.json。 |
| fileName / name | 模型展示名称。 |
| longitude / latitude | 模型中心点经纬度,用于定位和飞行。 |
| height | 模型高度或定位高度,按业务接口实际含义传入。 |
模型地址解析
不同项目的模型文件可能放在不同域名、不同前缀下,所以建议传入 resolveTilesetUrl:
function resolveTilesetUrl(item: MaterialModelItem) {
if (!item.file) return ''
if (/^https?:\/\//i.test(item.file)) {
return item.file.endsWith('tileset.json') ? item.file : `${item.file}/tileset.json`
}
return `/mapdata/${String(item.file).replace(/^\/+|\/+$/g, '')}/tileset.json`
}如果不传 resolveTilesetUrl,包内默认逻辑会把 file 解析成:
/mapdata/<file>/tileset.jsonProps
| Prop | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| configUrl | string | ${import.meta.env.BASE_URL}config/config.json | Mars3D 地图配置地址,默认跟随宿主 Vite base。 |
| mapKey | string | common-3d | 地图实例 key,会用于生成容器 id;同页多个地图时必须不同。 |
| options | Record<string, unknown> | {} | 额外 Mars3D 地图配置,会合并到地图初始化配置里。 |
| center | Map3dCenterPoint | - | 外部注入的地图中心配置 { lng, lat, alt?, zoom? },支持数字或数字字符串;配置变化时会自动飞到新中心。 |
| initialView | Map3dInitialView \| false | 内置默认视角 | 初始总览视角;传 false 可禁用回到总览能力。 |
| flyToInitialView | boolean | true | 地图创建后是否飞到初始视角。 |
| showRealModelLabels | boolean | true | 是否展示模型标签。 |
| preloadModels | boolean | true | 是否预加载模型元数据。 |
| modelGroups | MaterialModelGroup[] | - | 直接传入的分组模型数据。 |
| modelItems | MaterialModelItem[] | - | 直接传入的平铺模型数据。 |
| dataSource | ThreeDimensionalMapDataSource | - | 外部异步数据源。 |
| resolveTilesetUrl | MaterialTilesetUrlResolver | 内置 /mapdata 解析 | 把模型项转换成 3D Tiles 地址。 |
| showBackButton | boolean | true | 是否显示左上角返回按钮。 |
| backButtonText | string | 返回 | 返回按钮文字。 |
| backFallbackUrl | string | / | 没有浏览器历史可退时跳转的兜底地址。 |
| onBack | () => void | - | 自定义返回行为。 |
常用导出
export {
ThreeDimensionalMap,
ThreeDimensionalMapPage,
createMapApi,
provideMapApi,
formatMaterialModelTree,
isThreeDimensionalModel,
resolveTilesetUrl,
resolveMap3dPublicUrl
}常用类型:
export type {
MaterialModelGroup,
MaterialModelItem,
MaterialTilesetUrlResolver,
ThreeDimensionalMapDataSource,
Map3dInitialView
}发布前检查
发布前先执行:
pnpm --filter @uavs/3d-model-map build
pnpm --filter @uavs/3d-model-map pack:checkpack:check 会执行构建并运行 npm pack --dry-run,用于确认最终 npm 包里只包含需要发布的文件。
发布
切换 npm 账号
发布前先确认当前登录账号:
npm whoami如果当前不是要发布 @uavs/3d-model-map 的账号,先退出旧账号:
npm logout --registry=https://registry.npmjs.org/然后登录新账号:
npm login --registry=https://registry.npmjs.org/登录完成后再次确认账号:
npm whoami确认新账号有 @uavs scope 或当前包的发布权限:
npm access list packages @uavs
npm owner ls @uavs/3d-model-map如果 @uavs 还没有在 npm 上创建,需要先到 npm 官网创建 uavs organization;@uavs/3d-model-map 包不需要提前创建,第一次发布成功时会自动创建。
如果发布时报 Two-factor authentication or granular access token with bypass 2FA enabled is required to publish packages,说明 npm 要求当前账号启用 2FA,或者使用允许发布的 granular access token。
本地手动发布推荐在 npm 官网账号设置里启用 2FA,然后用一次性验证码发布:
pnpm --filter @uavs/3d-model-map publish --access public --otp <6位验证码>CI 或自动化发布推荐在 npm 官网创建 granular access token,给 @uavs 或 @uavs/3d-model-map 配置 Read and write 权限,并启用 Bypass two-factor authentication,再把 token 配到发布环境的 npm auth token 中。
本机临时使用 access token 发布时,需要把新 token 写入当前 npm 配置:
npm config set //registry.npmjs.org/:_authToken=<npm_access_token>
npm whoami
pnpm --filter @uavs/3d-model-map publish --access public如果仍然报 2FA/token 错误,通常是 token 没有勾选 Bypass two-factor authentication,或者 package/scope 权限不是 Read and write。
公开发布:
pnpm --filter @uavs/3d-model-map publish --access public如果发布到私有源,需要先在发布环境里配置 registry 和登录信息:
pnpm config set @uavs:registry <registry-url>
npm login --registry <registry-url>
pnpm --filter @uavs/3d-model-map publish接入项目检查清单
- 已安装
@uavs/3d-model-map。 - 业务项目已有 Vue/Vite;
mars3d、mars3d-cesium、@turf/turf会随@uavs/3d-model-map安装。 - 已导入
@uavs/3d-model-map/style.css。 - Vite 项目已从
@uavs/3d-model-map/vite/cesium接入createCesiumStaticPlugins,用于提供/lib/Cesium/*和/lib/Mars3D/*。 - Vite 项目已把
mars3d-cesiumalias 到@uavs/3d-model-map/runtime/mars3d-cesium-shim。 - Vite 项目已在
optimizeDeps.exclude中排除mars3d和mars3d-cesium。 - 已准备 Mars3D 配置文件,默认会从宿主应用的
BASE_URL + config/config.json读取,例如base: '/uavs_frontend/'时请求/uavs_frontend/config/config.json;非 Vite 项目或自定义路径可通过configUrl指定。 - 已在业务项目里实现模型接口请求,并通过
dataSource传入。 - 已根据项目模型文件路径实现
resolveTilesetUrl。 - 地图容器有明确宽高。
- 如果不需要组件内返回按钮,传入
:show-back-button="false"。
模型概览与精细查看(0.1.8)
在组件挂载时设置 model-display-mode="overview",启用模型概览:
<ThreeDimensionalMap
model-display-mode="overview"
:data-source="dataSource"
:resolve-tileset-url="resolveTilesetUrl"
/>默认仍为 single,保留其他接入项目的行为。overview 模式忽略 preloadModels,避免提前创建所有精细图层。
- 概览使用粗模型提供空间轮廓;点击模型、标签或列表定位可进入精细查看,定位时自动勾选对应模型。列表支持单选显隐和全选操作。
- 镜头移动到相邻模型后,根据画面中的实际拾取结果与地面采样自动选择精细模型,不仅依赖标签中心点。
- 粗细层通过可见瓦片覆盖信息交接,加载期间保留粗层,减少切换时的空白;返回概览时等待粗层接替精细层。
- 精细查看目标 SSE 最低为 10。首次加载可先使用较粗层级铺底,再恢复目标清晰度;实际效果仍受模型数据、网络和引擎内存压力影响。
- 当前精细模型缓存从 2 GiB 起步,按占用及回看余量增长,最多 3 GiB,另有 512 MiB 溢出空间。同一图层预算不主动缩小,减少短距离移出再移入时的重复加载。
- 历史精细模型最多保留三个,历史缓存预算为 2 GiB,精细层总预算为 3.5 GiB;优先回收闲置且最久未使用的模型。
- 标签锚点优先参考模型内容,减少不连续模型的总范围中心落在空白区域的问题。
- 模型列表和当前模型操作面板默认隐藏;地图左上返回按钮下方保留隐形入口,悬停或键盘聚焦可显示入口,点击切换面板显隐。
- 返回按钮与地图工具栏使用一致的方形样式;底部标签图例已移除。
瓦片诊断日志可辅助观察加载、卸载、卸载后重载、内存占用与实际 SSE。Cesium 内存估算不包含全部浏览器堆、下载缓存、纹理解码和驱动开销,上述预算不是浏览器进程的内存硬上限。
发布前应结合实际模型验证初次进入、拖动回看、相邻模型切换、返回概览及卸载重进的表现。
