我们在cesium开发的过程中经常需要实时显示当前经纬度、高度、角度和刷新率等实时数据,本篇文章将介绍如何在基于Cesium的WebGL应用程序中创建一个自定义的状态栏组件。这个状态栏组件能够显示用户的当前位置(经度、纬度和海拔)、摄像机的方向(方向角和俯仰角)、摄像机的高度以及渲染性能指标(帧率和延迟)。此组件使用Vue.js框架编写,并且采用了TypeScript进行类型安全的开发。
组件结构
状态栏组件被设计为一个可复用的Vue组件,它接收一个viewer作为属性,并通过监听Cesium Viewer的各种事件来更新状态栏中的信息。
组件功能
- 位置信息:显示用户当前的经度、纬度和海拔高度。
- 摄像机方向:显示摄像机的方向角和俯仰角。
- 摄像机高度:显示摄像机相对于地球表面的高度。
- 性能指标:显示每秒帧数(FPS)和平均帧延迟(MS)。
技术栈
- Vue.js:构建用户界面。
- TypeScript:类型安全的JavaScript。
- Cesium:3D地理空间数据可视化库。
组件实现
-
模板结构:状态栏分为三部分,分别显示位置信息、摄像机方向和性能指标。
-
状态管理:使用Vue的
ref来存储状态栏中的各个数据项。 -
事件监听:
camera.changed:监听摄像机的变化,更新摄像机方向和高度。scene.postRender:监听场景渲染完成事件,更新帧率和延迟。screenSpaceEventHandler:监听鼠标移动事件,更新位置信息。
代码概览
-
模板:定义了状态栏的布局和样式。
-
脚本:
- 使用
setup函数初始化状态变量。 - 通过
onMounted和onUnmounted生命周期钩子来添加和移除事件监听器。 - 使用
throttle函数来限制更新频率,提高性能。
- 使用
-
样式:定义了状态栏的基本样式。
关键步骤
这个组件是个很基础的功能,唯一的关键难点在于获取 fps ,在这里我是参考了 从Cesium的源码,自定义帧率显示 这篇文章,并对其进行了小小的改动,获取到实时的帧率和延迟数据.
在这个项目中,经纬度的数据我获取的是鼠标的经纬度,你也可以用相机当前的经纬度。
import GetFPSInfo from '@/modules/status-bar/custom-fps';
let FPSInfo = new GetFPSInfo();
...
const updateFPS = throttle(() => {
if (viewer) {
let info = FPSInfo.update();
frameRateFPS.value = info.fps
frameRateMS.value = info.ms
}
}, 200)
示例代码
<template>
<div class="status-bar flex">
<div class="flex">
<div>经度: {{ longitude.toFixed(6) }}</div>
<div>纬度: {{ latitude.toFixed(6) }}</div>
<div>海拔:{{ altitude.toFixed(2) }} 米</div>
</div>
<div class="flex">
<div>方向:{{ heading.toFixed(2) }}°</div>
<div>俯仰角:{{ pitch.toFixed(2) }}°</div>
<div>视高:{{ eyeHeight.toFixed(2) }} 米</div>
</div>
<div class="flex">
<div>帧率:{{ frameRateFPS }} FPS</div>
<div>延迟:{{ frameRateMS }} MS</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, onUnmounted } from 'vue';
import * as Cesium from 'cesium';
import GetFPSInfo from '@/modules/status-bar/custom-fps';
const props = defineProps({
viewer: {
type: Object as () => Cesium.Viewer,
required: true
}
});
// 定义状态栏数据
const longitude = ref(0);
const latitude = ref(0);
const altitude = ref(0);
const heading = ref(0);
const pitch = ref(0);
const eyeHeight = ref(0);
const frameRateFPS = ref<number | string>(0);
const frameRateMS = ref<number | string>(0);
// 获取 Cesium 视图对象
let viewer: Cesium.Viewer | undefined;
let FPSInfo = new GetFPSInfo();
// 初始化状态栏
onMounted(() => {
viewer = props.viewer;
// 更新状态栏信息
if (viewer) {
// 监听相机变化
viewer.scene.camera.changed.addEventListener(updateStatus);
// 监听渲染
viewer.scene.postRender.addEventListener(updateFPS);
// 监听鼠标移动
viewer.screenSpaceEventHandler.setInputAction(updatePosition, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
});
// 更新状态栏信息
const updateStatus = throttle(() => {
if (viewer) {
eyeHeight.value = viewer.camera.positionCartographic.height;
heading.value = Cesium.Math.toDegrees(viewer.camera.heading);
pitch.value = Cesium.Math.toDegrees(viewer.camera.pitch);
}
}, 200);
const updateFPS = throttle(() => {
if (viewer) {
let info = FPSInfo.update();
frameRateFPS.value = info.fps;
frameRateMS.value = info.ms;
}
}, 200);
const updatePosition = throttle((movement: { endPosition: Cesium.Cartesian2 }) => {
// 获取鼠标在屏幕上的位置
const screenPosition = movement.endPosition;
// 将屏幕位置转换为经纬度
const cartesian = viewer?.scene.globe.pick(viewer.camera.getPickRay(screenPosition), viewer.scene);
if (cartesian) {
const cartographic = viewer?.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
longitude.value = Cesium.Math.toDegrees(cartographic.longitude);
latitude.value = Cesium.Math.toDegrees(cartographic.latitude);
altitude.value = cartographic.height;
}
}, 200);
// 节流函数
function throttle<T extends (...args: any[]) => any>(
func: T,
wait: number,
): T & {
cancel?: () => void;
flush?: () => void;
} {
...
}
// 清理工作
onUnmounted(() => {
if (viewer) {
FPSInfo = new GetFPSInfo();
viewer.scene.camera.changed.removeEventListener(updateStatus);
viewer.scene.postRender.removeEventListener(updateFPS);
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
});
</script>
<style scoped lang="scss">
...
</style>
总结
本组件通过监听Cesium Viewer的各种事件并更新状态栏中的信息,为用户提供了一个直观的界面来了解当前的地理位置、摄像机方向和系统性能。通过这种方式,用户可以在探索虚拟地球的同时,更加清晰地了解自己的位置和系统的运行状况。
源码
完整源码和使用案例 请看这里,里面还有其他一些我写案例东西,可以的话请给个star