【Vue3】Cesium实现卫星及无人机轨迹跟踪
🌍开发思路
一张图看懂 Cesium 高频 API、组件方法与 Vue 集成要点
1️⃣ Cesium 核心 API
类 | 一句话描述 | 高频用法 |
---|---|---|
Cesium.Viewer | 3D 地球的「根容器」 | new Viewer('cesiumContainer', { terrain: Terrain.fromWorldTerrain(), shouldAnimate: true }) |
Cesium.JulianDate | 高精度时间计算 | JulianDate.fromIso8601('2025-08-25T12:00:00Z') |
Cesium.CzmlDataSource | 载入动态场景(CZML) | await CzmlDataSource.load('tracking.czml') |
Cesium.Cartesian3 | 3D 笛卡尔坐标 | entity.viewFrom = new Cartesian3(x, y, z) |
Cesium.TrackingReferenceFrame | 实体跟踪时的坐标框架 | 可选:AUTODETECT / INERTIAL / VELOCITY / ENU |
Cesium.Terrain | 全球地形数据管理 | Terrain.fromWorldTerrain() |
2️⃣ 组件核心方法
方法 | 职责 | 关键步骤 |
---|---|---|
initMap() | 初始化地球 + 载入 CZML | ① 创建 Viewer ② 设置时间范围 ③ 载入 tracking.czml ④ 缓存实体引用 ⑤ 设置 viewFrom |
trackSatellite() | 进入卫星跟踪模式 | 时钟停止时间、30× 倍速、缩放到卫星时间线、设置 viewer.trackedEntity |
trackDrone() | 进入无人机跟踪模式 | 同上,倍速改为 1× |
updateTrackingReferenceFrame() | 动态切换跟踪框架 | 根据下拉选项把 trackingReferenceFrame 赋给卫星/无人机 |
3️⃣ Vue 生命周期 & 状态管理
项目 | 代码片段 | 说明 |
---|---|---|
响应式状态 | const trackingFrame = ref('autodetect') | 跟踪框架下拉框绑定 |
挂载 | onMounted(initMap) | 组件渲染后初始化地图 |
卸载 | onUnmounted(() => viewer?.destroy()) | 释放 GPU & 内存 |
4️⃣ 实体级常用链式 API
// 1. 添加数据源
const ds = await viewer.dataSources.add(await CzmlDataSource.load('tracking.czml')
);// 2. 按 ID 取实体
const satellite = ds.entities.getById('Satellite');
const drone = ds.entities.getById('Drone');// 3. 设置相机偏移
satellite.viewFrom = new Cesium.Cartesian3(-10_000, 0, 5_000);// 4. 控制时间系统
viewer.clock.stopTime = Cesium.JulianDate.fromIso8601('2025-08-25T16:00:00Z');
viewer.clock.currentTime = Cesium.JulianDate.fromIso8601('2025-08-25T12:00:00Z');
viewer.clock.multiplier = 30; // 30× 快进// 5. 缩放时间线
viewer.timeline.zoomTo(startTime, stopTime);// 6. 开始跟踪
viewer.trackedEntity = satellite; // 相机会自动跟随
🌍工程实现
工程创建及配置参考:【Vue3】Cesium加载glb格式3D模型-CSDN博客
🛰️准备 Cesium 轨迹文件
官方地址:https://github.com/CesiumGS/cesium/blob/main/Apps/SampleData/tracking.czml
下载后将文件存放到工程的src\assets\tracking.czml
🛰️编写核心代码
创建src\components\EntrityTracking.vue,代码如下
<template><divstyle="display: flex; flex-direction: column; width: 100vw; height: 100vh; margin: 0; padding: 0; overflow: hidden;"><div class="cesium" id="cesiumContainer" style="width: 100%; height: 100%;"></div><div style="position: absolute; top: 20px; left: 20px; z-index: 100; background: rgba(0, 0, 0, 0.7); padding: 10px; color: white;"><button @click="trackSatellite" style="margin-right: 10px; padding: 5px 10px; background: #4CAF50; color: white; border: none; cursor: pointer;">卫星</button><button @click="trackDrone" style="margin-right: 10px; padding: 5px 10px; background: #2196F3; color: white; border: none; cursor: pointer;">无人机</button><select v-model="trackingFrame" @change="updateTrackingReferenceFrame" style="padding: 5px;"><option value="autodetect">跟踪参考框架: 自动检测</option><option value="inertial">跟踪参考框架: 惯性</option><option value="velocity">跟踪参考框架: 速度</option><option value="enu">跟踪参考框架: 东北天</option></select></div></div>
</template><script setup>
import { onMounted, onUnmounted, ref } from "vue";
import * as Cesium from "cesium";let viewer = null;
let satellite = null;
let drone = null;
const trackingFrame = ref('autodetect');
let dataSource = null;// Cesium Ion 访问令牌
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxM2M4ZTg1Ni0zYWFkLTRhMzMtYTE4My05MmZjNmY2YjAxNWYiLCJpZCI6MzI0MzUyLCJpYXQiOjE3NTMyODExOTJ9.FTPTi9u7zGDoZNOEeUq7kQxGEN2sn9NQuxGEY5bZAcI';const initMap = async () => {viewer = new Cesium.Viewer('cesiumContainer', {terrain: Cesium.Terrain.fromWorldTerrain(),shouldAnimate: true});const startTime = Cesium.JulianDate.fromIso8601("2012-03-15T10:00:00Z");const satelliteStopTime = Cesium.JulianDate.fromIso8601("2012-03-16T10:00:00Z");const droneStopTime = Cesium.JulianDate.fromIso8601("2012-03-15T10:00:30Z");// 加载正确路径的 CZML 文件dataSource = await viewer.dataSources.add(Cesium.CzmlDataSource.load('/src/assets/tracking.czml'));satellite = dataSource.entities.getById("Satellite/ISS");drone = dataSource.entities.getById("CesiumDrone");// 设置视图偏移satellite.viewFrom = new Cesium.Cartesian3(-300, 20, 100);drone.viewFrom = new Cesium.Cartesian3(-50, 0, 5);
};// 跟踪卫星
const trackSatellite = () => {if (!viewer || !satellite) return;const startTime = Cesium.JulianDate.fromIso8601("2012-03-15T10:00:00Z");const satelliteStopTime = Cesium.JulianDate.fromIso8601("2012-03-16T10:00:00Z");viewer.clock.stopTime = satelliteStopTime;viewer.clock.currentTime = startTime;viewer.clock.multiplier = 30;viewer.timeline.zoomTo(startTime, satelliteStopTime);viewer.trackedEntity = satellite;
};// 跟踪无人机
const trackDrone = () => {if (!viewer || !drone) return;const startTime = Cesium.JulianDate.fromIso8601("2012-03-15T10:00:00Z");const droneStopTime = Cesium.JulianDate.fromIso8601("2012-03-15T10:00:30Z");viewer.clock.stopTime = droneStopTime;viewer.clock.currentTime = startTime;viewer.clock.multiplier = 1;viewer.timeline.zoomTo(startTime, droneStopTime);viewer.trackedEntity = drone;
};// 更新跟踪参考框架
const updateTrackingReferenceFrame = () => {if (!satellite || !drone) return;switch (trackingFrame.value) {case 'autodetect':satellite.trackingReferenceFrame = Cesium.TrackingReferenceFrame.AUTODETECT;drone.trackingReferenceFrame = Cesium.TrackingReferenceFrame.AUTODETECT;break;case 'inertial':satellite.trackingReferenceFrame = Cesium.TrackingReferenceFrame.INERTIAL;drone.trackingReferenceFrame = Cesium.TrackingReferenceFrame.INERTIAL;break;case 'velocity':satellite.trackingReferenceFrame = Cesium.TrackingReferenceFrame.VELOCITY;drone.trackingReferenceFrame = Cesium.TrackingReferenceFrame.VELOCITY;break;case 'enu':satellite.trackingReferenceFrame = Cesium.TrackingReferenceFrame.ENU;drone.trackingReferenceFrame = Cesium.TrackingReferenceFrame.ENU;break;}
};onMounted(() => {initMap();
});onUnmounted(() => {if (viewer) {viewer.destroy();}
});
</script>
官方参考:Cesium Sandcastle