前言
Cesium 是一个用于构建高性能 3D 地理空间应用程序的开源 JavaScript 库,主要用于可视化地球、地图、地形、3D 模型和各种地理数据;可在一些大屏场景下完成一下三维地图交互功能。
本文使用的cesium版本为:v1.123.0,前端框架为:vue3+vite,本文中示例地图为涠洲岛。
1.安装cesium
npm install cesium vite-plugin-cesium
2.配置cesium
vite.config.js
import cesium from 'vite-plugin-cesium';
3.创建一个cesium容器
<div ref="cesiumContainerRef" id="cesiumContainer"></div>
4.初始化cesium配置
new Cesium.Viewer("cesiumContainer", {
infoBox: false, // 关闭cesium右下角的信息框
animation: false, // 隐藏动画控件
baseLayerPicker: false, // 隐藏图层选择控件
fullscreenButton: false, // 隐藏全屏按钮
vrButton: false, // 隐藏VR按钮,默认false
geocoder: false, // 隐藏地名查找控件
homeButton: false, // 隐藏Home按钮
sceneModePicker: false, // 隐藏场景模式选择控件
selectionIndicator: true, // 显示实体对象选择框,默认true
timeline: false, // 隐藏时间线控件
navigationHelpButton: false, // 隐藏帮助按钮
// scene3DOnly: true, // 每个几何实例将只在3D中呈现,以节省GPU内存
shouldAnimate: true, // 开启动画自动播放
sceneMode: Cesium.SceneMode.COLUMBUS_VIEW, //SCENE2D, COLUMBUS_VIEW ,SCENE3D,MORPHING
requestRenderMode: true, // 减少Cesium渲染新帧总时间并减少Cesium在应用程序中总体CPU使用率
// 如场景中的元素没有随仿真时间变化,请考虑将设置maximumRenderTimeChange为较高的值,例如Infinity
maximumRenderTimeChange: Infinity,
imageryProvider: new Cesium.SingleTileImageryProvider({
url: "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==",
tileWidth: dom.width,
tileHeight: dom.height
}),
//需要纯色背景必须设置
contextOptions: {
webgl: {
alpha: true,
}
},
})
5.其他设置,可自行选择配置
//背景设置为全黑
viewer.scene.backgroundColor = new Cesium.Color(0.0, 0.0, 0.0, 1.0);
//关闭大气
viewer.scene.skyAtmosphere.show = false
//抗锯齿
viewer.scene.fxaa = true;
viewer.scene.postProcessStages.fxaa.enabled = true;
//关闭天空月亮
viewer.scene.sun.show = false;
viewer.scene.moon.show = false;
//关闭天空盒,否则会显示天空颜色
viewer.scene.skyBox.show = false;
//隐藏地球
viewer.scene.undergroundMode = true;
viewer.scene.globe.baseColor = new Cesium.Color(0, 0, 0, 1);
viewer._cesiumWidget._creditContainer.style.display = "none"; //去掉logo
6.鼠标按键设置
// 鼠标右键 倾斜操作
viewer.scene.screenSpaceCameraController.tiltEventTypes = [
Cesium.CameraEventType.RIGHT_DRAG
];
// 鼠标滑轮 放缩操作
viewer.scene.screenSpaceCameraController.zoomEventTypes = [
Cesium.CameraEventType.WHEEL,
];
// 鼠标左键 平移
viewer.scene.screenSpaceCameraController.rotateEventTypes = [
Cesium.CameraEventType.LEFT_DRAG
];
7.添加坐标拾取监听
// 坐标拾取
viewer.screenSpaceEventHandler.setInputAction((movement) => {
const pick = viewer.scene.pickPosition(movement.position);
if (Cesium.defined(pick)) {
const cartesian = viewer.scene.pickPosition(movement.position);
if (Cesium.defined(cartesian)) {
// 将笛卡尔坐标转换为地理坐标(经纬度)
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;
console.log(`经度: ${longitude}, 纬度: ${latitude}, 高度: ${height}`);
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
8.加载自定义瓦片
自定义TMS瓦片
const tms = await Cesium.TileMapServiceImageryProvider.fromUrl(
"tms地址", {
fileExtension: 'png',
});
viewer.imageryLayers.addImageryProvider(tms);
geoServer
const tifLayer = await new Cesium.WebMapServiceImageryProvider({
url: 'geoserver服务地址', // geoserver服务地址
layers: '工作区名:图层名', // 工作区名:图层名
parameters: {
service: 'WMS',
format: 'image/png',
transparent: true
},
srs: 'EPSG:4326',
crs: 'EPSG:4326',
});
viewer.imageryLayers.addImageryProvider(tifLayer);
9.如果有地形数据
const terrainProvider = await Cesium.CesiumTerrainProvider.fromUrl(
"terrain地形切片地址", {
requestWaterMask: true,
requestVertexNormals: true,
});
viewer.terrainProvider = terrainProvider;
10.设置相机默认位置
viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(114.08246, 10.92367, 8000.0), // 地图中选经纬度和高度
orientation: {
heading: Cesium.Math.toRadians(0), // 方位角
pitch: Cesium.Math.toRadians(-90.0), // 俯仰角,从上往下看为-90
roll: Cesium.Math.toRadians(0.0) // 翻滚角
}
});
11.完整代码
<template>
<div class="content cesiumMap">
<div ref="cesiumContainerRef" id="cesiumContainer"></div>
</div>
</template>
<script setup>
import { getCurrentInstance, onMounted, ref, reactive } from 'vue'
const { proxy } = getCurrentInstance()
import * as Cesium from 'cesium';
let cesiumContainerRef = ref(null)
let viewer = '';
let dom = reactive({
width: 0,
height: 0
})
//初始化cesium
const initCesium = async () => {
viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false, // 关闭cesium右下角的信息框
animation: false, // 隐藏动画控件
baseLayerPicker: false, // 隐藏图层选择控件
fullscreenButton: false, // 隐藏全屏按钮
vrButton: false, // 隐藏VR按钮,默认false
geocoder: false, // 隐藏地名查找控件
homeButton: false, // 隐藏Home按钮
sceneModePicker: false, // 隐藏场景模式选择控件
selectionIndicator: true, // 显示实体对象选择框,默认true
timeline: false, // 隐藏时间线控件
navigationHelpButton: false, // 隐藏帮助按钮
// scene3DOnly: true, // 每个几何实例将只在3D中呈现,以节省GPU内存
shouldAnimate: true, // 开启动画自动播放
sceneMode: Cesium.SceneMode.COLUMBUS_VIEW, //SCENE2D, COLUMBUS_VIEW ,SCENE3D,MORPHING
requestRenderMode: true, // 减少Cesium渲染新帧总时间并减少Cesium在应用程序中总体CPU使用率
// 如场景中的元素没有随仿真时间变化,请考虑将设置maximumRenderTimeChange为较高的值,例如Infinity
maximumRenderTimeChange: Infinity,
imageryProvider: new Cesium.SingleTileImageryProvider({
url: "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==",
tileWidth: dom.width,
tileHeight: dom.height
}),
//需要纯色背景必须设置
contextOptions: {
webgl: {
alpha: true,
}
},
})
//背景设置为全黑
viewer.scene.backgroundColor = new Cesium.Color(0.0, 0.0, 0.0, 1.0);
//关闭大气
viewer.scene.skyAtmosphere.show = false
//抗锯齿
viewer.scene.fxaa = true;
viewer.scene.postProcessStages.fxaa.enabled = true;
//关闭天空月亮
viewer.scene.sun.show = false;
viewer.scene.moon.show = false;
viewer.scene.skyBox.show = false;
//隐藏地球
viewer.scene.undergroundMode = true;
viewer.scene.globe.baseColor = new Cesium.Color(0, 0, 0, 1);
viewer._cesiumWidget._creditContainer.style.display = "none"; //去掉logo
// 鼠标右键 倾斜操作
viewer.scene.screenSpaceCameraController.tiltEventTypes = [
Cesium.CameraEventType.RIGHT_DRAG
];
// 鼠标滑轮 放缩操作
viewer.scene.screenSpaceCameraController.zoomEventTypes = [
Cesium.CameraEventType.WHEEL,
];
// 鼠标左键
viewer.scene.screenSpaceCameraController.rotateEventTypes = [
Cesium.CameraEventType.LEFT_DRAG
];
// 坐标拾取
viewer.screenSpaceEventHandler.setInputAction((movement) => {
const pick = viewer.scene.pickPosition(movement.position);
if (Cesium.defined(pick)) {
const cartesian = viewer.scene.pickPosition(movement.position);
if (Cesium.defined(cartesian)) {
// 将笛卡尔坐标转换为地理坐标(经纬度)
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;
console.log(`经度: ${longitude}, 纬度: ${latitude}, 高度: ${height}`);
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 解决倾斜飘漂移,但是会损耗性能
viewer.scene.globe.depthTestAgainstTerrain = true;
}
//初始化地图显示
const initMap = async () => {
// 加载瓦片地图
try {
// 加载oss自定义瓦片地图
const tms = await Cesium.TileMapServiceImageryProvider.fromUrl(
"tms地址", {
fileExtension: 'png',
}
);
viewer.imageryLayers.addImageryProvider(tms);
} catch (error) {
console.log(`tif加载失败: ${error}`);
}
// 添加地形数据
// try {
// const terrainProvider = await Cesium.CesiumTerrainProvider.fromUrl(
// "terrain地址", {
// requestWaterMask: true,
// requestVertexNormals: true,
// });
// viewer.terrainProvider = terrainProvider;
// } catch (error) {
// console.log(`terrain加载失败: ${error}`);
// }
//设置相机位置
viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(109.11282,21.049105, 14000.0), // 经纬度和高度
orientation: {
heading: Cesium.Math.toRadians(0), // 方位角
pitch: Cesium.Math.toRadians(-90.0), // 俯仰角,从上往下看为-90
roll: Cesium.Math.toRadians(0.0) // 翻滚角
}
});
}
const resize = () => {
// 获取 DOM 元素的宽度和高度
const container = cesiumContainerRef.value;
const width = container.offsetWidth;
const height = container.offsetHeight;
dom.width = width;
dom.height = height;
}
onMounted(() => {
resize();
// 初始化cesium
initCesium();
initMap();
})
</script>