feat(*): 代码梳理与精简|删除冗余功能

This commit is contained in:
jiang teng 2024-09-29 15:18:03 +08:00
parent 9594ee1914
commit 9f4c8128cc
5 changed files with 100 additions and 247 deletions

View File

@ -6,8 +6,6 @@ function getTleDataFromExternal(path = "") {
let uri = `${BASE_URL}/NORAD/elements/gp.php?GROUP=${path}&FORMAT=tle`; let uri = `${BASE_URL}/NORAD/elements/gp.php?GROUP=${path}&FORMAT=tle`;
return axios.get(uri).then(res => { return axios.get(uri).then(res => {
if (res.status === 200) { if (res.status === 200) {
ElMessage.success('获取TLE成功');
localStorage.setItem(path, res.data); // 缓存TLE数据减轻数据服务压力
return Promise.resolve(res.data); return Promise.resolve(res.data);
} else { } else {
ElMessage.error('获取TLE失败'); ElMessage.error('获取TLE失败');
@ -16,6 +14,4 @@ function getTleDataFromExternal(path = "") {
}); });
} }
export { getTleDataFromExternal }; export { getTleDataFromExternal };

View File

@ -51,6 +51,7 @@ class SatelliteEntity {
createSatelliteEntity() { createSatelliteEntity() {
const start = Cesium.JulianDate.fromIso8601(new Date().toISOString()); const start = Cesium.JulianDate.fromIso8601(new Date().toISOString());
const stop = Cesium.JulianDate.addSeconds(start, this.totalSeconds, new Cesium.JulianDate()); const stop = Cesium.JulianDate.addSeconds(start, this.totalSeconds, new Cesium.JulianDate());
const color = Cesium.Color.fromRandom({ alpha: 1.0 });
let satelliteEntity = { let satelliteEntity = {
name: this.name, name: this.name,
description: this.name, description: this.name,
@ -58,15 +59,15 @@ class SatelliteEntity {
position: this._getPositionProperty(), position: this._getPositionProperty(),
point: { point: {
pixelSize: 8, pixelSize: 8,
color: Cesium.Color.fromRandom({ alpha: 1.0 }), color: color,
// scaleByDistance: new Cesium.NearFarScalar(1.5e3, 1, 8.0e8, 0.5), // scaleByDistance: new Cesium.NearFarScalar(1.5e3, 1, 8.0e8, 0.5),
}, },
path: new Cesium.PathGraphics({ path: new Cesium.PathGraphics({
width: 1, width: 0.5,
show: false, show: true,
leadTime: this.leadTime, leadTime: this.leadTime,
trailTime: this.trailTime, trailTime: this.trailTime,
material: Cesium.Color.LIME, material: color,
}), }),
label: { label: {
text: this.name, text: this.name,
@ -79,7 +80,7 @@ class SatelliteEntity {
horizontalOrigin: Cesium.VerticalOrigin.LEFT, horizontalOrigin: Cesium.VerticalOrigin.LEFT,
pixelOffset: new Cesium.Cartesian2(0, 5), pixelOffset: new Cesium.Cartesian2(0, 5),
fillColor: Cesium.Color.WHITE, fillColor: Cesium.Color.WHITE,
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 5000000), // distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 50000000),
} }
} }
return satelliteEntity; return satelliteEntity;

22
src/utils/index.js Normal file
View File

@ -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 };

View File

@ -4,17 +4,8 @@
<div class="menu_button" @click="drawer = !drawer" title="卫星星座选择"> <div class="menu_button" @click="drawer = !drawer" title="卫星星座选择">
<img src="../../assets/menu.svg" width="28" height="28" alt="卫星星座选择"> <img src="../../assets/menu.svg" width="28" height="28" alt="卫星星座选择">
</div> </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> </div>
<!-- 抽屉1 -->
<el-drawer v-model="drawer" title="卫星星座选择" direction="ltr"> <el-drawer v-model="drawer" title="卫星星座选择" direction="ltr">
<el-checkbox-group v-model="checked" @change="handleSatelliteChange" :max=5> <el-checkbox-group v-model="checked" @change="handleSatelliteChange" :max=5>
<template v-for="(item, index) in allSatellite" :key="index"> <template v-for="(item, index) in allSatellite" :key="index">
@ -23,24 +14,6 @@
</template> </template>
</el-checkbox-group> </el-checkbox-group>
</el-drawer> </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> </template>
<script setup> <script setup>
@ -48,45 +21,29 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import "cesium/Build/Cesium/Widgets/widgets.css"; import "cesium/Build/Cesium/Widgets/widgets.css";
import { onMounted, ref, watch } from 'vue'; import { onMounted, ref, watch } from 'vue';
import "./SatelliteTrack.scss" import "./SatelliteTrack.scss"
import { getTleDataFromExternal } from '@/http/index' import { getTleDataFromExternal } from '@/http/index'
import SatelliteEntity from '@/js/SatelliteEntity'; import SatelliteEntity from '@/js/SatelliteEntity';
import { specialSatellite, weatherSatellite, communicationSatellite, navigationSatellite, scientificSatellite, miscellaneousSatellite } from "./satelliteType" 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'; window.CESIUM_BASE_URL = import.meta.env.MODE === 'development' ? '/cesium' : '/satellite-track/cesium';
let viewer; let viewer;
//
const totalSeconds = 86400; const totalSeconds = 86400;
// //
const satelliteMap = new Map(); const satelliteMap = new Map();
//
const customSatelliteMap = new Map();
// //
const drawer = ref(false); 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'; Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiYjZmMWM4Ny01YzQ4LTQ3MzUtYTI5Mi1hNTgyNjdhMmFiMmMiLCJpZCI6NjIwMjgsImlhdCI6MTYyNjY3MTMxNX0.5SelYUyzXWRoMyjjFvmFIAoPtWlJPQMjsVl2e_jQe-c';
@ -99,12 +56,6 @@ function initCesium() {
return Cesium.JulianDate.toIso8601(dataZone8).slice(0, 19); 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({ let gaoDeSatelliteImgLayer = new Cesium.UrlTemplateImageryProvider({
url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}", 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(), 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', { viewer = new Cesium.Viewer('cesiumContainer', {
baseLayerPicker: true, baseLayerPicker: true,
geocoder: false, geocoder: false,
@ -191,23 +135,6 @@ function parseTle(data = "") {
return tles; 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() { function addCesiumEventListener() {
let callback = viewer.screenSpaceEventHandler.getInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); let callback = viewer.screenSpaceEventHandler.getInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) { viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) {
@ -218,9 +145,7 @@ function addCesiumEventListener() {
} }
if (pickedFeature) { if (pickedFeature) {
pickedFeature.id.path.show = new Cesium.ConstantProperty(true);
pickedFeature.id.label.distanceDisplayCondition = undefined;
clickedSatelliteArray.push(pickedFeature);
} }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK); }, 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) { async function getTleData(path) {
let data = localStorage.getItem(path); let data = tleCache.get(path);
if (data) { if (data) {
console.log(`%c 命中缓存,key值为${path}`, 'color:#0f0;'); console.log(`%c 命中缓存,key值为${path}`, 'color:#0f0;');
return data; return data;
} else { } else {
console.warn("未命中缓存开始下载TLE数据"); 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) => { watch(checked, (newValue, oldValue) => {
let filterValue = newValue.concat(oldValue).filter((item, index, arr) => arr.indexOf(item) === arr.lastIndexOf(item)); const { addedItems, removedItems } = compareArrays(oldValue, newValue);
let satelliteClassify = allSatellite.find(item => item.value === filterValue[0]); if (addedItems.length) {
// // addedItems, removedItems
if (newValue.length > oldValue.length) { addSatellite(addedItems[0]);
addSatellite(satelliteClassify.group); }
} else { if (removedItems.length) {
// removeSatellite(removedItems[0]);
removeSatellite(satelliteClassify.group);
} }
}) })
@ -381,7 +216,6 @@ onMounted(async () => {
initCesium(); initCesium();
initTimeLine(); initTimeLine();
addCesiumEventListener(); addCesiumEventListener();
addSatellite('last-30-days');
}) })

View File

@ -7,27 +7,27 @@ let specialSatellite = [
}, },
{ {
label: "Last 30 Days' Launches", label: "Last 30 Days' Launches",
value: 1, value: 'last-30-days',
group: 'last-30-days' group: 'last-30-days'
}, },
{ {
label: 'Space Stations', label: 'Space Stations',
value: 2, value: 'stations',
group: 'stations' group: 'stations'
}, },
{ {
label: '100 (or so) Brightest', label: '100 (or so) Brightest',
value: 3, value: 'visual',
group: 'visual' group: 'visual'
}, },
{ {
label: 'Active Satellites', label: 'Active Satellites',
value: 4, value: 'active',
group: 'active' group: 'active'
}, },
{ {
label: 'Analyst Satellites ', label: 'Analyst Satellites ',
value: 5, value: 'analyst',
group: 'analyst' group: 'analyst'
} }
]; ];
@ -41,52 +41,52 @@ let weatherSatellite = [
}, },
{ {
label: 'Weather', label: 'Weather',
value: 6, value: 'weather',
group: 'weather' group: 'weather'
}, },
{ {
label: 'NOAA', label: 'NOAA',
value: 7, value: 'noaa',
group: 'noaa' group: 'noaa'
}, },
{ {
label: 'GOES', label: 'GOES',
value: 8, value: 'goes',
group: 'goes' group: 'goes'
}, },
{ {
label: 'Earth Resources', label: 'Earth Resources',
value: 9, value: 'resource',
group: 'resource' group: 'resource'
}, },
{ {
label: 'Search & Rescue (SARSAT) ', label: 'Search & Rescue (SARSAT) ',
value: 10, value: 'sarsat',
group: 'sarsat' group: 'sarsat'
}, },
{ {
label: 'Disaster Monitoring', label: 'Disaster Monitoring',
value: 11, value: 'dmc',
group: 'dmc' group: 'dmc'
}, },
{ {
label: 'TDRSS', label: 'TDRSS',
value: 12, value: 'tdrss',
group: 'tdrss' group: 'tdrss'
}, },
{ {
label: 'ARGOS Data Collection System', label: 'ARGOS Data Collection System',
value: 13, value: 'argos',
group: 'argos' group: 'argos'
}, },
{ {
label: 'Planet', label: 'Planet',
value: 14, value: 'planet',
group: 'planet' group: 'planet'
}, },
{ {
label: 'Spire', label: 'Spire',
value: 15, value: 'spire',
group: 'spire' group: 'spire'
} }
]; ];
@ -100,97 +100,97 @@ let communicationSatellite = [
}, },
{ {
label: 'Active Geosynchronous', label: 'Active Geosynchronous',
value: 16, value: 'geo',
group: 'geo' group: 'geo'
}, },
{ {
label: 'GEO Protected Zone', label: 'GEO Protected Zone',
value: 17, value: 'gpz',
group: 'gpz' group: 'gpz'
}, },
{ {
label: 'GEO Protected Zone Plus', label: 'GEO Protected Zone Plus',
value: 18, value: 'gpz-plus',
group: 'gpz-plus' group: 'gpz-plus'
}, },
{ {
label: 'Intelsat', label: 'Intelsat',
value: 19, value: 'intelsat',
group: 'intelsat' group: 'intelsat'
}, },
{ {
label: 'SES', label: 'SES',
value: 20, value: 'ses',
group: 'ses' group: 'ses'
}, },
{ {
label: 'Iridium', label: 'Iridium',
value: 21, value: 'iridium',
group: 'iridium' group: 'iridium'
}, },
{ {
label: 'Iridium NEXT', label: 'Iridium NEXT',
value: 22, value: 'iridium-NEXT',
group: 'iridium-NEXT' group: 'iridium-NEXT'
}, },
{ {
label: 'Starlink', label: 'Starlink',
value: 23, value: 'starlink',
group: 'starlink' group: 'starlink'
}, },
{ {
label: 'OneWeb', label: 'OneWeb',
value: 24, value: 'oneweb',
group: 'oneweb' group: 'oneweb'
}, },
{ {
label: 'Orbcomm', label: 'Orbcomm',
value: 25, value: 'orbcomm',
group: 'orbcomm' group: 'orbcomm'
}, },
{ {
label: 'Globalstar', label: 'Globalstar',
value: 26, value: 'globalstar',
group: 'globalstar' group: 'globalstar'
}, },
{ {
label: 'Swarm', label: 'Swarm',
value: 27, value: 'swarm',
group: 'swarm' group: 'swarm'
}, },
{ {
label: 'Amateur Radio', label: 'Amateur Radio',
value: 28, value: 'amateur',
group: 'amateur' group: 'amateur'
}, },
{ {
label: 'Experimental Comm', label: 'Experimental Comm',
value: 29, value: 'x-comm',
group: 'x-comm' group: 'x-comm'
}, },
{ {
label: 'Other Comm', label: 'Other Comm',
value: 30, value: 'other-comm',
group: 'other-comm' group: 'other-comm'
}, },
{ {
label: 'SatNOGS', label: 'SatNOGS',
value: 31, value: 'satnogs',
group: 'satnogs' group: 'satnogs'
}, },
{ {
label: 'Gorizont', label: 'Gorizont',
value: 32, value: 'gorizont',
group: 'gorizont' group: 'gorizont'
}, },
{ {
label: 'Raduga', label: 'Raduga',
value: 33, value: 'raduga',
group: 'raduga' group: 'raduga'
}, },
{ {
label: 'Molniya', label: 'Molniya',
value: 34, value: 'molniya',
group: 'molniya' group: 'molniya'
}, },
]; ];
@ -204,42 +204,42 @@ let navigationSatellite = [
}, },
{ {
label: 'GNSS', label: 'GNSS',
value: 35, value: 'gnss',
group: 'gnss' group: 'gnss'
}, },
{ {
label: 'GPS Operational', label: 'GPS Operational',
value: 36, value: 'gps-ops',
group: 'gps-ops' group: 'gps-ops'
}, },
{ {
label: 'GLONASS Operational', label: 'GLONASS Operational',
value: 37, value: 'glo-ops',
group: 'glo-ops' group: 'glo-ops'
}, },
{ {
label: 'Galileo', label: 'Galileo',
value: 38, value: 'galileo',
group: 'galileo' group: 'galileo'
}, },
{ {
label: 'Beidou', label: 'Beidou',
value: 39, value: 'beidou',
group: 'beidou' group: 'beidou'
}, },
{ {
label: 'Satellite-Based Augmentation System', label: 'Satellite-Based Augmentation System',
value: 40, value: 'sbas',
group: 'sbas' group: 'sbas'
}, },
{ {
label: 'Navy Navigation Satellite System (NNSS)', label: 'Navy Navigation Satellite System (NNSS)',
value: 41, value: 'nnss',
group: 'nnss' group: 'nnss'
}, },
{ {
label: 'Russian LEO Navigation', label: 'Russian LEO Navigation',
value: 42, value: 'musson',
group: 'musson' group: 'musson'
}, },
]; ];
@ -253,22 +253,22 @@ let scientificSatellite = [
}, },
{ {
label: 'Space & Earth Science', label: 'Space & Earth Science',
value: 43, value: 'science',
group: 'science' group: 'science'
}, },
{ {
label: 'Geodetic', label: 'Geodetic',
value: 44, value: 'geodetic',
group: 'geodetic' group: 'geodetic'
}, },
{ {
label: 'Engineering', label: 'Engineering',
value: 45, value: 'engineering',
group: 'engineering' group: 'engineering'
}, },
{ {
label: 'Education', label: 'Education',
value: 46, value: 'education',
group: 'education' group: 'education'
} }
]; ];
@ -282,22 +282,22 @@ let miscellaneousSatellite = [
}, },
{ {
label: 'Miscellaneous Military', label: 'Miscellaneous Military',
value: 47, value: 'military',
group: 'military' group: 'military'
}, },
{ {
label: 'Radar Calibration', label: 'Radar Calibration',
value: 48, value: 'radar',
group: 'radar' group: 'radar'
}, },
{ {
label: 'CubeSats', label: 'CubeSats',
value: 49, value: 'cubesat',
group: 'cubesat' group: 'cubesat'
}, },
{ {
label: 'Other Satellites', label: 'Other Satellites',
value: 50, value: 'other',
group: 'other' group: 'other'
} }
] ]