From 9f4c8128cc2525bba0134c6ce32911564c018b6d Mon Sep 17 00:00:00 2001 From: jiang teng <1348746268@qq.com> Date: Sun, 29 Sep 2024 15:18:03 +0800 Subject: [PATCH] =?UTF-8?q?feat(*):=20=E4=BB=A3=E7=A0=81=E6=A2=B3=E7=90=86?= =?UTF-8?q?=E4=B8=8E=E7=B2=BE=E7=AE=80|=E5=88=A0=E9=99=A4=E5=86=97?= =?UTF-8?q?=E4=BD=99=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/http/index.js | 4 - src/js/SatelliteEntity.js | 11 +- src/utils/index.js | 22 ++ src/views/satellite-track/SatelliteTrack.vue | 210 ++----------------- src/views/satellite-track/satelliteType.js | 100 ++++----- 5 files changed, 100 insertions(+), 247 deletions(-) create mode 100644 src/utils/index.js diff --git a/src/http/index.js b/src/http/index.js index 7192a0b..2744f42 100644 --- a/src/http/index.js +++ b/src/http/index.js @@ -6,8 +6,6 @@ function getTleDataFromExternal(path = "") { let uri = `${BASE_URL}/NORAD/elements/gp.php?GROUP=${path}&FORMAT=tle`; return axios.get(uri).then(res => { if (res.status === 200) { - ElMessage.success('获取TLE成功'); - localStorage.setItem(path, res.data); // 缓存TLE数据,减轻数据服务压力 return Promise.resolve(res.data); } else { ElMessage.error('获取TLE失败'); @@ -16,6 +14,4 @@ function getTleDataFromExternal(path = "") { }); } - - export { getTleDataFromExternal }; \ No newline at end of file diff --git a/src/js/SatelliteEntity.js b/src/js/SatelliteEntity.js index 14486ae..49a42a6 100644 --- a/src/js/SatelliteEntity.js +++ b/src/js/SatelliteEntity.js @@ -51,6 +51,7 @@ class SatelliteEntity { createSatelliteEntity() { const start = Cesium.JulianDate.fromIso8601(new Date().toISOString()); const stop = Cesium.JulianDate.addSeconds(start, this.totalSeconds, new Cesium.JulianDate()); + const color = Cesium.Color.fromRandom({ alpha: 1.0 }); let satelliteEntity = { name: this.name, description: this.name, @@ -58,15 +59,15 @@ class SatelliteEntity { position: this._getPositionProperty(), point: { pixelSize: 8, - color: Cesium.Color.fromRandom({ alpha: 1.0 }), + color: color, // scaleByDistance: new Cesium.NearFarScalar(1.5e3, 1, 8.0e8, 0.5), }, path: new Cesium.PathGraphics({ - width: 1, - show: false, + width: 0.5, + show: true, leadTime: this.leadTime, trailTime: this.trailTime, - material: Cesium.Color.LIME, + material: color, }), label: { text: this.name, @@ -79,7 +80,7 @@ class SatelliteEntity { horizontalOrigin: Cesium.VerticalOrigin.LEFT, pixelOffset: new Cesium.Cartesian2(0, 5), fillColor: Cesium.Color.WHITE, - distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 5000000), + // distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 50000000), } } return satelliteEntity; diff --git a/src/utils/index.js b/src/utils/index.js new file mode 100644 index 0000000..6d24326 --- /dev/null +++ b/src/utils/index.js @@ -0,0 +1,22 @@ +/** + * 比较两个数组之间的差异 + * + * @param {Array} oldArray - 旧的数组 + * @param {Array} newArray - 新的数组 + * @throws {Error} 如果oldArray或newArray不是数组,则抛出错误 + * @returns {Object} 返回一个对象,包含两个属性:addedItems(新数组中新增的元素)和removedItems(旧数组中被移除的元素) + */ +function compareArrays(oldArray, newArray) { + // 验证参数类型,确保oldArray和newArray都是数组 + if (!Array.isArray(oldArray) || !Array.isArray(newArray)) { + throw new Error('Both oldArray and newArray must be arrays.'); + } + // 使用filter方法找出newArray中oldArray不包含的元素,即新增的元素 + const addedItems = newArray.filter(x => !oldArray.includes(x)); + // 使用filter方法找出oldArray中newArray不包含的元素,即被移除的元素 + const removedItems = oldArray.filter(x => !newArray.includes(x)); + // 返回新增的元素和被移除的元素 + return { addedItems, removedItems }; +} + +export { compareArrays }; \ No newline at end of file diff --git a/src/views/satellite-track/SatelliteTrack.vue b/src/views/satellite-track/SatelliteTrack.vue index 59e06e1..84e2cc3 100644 --- a/src/views/satellite-track/SatelliteTrack.vue +++ b/src/views/satellite-track/SatelliteTrack.vue @@ -4,17 +4,8 @@ <div class="menu_button" @click="drawer = !drawer" title="卫星星座选择"> <img src="../../assets/menu.svg" width="28" height="28" alt="卫星星座选择"> </div> - <div class="menu_button" @click="drawerImport = !drawerImport" title="自定义导入TLE数据"> - <img src="../../assets/import.svg" width="28" height="28" alt="自定义导入TLE数据"> - </div> - <div class="menu_button" @click="handleClearTLECache" title="清除TLE缓存"> - <img src="../../assets/clean.svg" width="24" height="24" alt="清除TLE缓存"> - </div> - <div class="menu_button" @click="clearSatelliteOrbit" title="清除轨道"> - <img src="../../assets/hide.svg" width="24" height="24" alt="清除轨道"> - </div> </div> - <!-- 抽屉1 --> + <el-drawer v-model="drawer" title="卫星星座选择" direction="ltr"> <el-checkbox-group v-model="checked" @change="handleSatelliteChange" :max=5> <template v-for="(item, index) in allSatellite" :key="index"> @@ -23,24 +14,6 @@ </template> </el-checkbox-group> </el-drawer> - <!-- 抽屉2 --> - <el-drawer v-model="drawerImport" title="自定义卫星数据" direction="ltr"> - <el-input v-model="tleData" type="textarea" placeholder="Please input tle data" :rows="20" /> - <el-row class="add_satellite"> - <el-button type="primary" @click="handleAddSatellite"> - 添加 - </el-button> - <el-upload class="upload_button" :on-change="handleImportSatellite" :show-file-list="false" accept="txt" :limit="1" :auto-upload="false" ref="upload"> - <template #trigger> - <el-button type="default">导入</el-button> - </template> - </el-upload> - <el-button type="danger" @click="handleClearSatellite"> - 清空 - </el-button> - </el-row> - - </el-drawer> </template> <script setup> @@ -48,45 +21,29 @@ import * as Cesium from 'cesium'; import "cesium/Build/Cesium/Widgets/widgets.css"; - import { onMounted, ref, watch } from 'vue'; - import "./SatelliteTrack.scss" - import { getTleDataFromExternal } from '@/http/index' - import SatelliteEntity from '@/js/SatelliteEntity'; - import { specialSatellite, weatherSatellite, communicationSatellite, navigationSatellite, scientificSatellite, miscellaneousSatellite } from "./satelliteType" +import { compareArrays } from '@/utils'; -let allSatellite = [...specialSatellite, ...weatherSatellite, ...communicationSatellite, ...navigationSatellite, ...scientificSatellite, ...miscellaneousSatellite]; - +const allSatellite = [...specialSatellite, ...weatherSatellite, ...communicationSatellite, ...navigationSatellite, ...scientificSatellite, ...miscellaneousSatellite]; window.CESIUM_BASE_URL = import.meta.env.MODE === 'development' ? '/cesium' : '/satellite-track/cesium'; let viewer; +// 默认场景的时间跨度 const totalSeconds = 86400; -// 保存所有的卫星实例 +// 保存分组的卫星实例 const satelliteMap = new Map(); -// 自定义的卫星 -const customSatelliteMap = new Map(); // 响应式数据 const drawer = ref(false); +// 默认勾选 +const checked = ref(["last-30-days"]); +// TLE缓存 +const tleCache = new Map(); -const drawerImport = ref(false); - -const checked = ref([1]); - -const clickedSatelliteArray = []; - -const upload = ref(null); - -let tleData = ref(`BEIDOU-3 G2 -1 45344U 20017A 23037.82027362 -.00000136 00000+0 00000+0 0 9994 -2 45344 1.9879 4.6761 0000950 328.7503 178.5761 1.00272999 10962 -BEIDOU-3 G3 -1 45807U 20040A 23037.85365455 -.00000347 00000+0 00000+0 0 9999 -2 45807 0.9369 314.6571 0008244 342.4957 257.2704 1.00264764 9772`); Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiYjZmMWM4Ny01YzQ4LTQ3MzUtYTI5Mi1hNTgyNjdhMmFiMmMiLCJpZCI6NjIwMjgsImlhdCI6MTYyNjY3MTMxNX0.5SelYUyzXWRoMyjjFvmFIAoPtWlJPQMjsVl2e_jQe-c'; @@ -99,12 +56,6 @@ function initCesium() { return Cesium.JulianDate.toIso8601(dataZone8).slice(0, 19); } - // mapBox 卫星地图 - let mapBoxImgLayer = new Cesium.MapboxImageryProvider({ - mapId: 'mapbox.satellite', - accessToken: 'pk.eyJ1Ijoiamlhbmd0ZW5nIiwiYSI6ImNqbGhhcDhzMjAxdncza294c2ZqcHFxNGIifQ.rjSmtZ5QzE2sJ-qDANh3WQ' - }); - //高德卫星地图 let gaoDeSatelliteImgLayer = new Cesium.UrlTemplateImageryProvider({ url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}", @@ -113,13 +64,6 @@ function initCesium() { tilingScheme: new Cesium.WebMercatorTilingScheme(), }); - // 高德地图路网图层 - let gaoDeImageryProvider = new Cesium.UrlTemplateImageryProvider({ - url: "http://webst02.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8", - minimumLevel: 3, - maximumLevel: 18, - }) - viewer = new Cesium.Viewer('cesiumContainer', { baseLayerPicker: true, geocoder: false, @@ -191,23 +135,6 @@ function parseTle(data = "") { return tles; } -function parseTleWithSimpleSplit(data = "") { - if (data.length === 0) return; - let result = data.split("\n"); - console.log(result) - let tles = [], i = 0, tem = []; - result.forEach(item => { - i++; - tem.push(item) - if (i === 3) { - tles.push(tem.join("\r\n")); - tem = []; - i = 0; - } - }); - return tles; -} - function addCesiumEventListener() { let callback = viewer.screenSpaceEventHandler.getInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) { @@ -218,9 +145,7 @@ function addCesiumEventListener() { } if (pickedFeature) { - pickedFeature.id.path.show = new Cesium.ConstantProperty(true); - pickedFeature.id.label.distanceDisplayCondition = undefined; - clickedSatelliteArray.push(pickedFeature); + } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); @@ -231,106 +156,18 @@ function handleSatelliteChange(e) { } -function handleClearTLECache() { - ElMessageBox.confirm("清空TLE缓存后手动刷新页面将重新下载TLE数据,是否继续?", "提示", { - distinguishCancelAndClose: true, - confirmButtonText: '确定', - cancelButtonText: '取消', - }).then(() => { - clearTLECache(); - }).catch(() => { - console.log('取消'); - }) -} - -function clearTLECache() { - // satelliteMap.forEach(satelliteSet => satelliteSet.forEach(sate => viewer.entities.remove(sate))); - // satelliteMap.clear(); // 一级缓存 - localStorage.clear(); // 二级缓存 - ElMessage.success('清除成功') -} - -function clearSatelliteOrbit() { - if (clickedSatelliteArray.length) { - clickedSatelliteArray.forEach(item => { - item.id ? item.id.path.show = false : ''; - }) - } -} - -function checkTleData(data) { - try { - if (!data.length) { - return false; - } - let dataArray = data.split('\n'); - if (dataArray.length % 3 !== 0) { - return false; - } - dataArray.forEach((item, index) => { - if (index % 3 === 0 && !item) throw new Error(false); - if (index % 3 === 1 && item.length < 69) throw new Error(false); - if (index % 3 === 2 && item.length < 69) throw new Error(false); - }) - return true; - } catch (error) { - console.log(error); - return false; - } -} - -// 添加自定义卫星实例 -function handleAddSatellite() { - if (!checkTleData(tleData.value)) { - ElMessage.error('wrong TLE data'); - return; - } - clearCustomSatelliteMap(); - let result = parseTleWithSimpleSplit(tleData.value); - result.forEach(tle => { - let satellite = new SatelliteEntity(tle); - let cesiumSateEntity = satellite.createSatelliteEntity(); - let result = viewer.entities.add(cesiumSateEntity); - customSatelliteMap.set(satellite.name, result) - }); - viewer.zoomTo(viewer.entities); - -} - -async function handleImportSatellite(uploadFiles) { - upload.value.clearFiles(); - if (uploadFiles.raw.type !== "text/plain") { - ElMessage.warning('请上传TXT格式的TLE数据'); - return; - } - let data = await uploadFiles.raw.text(); - tleData.value = data; -} - -// 清空所有状态,输入框和cesium实例 -function handleClearSatellite() { - clearCustomSatelliteMap(); - tleData.value = ""; - upload.value.clearFiles(); -} - -// 清空卫星实例; -function clearCustomSatelliteMap() { - customSatelliteMap.forEach(item => viewer.entities.remove(item)); - customSatelliteMap.clear(); -} - - -// 获取tle数据,从缓存中获取,若无请求数据 +// 获取tle数据,从缓存中获取,若无则请求数据 async function getTleData(path) { - let data = localStorage.getItem(path); + let data = tleCache.get(path); if (data) { console.log(`%c 命中缓存,key值为${path}`, 'color:#0f0;'); return data; } else { console.warn("未命中缓存,开始下载TLE数据"); - return await getTleDataFromExternal(path); + const res = await getTleDataFromExternal(path); + tleCache.set(path, res); + return res; } } @@ -362,16 +199,14 @@ function removeSatellite(path) { } } -// 侦听器 watch(checked, (newValue, oldValue) => { - let filterValue = newValue.concat(oldValue).filter((item, index, arr) => arr.indexOf(item) === arr.lastIndexOf(item)); - let satelliteClassify = allSatellite.find(item => item.value === filterValue[0]); - // 勾选了卫星 - if (newValue.length > oldValue.length) { - addSatellite(satelliteClassify.group); - } else { - //取消了勾选 - removeSatellite(satelliteClassify.group); + const { addedItems, removedItems } = compareArrays(oldValue, newValue); + if (addedItems.length) { + // 默认只会有一次操作,也就是说addedItems, removedItems数组中的元素只会有一个,可以直接取第一个元素 + addSatellite(addedItems[0]); + } + if (removedItems.length) { + removeSatellite(removedItems[0]); } }) @@ -381,7 +216,6 @@ onMounted(async () => { initCesium(); initTimeLine(); addCesiumEventListener(); - addSatellite('last-30-days'); }) diff --git a/src/views/satellite-track/satelliteType.js b/src/views/satellite-track/satelliteType.js index 15b8af0..8f27c06 100644 --- a/src/views/satellite-track/satelliteType.js +++ b/src/views/satellite-track/satelliteType.js @@ -7,27 +7,27 @@ let specialSatellite = [ }, { label: "Last 30 Days' Launches", - value: 1, + value: 'last-30-days', group: 'last-30-days' }, { label: 'Space Stations', - value: 2, + value: 'stations', group: 'stations' }, { label: '100 (or so) Brightest', - value: 3, + value: 'visual', group: 'visual' }, { label: 'Active Satellites', - value: 4, + value: 'active', group: 'active' }, { label: 'Analyst Satellites ', - value: 5, + value: 'analyst', group: 'analyst' } ]; @@ -41,52 +41,52 @@ let weatherSatellite = [ }, { label: 'Weather', - value: 6, + value: 'weather', group: 'weather' }, { label: 'NOAA', - value: 7, + value: 'noaa', group: 'noaa' }, { label: 'GOES', - value: 8, + value: 'goes', group: 'goes' }, { label: 'Earth Resources', - value: 9, + value: 'resource', group: 'resource' }, { label: 'Search & Rescue (SARSAT) ', - value: 10, + value: 'sarsat', group: 'sarsat' }, { label: 'Disaster Monitoring', - value: 11, + value: 'dmc', group: 'dmc' }, { label: 'TDRSS', - value: 12, + value: 'tdrss', group: 'tdrss' }, { label: 'ARGOS Data Collection System', - value: 13, + value: 'argos', group: 'argos' }, { label: 'Planet', - value: 14, + value: 'planet', group: 'planet' }, { label: 'Spire', - value: 15, + value: 'spire', group: 'spire' } ]; @@ -100,97 +100,97 @@ let communicationSatellite = [ }, { label: 'Active Geosynchronous', - value: 16, + value: 'geo', group: 'geo' }, { label: 'GEO Protected Zone', - value: 17, + value: 'gpz', group: 'gpz' }, { label: 'GEO Protected Zone Plus', - value: 18, + value: 'gpz-plus', group: 'gpz-plus' }, { label: 'Intelsat', - value: 19, + value: 'intelsat', group: 'intelsat' }, { label: 'SES', - value: 20, + value: 'ses', group: 'ses' }, { label: 'Iridium', - value: 21, + value: 'iridium', group: 'iridium' }, { label: 'Iridium NEXT', - value: 22, + value: 'iridium-NEXT', group: 'iridium-NEXT' }, { label: 'Starlink', - value: 23, + value: 'starlink', group: 'starlink' }, { label: 'OneWeb', - value: 24, + value: 'oneweb', group: 'oneweb' }, { label: 'Orbcomm', - value: 25, + value: 'orbcomm', group: 'orbcomm' }, { label: 'Globalstar', - value: 26, + value: 'globalstar', group: 'globalstar' }, { label: 'Swarm', - value: 27, + value: 'swarm', group: 'swarm' }, { label: 'Amateur Radio', - value: 28, + value: 'amateur', group: 'amateur' }, { label: 'Experimental Comm', - value: 29, + value: 'x-comm', group: 'x-comm' }, { label: 'Other Comm', - value: 30, + value: 'other-comm', group: 'other-comm' }, { label: 'SatNOGS', - value: 31, + value: 'satnogs', group: 'satnogs' }, { label: 'Gorizont', - value: 32, + value: 'gorizont', group: 'gorizont' }, { label: 'Raduga', - value: 33, + value: 'raduga', group: 'raduga' }, { label: 'Molniya', - value: 34, + value: 'molniya', group: 'molniya' }, ]; @@ -204,42 +204,42 @@ let navigationSatellite = [ }, { label: 'GNSS', - value: 35, + value: 'gnss', group: 'gnss' }, { label: 'GPS Operational', - value: 36, + value: 'gps-ops', group: 'gps-ops' }, { label: 'GLONASS Operational', - value: 37, + value: 'glo-ops', group: 'glo-ops' }, { label: 'Galileo', - value: 38, + value: 'galileo', group: 'galileo' }, { label: 'Beidou', - value: 39, + value: 'beidou', group: 'beidou' }, { label: 'Satellite-Based Augmentation System', - value: 40, + value: 'sbas', group: 'sbas' }, { label: 'Navy Navigation Satellite System (NNSS)', - value: 41, + value: 'nnss', group: 'nnss' }, { label: 'Russian LEO Navigation', - value: 42, + value: 'musson', group: 'musson' }, ]; @@ -253,22 +253,22 @@ let scientificSatellite = [ }, { label: 'Space & Earth Science', - value: 43, + value: 'science', group: 'science' }, { label: 'Geodetic', - value: 44, + value: 'geodetic', group: 'geodetic' }, { label: 'Engineering', - value: 45, + value: 'engineering', group: 'engineering' }, { label: 'Education', - value: 46, + value: 'education', group: 'education' } ]; @@ -282,22 +282,22 @@ let miscellaneousSatellite = [ }, { label: 'Miscellaneous Military', - value: 47, + value: 'military', group: 'military' }, { label: 'Radar Calibration', - value: 48, + value: 'radar', group: 'radar' }, { label: 'CubeSats', - value: 49, + value: 'cubesat', group: 'cubesat' }, { label: 'Other Satellites', - value: 50, + value: 'other', group: 'other' } ]