🎬 效果演示截图

✨ 前言
在实际项目开发中,我们经常需要提供「二维地图 + 三维地形」的可视化效果切换,例如:
-
智慧农业展示耕地分布 + 三维地形起伏;
-
智慧城市展示建筑物点位 + 三维城市;
-
数字孪生场景中,2D/3D 切换已是标配功能。
本文将手把手教你如何使用 Vue 3 + OpenLayers + Cesium 结合 ol-cesium
实现一键切换 2D/3D 地图视图。
📦 技术选型说明
工具库 | 说明 |
---|---|
Vue 3 + Composition API |
构建 UI 和交互 |
OpenLayers (ol@10.x) |
作为主地图引擎,承载2D地图 |
Cesium (cesium@1.131) |
提供3D地形图、3D建筑、卫星视角等能力 |
ol-cesium (v2.17) |
连接 OpenLayers 和 Cesium 的桥梁 |
Vite (推荐) |
高速构建工具,适配 Cesium 配置更方便 |
🔧 环境配置
1️⃣ 安装依赖
javascript
pnpm add ol cesium ol-cesium
或:
javascript
npm install ol cesium ol-cesium
2️⃣ 配置 Cesium 静态资源
推荐方式:使用 vite-plugin-cesium 自动处理 Cesium 资源路径
javascript
pnpm add vite-plugin-cesium -D
在 vite.config.ts
中配置插件:
javascript
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import cesium from 'vite-plugin-cesium'
export default defineConfig({
plugins: [vue(), cesium()]
})
✅ 这样可以让
CESIUM_BASE_URL
自动指向/cesium/
路径,无需手动复制 Cesium 静态文件。
💻 核心代码实现
以下是完整的 MapSwitcher.vue
示例组件,支持 2D/3D 地图切换:
🧩 组件结构代码
javascript
<!--
* @Author: 彭麒
* @Date: 2025/7/15
* @Email: 1062470959@qq.com
* @Description: 此源码版权归吉檀迦俐所有,可供学习和借鉴或商用。
-->
<template>
<div class="full-screen">
<div ref="mapContainer" class="map-container"></div>
<button class="toggle-btn" @click="toggle3D">
切换到 {{ is3D ? '2D' : '3D' }}
</button>
</div>
</template>
<script setup lang="ts">
import {onBeforeUnmount, onMounted, ref} from 'vue'
import 'ol/ol.css'
import {Map, View} from 'ol'
import TileLayer from 'ol/layer/Tile'
import OSM from 'ol/source/OSM'
import {fromLonLat} from 'ol/proj'
// 定义全局变量类型
declare global {
interface Window {
CESIUM_BASE_URL: string;
Cesium: any; // 添加全局Cesium类型
}
}
// 设置Cesium资源路径 - 使用相对路径
window.CESIUM_BASE_URL = './node_modules/cesium/Build/Cesium';
// 导入Cesium并赋值给全局对象
import * as Cesium from 'cesium'
window.Cesium = Cesium; // 关键步骤:将Cesium设为全局对象
import 'cesium/Build/Cesium/Widgets/widgets.css'
// @ts-ignore
import OLCesium from 'ol-cesium'
const mapContainer = ref<HTMLDivElement | null>(null)
const is3D = ref(false)
let map: Map
let olCesiumObj: any
onMounted(() => {
// 初始化2D地图
map = new Map({
target: mapContainer.value!,
layers: [new TileLayer({ source: new OSM() })],
view: new View({
center: fromLonLat([104.0668, 30.5728]),
zoom: 5
})
})
try {
// 确保Cesium已加载
if (!window.Cesium) {
console.error('Cesium未正确加载为全局对象')
return
}
// 初始化3D视图
olCesiumObj = new OLCesium({
map: map
})
// 初始设置为2D模式
olCesiumObj.setEnabled(false)
// 设置地形
initTerrain()
} catch (error) {
console.error('初始化Cesium失败:', error)
}
})
function initTerrain() {
try {
if (window.Cesium && window.Cesium.createWorldTerrainAsync) {
window.Cesium.createWorldTerrainAsync({
requestWaterMask: true,
requestVertexNormals: true
}).then(terrainProvider => {
if (olCesiumObj && olCesiumObj.getCesiumScene) {
olCesiumObj.getCesiumScene().terrainProvider = terrainProvider;
}
}).catch(error => {
console.error('加载地形失败:', error);
});
}
} catch (error) {
console.error('设置地形失败:', error);
}
}
onBeforeUnmount(() => {
if (olCesiumObj) {
olCesiumObj.setEnabled(false)
olCesiumObj.destroy()
}
map?.setTarget(undefined)
})
function toggle3D() {
is3D.value = !is3D.value
olCesiumObj?.setEnabled(is3D.value)
}
</script>
<style scoped>
.full-screen {
position: relative;
width: 100%;
height: 100vh;
}
.map-container {
width: 100%;
height: 100%;
}
.toggle-btn {
position: absolute;
top: 16px;
left: 16px;
z-index: 1000;
padding: 8px 12px;
background: white;
border: 1px solid #ccc;
cursor: pointer;
}
</style>
💡 项目拓展建议
-
✅ 添加图层切换、绘图、定位等功能;
-
✅ 使用 Cesium 加载 3D 模型(glTF、倾斜摄影);
-
✅ 增加鼠标拾取、飞行动画;
-
✅ 与 GIS 属性数据结合进行业务可视化。
❓常见问题汇总
问题 | 解决方式 |
---|---|
OLCesium is not a constructor |
确保导入的是 ol-cesium 并正确写法:import OLCesium from 'ol-cesium' |
Cesium 未加载 |
必须设置 window.Cesium = Cesium ,否则 ol-cesium 找不到全局对象 |
地形不生效 | 检查 createWorldTerrainAsync 调用是否报错、scene 是否为空 |
Cesium 路径报错 | 使用 vite-plugin-cesium 自动设置 CESIUM_BASE_URL ,避免路径问题 |
📚 参考资料
-
Cesium 官方文档
✍️ 结语
如果你也在做地图相关项目,希望本文能帮你快速搭建一个可切换的 2D/3D 地图系统。该示例可直接嵌入业务页面,未来也可以拓展更多可视化能力。