feat(SAT): add CesiumViewer component and utility functions; update dependencies
All checks were successful
/ depcheck (push) Successful in 1m58s
/ build-and-deploy-to-vercel (push) Successful in 2m4s
/ surge (push) Successful in 1m44s
/ playwright (push) Successful in 2m4s

This commit is contained in:
严浩
2025-02-10 17:34:24 +08:00
parent f26342ddfc
commit 19e46190f1
9 changed files with 206 additions and 22 deletions

View File

@ -9,7 +9,7 @@
</template>
<script setup lang="ts">
const { countdownTime, triggerCountdown, isCounting } = useCountdown($__DEV__ ? 5 : 60);
const { remaining: countdownTime, start: startCountdown, isActive: isCounting } = useCountdown($__DEV__ ? 3 : 60);
const isSending = ref(false);
const sendSms = async () => {
@ -17,7 +17,7 @@ const sendSms = async () => {
isSending.value = true;
try {
await new Promise((resolve) => setTimeout(resolve, 1000));
triggerCountdown();
startCountdown();
ToastService.add({ severity: 'info', summary: '提示', life: 3000, detail: '验证码发送成功' });
} finally {
isSending.value = false;

View File

@ -11,12 +11,16 @@ import {
ImageryLayer,
// VERSION,
EmbeddedTileServiceImageryProvider,
DynamicTimeline,
SpaceEntity,
} from 'orbpro';
// let viewer: Viewer;
import { demoOrbitGeneration } from './fns';
let viewer: Viewer;
onMounted(() => {
new Viewer('cesiumContainer', {
viewer = new Viewer('cesiumContainer', {
// globe: false, //
baseLayerPicker: true,
homeButton: true, // Home
@ -26,10 +30,10 @@ onMounted(() => {
navigationHelpButton: !true, //
projectionPicker: !true, //
sceneModePicker: true, // (2D/3D)
animation: !true, //
animation: true, //
animationContainer: !true,
timeline: !true, // If set to false, the Timeline widget will not be created.
timelineContainer: !true,
timelineContainer: true,
selectionIndicator: true,
requestRenderMode: !true, // CPU/GPU使使{@link Scene#requestRender}API{@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|使}
showRenderLoopErrors: true, // HTML
@ -37,11 +41,24 @@ onMounted(() => {
orderIndependentTranslucency: false, //
shadows: true, // Determines if shadows are cast by light sources.
});
viewer.scene.debugShowFramesPerSecond = true;
new DynamicTimeline(viewer.timeline.container, viewer);
// @ts-expect-error Open console to debug app
globalThis.viewer = viewer;
/* if ($__DEV__) */ demoOrbitGeneration(viewer);
});
</script>
<template>
<div id="cesiumContainer" />
<div class="h-full flex flex-col gap-2">
<div class="shrink-0">
<Button @click="demoOrbitGeneration(viewer)">轨道生成</Button>
</div>
<div id="cesiumContainer" class="flex-1" />
</div>
<!--
{#if $selectedEntity}
<SelectionWidget {viewer} />
@ -51,7 +68,6 @@ onMounted(() => {
<style>
#cesiumContainer {
height: 100%;
width: 100%;
}
</style>

148
src/pages/SAT/fns/demo.ts Normal file
View File

@ -0,0 +1,148 @@
import { PromiseConfirmationService } from '@/utils';
import {
Cartesian2,
Cartesian3,
Color,
MakeBillboardLabel,
NearFarScalar,
SpaceCatalogDataSource,
SpaceEntity,
VerticalOrigin,
viewerReferenceFrameMixin,
type Viewer,
} from 'orbpro';
declare global {
interface Window {
spaceCatalog: SpaceCatalogDataSource;
}
}
export async function demoOrbitGeneration(viewer: Viewer) {
window.spaceCatalog = new SpaceCatalogDataSource({ name: 'celestrak' });
viewer.extend(viewerReferenceFrameMixin);
viewer.referenceFrame = 1;
// https://spacedatastandards.org/#/standards?search=OMM
const ISS = new SpaceEntity({
id: '25544',
name: 'ISS',
point: {
pixelSize: 1,
},
label: {
show: false,
font: `1rem Helvetica`,
showBackground: true,
backgroundColor: new Color(0.1, 0.1, 0.1, 0.9),
pixelOffset: new Cartesian2(10, 0),
scaleByDistance: new NearFarScalar(1.5e2, 1.5, 13.0e7, 0.0),
pixelOffsetScaleByDistance: new NearFarScalar(1.5e2, 3.0, 1.5e7, 0.5),
},
viewFrom: new Cartesian3(-1678500.7493507154, -17680994.63403464, 24667690.486357275),
});
ISS.position.loadOMM({
/* CCSDS OMM版本 */ CCSDS_OMM_VERS: 0.0,
/* 创建日期(ISO 8601 UTC格式) */ CREATION_DATE: null,
/* 创建者 */ ORIGINATOR: null,
/* 卫星名称 */ OBJECT_NAME: 'ISS (ZARYA)',
/* 国际标识符(YYYY-NNNAAA) */ OBJECT_ID: '1998-067A',
/* 中心名称(例如:EARTH, MARS) */ CENTER_NAME: null,
/* 参考坐标系 */ REFERENCE_FRAME: 2,
/* 参考坐标系历元(ISO 8601 UTC格式) */ REFERENCE_FRAME_EPOCH: null,
/* 时间系统[M, UTC] */ TIME_SYSTEM: 11,
/* 平均元素理论 */ MEAN_ELEMENT_THEORY: 0,
/* 注释 */ COMMENT: null,
/* 平均开普勒根数的历元(ISO 8601 UTC格式) */ EPOCH: '2024-05-08T19:52:52.426848',
/* 半长轴(km) */ SEMI_MAJOR_AXIS: 0,
/* 平均运动(圈/天) */ MEAN_MOTION: 15.51025615,
/* 偏心率(无量纲) */ ECCENTRICITY: 0.0003349,
/* 轨道倾角(度) */ INCLINATION: 51.6355,
/* 升交点赤经(度) */ RA_OF_ASC_NODE: 150.5366,
/* 近地点幅角(度) */ ARG_OF_PERICENTER: 149.2285,
/* 平近点角(度) */ MEAN_ANOMALY: 210.8902,
/* 引力常数(km³/s²) */ GM: 0,
/* 质量(kg) */ MASS: 0,
/* 太阳辐射面积(m²) */ SOLAR_RAD_AREA: 0,
/* 太阳辐射压系数(无量纲) */ SOLAR_RAD_COEFF: 0,
/* 大气阻力面积(m²) */ DRAG_AREA: 0,
/* 大气阻力系数(无量纲) */ DRAG_COEFF: 0,
/* 星历类型(SGP,SGP4等) */ EPHEMERIS_TYPE: 0,
/* 分类类型,默认'U' */ CLASSIFICATION_TYPE: 'U',
/* NORAD编号 */ NORAD_CAT_ID: 25544,
/* 根数组编号 */ ELEMENT_SET_NO: 999,
/* 历元时的圈次 */ REV_AT_EPOCH: 45244,
/* 气阻系数(1/地球半径) */ BSTAR: 0.00028217,
/* 平均运动一阶导数(圈/天²) */ MEAN_MOTION_DOT: 0.00016275,
/* 平均运动二阶导数(圈/天³) */ MEAN_MOTION_DDOT: 0,
/* 协方差矩阵参考坐标系 */ COV_REFERENCE_FRAME: 23,
/* --- 位置/速度协方差矩阵(6x6下三角) --- */
/* 位置协方差矩阵元素(km²) */ CX_X: 0,
/* 位置协方差矩阵元素(km²) */ CY_X: 0,
/* 位置协方差矩阵元素(km²) */ CY_Y: 0,
/* 位置协方差矩阵元素(km²) */ CZ_X: 0,
/* 位置协方差矩阵元素(km²) */ CZ_Y: 0,
/* 位置协方差矩阵元素(km²) */ CZ_Z: 0,
/* 速度-位置协方差矩阵元素(km²/s) */ CX_DOT_X: 0,
/* 速度-位置协方差矩阵元素(km²/s) */ CX_DOT_Y: 0,
/* 速度-位置协方差矩阵元素(km²/s) */ CX_DOT_Z: 0,
/* 速度协方差矩阵元素(km²/s²) */ CX_DOT_X_DOT: 0,
/* 速度-位置协方差矩阵元素(km²/s) */ CY_DOT_X: 0,
/* 速度-位置协方差矩阵元素(km²/s) */ CY_DOT_Y: 0,
/* 速度-位置协方差矩阵元素(km²/s) */ CY_DOT_Z: 0,
/* 速度协方差矩阵元素(km²/s²) */ CY_DOT_X_DOT: 0,
/* 速度协方差矩阵元素(km²/s²) */ CY_DOT_Y_DOT: 0,
/* 速度-位置协方差矩阵元素(km²/s) */ CZ_DOT_X: 0,
/* 速度-位置协方差矩阵元素(km²/s) */ CZ_DOT_Y: 0,
/* 速度-位置协方差矩阵元素(km²/s) */ CZ_DOT_Z: 0,
/* 速度协方差矩阵元素(km²/s²) */ CZ_DOT_X_DOT: 0,
/* 速度协方差矩阵元素(km²/s²) */ CZ_DOT_Y_DOT: 0,
/* 速度协方差矩阵元素(km²/s²) */ CZ_DOT_Z_DOT: 0,
/* --- 用户自定义字段 --- */
/* 用户自定义BIP-0044类型 */ USER_DEFINED_BIP_0044_TYPE: 0,
/* 用户自定义对象标识符 */ USER_DEFINED_OBJECT_DESIGNATOR: null,
/* 用户自定义地球模型 */ USER_DEFINED_EARTH_MODEL: null,
/* 用户自定义历元时间戳 */ USER_DEFINED_EPOCH_TIMESTAMP: 0,
/* 用户自定义微秒数 */ USER_DEFINED_MICROSECONDS: 0,
});
ISS.point!.pixelSize = 10 as any;
ISS.point!.color = Color.WHITE as any;
MakeBillboardLabel({
entity: ISS,
text: 'ISS-text',
fontSize: 36,
verticalOrigin: VerticalOrigin.CENTER,
});
const issDataSource = new SpaceCatalogDataSource({ name: 'issSource' });
issDataSource.entities.add(ISS);
await viewer.dataSources.add(issDataSource);
// await new Promise((_r) => setTimeout(_r, 1000));
// viewer.camera.flyTo({
// destination: ISS.position.getValue(viewer.clock.currentTime)!,
// orientation: {
// heading: 0.0,
// pitch: -Math.PI / 2,
// roll: 0.0,
// },
// duration: 2,
// });
viewer.extend(viewerReferenceFrameMixin);
viewer.referenceFrame = 1;
const shshowOrbitow = await PromiseConfirmationService({ message: '要显示轨道吗?' });
ISS.showOrbit({ show: shshowOrbitow });
const showCoverage = await PromiseConfirmationService({ message: '要显示覆盖区吗?' });
ISS.showCoverage({ show: showCoverage });
// /* let dynamicTimeline = */ new DynamicTimeline(viewer.timeline.container, viewer);
const track = await PromiseConfirmationService({ message: '要追踪卫星吗?' });
if (track) viewer.trackedEntity = ISS;
}

View File

@ -0,0 +1 @@
export * from './demo.ts';

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import Viewer from './Viewer.vue';
import CesiumViewer from './CesiumViewer.vue';
const $datatableShow = ref(false);
</script>
@ -8,7 +8,7 @@ const $datatableShow = ref(false);
<div class="relative w-full h-full SAT">
<div id="container" class="absolute w-full h-full select-none">
<div class="viewer" :style="$datatableShow ? 'height:70%' : 'height: 100%'">
<Viewer />
<CesiumViewer />
</div>
<div
:class="[$datatableShow ? 'visible' : 'hidden', 'datatable absolute w-full b-0 l-0']"
@ -33,9 +33,9 @@ const $datatableShow = ref(false);
flex: 1;
}
</style>
<!--
<style scoped>
#container {
background-color: pink;
}
</style>
</style> -->

12
src/utils/index.ts Normal file
View File

@ -0,0 +1,12 @@
export async function PromiseConfirmationService({ message }: { message: string }) {
return await new Promise<boolean>((reslove) => {
ConfirmationService.require({
position: 'bottomright',
modal: false,
header: '提示',
message: message,
accept: () => reslove(true),
reject: () => reslove(false),
});
});
}