1. 前言
在可视化开发中,卫星轨迹的实时计算与展示是一个比较有趣的应用场景。TLE(Two-Line Element Set)
是一种用于描述卫星轨道参数的格式,我们可以通过 satellite.js
解析 TLE 数据,并计算卫星在任意时间点的位置。
本文介绍如何在 Vue3
中使用 OpenLayers
,结合 satellite.js
解析 TLE
数据,实现卫星轨迹的动态计算和可视化展示。
2. 项目技术栈
在本示例中,我们使用以下技术:
- Vue3 + Composition API —— 现代化 Vue 组件开发方式
- OpenLayers —— 强大的地图渲染库
- satellite.js —— 计算卫星轨迹的 JS 库
- dayjs —— 处理日期和时间
3. 安装依赖
在 Vue3 项目中,我们需要安装 OpenLayers
和 satellite.js
这两个核心库:
npm install ol satellite.js dayjs
4. 代码实现
4.1 组件结构
我们使用 Vue3 的 Composition API
,并封装一个 Map
组件,实现以下功能:
- 使用
OpenLayers
创建地图并加载OSM
底图; - 解析
TLE
计算卫星的位置; - 计算并绘制卫星的轨迹;
- 实时更新卫星位置。
完整代码如下:
<template><div class="container"><div class="w-full flex justify-center flex-wrap"><div class="font-bold text-[24px]">在Vue3中使用OpenLayers利用TLE动态计算并显示单个卫星的位置及轨迹</div></div><div id="vue-openlayers"></div></div>
</template><script setup>
import { ref, onMounted, onUnmounted } from 'vue'; // 引入 Vue 的 ref, onMounted 和 onUnmounted 函数
import 'ol/ol.css'; // 引入 OpenLayers 的 CSS 样式
import Map from 'ol/Map'; // 引入 OpenLayers 的 Map 类
import View from 'ol/View'; // 引入 OpenLayers 的 View 类
import OSM from 'ol/source/OSM'; // 引入 OpenLayers 的 OSM 类
import TileLayer from 'ol/layer/Tile'; // 引入 OpenLayers 的 TileLayer 类
import VectorLayer from 'ol/layer/Vector'; // 引入 OpenLayers 的 VectorLayer 类
import VectorSource from 'ol/source/Vector'; // 引入 OpenLayers 的 VectorSource 类
import { Point, LineString } from 'ol/geom'; // 引入 OpenLayers 的 Point 和 LineString 类
import Feature from 'ol/Feature'; // 引入 OpenLayers 的 Feature 类
import Style from 'ol/style/Style'; // 引入 OpenLayers 的 Style 类
import Fill from 'ol/style/Fill'; // 引入 OpenLayers 的 Fill 类
import Stroke from 'ol/style/Stroke'; // 引入 OpenLayers 的 Stroke 类
import Icon from 'ol/style/Icon'; // 引入 OpenLayers 的 Icon 类
import * as satellite from 'satellite.js'; // 引入 satellite.js 库
import dayjs from 'dayjs'; // 引入 dayjs 库
import utc from 'dayjs/plugin/utc'; // 引入 dayjs 的 utc 插件
import satImg from '@/assets/OpenLayers/satellite.png'; // 引入卫星图标dayjs.extend(utc); // 使用 dayjs 的 utc 插件const map = ref(null); // 定义 map 变量并初始化为 null
const tleLine1 = '1 25544U 98067A 19156.50900463 .00003075 00000-0 59442-4 0 9992'; // 定义 TLE 数据的第一行
const tleLine2 = '2 25544 51.6433 59.2583 0008217 16.4489 347.6017 15.51174618173442'; // 定义 TLE 数据的第二行const satelliteSource = new VectorSource({ wrapX: true }); // 创建一个新的 VectorSource 用于卫星位置
const satelliteTrackSource = new VectorSource({ wrapX: true }); // 创建一个新的 VectorSource 用于卫星轨迹let timerId = null; // 定义定时器 IDconst getSatTrack = () => {let curTime = new Date(); // 获取当前时间let lineData = []; // 定义一个数组用于存储轨迹数据for (let i = 0; i < 50; i++) { // 循环 50 次let newTimePoint = dayjs(curTime).add(i, 'minute').toDate(); // 获取未来的时间点let one = onePoint(newTimePoint); // 计算该时间点的卫星位置lineData.push(one); // 将位置添加到轨迹数据中}showTrack(lineData); // 显示轨迹
};const onePoint = (timePoint) => {let satrec = satellite.twoline2satrec(tleLine1, tleLine2); // 使用 TLE 数据创建卫星记录let positionAndVelocity = satellite.propagate(satrec, timePoint); // 计算卫星在指定时间点的位置和速度let positionEci = positionAndVelocity.position; // 获取卫星的 ECI 坐标let gmst = satellite.gstime(timePoint); // 计算格林尼治平恒时let positionGd = satellite.eciToGeodetic(positionEci, gmst); // 将 ECI 坐标转换为地理坐标let lonlat = [satellite.degreesLong(positionGd.longitude), // 获取经度satellite.degreesLat(positionGd.latitude), // 获取纬度];return lonlat; // 返回经纬度
};const getSatInfo = () => {let aaa = onePoint(new Date()); // 获取当前时间的卫星位置let min5 = dayjs(new Date()).add(5, 'minute').toDate(); // 获取 5 分钟后的时间let bbb = onePoint(min5); // 获取 5 分钟后的卫星位置let dx = bbb[0] - aaa[0]; // 计算经度差let dy = bbb[1] - aaa[1]; // 计算纬度差let rotation = Math.atan2(dy, dx) + 0.887; // 计算卫星的旋转角度showPoint(aaa, -rotation); // 显示卫星位置
};const showPoint = (coords, rotation) => {satelliteSource.clear(); // 清空卫星位置源let pointFeature = new Feature({geometry: new Point(coords), // 创建一个新的点特征});pointFeature.setStyle(satStyle(rotation)); // 设置点特征的样式satelliteSource.addFeature(pointFeature); // 将点特征添加到卫星位置源
};const showTrack = (coords) => {satelliteTrackSource.clear(); // 清空卫星轨迹源let lineFeature = new Feature({geometry: new LineString(coords), // 创建一个新的线特征});lineFeature.setStyle(trackStyle()); // 设置线特征的样式satelliteTrackSource.addFeature(lineFeature); // 将线特征添加到卫星轨迹源
};const trackStyle = () => {return new Style({fill: new Fill({ color: '#00f' }), // 设置填充颜色stroke: new Stroke({ width: 2, color: '#f00' }), // 设置描边颜色和宽度});
};const satStyle = (rotation) => {return new Style({image: new Icon({src: satImg, // 设置图标的源anchor: [0.5, 0.5], // 设置图标的锚点scale: 0.1, // 设置图标的缩放比例rotation: rotation, // 设置图标的旋转角度}),});
};const initMap = () => {let satelliteLayer = new VectorLayer({source: satelliteSource, // 创建一个新的矢量图层用于卫星位置});let satelliteTrackLayer = new VectorLayer({source: satelliteTrackSource, // 创建一个新的矢量图层用于卫星轨迹});map.value = new Map({layers: [new TileLayer({ source: new OSM() }), // 创建一个新的瓦片图层satelliteTrackLayer, // 添加卫星轨迹图层satelliteLayer, // 添加卫星位置图层],target: 'vue-openlayers', // 设置地图的目标元素view: new View({center: [116, 39], // 设置地图的中心点projection: 'EPSG:4326', // 设置地图的投影zoom: 2, // 设置地图的缩放级别}),});getSatTrack(); // 获取卫星轨迹
};onMounted(() => {initMap(); // 初始化地图timerId = setInterval(() => {getSatInfo(); // 获取卫星信息}, 1000); // 每秒获取一次
});onUnmounted(() => {clearInterval(timerId); // 清除定时器
});
</script><style scoped>
.container {width: 840px;height: 520px;margin: 50px auto;border: 1px solid #42B983;
}#vue-openlayers {width: 800px;height: 400px;margin: 0 auto;border: 1px solid #42B983;position: relative;
}
</style>
5. 运行效果
运行代码后,页面中会显示:
- 一个
OSM
地图 - 一颗实时移动的卫星
- 卫星轨迹的连线
- 卫星每秒刷新位置
6. 结语
通过 OpenLayers + satellite.js
,我们成功在 Vue3 项目中实现了卫星轨迹的可视化,并且代码封装合理,方便扩展。
你可以进一步优化:
- 增加多个卫星的轨迹
- 结合
Cesium.js
进行 3D 轨迹可视化 - 使用 WebSocket 获取实时卫星数据
如果你喜欢这篇文章,欢迎点赞、收藏、关注!🚀