@zendir/ui 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/index.js +0 -169
  2. package/dist/index.js.map +1 -1
  3. package/dist/react/context/DisplaySettingsContext.js +0 -12
  4. package/dist/react/context/DisplaySettingsContext.js.map +1 -1
  5. package/dist/react/core/AstroIcon.js +1 -816
  6. package/dist/react/core/AstroIcon.js.map +1 -1
  7. package/dist/react/core/index.d.ts +0 -1
  8. package/dist/react/index.d.ts +2 -42
  9. package/dist/react/utils/index.js +0 -8
  10. package/dist/react/utils/index.js.map +1 -1
  11. package/dist/react.js +0 -169
  12. package/dist/react.js.map +1 -1
  13. package/package.json +1 -1
  14. package/dist/react/3d/EarthViewer.js +0 -836
  15. package/dist/react/3d/EarthViewer.js.map +0 -1
  16. package/dist/react/3d/SolarSystemViewer.js +0 -372
  17. package/dist/react/3d/SolarSystemViewer.js.map +0 -1
  18. package/dist/react/3d/ZenSpace3D.js +0 -1253
  19. package/dist/react/3d/ZenSpace3D.js.map +0 -1
  20. package/dist/react/3d/ZenSpace3DCesium.js +0 -186
  21. package/dist/react/3d/ZenSpace3DCesium.js.map +0 -1
  22. package/dist/react/3d/ZenSpace3DShaders.js +0 -94
  23. package/dist/react/3d/ZenSpace3DShaders.js.map +0 -1
  24. package/dist/react/3d/ZenSpace3DUtils.js +0 -213
  25. package/dist/react/3d/ZenSpace3DUtils.js.map +0 -1
  26. package/dist/react/3d/threeLoader.js +0 -18
  27. package/dist/react/3d/threeLoader.js.map +0 -1
  28. package/dist/react/cards/AccessCard.js +0 -410
  29. package/dist/react/cards/AccessCard.js.map +0 -1
  30. package/dist/react/cards/OrbitCard.js +0 -372
  31. package/dist/react/cards/OrbitCard.js.map +0 -1
  32. package/dist/react/cards/SpacecraftCard.js +0 -941
  33. package/dist/react/cards/SpacecraftCard.js.map +0 -1
  34. package/dist/react/cards/TelemetryCard.js +0 -742
  35. package/dist/react/cards/TelemetryCard.js.map +0 -1
  36. package/dist/react/cards/TelemetryStreamCard.js +0 -309
  37. package/dist/react/cards/TelemetryStreamCard.js.map +0 -1
  38. package/dist/react/charts/GroundTrackMap.js +0 -1123
  39. package/dist/react/charts/GroundTrackMap.js.map +0 -1
  40. package/dist/react/charts/GroundTrackMapLeaflet.js +0 -571
  41. package/dist/react/charts/GroundTrackMapLeaflet.js.map +0 -1
  42. package/dist/react/charts/groundTrackMapLeafletTiles.js +0 -11
  43. package/dist/react/charts/groundTrackMapLeafletTiles.js.map +0 -1
  44. package/dist/react/charts/groundTrackMapLeafletUtils.js +0 -109
  45. package/dist/react/charts/groundTrackMapLeafletUtils.js.map +0 -1
  46. package/dist/react/charts/unified/AstroChart.js +0 -1405
  47. package/dist/react/charts/unified/AstroChart.js.map +0 -1
  48. package/dist/react/charts/unified/PowerOverviewChart.js +0 -488
  49. package/dist/react/charts/unified/PowerOverviewChart.js.map +0 -1
  50. package/dist/react/charts/unified/domain.js +0 -3168
  51. package/dist/react/charts/unified/domain.js.map +0 -1
  52. package/dist/react/charts/unified/generators.js +0 -518
  53. package/dist/react/charts/unified/generators.js.map +0 -1
  54. package/dist/react/charts/unified/presets.js +0 -999
  55. package/dist/react/charts/unified/presets.js.map +0 -1
  56. package/dist/react/charts/unified/sync.js +0 -219
  57. package/dist/react/charts/unified/sync.js.map +0 -1
  58. package/dist/react/charts/unified/theme.js +0 -562
  59. package/dist/react/charts/unified/theme.js.map +0 -1
  60. package/dist/react/charts/unified/useChartStream.js +0 -226
  61. package/dist/react/charts/unified/useChartStream.js.map +0 -1
  62. package/dist/react/chatgpt/AppCard.js +0 -306
  63. package/dist/react/chatgpt/AppCard.js.map +0 -1
  64. package/dist/react/chatgpt/index.js +0 -166
  65. package/dist/react/chatgpt/index.js.map +0 -1
  66. package/dist/react/hooks/useSpacecraftPosition.js +0 -89
  67. package/dist/react/hooks/useSpacecraftPosition.js.map +0 -1
  68. package/dist/react/hooks/useTelemetry.js +0 -73
  69. package/dist/react/hooks/useTelemetry.js.map +0 -1
  70. package/dist/react/hooks/useZendirSession.js +0 -148
  71. package/dist/react/hooks/useZendirSession.js.map +0 -1
  72. package/dist/react/visualizations/EclipseTimerCard.js +0 -250
  73. package/dist/react/visualizations/EclipseTimerCard.js.map +0 -1
  74. package/dist/react/visualizations/LinkBudgetCard.js +0 -444
  75. package/dist/react/visualizations/LinkBudgetCard.js.map +0 -1
  76. package/dist/react/visualizations/NavBallCard.js +0 -243
  77. package/dist/react/visualizations/NavBallCard.js.map +0 -1
  78. package/dist/react/visualizations/PropulsionCard.js +0 -298
  79. package/dist/react/visualizations/PropulsionCard.js.map +0 -1
  80. package/dist/react/visualizations/SensorFootprintCard.js +0 -326
  81. package/dist/react/visualizations/SensorFootprintCard.js.map +0 -1
  82. package/dist/react/visualizations/ThermalHeatmapCard.js +0 -372
  83. package/dist/react/visualizations/ThermalHeatmapCard.js.map +0 -1
  84. package/dist/shaders/atmosphere.frag.js +0 -5
  85. package/dist/shaders/atmosphere.frag.js.map +0 -1
  86. package/dist/shaders/atmosphere.vert.js +0 -5
  87. package/dist/shaders/atmosphere.vert.js.map +0 -1
  88. package/dist/shaders/stars.frag.js +0 -5
  89. package/dist/shaders/stars.frag.js.map +0 -1
  90. package/dist/shaders/stars.vert.js +0 -5
  91. package/dist/shaders/stars.vert.js.map +0 -1
  92. package/dist/style.css +0 -143
@@ -1,3168 +0,0 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { memo, forwardRef, useMemo, useState, useEffect } from "react";
3
- import { AstroChart } from "./AstroChart.js";
4
- import { ASTRO_DATA_VIZ_COLORS, ZENDIR_BRAND_COLORS, STATUS_COLORS } from "./theme.js";
5
- import { useTheme } from "../../theme/ThemeProvider.js";
6
- let _echartsGlReady = false;
7
- let _echartsGlPromise = null;
8
- function _loadEchartsGl() {
9
- if (!_echartsGlPromise) {
10
- _echartsGlPromise = import("echarts-gl").then(() => {
11
- _echartsGlReady = true;
12
- return true;
13
- }).catch((err) => {
14
- console.warn("[zendir-ui] echarts-gl failed to load — 3D charts will not render:", err);
15
- return false;
16
- });
17
- }
18
- return _echartsGlPromise;
19
- }
20
- _loadEchartsGl();
21
- function useEchartsGlReady() {
22
- const [ready, setReady] = useState(_echartsGlReady);
23
- useEffect(() => {
24
- if (!_echartsGlReady) {
25
- _loadEchartsGl().then((ok) => {
26
- if (ok) setReady(true);
27
- });
28
- }
29
- }, []);
30
- return ready;
31
- }
32
- const SOFT_STATUS_COLORS = {
33
- normal: "#6ed86e",
34
- caution: "#ffd54f",
35
- critical: "#e57373",
36
- standby: "#4fc3f7"
37
- };
38
- function useChartTooltipStyle() {
39
- const { tokens, mode } = useTheme();
40
- const isDark = mode === "dark";
41
- return {
42
- backgroundColor: isDark ? "rgba(15, 23, 42, 0.95)" : "rgba(255, 255, 255, 0.95)",
43
- borderColor: isDark ? "rgba(100, 116, 139, 0.4)" : "rgba(100, 116, 139, 0.3)",
44
- textStyle: {
45
- color: tokens.colors.text.primary,
46
- fontSize: 12
47
- }
48
- };
49
- }
50
- function useChartLegendStyle() {
51
- const { tokens } = useTheme();
52
- return {
53
- textStyle: {
54
- color: tokens.colors.text.secondary
55
- }
56
- };
57
- }
58
- function useChartVisualMapStyle() {
59
- const { tokens } = useTheme();
60
- return {
61
- textStyle: {
62
- color: tokens.colors.text.tertiary
63
- },
64
- // Allow drag selection on the visualMap bar
65
- calculable: true,
66
- // Enable hover linking - when hovering on visualMap, highlight only that range
67
- hoverLink: true,
68
- // Non-hovered regions get faded opacity (not invisible, just light)
69
- outOfRange: {
70
- color: "rgba(128, 128, 128, 0.12)",
71
- // Very light gray with low opacity
72
- opacity: 0.15
73
- // Also reduce opacity for 3D elements
74
- },
75
- // Handle styles for the interactive bar (the draggable endpoints)
76
- handleStyle: {
77
- borderColor: tokens.colors.accent.primary,
78
- color: tokens.colors.accent.primary
79
- },
80
- // Indicator style when hovering
81
- indicatorStyle: {
82
- borderColor: "#fff"
83
- },
84
- // Smooth transition when highlighting
85
- realtime: true
86
- };
87
- }
88
- const PowerChart = memo(forwardRef(
89
- function PowerChart2({
90
- data = [],
91
- title = "Power system",
92
- showLegend = true,
93
- width = "100%",
94
- height = 250,
95
- showEclipse = true,
96
- loading = false,
97
- enableZoom = false,
98
- className = "",
99
- export: exportOptions,
100
- infoTooltip,
101
- // Icon/status props
102
- icon,
103
- iconStatus,
104
- statusMessage
105
- }, ref) {
106
- const { series, annotations } = useMemo(() => {
107
- const solarSeries = {
108
- id: "solar",
109
- name: "Solar",
110
- type: "line",
111
- data: data.map((d) => ({ x: d.time, y: d.solarPower })),
112
- color: SOFT_STATUS_COLORS.standby,
113
- // Cyan for solar
114
- yAxisIndex: 0,
115
- smooth: true,
116
- symbol: { type: "none" }
117
- };
118
- const batterySeries = {
119
- id: "battery",
120
- name: "Battery",
121
- type: "line",
122
- data: data.map((d) => ({ x: d.time, y: d.batteryPercent })),
123
- color: SOFT_STATUS_COLORS.normal,
124
- // Green for battery
125
- yAxisIndex: 1,
126
- smooth: true,
127
- symbol: { type: "none" }
128
- };
129
- const netPowerSeries = {
130
- id: "netPower",
131
- name: "Net",
132
- type: "line",
133
- data: data.map((d) => ({ x: d.time, y: d.netPower })),
134
- color: ZENDIR_BRAND_COLORS.electric,
135
- // Zendir Electric
136
- yAxisIndex: 0,
137
- smooth: true,
138
- symbol: { type: "none" }
139
- };
140
- const consumptionSeries = {
141
- id: "consumption",
142
- name: "Load",
143
- type: "line",
144
- data: data.map((d) => ({ x: d.time, y: d.consumption })),
145
- color: SOFT_STATUS_COLORS.critical,
146
- // Red for consumption
147
- yAxisIndex: 0,
148
- lineStyle: { type: "dashed", width: 1.5 },
149
- smooth: true,
150
- symbol: { type: "none" }
151
- };
152
- const eclipseAreas = { data: [] };
153
- if (showEclipse) {
154
- let inEclipse = false;
155
- let eclipseStart = 0;
156
- data.forEach((d, _i) => {
157
- if (d.eclipse && !inEclipse) {
158
- inEclipse = true;
159
- eclipseStart = d.time;
160
- } else if (!d.eclipse && inEclipse) {
161
- inEclipse = false;
162
- eclipseAreas.data.push([
163
- { xAxis: eclipseStart, name: "Eclipse" },
164
- { xAxis: d.time }
165
- ]);
166
- }
167
- });
168
- if (inEclipse && data.length > 0) {
169
- eclipseAreas.data.push([
170
- { xAxis: eclipseStart, name: "Eclipse" },
171
- { xAxis: data[data.length - 1].time }
172
- ]);
173
- }
174
- eclipseAreas.itemStyle = {
175
- color: `${STATUS_COLORS.critical}15`
176
- };
177
- }
178
- return {
179
- series: [solarSeries, batterySeries, netPowerSeries, consumptionSeries],
180
- annotations: showEclipse && eclipseAreas.data.length > 0 ? { markAreas: eclipseAreas } : void 0
181
- };
182
- }, [data, showEclipse]);
183
- const tooltipConfig = useMemo(() => ({
184
- trigger: "axis",
185
- crosshair: "x",
186
- formatter: (params) => {
187
- var _a;
188
- const p = Array.isArray(params) ? params : [];
189
- if (p.length === 0) return "";
190
- const axisVal = p[0].axisValue ?? p[0].value;
191
- const time = typeof axisVal === "number" ? axisVal : axisVal instanceof Date ? axisVal.getTime() : Number(axisVal);
192
- const inEclipse = ((_a = annotations == null ? void 0 : annotations.markAreas) == null ? void 0 : _a.data) ? annotations.markAreas.data.some(
193
- (pair) => {
194
- const start = pair[0].xAxis ?? 0;
195
- const end = pair[1].xAxis ?? 0;
196
- return time >= start && time <= end;
197
- }
198
- ) : false;
199
- const lines = p.map(
200
- (item) => `${item.marker ?? ""} ${item.seriesName ?? ""}: ${item.value ?? ""}`
201
- );
202
- if (inEclipse) lines.push("◐ Eclipse — spacecraft in shadow; solar panels off");
203
- return lines.join("<br/>");
204
- }
205
- }), [annotations]);
206
- return /* @__PURE__ */ jsx(
207
- AstroChart,
208
- {
209
- ref,
210
- type: "line",
211
- title,
212
- series,
213
- width,
214
- height,
215
- loading,
216
- className,
217
- icon,
218
- iconStatus,
219
- statusMessage,
220
- xAxis: { type: "time", name: "" },
221
- yAxis: [
222
- {
223
- name: "Power [W]",
224
- position: "left",
225
- min: 0
226
- },
227
- {
228
- name: "Battery [%]",
229
- position: "right",
230
- min: 0,
231
- max: 100
232
- }
233
- ],
234
- tooltip: tooltipConfig,
235
- legend: { show: showLegend, position: "bottom" },
236
- zoom: enableZoom ? { enabled: true, type: "inside", axis: "x" } : void 0,
237
- annotations,
238
- export: exportOptions,
239
- infoTooltip
240
- }
241
- );
242
- }
243
- ));
244
- const AttitudeChart = memo(forwardRef(
245
- function AttitudeChart2({
246
- data = [],
247
- title = "Attitude control",
248
- showLegend = true,
249
- width = "100%",
250
- height = 200,
251
- loading = false,
252
- enableZoom = false,
253
- showError = true,
254
- showAngularVelocity = true,
255
- className = "",
256
- export: exportOptions,
257
- infoTooltip,
258
- // Icon/status props
259
- icon,
260
- iconStatus,
261
- statusMessage
262
- }, ref) {
263
- const series = useMemo(() => {
264
- const result = [
265
- {
266
- id: "roll",
267
- name: "Roll",
268
- type: "line",
269
- data: data.map((d) => ({ x: d.time, y: d.roll })),
270
- color: SOFT_STATUS_COLORS.critical,
271
- // Red
272
- smooth: true,
273
- symbol: { type: "none" }
274
- },
275
- {
276
- id: "pitch",
277
- name: "Pitch",
278
- type: "line",
279
- data: data.map((d) => ({ x: d.time, y: d.pitch })),
280
- color: SOFT_STATUS_COLORS.normal,
281
- // Green
282
- smooth: true,
283
- symbol: { type: "none" }
284
- },
285
- {
286
- id: "yaw",
287
- name: "Yaw",
288
- type: "line",
289
- data: data.map((d) => ({ x: d.time, y: d.yaw })),
290
- color: ZENDIR_BRAND_COLORS.electric,
291
- // Zendir Electric
292
- smooth: true,
293
- symbol: { type: "none" }
294
- }
295
- ];
296
- if (showError && data.some((d) => d.pointingError !== void 0)) {
297
- result.push({
298
- id: "error",
299
- name: "Error",
300
- type: "line",
301
- data: data.filter((d) => d.pointingError !== void 0).map((d) => ({ x: d.time, y: d.pointingError })),
302
- color: SOFT_STATUS_COLORS.caution,
303
- // Yellow (status color)
304
- smooth: true,
305
- symbol: { type: "none" },
306
- lineStyle: { width: 1.5 }
307
- });
308
- }
309
- if (showAngularVelocity && data.some((d) => d.angularVelocity !== void 0)) {
310
- result.push({
311
- id: "angVel",
312
- name: "ω",
313
- type: "line",
314
- data: data.filter((d) => d.angularVelocity !== void 0).map((d) => ({ x: d.time, y: d.angularVelocity })),
315
- color: ZENDIR_BRAND_COLORS.purple,
316
- // Zendir Purple
317
- smooth: true,
318
- symbol: { type: "none" },
319
- lineStyle: { type: "dashed", width: 1 }
320
- });
321
- }
322
- return result;
323
- }, [data, showError, showAngularVelocity]);
324
- return /* @__PURE__ */ jsx(
325
- AstroChart,
326
- {
327
- ref,
328
- type: "line",
329
- title,
330
- series,
331
- width,
332
- height,
333
- loading,
334
- className,
335
- icon,
336
- iconStatus,
337
- statusMessage,
338
- xAxis: { type: "time", name: "" },
339
- yAxis: {
340
- name: "Attitude [deg]"
341
- // Center zero line
342
- },
343
- tooltip: { trigger: "axis", crosshair: "x" },
344
- legend: { show: showLegend, position: "bottom" },
345
- zoom: enableZoom ? { enabled: true, type: "inside", axis: "x" } : void 0,
346
- annotations: {
347
- markLines: {
348
- data: [{ yAxis: 0, label: "", lineStyle: { type: "solid", width: 1 } }]
349
- }
350
- },
351
- export: exportOptions,
352
- infoTooltip
353
- }
354
- );
355
- }
356
- ));
357
- const ThermalHeatmapChart = memo(forwardRef(
358
- function ThermalHeatmapChart2({
359
- data = [],
360
- zones = [],
361
- title = "Thermal zones",
362
- width = "100%",
363
- height = 300,
364
- range = [-40, 80],
365
- loading = false,
366
- className = "",
367
- export: exportOptions,
368
- infoTooltip
369
- }, ref) {
370
- const { series, timeLabels } = useMemo(() => {
371
- const timeLabels2 = data.map(
372
- (d) => new Date(d.time).toLocaleTimeString([], {
373
- hour: "2-digit",
374
- minute: "2-digit",
375
- hour12: false
376
- })
377
- );
378
- const heatmapData = [];
379
- data.forEach((d, timeIdx) => {
380
- zones.forEach((zone, zoneIdx) => {
381
- const temp = d.zones[zone] ?? 0;
382
- heatmapData.push([timeIdx, zoneIdx, temp]);
383
- });
384
- });
385
- return {
386
- series: [{
387
- id: "thermal",
388
- name: "Temperature",
389
- type: "heatmap",
390
- data: heatmapData
391
- }],
392
- timeLabels: timeLabels2
393
- };
394
- }, [data, zones]);
395
- return /* @__PURE__ */ jsx(
396
- AstroChart,
397
- {
398
- ref,
399
- type: "heatmap",
400
- title,
401
- series,
402
- width,
403
- height,
404
- loading,
405
- className,
406
- xAxis: { type: "category" },
407
- yAxis: { type: "category" },
408
- tooltip: { trigger: "item" },
409
- echartsOptions: {
410
- xAxis: { data: timeLabels },
411
- yAxis: { data: zones },
412
- visualMap: {
413
- min: range[0],
414
- max: range[1],
415
- calculable: true,
416
- orient: "vertical",
417
- right: 10,
418
- top: "center",
419
- // Enable hover linking - highlight only hovered range
420
- hoverLink: true,
421
- // Non-hovered regions get faded opacity
422
- outOfRange: {
423
- color: "rgba(128, 128, 128, 0.12)",
424
- opacity: 0.15
425
- },
426
- // Thermal gradient (cold → hot) - Original high-contrast palette
427
- // Multi-hue gradient for clear temperature differentiation
428
- inRange: {
429
- color: [
430
- "#313695",
431
- // Deep blue (very cold)
432
- "#4575b4",
433
- // Blue
434
- "#74add1",
435
- // Light blue
436
- "#abd9e9",
437
- // Pale blue
438
- "#e0f3f8",
439
- // Very pale blue
440
- "#ffffbf",
441
- // Pale yellow (neutral)
442
- "#fee090",
443
- // Light orange
444
- "#fdae61",
445
- // Orange
446
- "#f46d43",
447
- // Red-orange
448
- "#d73027",
449
- // Red
450
- "#a50026"
451
- // Dark red (very hot)
452
- ]
453
- }
454
- },
455
- series: [{
456
- type: "heatmap",
457
- data: series[0].data,
458
- label: { show: true, formatter: (p) => Array.isArray(p.value) && typeof p.value[2] === "number" ? `${p.value[2]}°` : "" },
459
- emphasis: {
460
- itemStyle: {
461
- shadowBlur: 10,
462
- shadowColor: "rgba(0, 0, 0, 0.5)"
463
- }
464
- }
465
- }]
466
- },
467
- export: exportOptions,
468
- infoTooltip
469
- }
470
- );
471
- }
472
- ));
473
- const LinkBudgetChart = memo(forwardRef(
474
- function LinkBudgetChart2({
475
- data = [],
476
- title = "Link budget",
477
- showLegend = true,
478
- width = "100%",
479
- height = 200,
480
- marginThreshold = 3,
481
- loading = false,
482
- className = "",
483
- export: exportOptions,
484
- infoTooltip
485
- }, ref) {
486
- const series = useMemo(() => [
487
- {
488
- id: "signal",
489
- name: "Signal",
490
- type: "area",
491
- data: data.map((d) => ({ x: d.time, y: d.signalStrength })),
492
- color: SOFT_STATUS_COLORS.normal,
493
- smooth: true,
494
- symbol: { type: "none" },
495
- areaStyle: { opacity: 0.2 }
496
- },
497
- {
498
- id: "noise",
499
- name: "Noise floor",
500
- type: "line",
501
- data: data.map((d) => ({ x: d.time, y: d.noiseFloor })),
502
- color: SOFT_STATUS_COLORS.critical,
503
- smooth: true,
504
- symbol: { type: "none" },
505
- lineStyle: { type: "dashed", width: 1 }
506
- },
507
- {
508
- id: "margin",
509
- name: "Margin",
510
- type: "line",
511
- data: data.map((d) => ({ x: d.time, y: d.margin })),
512
- color: SOFT_STATUS_COLORS.standby,
513
- yAxisIndex: 1,
514
- smooth: true,
515
- symbol: { type: "none" }
516
- }
517
- ], [data]);
518
- return /* @__PURE__ */ jsx(
519
- AstroChart,
520
- {
521
- ref,
522
- type: "line",
523
- title,
524
- series,
525
- width,
526
- height,
527
- loading,
528
- className,
529
- xAxis: { type: "time" },
530
- yAxis: [
531
- { name: "dBm", position: "left" },
532
- { name: "Margin [dB]", position: "right", min: 0 }
533
- ],
534
- tooltip: { trigger: "axis", crosshair: "x" },
535
- legend: { show: showLegend, position: "bottom" },
536
- annotations: {
537
- markLines: {
538
- data: [
539
- {
540
- yAxis: marginThreshold,
541
- label: `Min margin (${marginThreshold} dB)`,
542
- color: SOFT_STATUS_COLORS.caution,
543
- lineStyle: { type: "dashed" }
544
- }
545
- ]
546
- }
547
- },
548
- export: exportOptions,
549
- infoTooltip
550
- }
551
- );
552
- }
553
- ));
554
- const SubsystemGauge = memo(forwardRef(
555
- function SubsystemGauge2({
556
- value,
557
- name,
558
- unit = "%",
559
- width = 200,
560
- height = 200,
561
- thresholds = { caution: 70, critical: 90 },
562
- loading = false,
563
- className = "",
564
- export: exportOptions,
565
- infoTooltip
566
- }, ref) {
567
- const clampedValue = Math.max(0, Math.min(100, value));
568
- const widthPx = typeof width === "number" ? width : height;
569
- const gaugeSize = Math.max(110, Math.min(widthPx, height));
570
- const arcWidth = Math.max(8, Math.round(gaugeSize * 0.085));
571
- const valueFontSize = Math.max(18, Math.round(gaugeSize * 0.17));
572
- const titleFontSize = Math.max(10, Math.round(gaugeSize * 0.085));
573
- const compactGauge = gaugeSize < 150;
574
- const centerY = compactGauge ? "53%" : "55%";
575
- const detailY = compactGauge ? "10%" : "15%";
576
- const titleY = compactGauge ? "78%" : "84%";
577
- const unitSuffix = (unit == null ? void 0 : unit.trim()) ?? "";
578
- const longUnit = unitSuffix.length > 4;
579
- const getValueColor = () => {
580
- if (thresholds.critical && clampedValue >= thresholds.critical) return SOFT_STATUS_COLORS.critical;
581
- if (thresholds.caution && clampedValue >= thresholds.caution) return SOFT_STATUS_COLORS.caution;
582
- return SOFT_STATUS_COLORS.normal;
583
- };
584
- return /* @__PURE__ */ jsx(
585
- AstroChart,
586
- {
587
- ref,
588
- type: "gauge",
589
- series: [],
590
- width,
591
- height,
592
- loading,
593
- className,
594
- echartsOptions: {
595
- series: [{
596
- type: "gauge",
597
- min: 0,
598
- max: 100,
599
- startAngle: 200,
600
- endAngle: -20,
601
- radius: "90%",
602
- center: ["50%", centerY],
603
- // Modern minimal track
604
- axisLine: {
605
- lineStyle: {
606
- width: arcWidth,
607
- color: [[1, "rgba(100, 116, 139, 0.15)"]]
608
- // Subtle track
609
- }
610
- },
611
- // Hide all traditional gauge elements
612
- axisTick: { show: false },
613
- splitLine: { show: false },
614
- axisLabel: { show: false },
615
- pointer: { show: false },
616
- // No pointer for modern look
617
- // Progress arc with gradient
618
- progress: {
619
- show: true,
620
- width: arcWidth,
621
- roundCap: true,
622
- itemStyle: {
623
- color: {
624
- type: "linear",
625
- x: 0,
626
- y: 0,
627
- x2: 1,
628
- y2: 0,
629
- colorStops: [
630
- { offset: 0, color: "rgba(100, 200, 200, 0.6)" },
631
- { offset: 1, color: getValueColor() }
632
- ]
633
- },
634
- shadowColor: getValueColor(),
635
- shadowBlur: 8
636
- }
637
- },
638
- // Clean title below
639
- title: {
640
- show: true,
641
- offsetCenter: [0, titleY],
642
- fontSize: titleFontSize,
643
- fontWeight: 500,
644
- color: "rgba(255, 255, 255, 0.7)"
645
- },
646
- // Modern centered value
647
- detail: {
648
- valueAnimation: true,
649
- formatter: (currentValue) => {
650
- const rounded = Math.round(currentValue);
651
- if (!unitSuffix) return `${rounded}`;
652
- if (longUnit) return `${rounded}
653
- {unit|${unitSuffix}}`;
654
- return `${rounded}${unitSuffix}`;
655
- },
656
- fontSize: valueFontSize,
657
- fontWeight: 700,
658
- // AstroUXDS bold for gauge values
659
- lineHeight: Math.round(valueFontSize * 1.05),
660
- offsetCenter: [0, detailY],
661
- color: getValueColor(),
662
- rich: {
663
- unit: {
664
- color: "rgba(255, 255, 255, 0.75)",
665
- fontSize: Math.max(10, Math.round(valueFontSize * 0.5)),
666
- fontWeight: 500,
667
- lineHeight: Math.round(valueFontSize * 0.8)
668
- }
669
- }
670
- },
671
- data: [{ value: clampedValue, name }]
672
- }]
673
- },
674
- export: exportOptions,
675
- infoTooltip
676
- }
677
- );
678
- }
679
- ));
680
- const OrbitChart = memo(forwardRef(
681
- function OrbitChart2({
682
- data = [],
683
- title = "Polar Projection",
684
- referenceAltitude,
685
- width = 300,
686
- height = 300,
687
- loading = false,
688
- className = "",
689
- export: exportOptions,
690
- infoTooltip
691
- }, ref) {
692
- return /* @__PURE__ */ jsx(
693
- AstroChart,
694
- {
695
- ref,
696
- type: "scatter",
697
- title,
698
- series: [],
699
- width,
700
- height,
701
- loading,
702
- className,
703
- echartsOptions: {
704
- polar: {
705
- radius: ["0%", "75%"],
706
- center: ["50%", "50%"]
707
- },
708
- angleAxis: {
709
- type: "value",
710
- min: 0,
711
- max: 360,
712
- startAngle: 90,
713
- interval: 30,
714
- axisLine: { show: false },
715
- axisTick: { show: false },
716
- splitLine: {
717
- show: true,
718
- lineStyle: {
719
- color: "rgba(100, 116, 139, 0.15)",
720
- type: "dashed"
721
- }
722
- },
723
- axisLabel: {
724
- fontSize: 9,
725
- color: "rgba(255, 255, 255, 0.4)",
726
- formatter: (value) => value === 0 ? "" : `${value}°`
727
- }
728
- },
729
- radiusAxis: {
730
- min: referenceAltitude ? referenceAltitude * 0.9 : "dataMin",
731
- max: referenceAltitude ? referenceAltitude * 1.1 : "dataMax",
732
- axisLine: { show: false },
733
- axisTick: { show: false },
734
- axisLabel: { show: false },
735
- splitLine: {
736
- show: true,
737
- lineStyle: {
738
- color: "rgba(100, 116, 139, 0.2)",
739
- type: "dashed"
740
- }
741
- }
742
- },
743
- series: [{
744
- type: "scatter",
745
- name: "Position",
746
- coordinateSystem: "polar",
747
- data: data.map((d) => [d.altitude, d.angle]),
748
- symbolSize: 8,
749
- itemStyle: {
750
- color: ZENDIR_BRAND_COLORS.electric,
751
- // Zendir Electric
752
- shadowColor: ZENDIR_BRAND_COLORS.electric,
753
- shadowBlur: 6
754
- }
755
- }]
756
- },
757
- export: exportOptions,
758
- infoTooltip
759
- }
760
- );
761
- }
762
- ));
763
- const ContactWindowChart = memo(forwardRef(
764
- function ContactWindowChart2({
765
- data = [],
766
- title = "Contact windows",
767
- timeRange,
768
- width = "100%",
769
- height = 200,
770
- loading = false,
771
- enableZoom = true,
772
- className = "",
773
- export: exportOptions,
774
- infoTooltip
775
- }, ref) {
776
- const { categories, ganttData } = useMemo(() => {
777
- const cats = data.map((d) => d.name);
778
- const items = [];
779
- data.forEach((station, stationIdx) => {
780
- station.windows.forEach((w) => {
781
- w.signalQuality === "poor" ? STATUS_COLORS.critical : w.signalQuality === "marginal" ? STATUS_COLORS.caution : STATUS_COLORS.normal;
782
- items.push({
783
- name: station.name,
784
- value: [stationIdx, w.start, w.end, w.label]
785
- });
786
- });
787
- });
788
- return { categories: cats, ganttData: items };
789
- }, [data]);
790
- const series = [{
791
- id: "contacts",
792
- name: "Contacts",
793
- type: "bar",
794
- data: []
795
- }];
796
- return /* @__PURE__ */ jsx(
797
- AstroChart,
798
- {
799
- ref,
800
- type: "bar",
801
- title,
802
- series,
803
- width,
804
- height,
805
- loading,
806
- className,
807
- zoom: enableZoom ? { enabled: true, type: "inside", axis: "x" } : void 0,
808
- echartsOptions: {
809
- tooltip: {
810
- trigger: "item",
811
- formatter: (params) => {
812
- const p = params;
813
- const [, start, end, label] = p.value;
814
- const duration = ((end - start) / 6e4).toFixed(1);
815
- return `${label || "Contact"}<br/>Duration: ${duration} min`;
816
- }
817
- },
818
- grid: { left: 100, right: 20, top: 40, bottom: 40 },
819
- xAxis: {
820
- type: "time",
821
- min: timeRange == null ? void 0 : timeRange[0],
822
- max: timeRange == null ? void 0 : timeRange[1]
823
- },
824
- yAxis: {
825
- type: "category",
826
- data: categories
827
- },
828
- series: [{
829
- type: "custom",
830
- renderItem: (_params, api) => {
831
- const a = api;
832
- const catIdx = a.value(0);
833
- const start = a.coord([a.value(1), catIdx]);
834
- const end = a.coord([a.value(2), catIdx]);
835
- const height2 = a.size([0, 1])[1] * 0.6;
836
- return {
837
- type: "rect",
838
- shape: {
839
- x: start[0],
840
- y: start[1] - height2 / 2,
841
- width: end[0] - start[0],
842
- height: height2
843
- },
844
- style: {
845
- fill: STATUS_COLORS.normal,
846
- stroke: STATUS_COLORS.standby
847
- }
848
- };
849
- },
850
- encode: { x: [1, 2], y: 0 },
851
- data: ganttData
852
- }]
853
- },
854
- export: exportOptions,
855
- infoTooltip
856
- }
857
- );
858
- }
859
- ));
860
- const SpectrumChart = memo(forwardRef(
861
- function SpectrumChart2({
862
- data = [],
863
- title = "RF spectrum",
864
- frequencyRange,
865
- powerRange,
866
- noiseFloor,
867
- width = "100%",
868
- height = 200,
869
- loading = false,
870
- className = "",
871
- export: exportOptions,
872
- infoTooltip
873
- }, ref) {
874
- const series = useMemo(() => [{
875
- id: "spectrum",
876
- name: "Power",
877
- type: "area",
878
- data: data.map((d) => ({ x: d.frequency, y: d.power })),
879
- color: ZENDIR_BRAND_COLORS.electric,
880
- // Zendir Electric
881
- smooth: false,
882
- areaStyle: { opacity: 0.3 },
883
- symbol: { type: "none" }
884
- }], [data]);
885
- return /* @__PURE__ */ jsx(
886
- AstroChart,
887
- {
888
- ref,
889
- type: "area",
890
- title,
891
- series,
892
- width,
893
- height,
894
- loading,
895
- className,
896
- xAxis: {
897
- type: "value",
898
- name: "Frequency",
899
- min: frequencyRange == null ? void 0 : frequencyRange[0],
900
- max: frequencyRange == null ? void 0 : frequencyRange[1]
901
- },
902
- yAxis: {
903
- type: "value",
904
- name: "dBm",
905
- min: powerRange == null ? void 0 : powerRange[0],
906
- max: powerRange == null ? void 0 : powerRange[1]
907
- },
908
- tooltip: { trigger: "axis", crosshair: "x" },
909
- annotations: noiseFloor !== void 0 ? {
910
- markLines: {
911
- data: [{
912
- yAxis: noiseFloor,
913
- label: `Noise floor (${noiseFloor} dBm)`,
914
- color: SOFT_STATUS_COLORS.caution,
915
- lineStyle: { type: "dashed" }
916
- }]
917
- }
918
- } : void 0,
919
- export: exportOptions,
920
- infoTooltip
921
- }
922
- );
923
- }
924
- ));
925
- const ManeuverBudgetChart = memo(forwardRef(
926
- function ManeuverBudgetChart2({
927
- data = [],
928
- title = "Delta-V budget",
929
- totalBudget,
930
- width = "100%",
931
- height = 200,
932
- loading = false,
933
- className = "",
934
- export: exportOptions,
935
- infoTooltip
936
- }, ref) {
937
- const series = useMemo(() => {
938
- const typeColors = {
939
- executed: STATUS_COLORS.normal,
940
- // Green (completed)
941
- planned: STATUS_COLORS.standby,
942
- // Cyan (scheduled)
943
- remaining: ZENDIR_BRAND_COLORS.electric,
944
- // Zendir Electric
945
- margin: ZENDIR_BRAND_COLORS.purple
946
- // Zendir Purple
947
- };
948
- return [{
949
- id: "deltaV",
950
- name: "Delta-V",
951
- type: "bar",
952
- data: data.map((d) => ({
953
- x: d.name,
954
- y: d.deltaV,
955
- meta: { type: d.type, color: typeColors[d.type] || STATUS_COLORS.standby }
956
- }))
957
- }];
958
- }, [data]);
959
- return /* @__PURE__ */ jsx(
960
- AstroChart,
961
- {
962
- ref,
963
- type: "bar",
964
- title,
965
- subtitle: totalBudget ? `Total: ${totalBudget} m/s` : void 0,
966
- series,
967
- width,
968
- height,
969
- loading,
970
- className,
971
- xAxis: { type: "category" },
972
- yAxis: { type: "value", name: "m/s" },
973
- tooltip: { trigger: "axis" },
974
- echartsOptions: {
975
- series: [{
976
- type: "bar",
977
- data: data.map((d) => ({
978
- value: d.deltaV,
979
- name: d.name,
980
- itemStyle: {
981
- color: d.type === "executed" ? STATUS_COLORS.normal : d.type === "planned" ? STATUS_COLORS.standby : d.type === "remaining" ? ZENDIR_BRAND_COLORS.electric : ZENDIR_BRAND_COLORS.purple
982
- }
983
- }))
984
- }]
985
- },
986
- export: exportOptions,
987
- infoTooltip
988
- }
989
- );
990
- }
991
- ));
992
- const EclipseTimelineChart = memo(forwardRef(
993
- function EclipseTimelineChart2({
994
- data = [],
995
- title = "Eclipse timeline",
996
- timeRange,
997
- width = "100%",
998
- height = 100,
999
- loading = false,
1000
- enableZoom = true,
1001
- className = "",
1002
- export: exportOptions,
1003
- infoTooltip
1004
- }, ref) {
1005
- const series = [{
1006
- id: "eclipse",
1007
- name: "Eclipse",
1008
- type: "bar",
1009
- data: []
1010
- }];
1011
- const typeColors = {
1012
- umbra: ZENDIR_BRAND_COLORS.prussianBlue,
1013
- // Deep Zendir blue
1014
- penumbra: ZENDIR_BRAND_COLORS.electricDark,
1015
- // Dark electric
1016
- sunlight: STATUS_COLORS.caution
1017
- // Standard yellow for sunlight
1018
- };
1019
- return /* @__PURE__ */ jsx(
1020
- AstroChart,
1021
- {
1022
- ref,
1023
- type: "bar",
1024
- title,
1025
- series,
1026
- width,
1027
- height,
1028
- loading,
1029
- className,
1030
- zoom: enableZoom ? { enabled: true, type: "inside", axis: "x" } : void 0,
1031
- echartsOptions: {
1032
- tooltip: {
1033
- trigger: "item",
1034
- formatter: (params) => {
1035
- const p = params;
1036
- const [start, end, eclipseType] = p.data.value;
1037
- const duration = ((end - start) / 6e4).toFixed(1);
1038
- return `${eclipseType.charAt(0).toUpperCase() + eclipseType.slice(1)}<br/>Duration: ${duration} min`;
1039
- }
1040
- },
1041
- grid: { left: 60, right: 20, top: 30, bottom: 30 },
1042
- xAxis: {
1043
- type: "time",
1044
- min: timeRange == null ? void 0 : timeRange[0],
1045
- max: timeRange == null ? void 0 : timeRange[1]
1046
- },
1047
- yAxis: {
1048
- type: "category",
1049
- data: [""],
1050
- show: false
1051
- },
1052
- series: [{
1053
- type: "custom",
1054
- renderItem: (_params, api) => {
1055
- const a = api;
1056
- const start = a.coord([a.value(0), 0]);
1057
- const end = a.coord([a.value(1), 0]);
1058
- const eclipseType = a.value(2);
1059
- const h = 30;
1060
- return {
1061
- type: "rect",
1062
- shape: {
1063
- x: start[0],
1064
- y: start[1] - h / 2,
1065
- width: Math.max(end[0] - start[0], 2),
1066
- height: h
1067
- },
1068
- style: {
1069
- fill: typeColors[eclipseType] || typeColors.sunlight
1070
- }
1071
- };
1072
- },
1073
- encode: { x: [0, 1] },
1074
- data: data.map((d) => ({ value: [d.start, d.end, d.type] }))
1075
- }]
1076
- },
1077
- export: exportOptions,
1078
- infoTooltip
1079
- }
1080
- );
1081
- }
1082
- ));
1083
- const RoseDiagram = memo(forwardRef(
1084
- function RoseDiagram2({
1085
- data = [],
1086
- title = "Rose Diagram",
1087
- width = "100%",
1088
- height = 400,
1089
- bins = 16,
1090
- loading = false,
1091
- className = "",
1092
- export: exportOptions,
1093
- infoTooltip
1094
- }, ref) {
1095
- const binData = useMemo(() => {
1096
- const binSize = 360 / bins;
1097
- const binCounts = new Array(bins).fill(0);
1098
- data.forEach((d) => {
1099
- const normalizedAngle = (d.direction % 360 + 360) % 360;
1100
- const binIndex = Math.floor(normalizedAngle / binSize);
1101
- binCounts[binIndex] += d.magnitude;
1102
- });
1103
- return binCounts.map((count, i) => ({
1104
- name: `${(i * binSize).toFixed(0)}°`,
1105
- value: count
1106
- }));
1107
- }, [data, bins]);
1108
- return /* @__PURE__ */ jsx(
1109
- AstroChart,
1110
- {
1111
- ref,
1112
- type: "bar",
1113
- series: [],
1114
- title,
1115
- width,
1116
- height,
1117
- loading,
1118
- className,
1119
- echartsOptions: {
1120
- polar: {
1121
- radius: ["10%", "70%"],
1122
- center: ["50%", "50%"]
1123
- },
1124
- angleAxis: {
1125
- type: "category",
1126
- data: binData.map((d) => d.name),
1127
- startAngle: 90,
1128
- boundaryGap: true,
1129
- axisLine: { show: false },
1130
- axisTick: { show: false },
1131
- axisLabel: {
1132
- fontSize: 9,
1133
- color: "rgba(255, 255, 255, 0.5)",
1134
- margin: 8
1135
- },
1136
- splitLine: {
1137
- show: true,
1138
- lineStyle: {
1139
- color: "rgba(100, 116, 139, 0.12)",
1140
- type: "dashed"
1141
- }
1142
- }
1143
- },
1144
- radiusAxis: {
1145
- min: 0,
1146
- axisLine: { show: false },
1147
- axisTick: { show: false },
1148
- axisLabel: { show: false },
1149
- splitLine: {
1150
- show: true,
1151
- lineStyle: {
1152
- color: "rgba(100, 116, 139, 0.15)",
1153
- type: "dashed"
1154
- }
1155
- }
1156
- },
1157
- tooltip: {
1158
- trigger: "item",
1159
- backgroundColor: "rgba(20, 30, 48, 0.95)",
1160
- borderColor: "rgba(100, 116, 139, 0.3)",
1161
- textStyle: { color: "rgba(255, 255, 255, 0.87)" }
1162
- // High contrast white
1163
- },
1164
- series: [{
1165
- type: "bar",
1166
- data: binData.map((d) => d.value),
1167
- coordinateSystem: "polar",
1168
- roundCap: true,
1169
- itemStyle: {
1170
- // Zendir Electric → Purple gradient
1171
- color: {
1172
- type: "linear",
1173
- x: 0,
1174
- y: 0,
1175
- x2: 1,
1176
- y2: 0,
1177
- colorStops: [
1178
- { offset: 0, color: ZENDIR_BRAND_COLORS.electric },
1179
- // #3E3CFF
1180
- { offset: 1, color: ZENDIR_BRAND_COLORS.purple }
1181
- // #9D70FF
1182
- ]
1183
- },
1184
- shadowColor: ZENDIR_BRAND_COLORS.purple,
1185
- shadowBlur: 4
1186
- }
1187
- }]
1188
- },
1189
- export: exportOptions,
1190
- infoTooltip
1191
- }
1192
- );
1193
- }
1194
- ));
1195
- const ORBIT_COLOR_MAP = {
1196
- // Human-made objects: Zendir Purple/Blue shades
1197
- spacecraft: "#3E3CFF",
1198
- // Zendir Electric
1199
- satellite: "#9D70FF",
1200
- // Zendir Purple
1201
- station: "#3548C0",
1202
- // Zendir Prussian Blue Light
1203
- probe: "#1B2DA0",
1204
- // Zendir Prussian Blue
1205
- // Natural objects: Realistic colors
1206
- planet: "#5BC0DE",
1207
- // Teal-blue (default)
1208
- // Debris/Asteroids: Brown/Gray shades
1209
- asteroid: "#8B7355",
1210
- // Warm brown
1211
- debris: "#6B6B6B",
1212
- // Gray
1213
- // Comets: Brown with icy tones
1214
- comet: "#5C4033"
1215
- // Dark brown
1216
- };
1217
- const ORBIT_TYPE_LABELS = {
1218
- spacecraft: "Spacecraft",
1219
- satellite: "Satellite",
1220
- station: "Space Station",
1221
- probe: "Deep Space Probe",
1222
- planet: "Planet",
1223
- asteroid: "Asteroid",
1224
- debris: "Debris",
1225
- comet: "Comet"
1226
- };
1227
- const HeliocentricOrbitPlot = memo(forwardRef(
1228
- function HeliocentricOrbitPlot2({
1229
- data = [],
1230
- title = "Heliocentric Orbit",
1231
- width = "100%",
1232
- height = 500,
1233
- showGrid = true,
1234
- enableZoom = true,
1235
- showLabels = true,
1236
- mode = "2d",
1237
- loading = false,
1238
- className = "",
1239
- export: exportOptions,
1240
- infoTooltip,
1241
- onBodyClick: _onBodyClick
1242
- }, ref) {
1243
- const { tokens, mode: themeMode } = useTheme();
1244
- const tooltipStyle = useChartTooltipStyle();
1245
- useChartLegendStyle();
1246
- const labelPrimary = tokens.colors.text.primary;
1247
- const labelSecondary = tokens.colors.text.secondary;
1248
- tokens.colors.text.tertiary;
1249
- const labelBg = themeMode === "dark" ? "rgba(15, 23, 42, 0.72)" : "rgba(255, 255, 255, 0.9)";
1250
- const bodyDataMap = useMemo(() => {
1251
- const map = /* @__PURE__ */ new Map();
1252
- data.forEach((body) => map.set(body.name, body));
1253
- return map;
1254
- }, [data]);
1255
- const echarts2DOptions = useMemo(() => {
1256
- const seriesArray = [];
1257
- data.forEach((body, idx) => {
1258
- const bodyColor = body.color || ORBIT_COLOR_MAP[body.type || "spacecraft"] || ASTRO_DATA_VIZ_COLORS.mixed[idx % ASTRO_DATA_VIZ_COLORS.mixed.length];
1259
- const typeLabel = ORBIT_TYPE_LABELS[body.type || "spacecraft"] || "Object";
1260
- if (body.orbitPath && body.orbitPath.length > 0) {
1261
- const orbitRadius = body.semiMajorAxis || Math.max(...body.orbitPath.map((p) => Math.sqrt(p.x * p.x + p.y * p.y)));
1262
- seriesArray.push({
1263
- type: "line",
1264
- name: `${body.name} Orbit`,
1265
- data: body.orbitPath.map((p) => [p.x, p.y, body.name, typeLabel, orbitRadius, body.period, body.inclination]),
1266
- lineStyle: {
1267
- color: bodyColor,
1268
- type: "dashed",
1269
- width: 1.5,
1270
- opacity: 0.6
1271
- },
1272
- symbol: "none",
1273
- silent: false,
1274
- emphasis: {
1275
- lineStyle: {
1276
- width: 3.5,
1277
- opacity: 1,
1278
- shadowBlur: 8,
1279
- shadowColor: bodyColor
1280
- }
1281
- },
1282
- z: 1
1283
- });
1284
- }
1285
- seriesArray.push({
1286
- type: "scatter",
1287
- name: body.name,
1288
- symbolSize: body.size || (body.type === "planet" ? 20 : 12),
1289
- data: [[body.x, body.y, body.z || 0, body.type, typeLabel, body.description, body.semiMajorAxis, body.period]],
1290
- itemStyle: {
1291
- color: bodyColor,
1292
- shadowColor: bodyColor,
1293
- shadowBlur: body.type === "planet" ? 10 : 5
1294
- },
1295
- label: {
1296
- show: showLabels,
1297
- position: "top",
1298
- formatter: body.name,
1299
- fontSize: 11,
1300
- color: labelSecondary,
1301
- textBorderColor: "transparent",
1302
- textBorderWidth: 0
1303
- },
1304
- emphasis: {
1305
- scale: 1.6,
1306
- itemStyle: {
1307
- shadowBlur: 20
1308
- },
1309
- label: {
1310
- show: true,
1311
- fontWeight: "bold",
1312
- fontSize: 12,
1313
- color: labelPrimary
1314
- }
1315
- },
1316
- z: 10
1317
- });
1318
- });
1319
- return {
1320
- tooltip: {
1321
- trigger: "item",
1322
- ...tooltipStyle,
1323
- borderWidth: 1,
1324
- padding: [12, 16],
1325
- formatter: (params) => {
1326
- const seriesName = params.seriesName || "";
1327
- if (params.seriesType === "line") {
1328
- const [_x, _y, bodyName, typeLabel, orbitRadius, period, inclination] = params.value || [];
1329
- const bodyInfo = bodyDataMap.get(bodyName);
1330
- let html = `<div style="font-weight:600;font-size:13px;margin-bottom:6px;color:#3E3CFF">${seriesName}</div>`;
1331
- html += `<div style="color:rgba(255,255,255,0.5);font-size:10px;margin-bottom:8px;text-transform:uppercase;letter-spacing:0.5px">${typeLabel || "Orbital Path"}</div>`;
1332
- html += `<div style="border-top:1px solid rgba(100,116,139,0.3);padding-top:8px">`;
1333
- if (orbitRadius) {
1334
- html += `<div style="display:flex;justify-content:space-between;margin-bottom:4px"><span style="color:rgba(255,255,255,0.6)">Semi-major axis:</span><span style="font-family:monospace">${orbitRadius.toFixed(3)} AU</span></div>`;
1335
- }
1336
- if (period) {
1337
- html += `<div style="display:flex;justify-content:space-between;margin-bottom:4px"><span style="color:rgba(255,255,255,0.6)">Orbital period:</span><span style="font-family:monospace">${period.toFixed(1)} days</span></div>`;
1338
- }
1339
- if (inclination !== void 0) {
1340
- html += `<div style="display:flex;justify-content:space-between;margin-bottom:4px"><span style="color:rgba(255,255,255,0.6)">Inclination:</span><span style="font-family:monospace">${inclination.toFixed(1)}°</span></div>`;
1341
- }
1342
- if (bodyInfo == null ? void 0 : bodyInfo.description) {
1343
- html += `<div style="margin-top:6px;color:rgba(255,255,255,0.7);font-style:italic;font-size:11px">${bodyInfo.description}</div>`;
1344
- }
1345
- html += `</div>`;
1346
- return html;
1347
- }
1348
- if (params.seriesType === "scatter") {
1349
- const [x, y, z, _bodyType, typeLabel, description, sma, period] = params.value;
1350
- const distance = Math.sqrt(x * x + y * y + (z || 0) * (z || 0));
1351
- let html = `<div style="font-weight:600;font-size:13px;margin-bottom:4px">${seriesName}</div>`;
1352
- html += `<div style="color:rgba(255,255,255,0.5);font-size:10px;margin-bottom:8px;text-transform:uppercase;letter-spacing:0.5px">${typeLabel || "Object"}</div>`;
1353
- html += `<div style="border-top:1px solid rgba(100,116,139,0.3);padding-top:8px">`;
1354
- html += `<div style="display:flex;justify-content:space-between;margin-bottom:3px"><span style="color:rgba(255,255,255,0.6)">X:</span><span style="font-family:monospace">${x.toFixed(3)} AU</span></div>`;
1355
- html += `<div style="display:flex;justify-content:space-between;margin-bottom:3px"><span style="color:rgba(255,255,255,0.6)">Y:</span><span style="font-family:monospace">${y.toFixed(3)} AU</span></div>`;
1356
- if (z !== 0 && z !== void 0) {
1357
- html += `<div style="display:flex;justify-content:space-between;margin-bottom:3px"><span style="color:rgba(255,255,255,0.6)">Z:</span><span style="font-family:monospace">${z.toFixed(3)} AU</span></div>`;
1358
- }
1359
- html += `<div style="display:flex;justify-content:space-between;margin-bottom:3px;border-top:1px solid rgba(100,116,139,0.2);padding-top:6px;margin-top:4px"><span style="color:rgba(255,255,255,0.6)">Distance from Sun:</span><span style="font-family:monospace;color:#5BC0DE">${distance.toFixed(3)} AU</span></div>`;
1360
- if (sma) {
1361
- html += `<div style="display:flex;justify-content:space-between;margin-bottom:3px"><span style="color:rgba(255,255,255,0.6)">Semi-major axis:</span><span style="font-family:monospace">${sma.toFixed(3)} AU</span></div>`;
1362
- }
1363
- if (period) {
1364
- html += `<div style="display:flex;justify-content:space-between;margin-bottom:3px"><span style="color:rgba(255,255,255,0.6)">Period:</span><span style="font-family:monospace">${period.toFixed(1)} days</span></div>`;
1365
- }
1366
- if (description) {
1367
- html += `<div style="margin-top:8px;color:rgba(255,255,255,0.7);font-style:italic;font-size:11px;max-width:200px">${description}</div>`;
1368
- }
1369
- html += `</div>`;
1370
- return html;
1371
- }
1372
- return seriesName;
1373
- }
1374
- },
1375
- toolbox: {
1376
- show: enableZoom,
1377
- right: 20,
1378
- top: 10,
1379
- feature: {
1380
- dataZoom: { show: true, title: { zoom: "Zoom", back: "Reset" } },
1381
- restore: { show: true, title: "Reset" }
1382
- },
1383
- iconStyle: { borderColor: "rgba(255, 255, 255, 0.5)" }
1384
- },
1385
- dataZoom: enableZoom ? [
1386
- { type: "inside", xAxisIndex: 0, filterMode: "none" },
1387
- { type: "inside", yAxisIndex: 0, filterMode: "none" }
1388
- ] : void 0,
1389
- grid: {
1390
- containLabel: true,
1391
- left: 60,
1392
- right: enableZoom ? 80 : 40,
1393
- top: 60,
1394
- bottom: 60
1395
- },
1396
- xAxis: {
1397
- type: "value",
1398
- name: "X (AU)",
1399
- nameLocation: "middle",
1400
- nameGap: 30,
1401
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
1402
- splitLine: { show: showGrid, lineStyle: { color: "rgba(100, 116, 139, 0.15)" } },
1403
- axisLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.3)" } },
1404
- axisLabel: { color: "rgba(255, 255, 255, 0.5)" }
1405
- },
1406
- yAxis: {
1407
- type: "value",
1408
- name: "Y (AU)",
1409
- nameLocation: "middle",
1410
- nameGap: 40,
1411
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
1412
- splitLine: { show: showGrid, lineStyle: { color: "rgba(100, 116, 139, 0.15)" } },
1413
- axisLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.3)" } },
1414
- axisLabel: { color: "rgba(255, 255, 255, 0.5)" }
1415
- },
1416
- animation: true,
1417
- animationDuration: 300,
1418
- series: seriesArray
1419
- };
1420
- }, [data, showGrid, enableZoom, showLabels, bodyDataMap, tooltipStyle]);
1421
- const echarts3DOptions = useMemo(() => {
1422
- const seriesArray = [];
1423
- data.forEach((body, idx) => {
1424
- const bodyColor = body.color || ORBIT_COLOR_MAP[body.type || "spacecraft"] || ASTRO_DATA_VIZ_COLORS.mixed[idx % ASTRO_DATA_VIZ_COLORS.mixed.length];
1425
- const typeLabel = ORBIT_TYPE_LABELS[body.type || "spacecraft"] || "Object";
1426
- if (body.orbitPath && body.orbitPath.length > 0) {
1427
- const orbitData = body.orbitPath.map((p) => [p.x, p.y, p.z || 0]);
1428
- if (orbitData.length > 2) {
1429
- orbitData.push(orbitData[0]);
1430
- }
1431
- seriesArray.push({
1432
- type: "line3D",
1433
- name: `${body.name} Orbit`,
1434
- coordinateSystem: "cartesian3D",
1435
- data: orbitData,
1436
- lineStyle: {
1437
- color: bodyColor,
1438
- width: 1.5,
1439
- opacity: 0.6
1440
- },
1441
- silent: false
1442
- });
1443
- }
1444
- seriesArray.push({
1445
- type: "scatter3D",
1446
- name: body.name,
1447
- coordinateSystem: "cartesian3D",
1448
- data: [{
1449
- name: body.name,
1450
- value: [body.x, body.y, body.z || 0],
1451
- itemStyle: { color: bodyColor },
1452
- typeLabel,
1453
- description: body.description
1454
- }],
1455
- symbolSize: body.size || (body.type === "planet" ? 16 : 10),
1456
- itemStyle: { color: bodyColor },
1457
- label: {
1458
- show: showLabels,
1459
- formatter: body.name,
1460
- textStyle: {
1461
- color: labelPrimary,
1462
- fontSize: 11,
1463
- backgroundColor: labelBg,
1464
- padding: [2, 4],
1465
- borderRadius: 2
1466
- }
1467
- },
1468
- emphasis: {
1469
- itemStyle: { opacity: 1 },
1470
- label: { show: true }
1471
- }
1472
- });
1473
- });
1474
- return {
1475
- tooltip: {
1476
- show: true,
1477
- ...tooltipStyle,
1478
- formatter: (params) => {
1479
- const d = params.data || {};
1480
- const seriesName = params.seriesName || "";
1481
- if (params.seriesType === "line3D") {
1482
- return `<div style="font-weight:600">${seriesName}</div>`;
1483
- }
1484
- const [x, y, z] = d.value || params.value || [0, 0, 0];
1485
- const distance = Math.sqrt(x * x + y * y + z * z);
1486
- let html = `<div style="font-weight:600;font-size:13px;margin-bottom:4px">${d.name || seriesName}</div>`;
1487
- html += `<div style="color:rgba(255,255,255,0.5);font-size:10px;margin-bottom:8px;text-transform:uppercase">${d.typeLabel || "Object"}</div>`;
1488
- html += `<div style="border-top:1px solid rgba(100,116,139,0.3);padding-top:8px">`;
1489
- html += `<div>X: <span style="font-family:monospace">${x.toFixed(3)}</span> AU</div>`;
1490
- html += `<div>Y: <span style="font-family:monospace">${y.toFixed(3)}</span> AU</div>`;
1491
- html += `<div>Z: <span style="font-family:monospace">${z.toFixed(3)}</span> AU</div>`;
1492
- html += `<div style="margin-top:4px;color:#5BC0DE">Distance: <span style="font-family:monospace">${distance.toFixed(3)}</span> AU</div>`;
1493
- if (d.description) {
1494
- html += `<div style="margin-top:6px;color:rgba(255,255,255,0.7);font-style:italic;font-size:11px">${d.description}</div>`;
1495
- }
1496
- html += `</div>`;
1497
- return html;
1498
- }
1499
- },
1500
- grid3D: {
1501
- boxWidth: 200,
1502
- boxHeight: 60,
1503
- boxDepth: 200,
1504
- viewControl: {
1505
- autoRotate: false,
1506
- autoRotateAfterStill: 5,
1507
- autoRotateSpeed: 5,
1508
- distance: 280,
1509
- alpha: 20,
1510
- beta: 40,
1511
- rotateSensitivity: 2,
1512
- zoomSensitivity: 1.5,
1513
- panSensitivity: 1
1514
- },
1515
- light: {
1516
- main: { intensity: 1.2, shadow: false },
1517
- ambient: { intensity: 0.4 }
1518
- },
1519
- postEffect: {
1520
- enable: true,
1521
- bloom: { enable: true, intensity: 0.05 }
1522
- }
1523
- },
1524
- xAxis3D: {
1525
- type: "value",
1526
- name: "X (AU)",
1527
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
1528
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
1529
- axisLabel: { color: "rgba(255, 255, 255, 0.4)", formatter: (v) => v.toFixed(1) },
1530
- splitLine: { show: showGrid, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } }
1531
- },
1532
- yAxis3D: {
1533
- type: "value",
1534
- name: "Y (AU)",
1535
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
1536
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
1537
- axisLabel: { color: "rgba(255, 255, 255, 0.4)", formatter: (v) => v.toFixed(1) },
1538
- splitLine: { show: showGrid, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } }
1539
- },
1540
- zAxis3D: {
1541
- type: "value",
1542
- name: "Z (AU)",
1543
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
1544
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
1545
- axisLabel: { color: "rgba(255, 255, 255, 0.4)", formatter: (v) => v.toFixed(1) },
1546
- splitLine: { show: showGrid, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } }
1547
- },
1548
- series: seriesArray
1549
- };
1550
- }, [data, showGrid, showLabels]);
1551
- const echartsOptions = mode === "3d" ? echarts3DOptions : echarts2DOptions;
1552
- return /* @__PURE__ */ jsx(
1553
- AstroChart,
1554
- {
1555
- ref,
1556
- type: "scatter",
1557
- series: [],
1558
- title,
1559
- width,
1560
- height,
1561
- loading,
1562
- className,
1563
- echartsOptions,
1564
- export: exportOptions,
1565
- infoTooltip
1566
- }
1567
- );
1568
- }
1569
- ));
1570
- const Scatter3DChart = memo(forwardRef(
1571
- function Scatter3DChart2({
1572
- data = [],
1573
- title,
1574
- width = "100%",
1575
- height = 500,
1576
- showGrid = true,
1577
- xAxisLabel = "X",
1578
- yAxisLabel = "Y",
1579
- zAxisLabel = "Z",
1580
- autoRotate = false,
1581
- loading = false,
1582
- className = "",
1583
- export: exportOptions,
1584
- infoTooltip
1585
- }, ref) {
1586
- const glReady = useEchartsGlReady();
1587
- const tooltipStyle = useChartTooltipStyle();
1588
- const legendStyle = useChartLegendStyle();
1589
- const echartsOptions = useMemo(() => {
1590
- const seriesArray = data.map((series, idx) => ({
1591
- type: "scatter3D",
1592
- name: series.name,
1593
- data: series.data.map((p) => ({
1594
- name: p.label || series.name,
1595
- value: [p.x, p.y, p.z],
1596
- itemStyle: p.color ? { color: p.color } : void 0,
1597
- meta: p.meta
1598
- })),
1599
- symbolSize: typeof series.symbolSize === "number" ? series.symbolSize : 12,
1600
- itemStyle: {
1601
- color: series.color || ASTRO_DATA_VIZ_COLORS.mixed[idx % ASTRO_DATA_VIZ_COLORS.mixed.length]
1602
- },
1603
- label: {
1604
- show: false
1605
- },
1606
- emphasis: {
1607
- itemStyle: { opacity: 1 },
1608
- label: { show: true, formatter: (params) => {
1609
- var _a;
1610
- return ((_a = params.data) == null ? void 0 : _a.name) || "";
1611
- } }
1612
- }
1613
- }));
1614
- return {
1615
- tooltip: {
1616
- show: true,
1617
- ...tooltipStyle,
1618
- formatter: (params) => {
1619
- const d = params.data || {};
1620
- const [x, y, z] = d.value || [0, 0, 0];
1621
- let html = `<div style="font-weight:600;font-size:13px;margin-bottom:4px">${d.name || params.seriesName}</div>`;
1622
- html += `<div>${xAxisLabel}: <span style="font-family:monospace">${x.toFixed(2)}</span></div>`;
1623
- html += `<div>${yAxisLabel}: <span style="font-family:monospace">${y.toFixed(2)}</span></div>`;
1624
- html += `<div>${zAxisLabel}: <span style="font-family:monospace">${z.toFixed(2)}</span></div>`;
1625
- return html;
1626
- }
1627
- },
1628
- legend: {
1629
- show: data.length > 1,
1630
- top: 10,
1631
- ...legendStyle
1632
- },
1633
- grid3D: {
1634
- boxWidth: 100,
1635
- boxHeight: 100,
1636
- boxDepth: 100,
1637
- viewControl: {
1638
- autoRotate,
1639
- autoRotateSpeed: 5,
1640
- distance: 200,
1641
- alpha: 25,
1642
- beta: 45,
1643
- rotateSensitivity: 2,
1644
- zoomSensitivity: 1.5
1645
- },
1646
- light: {
1647
- main: { intensity: 1.2, shadow: false },
1648
- ambient: { intensity: 0.4 }
1649
- },
1650
- postEffect: {
1651
- enable: true,
1652
- bloom: { enable: true, intensity: 0.05 }
1653
- }
1654
- },
1655
- xAxis3D: {
1656
- type: "value",
1657
- name: xAxisLabel,
1658
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
1659
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
1660
- axisLabel: { color: "rgba(255, 255, 255, 0.4)" },
1661
- splitLine: { show: showGrid, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } }
1662
- },
1663
- yAxis3D: {
1664
- type: "value",
1665
- name: yAxisLabel,
1666
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
1667
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
1668
- axisLabel: { color: "rgba(255, 255, 255, 0.4)" },
1669
- splitLine: { show: showGrid, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } }
1670
- },
1671
- zAxis3D: {
1672
- type: "value",
1673
- name: zAxisLabel,
1674
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
1675
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
1676
- axisLabel: { color: "rgba(255, 255, 255, 0.4)" },
1677
- splitLine: { show: showGrid, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } }
1678
- },
1679
- series: seriesArray
1680
- };
1681
- }, [data, showGrid, xAxisLabel, yAxisLabel, zAxisLabel, autoRotate, tooltipStyle, legendStyle]);
1682
- if (!glReady) return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading: true, className });
1683
- return /* @__PURE__ */ jsx(
1684
- AstroChart,
1685
- {
1686
- ref,
1687
- type: "scatter",
1688
- series: [],
1689
- title,
1690
- width,
1691
- height,
1692
- loading,
1693
- className,
1694
- echartsOptions,
1695
- export: exportOptions,
1696
- infoTooltip
1697
- }
1698
- );
1699
- }
1700
- ));
1701
- const Bar3DChart = memo(forwardRef(
1702
- function Bar3DChart2({
1703
- data = [],
1704
- title,
1705
- width = "100%",
1706
- height = 500,
1707
- xCategories = [],
1708
- yCategories = [],
1709
- xAxisLabel = "X",
1710
- yAxisLabel = "Y",
1711
- zAxisLabel = "Value",
1712
- shading = "lambert",
1713
- autoRotate = false,
1714
- loading = false,
1715
- className = "",
1716
- export: exportOptions,
1717
- infoTooltip
1718
- }, ref) {
1719
- const glReady = useEchartsGlReady();
1720
- const tooltipStyle = useChartTooltipStyle();
1721
- const visualMapStyle = useChartVisualMapStyle();
1722
- const { tokens } = useTheme();
1723
- const labelPrimary = tokens.colors.text.primary;
1724
- const labelSecondary = tokens.colors.text.secondary;
1725
- const labelTertiary = tokens.colors.text.tertiary;
1726
- const derivedXCategories = xCategories || [...new Set(data.map((d) => String(d.x)))];
1727
- const derivedYCategories = yCategories || [...new Set(data.map((d) => String(d.y)))];
1728
- const echartsOptions = useMemo(() => {
1729
- const seriesData = data.map((d) => {
1730
- const xIdx = derivedXCategories.indexOf(String(d.x));
1731
- const yIdx = derivedYCategories.indexOf(String(d.y));
1732
- return {
1733
- value: [xIdx, yIdx, d.z],
1734
- name: d.label || `${d.x} - ${d.y}`,
1735
- itemStyle: d.color ? { color: d.color } : void 0
1736
- };
1737
- });
1738
- const maxZ = Math.max(...data.map((d) => d.z), 1);
1739
- return {
1740
- tooltip: {
1741
- show: true,
1742
- ...tooltipStyle,
1743
- formatter: (params) => {
1744
- const d = params.data || {};
1745
- const [xIdx, yIdx, z] = d.value || [0, 0, 0];
1746
- const xLabel = derivedXCategories[xIdx] || xIdx;
1747
- const yLabel = derivedYCategories[yIdx] || yIdx;
1748
- let html = `<div style="font-weight:600;font-size:13px;margin-bottom:4px">${d.name || ""}</div>`;
1749
- html += `<div>${xAxisLabel}: ${xLabel}</div>`;
1750
- html += `<div>${yAxisLabel}: ${yLabel}</div>`;
1751
- html += `<div style="color:#3E3CFF">${zAxisLabel}: <span style="font-family:monospace">${z.toFixed(2)}</span></div>`;
1752
- return html;
1753
- }
1754
- },
1755
- visualMap: {
1756
- show: true,
1757
- min: 0,
1758
- max: maxZ,
1759
- inRange: {
1760
- color: ["#3E3CFF", "#9D70FF", "#22d3ee", "#56f000"]
1761
- },
1762
- ...visualMapStyle,
1763
- right: 10,
1764
- top: "center"
1765
- },
1766
- grid3D: {
1767
- boxWidth: 100,
1768
- boxHeight: 80,
1769
- boxDepth: 100,
1770
- viewControl: {
1771
- autoRotate,
1772
- autoRotateSpeed: 3,
1773
- distance: 250,
1774
- alpha: 25,
1775
- beta: 45,
1776
- rotateSensitivity: 2,
1777
- zoomSensitivity: 1.5
1778
- },
1779
- light: {
1780
- main: { intensity: 1.1, shadow: true, shadowQuality: "medium" },
1781
- ambient: { intensity: 0.4 }
1782
- }
1783
- },
1784
- xAxis3D: {
1785
- type: "category",
1786
- name: xAxisLabel,
1787
- data: derivedXCategories,
1788
- nameTextStyle: { color: labelSecondary },
1789
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
1790
- axisLabel: { color: labelSecondary, fontSize: 10 }
1791
- },
1792
- yAxis3D: {
1793
- type: "category",
1794
- name: yAxisLabel,
1795
- data: derivedYCategories,
1796
- nameTextStyle: { color: labelSecondary },
1797
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
1798
- axisLabel: { color: labelSecondary, fontSize: 10 }
1799
- },
1800
- zAxis3D: {
1801
- type: "value",
1802
- name: zAxisLabel,
1803
- nameTextStyle: { color: labelSecondary },
1804
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
1805
- axisLabel: { color: labelTertiary }
1806
- },
1807
- series: [{
1808
- type: "bar3D",
1809
- data: seriesData,
1810
- shading,
1811
- barSize: 15,
1812
- bevelSize: 0.1,
1813
- label: {
1814
- show: false
1815
- },
1816
- emphasis: {
1817
- label: {
1818
- show: true,
1819
- formatter: (params) => {
1820
- var _a;
1821
- return ((_a = params.data) == null ? void 0 : _a.name) || "";
1822
- },
1823
- textStyle: { color: labelPrimary, fontSize: 11 }
1824
- }
1825
- }
1826
- }]
1827
- };
1828
- }, [data, derivedXCategories, derivedYCategories, xAxisLabel, yAxisLabel, zAxisLabel, shading, autoRotate, tooltipStyle, visualMapStyle, labelPrimary, labelSecondary, labelTertiary]);
1829
- if (!glReady) return /* @__PURE__ */ jsx(AstroChart, { ref, type: "bar", series: [], title, width, height, loading: true, className });
1830
- return /* @__PURE__ */ jsx(
1831
- AstroChart,
1832
- {
1833
- ref,
1834
- type: "bar",
1835
- series: [],
1836
- title,
1837
- width,
1838
- height,
1839
- loading,
1840
- className,
1841
- echartsOptions,
1842
- export: exportOptions,
1843
- infoTooltip
1844
- }
1845
- );
1846
- }
1847
- ));
1848
- const Surface3DChart = memo(forwardRef(
1849
- function Surface3DChart2({
1850
- data = { data: [] },
1851
- title,
1852
- width = "100%",
1853
- height = 500,
1854
- xAxisLabel = "X",
1855
- yAxisLabel = "Y",
1856
- zAxisLabel = "Z",
1857
- shading = "realistic",
1858
- autoRotate = false,
1859
- loading = false,
1860
- className = "",
1861
- export: exportOptions,
1862
- infoTooltip
1863
- }, ref) {
1864
- const glReady = useEchartsGlReady();
1865
- const tooltipStyle = useChartTooltipStyle();
1866
- const visualMapStyle = useChartVisualMapStyle();
1867
- const echartsOptions = useMemo(() => {
1868
- var _a;
1869
- const surfaceData = [];
1870
- const rows = data.data.length;
1871
- const cols = rows > 0 ? data.data[0].length : 0;
1872
- for (let i = 0; i < rows; i++) {
1873
- for (let j = 0; j < cols; j++) {
1874
- const x = data.xRange ? data.xRange[0] + (data.xRange[1] - data.xRange[0]) * (i / (rows - 1 || 1)) : i;
1875
- const y = data.yRange ? data.yRange[0] + (data.yRange[1] - data.yRange[0]) * (j / (cols - 1 || 1)) : j;
1876
- surfaceData.push([x, y, data.data[i][j]]);
1877
- }
1878
- }
1879
- const allZ = data.data.flat();
1880
- const minZ = Math.min(...allZ);
1881
- const maxZ = Math.max(...allZ);
1882
- const colorRange = data.colorMap === "thermal" ? ["#0d0887", "#6a00a8", "#b12a90", "#e16462", "#fca636", "#f0f921"] : data.colorMap === "viridis" ? ["#440154", "#414487", "#2a788e", "#22a884", "#7ad151", "#fde725"] : ((_a = data.colorStops) == null ? void 0 : _a.map((s) => s.color)) || ["#1B2DA0", "#3E3CFF", "#9D70FF", "#22d3ee", "#56f000"];
1883
- return {
1884
- tooltip: {
1885
- show: true,
1886
- ...tooltipStyle
1887
- },
1888
- visualMap: {
1889
- show: true,
1890
- min: minZ,
1891
- max: maxZ,
1892
- inRange: { color: colorRange },
1893
- ...visualMapStyle,
1894
- right: 10,
1895
- top: "center"
1896
- },
1897
- grid3D: {
1898
- boxWidth: 100,
1899
- boxHeight: 60,
1900
- boxDepth: 100,
1901
- viewControl: {
1902
- autoRotate,
1903
- autoRotateSpeed: 3,
1904
- distance: 220,
1905
- alpha: 30,
1906
- beta: 45,
1907
- rotateSensitivity: 2,
1908
- zoomSensitivity: 1.5
1909
- },
1910
- light: {
1911
- main: { intensity: 1.2, shadow: true, shadowQuality: "medium" },
1912
- ambient: { intensity: 0.5 }
1913
- },
1914
- postEffect: {
1915
- enable: true,
1916
- SSAO: { enable: true, radius: 2 }
1917
- }
1918
- },
1919
- xAxis3D: {
1920
- type: "value",
1921
- name: xAxisLabel,
1922
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
1923
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
1924
- axisLabel: { color: "rgba(255, 255, 255, 0.4)" }
1925
- },
1926
- yAxis3D: {
1927
- type: "value",
1928
- name: yAxisLabel,
1929
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
1930
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
1931
- axisLabel: { color: "rgba(255, 255, 255, 0.4)" }
1932
- },
1933
- zAxis3D: {
1934
- type: "value",
1935
- name: zAxisLabel,
1936
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
1937
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
1938
- axisLabel: { color: "rgba(255, 255, 255, 0.4)" }
1939
- },
1940
- series: [{
1941
- type: "surface",
1942
- data: surfaceData,
1943
- shading,
1944
- wireframe: data.wireframe ? {
1945
- show: true,
1946
- lineStyle: { color: "rgba(255, 255, 255, 0.2)", width: 0.5 }
1947
- } : { show: false }
1948
- }]
1949
- };
1950
- }, [data, xAxisLabel, yAxisLabel, zAxisLabel, shading, autoRotate, tooltipStyle, visualMapStyle]);
1951
- if (!glReady) return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading: true, className });
1952
- return /* @__PURE__ */ jsx(
1953
- AstroChart,
1954
- {
1955
- ref,
1956
- type: "scatter",
1957
- series: [],
1958
- title,
1959
- width,
1960
- height,
1961
- loading,
1962
- className,
1963
- echartsOptions,
1964
- export: exportOptions,
1965
- infoTooltip
1966
- }
1967
- );
1968
- }
1969
- ));
1970
- const Lines3DChart = memo(forwardRef(
1971
- function Lines3DChart2({
1972
- data = [],
1973
- title,
1974
- width = "100%",
1975
- height = 500,
1976
- showGrid = true,
1977
- xAxisLabel = "X",
1978
- yAxisLabel = "Y",
1979
- zAxisLabel = "Z",
1980
- showFlowEffect = false,
1981
- autoRotate = false,
1982
- loading = false,
1983
- className = "",
1984
- export: exportOptions,
1985
- infoTooltip
1986
- }, ref) {
1987
- const { tokens, mode } = useTheme();
1988
- const tooltipStyle = useChartTooltipStyle();
1989
- const legendStyle = useChartLegendStyle();
1990
- tokens.colors.text.primary;
1991
- tokens.colors.text.secondary;
1992
- tokens.colors.text.tertiary;
1993
- const echartsOptions = useMemo(() => {
1994
- const seriesArray = [];
1995
- data.forEach((line, idx) => {
1996
- const lineColor = line.color || ASTRO_DATA_VIZ_COLORS.mixed[idx % ASTRO_DATA_VIZ_COLORS.mixed.length];
1997
- seriesArray.push({
1998
- type: "line3D",
1999
- name: line.name,
2000
- coordinateSystem: "cartesian3D",
2001
- data: line.path.map((p) => [p.x, p.y, p.z]),
2002
- lineStyle: {
2003
- color: lineColor,
2004
- width: line.lineWidth || 2,
2005
- type: line.lineStyle || "solid",
2006
- opacity: 0.8
2007
- }
2008
- });
2009
- if (line.showEndpoints) {
2010
- seriesArray.push({
2011
- type: "scatter3D",
2012
- name: `${line.name} Points`,
2013
- coordinateSystem: "cartesian3D",
2014
- data: [
2015
- { value: [line.path[0].x, line.path[0].y, line.path[0].z], name: "Start" },
2016
- { value: [line.path[line.path.length - 1].x, line.path[line.path.length - 1].y, line.path[line.path.length - 1].z], name: "End" }
2017
- ],
2018
- symbolSize: 8,
2019
- itemStyle: { color: lineColor }
2020
- });
2021
- }
2022
- });
2023
- return {
2024
- tooltip: {
2025
- show: true,
2026
- ...tooltipStyle,
2027
- formatter: (params) => {
2028
- const d = params.data || {};
2029
- if (params.seriesType === "line3D") {
2030
- return `<div style="font-weight:600">${params.seriesName}</div>`;
2031
- }
2032
- const [x, y, z] = d.value || [0, 0, 0];
2033
- return `<div style="font-weight:600">${d.name || params.seriesName}</div>
2034
- <div>${xAxisLabel}: ${x.toFixed(2)}</div>
2035
- <div>${yAxisLabel}: ${y.toFixed(2)}</div>
2036
- <div>${zAxisLabel}: ${z.toFixed(2)}</div>`;
2037
- }
2038
- },
2039
- legend: {
2040
- show: data.length > 1,
2041
- top: 10,
2042
- ...legendStyle
2043
- },
2044
- grid3D: {
2045
- boxWidth: 100,
2046
- boxHeight: 100,
2047
- boxDepth: 100,
2048
- viewControl: {
2049
- autoRotate,
2050
- autoRotateSpeed: 3,
2051
- distance: 200,
2052
- alpha: 25,
2053
- beta: 45,
2054
- rotateSensitivity: 2,
2055
- zoomSensitivity: 1.5
2056
- },
2057
- light: {
2058
- main: { intensity: 1.2, shadow: false },
2059
- ambient: { intensity: 0.4 }
2060
- },
2061
- postEffect: {
2062
- enable: true,
2063
- bloom: { enable: showFlowEffect, intensity: 0.1 }
2064
- }
2065
- },
2066
- xAxis3D: {
2067
- type: "value",
2068
- name: xAxisLabel,
2069
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
2070
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
2071
- axisLabel: { color: "rgba(255, 255, 255, 0.4)" },
2072
- splitLine: { show: showGrid, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } }
2073
- },
2074
- yAxis3D: {
2075
- type: "value",
2076
- name: yAxisLabel,
2077
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
2078
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
2079
- axisLabel: { color: "rgba(255, 255, 255, 0.4)" },
2080
- splitLine: { show: showGrid, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } }
2081
- },
2082
- zAxis3D: {
2083
- type: "value",
2084
- name: zAxisLabel,
2085
- nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" },
2086
- axisLine: { lineStyle: { color: "rgba(100, 116, 139, 0.4)" } },
2087
- axisLabel: { color: "rgba(255, 255, 255, 0.4)" },
2088
- splitLine: { show: showGrid, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } }
2089
- },
2090
- series: seriesArray
2091
- };
2092
- }, [data, showGrid, xAxisLabel, yAxisLabel, zAxisLabel, showFlowEffect, autoRotate, tooltipStyle, legendStyle]);
2093
- return /* @__PURE__ */ jsx(
2094
- AstroChart,
2095
- {
2096
- ref,
2097
- type: "scatter",
2098
- series: [],
2099
- title,
2100
- width,
2101
- height,
2102
- loading,
2103
- className,
2104
- echartsOptions,
2105
- export: exportOptions,
2106
- infoTooltip
2107
- }
2108
- );
2109
- }
2110
- ));
2111
- const SphericalRadar3DChart = memo(forwardRef(
2112
- function SphericalRadar3DChart2({
2113
- data = [],
2114
- title,
2115
- width = "100%",
2116
- height = 500,
2117
- maxRange = 1e3,
2118
- showRangeRings = true,
2119
- autoRotate = false,
2120
- loading = false,
2121
- className = "",
2122
- export: exportOptions,
2123
- infoTooltip
2124
- }, ref) {
2125
- const glReady = useEchartsGlReady();
2126
- const tooltipStyle = useChartTooltipStyle();
2127
- useChartLegendStyle();
2128
- const categoryColors = {
2129
- satellite: "#56f000",
2130
- debris: "#ff3838",
2131
- unknown: "#fce83a",
2132
- friendly: "#3E3CFF",
2133
- hostile: "#ff3838"
2134
- };
2135
- const echartsOptions = useMemo(() => {
2136
- const scatterData = data.map((obj) => {
2137
- const azRad = obj.azimuth * Math.PI / 180;
2138
- const elRad = obj.elevation * Math.PI / 180;
2139
- const r = obj.range / maxRange * 100;
2140
- return {
2141
- name: obj.name,
2142
- value: [
2143
- r * Math.cos(elRad) * Math.sin(azRad),
2144
- r * Math.sin(elRad),
2145
- r * Math.cos(elRad) * Math.cos(azRad)
2146
- ],
2147
- itemStyle: { color: obj.color || categoryColors[obj.category || "unknown"] },
2148
- symbolSize: obj.size || 12,
2149
- category: obj.category,
2150
- azimuth: obj.azimuth,
2151
- elevation: obj.elevation,
2152
- range: obj.range
2153
- };
2154
- });
2155
- const rangeRings = [];
2156
- if (showRangeRings) {
2157
- [0.25, 0.5, 0.75, 1].forEach((fraction) => {
2158
- const r = fraction * 100;
2159
- const ringPoints = Array.from({ length: 73 }, (_, i) => {
2160
- const angle = i / 72 * Math.PI * 2;
2161
- return [r * Math.sin(angle), 0, r * Math.cos(angle)];
2162
- });
2163
- rangeRings.push({
2164
- type: "line3D",
2165
- coordinateSystem: "cartesian3D",
2166
- data: ringPoints,
2167
- lineStyle: { color: "rgba(100, 116, 139, 0.3)", width: 1 },
2168
- silent: true
2169
- });
2170
- });
2171
- }
2172
- return {
2173
- tooltip: {
2174
- show: true,
2175
- ...tooltipStyle,
2176
- formatter: (params) => {
2177
- var _a, _b, _c;
2178
- const d = params.data || {};
2179
- let html = `<div style="font-weight:600;font-size:13px;margin-bottom:4px">${d.name}</div>`;
2180
- html += `<div style="color:rgba(255,255,255,0.5);text-transform:uppercase;font-size:10px;margin-bottom:6px">${d.category || "Unknown"}</div>`;
2181
- html += `<div>Azimuth: <span style="font-family:monospace">${(_a = d.azimuth) == null ? void 0 : _a.toFixed(1)}°</span></div>`;
2182
- html += `<div>Elevation: <span style="font-family:monospace">${(_b = d.elevation) == null ? void 0 : _b.toFixed(1)}°</span></div>`;
2183
- html += `<div style="color:#22d3ee">Range: <span style="font-family:monospace">${(_c = d.range) == null ? void 0 : _c.toFixed(1)} km</span></div>`;
2184
- return html;
2185
- }
2186
- },
2187
- grid3D: {
2188
- boxWidth: 100,
2189
- boxHeight: 50,
2190
- boxDepth: 100,
2191
- viewControl: {
2192
- autoRotate,
2193
- autoRotateSpeed: 2,
2194
- distance: 250,
2195
- alpha: 25,
2196
- beta: 45,
2197
- rotateSensitivity: 2,
2198
- zoomSensitivity: 1.5
2199
- },
2200
- light: {
2201
- main: { intensity: 1.2, shadow: false },
2202
- ambient: { intensity: 0.5 }
2203
- },
2204
- postEffect: { enable: true, bloom: { enable: true, intensity: 0.05 } }
2205
- },
2206
- xAxis3D: { type: "value", name: "East", min: -100, max: 100, axisLabel: { show: false }, splitLine: { show: false } },
2207
- yAxis3D: { type: "value", name: "Up", min: -50, max: 100, axisLabel: { show: false }, splitLine: { show: false } },
2208
- zAxis3D: { type: "value", name: "North", min: -100, max: 100, axisLabel: { show: false }, splitLine: { show: false } },
2209
- series: [...rangeRings, { type: "scatter3D", coordinateSystem: "cartesian3D", data: scatterData, symbolSize: 12 }]
2210
- };
2211
- }, [data, maxRange, showRangeRings, autoRotate, categoryColors, tooltipStyle]);
2212
- if (!glReady) return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading: true, className });
2213
- return /* @__PURE__ */ jsx(
2214
- AstroChart,
2215
- {
2216
- ref,
2217
- type: "scatter",
2218
- series: [],
2219
- title,
2220
- width,
2221
- height,
2222
- loading,
2223
- className,
2224
- echartsOptions,
2225
- export: exportOptions,
2226
- infoTooltip
2227
- }
2228
- );
2229
- }
2230
- ));
2231
- const TransferOrbit3DChart = memo(forwardRef(
2232
- function TransferOrbit3DChart2({
2233
- segments = [],
2234
- waypoints = [],
2235
- referenceOrbits = [],
2236
- title,
2237
- width = "100%",
2238
- height = 550,
2239
- showDeltaV = true,
2240
- autoRotate = false,
2241
- loading = false,
2242
- className = "",
2243
- export: exportOptions,
2244
- infoTooltip
2245
- }, ref) {
2246
- const glReady = useEchartsGlReady();
2247
- const tooltipStyle = useChartTooltipStyle();
2248
- const legendStyle = useChartLegendStyle();
2249
- const { tokens, mode } = useTheme();
2250
- const labelPrimary = tokens.colors.text.primary;
2251
- const labelSecondary = tokens.colors.text.secondary;
2252
- const labelTertiary = tokens.colors.text.tertiary;
2253
- const labelBg = mode === "dark" ? "rgba(15, 23, 42, 0.72)" : "rgba(255, 255, 255, 0.9)";
2254
- const segmentColors = { coast: "#9D70FF", burn: "#ff3838", "gravity-assist": "#22d3ee", spiral: "#56f000" };
2255
- const waypointColors = { departure: "#3E3CFF", arrival: "#56f000", flyby: "#22d3ee", node: "#fce83a", burn: "#ff3838" };
2256
- const echartsOptions = useMemo(() => {
2257
- const seriesArray = [];
2258
- referenceOrbits.forEach((orbit) => {
2259
- seriesArray.push({
2260
- type: "line3D",
2261
- name: orbit.name,
2262
- coordinateSystem: "cartesian3D",
2263
- data: orbit.path.map((p) => [p.x, p.y, p.z]),
2264
- lineStyle: { color: orbit.color || "rgba(100, 116, 139, 0.3)", width: 1, type: "dashed" },
2265
- silent: true
2266
- });
2267
- });
2268
- segments.forEach((segment, idx) => {
2269
- const color = segment.color || segmentColors[segment.type] || ASTRO_DATA_VIZ_COLORS.mixed[idx % ASTRO_DATA_VIZ_COLORS.mixed.length];
2270
- seriesArray.push({
2271
- type: "line3D",
2272
- name: segment.name,
2273
- coordinateSystem: "cartesian3D",
2274
- data: segment.path.map((p) => [p.x, p.y, p.z]),
2275
- lineStyle: { color, width: segment.type === "burn" ? 4 : 2 }
2276
- });
2277
- });
2278
- if (waypoints.length > 0) {
2279
- seriesArray.push({
2280
- type: "scatter3D",
2281
- name: "Waypoints",
2282
- coordinateSystem: "cartesian3D",
2283
- data: waypoints.map((wp) => ({
2284
- name: wp.name,
2285
- value: [wp.position.x, wp.position.y, wp.position.z],
2286
- itemStyle: { color: waypointColors[wp.type] || "#fff" },
2287
- symbolSize: wp.type === "burn" ? 14 : 18,
2288
- deltaV: wp.deltaV,
2289
- tof: wp.tof,
2290
- waypointType: wp.type
2291
- })),
2292
- label: { show: true, formatter: (p) => {
2293
- var _a;
2294
- return (_a = p.data) == null ? void 0 : _a.name;
2295
- }, textStyle: { color: labelPrimary, fontSize: 11, backgroundColor: labelBg, padding: [2, 4] } }
2296
- });
2297
- }
2298
- const totalDeltaV = segments.reduce((sum, s) => sum + (s.deltaV || 0), 0) + waypoints.reduce((sum, w) => sum + (w.deltaV || 0), 0);
2299
- return {
2300
- tooltip: {
2301
- show: true,
2302
- ...tooltipStyle,
2303
- formatter: (params) => {
2304
- const d = params.data || {};
2305
- if (params.seriesType === "line3D") {
2306
- const seg = segments.find((s) => s.name === params.seriesName);
2307
- return `<div style="font-weight:600">${params.seriesName}</div>${(seg == null ? void 0 : seg.deltaV) ? `<div style="color:#ff3838">ΔV: ${seg.deltaV.toFixed(2)} km/s</div>` : ""}`;
2308
- }
2309
- return `<div style="font-weight:600;margin-bottom:4px">${d.name}</div>${d.deltaV ? `<div style="color:#ff3838">ΔV: ${d.deltaV.toFixed(2)} km/s</div>` : ""}${d.tof ? `<div>TOF: ${d.tof.toFixed(0)} days</div>` : ""}`;
2310
- }
2311
- },
2312
- legend: { show: true, top: 10, ...legendStyle },
2313
- graphic: showDeltaV && totalDeltaV > 0 ? [{ type: "text", right: 20, top: 20, style: { text: `Total ΔV: ${totalDeltaV.toFixed(2)} km/s`, fill: "#ff3838", fontSize: 14, fontWeight: "bold" } }] : void 0,
2314
- grid3D: { boxWidth: 150, boxHeight: 80, boxDepth: 150, viewControl: { autoRotate, autoRotateSpeed: 2, distance: 280, alpha: 20, beta: 40 }, light: { main: { intensity: 1.2 }, ambient: { intensity: 0.4 } }, postEffect: { enable: true, bloom: { enable: true, intensity: 0.08 } } },
2315
- xAxis3D: { type: "value", name: "X (AU)", nameTextStyle: { color: labelSecondary }, axisLabel: { color: labelTertiary, formatter: (v) => v.toFixed(1) }, splitLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } } },
2316
- yAxis3D: { type: "value", name: "Z (AU)", nameTextStyle: { color: labelSecondary }, axisLabel: { color: labelTertiary, formatter: (v) => v.toFixed(1) }, splitLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } } },
2317
- zAxis3D: { type: "value", name: "Y (AU)", nameTextStyle: { color: labelSecondary }, axisLabel: { color: labelTertiary, formatter: (v) => v.toFixed(1) }, splitLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } } },
2318
- series: seriesArray
2319
- };
2320
- }, [segments, waypoints, referenceOrbits, showDeltaV, autoRotate, segmentColors, waypointColors, tooltipStyle, legendStyle, labelPrimary, labelSecondary, labelTertiary, labelBg]);
2321
- if (!glReady) return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading: true, className });
2322
- return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading, className, echartsOptions, export: exportOptions, infoTooltip });
2323
- }
2324
- ));
2325
- const AttitudeHistory3DChart = memo(forwardRef(
2326
- function AttitudeHistory3DChart2({
2327
- data = [],
2328
- title,
2329
- width = "100%",
2330
- height = 500,
2331
- mode = "euler",
2332
- showModeTransitions = true,
2333
- autoRotate = false,
2334
- loading = false,
2335
- className = "",
2336
- export: exportOptions,
2337
- infoTooltip
2338
- }, ref) {
2339
- const glReady = useEchartsGlReady();
2340
- const tooltipStyle = useChartTooltipStyle();
2341
- const legendStyle = useChartLegendStyle();
2342
- const echartsOptions = useMemo(() => {
2343
- const seriesArray = [];
2344
- if (mode === "euler" && data.length > 0) {
2345
- const pathData = data.filter((d) => d.euler).map((d) => [d.euler.roll, d.euler.pitch, d.euler.yaw]);
2346
- seriesArray.push({ type: "line3D", name: "Attitude Path", coordinateSystem: "cartesian3D", data: pathData, lineStyle: { color: "#3E3CFF", width: 2 } });
2347
- if (pathData.length > 0) {
2348
- seriesArray.push({ type: "scatter3D", name: "Start/End", coordinateSystem: "cartesian3D", data: [
2349
- { value: pathData[0], name: "Start", itemStyle: { color: "#56f000" } },
2350
- { value: pathData[pathData.length - 1], name: "End", itemStyle: { color: "#ff3838" } }
2351
- ], symbolSize: 14 });
2352
- }
2353
- if (showModeTransitions) {
2354
- const transitions = data.filter((d, i) => i > 0 && d.mode !== data[i - 1].mode && d.euler);
2355
- if (transitions.length > 0) {
2356
- seriesArray.push({ type: "scatter3D", name: "Mode Changes", coordinateSystem: "cartesian3D", data: transitions.map((d) => ({ value: [d.euler.roll, d.euler.pitch, d.euler.yaw], name: d.mode, itemStyle: { color: "#fce83a" } })), symbolSize: 10, symbol: "diamond" });
2357
- }
2358
- }
2359
- }
2360
- return {
2361
- tooltip: {
2362
- show: true,
2363
- ...tooltipStyle,
2364
- formatter: (params) => {
2365
- const d = params.data || {};
2366
- const [roll, pitch, yaw] = d.value || [0, 0, 0];
2367
- return `<div style="font-weight:600;margin-bottom:4px">${d.name || params.seriesName}</div><div>Roll: ${roll.toFixed(2)}°</div><div>Pitch: ${pitch.toFixed(2)}°</div><div>Yaw: ${yaw.toFixed(2)}°</div>`;
2368
- }
2369
- },
2370
- legend: { show: true, top: 10, ...legendStyle },
2371
- grid3D: { boxWidth: 100, boxHeight: 100, boxDepth: 100, viewControl: { autoRotate, distance: 220, alpha: 25, beta: 45 }, light: { main: { intensity: 1.2 }, ambient: { intensity: 0.4 } } },
2372
- xAxis3D: { type: "value", name: "Roll (°)", nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" }, axisLabel: { color: "rgba(255, 255, 255, 0.4)" }, splitLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } } },
2373
- yAxis3D: { type: "value", name: "Pitch (°)", nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" }, axisLabel: { color: "rgba(255, 255, 255, 0.4)" }, splitLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } } },
2374
- zAxis3D: { type: "value", name: "Yaw (°)", nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" }, axisLabel: { color: "rgba(255, 255, 255, 0.4)" }, splitLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } } },
2375
- series: seriesArray
2376
- };
2377
- }, [data, mode, showModeTransitions, autoRotate, tooltipStyle, legendStyle]);
2378
- if (!glReady) return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading: true, className });
2379
- return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading, className, echartsOptions, export: exportOptions, infoTooltip });
2380
- }
2381
- ));
2382
- const ConjunctionAssessment3DChart = memo(forwardRef(
2383
- function ConjunctionAssessment3DChart2({
2384
- events = [],
2385
- primaryOrbit = [],
2386
- title,
2387
- width = "100%",
2388
- height = 550,
2389
- showUncertainty = true,
2390
- warningThreshold = 5,
2391
- criticalThreshold = 1,
2392
- autoRotate = false,
2393
- loading = false,
2394
- className = "",
2395
- export: exportOptions,
2396
- infoTooltip
2397
- }, ref) {
2398
- const glReady = useEchartsGlReady();
2399
- const tooltipStyle = useChartTooltipStyle();
2400
- const legendStyle = useChartLegendStyle();
2401
- const { tokens, mode } = useTheme();
2402
- tokens.colors.text.primary;
2403
- tokens.colors.text.secondary;
2404
- tokens.colors.text.tertiary;
2405
- const echartsOptions = useMemo(() => {
2406
- const seriesArray = [];
2407
- if (primaryOrbit && primaryOrbit.length > 0) {
2408
- seriesArray.push({ type: "line3D", name: "Primary Orbit", coordinateSystem: "cartesian3D", data: primaryOrbit.map((p) => [p.x, p.y, p.z]), lineStyle: { color: "#3E3CFF", width: 2 } });
2409
- }
2410
- const eventData = events.map((evt) => {
2411
- const color = evt.missDistance < criticalThreshold ? "#ff3838" : evt.missDistance < warningThreshold ? "#fce83a" : "#56f000";
2412
- return { name: `${evt.primary} × ${evt.secondary}`, value: [evt.position.x, evt.position.y, evt.position.z], itemStyle: { color }, symbolSize: Math.max(8, Math.min(24, 30 - evt.missDistance * 3)), ...evt };
2413
- });
2414
- seriesArray.push({ type: "scatter3D", name: "Conjunctions", coordinateSystem: "cartesian3D", data: eventData, symbol: "circle", emphasis: { itemStyle: { borderColor: "#fff", borderWidth: 2 } } });
2415
- if (showUncertainty) {
2416
- events.filter((e) => e.uncertainty).forEach((evt) => {
2417
- const { x, y, z } = evt.position;
2418
- const { rx, ry, rz } = evt.uncertainty;
2419
- seriesArray.push({ type: "line3D", coordinateSystem: "cartesian3D", data: [[x - rx, y, z], [x + rx, y, z]], lineStyle: { color: "rgba(255, 255, 255, 0.3)", width: 1 }, silent: true });
2420
- seriesArray.push({ type: "line3D", coordinateSystem: "cartesian3D", data: [[x, y - ry, z], [x, y + ry, z]], lineStyle: { color: "rgba(255, 255, 255, 0.3)", width: 1 }, silent: true });
2421
- seriesArray.push({ type: "line3D", coordinateSystem: "cartesian3D", data: [[x, y, z - rz], [x, y, z + rz]], lineStyle: { color: "rgba(255, 255, 255, 0.3)", width: 1 }, silent: true });
2422
- });
2423
- }
2424
- return {
2425
- tooltip: {
2426
- show: true,
2427
- ...tooltipStyle,
2428
- formatter: (params) => {
2429
- var _a;
2430
- const d = params.data || {};
2431
- if (params.seriesType === "line3D") return "";
2432
- const mdColor = d.missDistance < criticalThreshold ? "#ff3838" : d.missDistance < warningThreshold ? "#fce83a" : "#56f000";
2433
- return `<div style="font-weight:600;margin-bottom:4px">${d.name}</div><div style="color:${mdColor}">Miss Distance: ${(_a = d.missDistance) == null ? void 0 : _a.toFixed(3)} km</div>${d.probability !== void 0 ? `<div>Probability: ${(d.probability * 100).toExponential(2)}%</div>` : ""}${d.relativeVelocity ? `<div>Rel. Velocity: ${d.relativeVelocity.toFixed(2)} km/s</div>` : ""}`;
2434
- }
2435
- },
2436
- legend: { show: true, top: 10, ...legendStyle },
2437
- grid3D: { boxWidth: 100, boxHeight: 100, boxDepth: 100, viewControl: { autoRotate, distance: 220, alpha: 25, beta: 45 }, light: { main: { intensity: 1.2 }, ambient: { intensity: 0.4 } }, postEffect: { enable: true, bloom: { enable: true, intensity: 0.05 } } },
2438
- xAxis3D: { type: "value", name: "X (km)", nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" }, axisLabel: { color: "rgba(255, 255, 255, 0.4)" }, splitLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } } },
2439
- yAxis3D: { type: "value", name: "Y (km)", nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" }, axisLabel: { color: "rgba(255, 255, 255, 0.4)" }, splitLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } } },
2440
- zAxis3D: { type: "value", name: "Z (km)", nameTextStyle: { color: "rgba(255, 255, 255, 0.5)" }, axisLabel: { color: "rgba(255, 255, 255, 0.4)" }, splitLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } } },
2441
- series: seriesArray
2442
- };
2443
- }, [events, primaryOrbit, showUncertainty, warningThreshold, criticalThreshold, autoRotate, tooltipStyle, legendStyle]);
2444
- if (!glReady) return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading: true, className });
2445
- return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading, className, echartsOptions, export: exportOptions, infoTooltip });
2446
- }
2447
- ));
2448
- const LaunchCorridor3DChart = memo(forwardRef(
2449
- function LaunchCorridor3DChart2({
2450
- data = { corridors: [] },
2451
- title,
2452
- width = "100%",
2453
- height = 550,
2454
- showTrajectory = true,
2455
- autoRotate = false,
2456
- loading = false,
2457
- className = "",
2458
- export: exportOptions,
2459
- infoTooltip
2460
- }, ref) {
2461
- const glReady = useEchartsGlReady();
2462
- const { tokens, mode } = useTheme();
2463
- const tooltipStyle = useChartTooltipStyle();
2464
- const labelPrimary = tokens.colors.text.primary;
2465
- const labelSecondary = tokens.colors.text.secondary;
2466
- const labelTertiary = tokens.colors.text.tertiary;
2467
- const labelBg = mode === "dark" ? "rgba(15, 23, 42, 0.72)" : "rgba(255, 255, 255, 0.9)";
2468
- const legendStyle = useChartLegendStyle();
2469
- const corridorColors = { nominal: "rgba(86, 240, 0, 0.4)", abort: "rgba(255, 179, 2, 0.4)", safety: "rgba(34, 211, 238, 0.4)", exclusion: "rgba(255, 56, 56, 0.4)" };
2470
- const echartsOptions = useMemo(() => {
2471
- const seriesArray = [];
2472
- const latLonTo3D = (lat, lon, alt) => [lon, alt * 0.1, lat];
2473
- data.corridors.forEach((corridor) => {
2474
- const color = corridor.color || corridorColors[corridor.type] || "rgba(100, 116, 139, 0.4)";
2475
- const lowerPath = corridor.groundFootprint.map((p) => latLonTo3D(p.lat, p.lon, corridor.altitudeRange[0]));
2476
- if (lowerPath.length > 0) lowerPath.push(lowerPath[0]);
2477
- seriesArray.push({ type: "line3D", name: `${corridor.name} (floor)`, coordinateSystem: "cartesian3D", data: lowerPath, lineStyle: { color, width: 2 } });
2478
- const upperPath = corridor.groundFootprint.map((p) => latLonTo3D(p.lat, p.lon, corridor.altitudeRange[1]));
2479
- if (upperPath.length > 0) upperPath.push(upperPath[0]);
2480
- seriesArray.push({ type: "line3D", name: `${corridor.name} (ceiling)`, coordinateSystem: "cartesian3D", data: upperPath, lineStyle: { color, width: 2, type: "dashed" } });
2481
- });
2482
- if (showTrajectory && data.trajectory && data.trajectory.length > 0) {
2483
- seriesArray.push({ type: "line3D", name: "Trajectory", coordinateSystem: "cartesian3D", data: data.trajectory.map((p) => latLonTo3D(p.lat, p.lon, p.altitude)), lineStyle: { color: "#fff", width: 3 } });
2484
- }
2485
- if (data.events && data.events.length > 0) {
2486
- seriesArray.push({ type: "scatter3D", name: "Events", coordinateSystem: "cartesian3D", data: data.events.map((e) => ({ name: e.name, value: latLonTo3D(e.lat, e.lon, e.altitude), itemStyle: { color: "#fce83a" }, altitude: e.altitude, time: e.time })), symbolSize: 12, symbol: "diamond", label: { show: true, formatter: (p) => {
2487
- var _a;
2488
- return (_a = p.data) == null ? void 0 : _a.name;
2489
- }, textStyle: { color: labelPrimary, fontSize: 10, backgroundColor: labelBg, padding: [2, 4] } } });
2490
- }
2491
- return {
2492
- tooltip: {
2493
- show: true,
2494
- ...tooltipStyle,
2495
- formatter: (params) => {
2496
- const d = params.data || {};
2497
- if (params.seriesType === "line3D") return `<div style="font-weight:600">${params.seriesName}</div>`;
2498
- return `<div style="font-weight:600;margin-bottom:4px">${d.name}</div>${d.altitude ? `<div>Altitude: ${d.altitude.toFixed(1)} km</div>` : ""}${d.time ? `<div>T+: ${d.time.toFixed(0)}s</div>` : ""}`;
2499
- }
2500
- },
2501
- legend: { show: true, top: 10, ...legendStyle },
2502
- grid3D: { boxWidth: 150, boxHeight: 60, boxDepth: 100, viewControl: { autoRotate, distance: 280, alpha: 30, beta: 30 }, light: { main: { intensity: 1.2 }, ambient: { intensity: 0.4 } } },
2503
- xAxis3D: { type: "value", name: "Longitude (°)", nameTextStyle: { color: labelSecondary }, axisLabel: { color: labelTertiary }, splitLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } } },
2504
- yAxis3D: { type: "value", name: "Altitude (km)", nameTextStyle: { color: labelSecondary }, axisLabel: { color: labelTertiary }, splitLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } } },
2505
- zAxis3D: { type: "value", name: "Latitude (°)", nameTextStyle: { color: labelSecondary }, axisLabel: { color: labelTertiary }, splitLine: { show: true, lineStyle: { color: "rgba(100, 116, 139, 0.1)" } } },
2506
- series: seriesArray
2507
- };
2508
- }, [data, showTrajectory, autoRotate, corridorColors, tooltipStyle, legendStyle, labelPrimary, labelSecondary, labelTertiary, labelBg]);
2509
- if (!glReady) return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading: true, className });
2510
- return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading, className, echartsOptions, export: exportOptions, infoTooltip });
2511
- }
2512
- ));
2513
- const AntennaPattern3DChart = memo(forwardRef(
2514
- function AntennaPattern3DChart2({
2515
- patterns = [],
2516
- title,
2517
- width = "100%",
2518
- height = 500,
2519
- minGain = -20,
2520
- autoRotate = true,
2521
- loading = false,
2522
- className = "",
2523
- export: exportOptions,
2524
- infoTooltip
2525
- }, ref) {
2526
- const glReady = useEchartsGlReady();
2527
- const { tokens } = useTheme();
2528
- const tooltipStyle = useChartTooltipStyle();
2529
- tokens.colors.text.primary;
2530
- tokens.colors.text.secondary;
2531
- const legendStyle = useChartLegendStyle();
2532
- const echartsOptions = useMemo(() => {
2533
- const seriesArray = [];
2534
- patterns.forEach((pattern, pIdx) => {
2535
- const color = pattern.color || ASTRO_DATA_VIZ_COLORS.mixed[pIdx % ASTRO_DATA_VIZ_COLORS.mixed.length];
2536
- const maxGain = Math.max(...pattern.pattern.map((p) => p.gain), 0);
2537
- const surfaceData = pattern.pattern.filter((p) => p.gain >= minGain).map((p) => {
2538
- const thetaRad = p.theta * Math.PI / 180;
2539
- const phiRad = p.phi * Math.PI / 180;
2540
- const r = Math.max(0, (p.gain - minGain) / (maxGain - minGain) * 80 + 20);
2541
- return { value: [r * Math.sin(thetaRad) * Math.cos(phiRad), r * Math.cos(thetaRad), r * Math.sin(thetaRad) * Math.sin(phiRad)], gain: p.gain, itemStyle: { color, opacity: 0.7 } };
2542
- });
2543
- seriesArray.push({ type: "scatter3D", name: pattern.name, coordinateSystem: "cartesian3D", data: surfaceData, symbolSize: 4 });
2544
- if (pattern.boresight) {
2545
- const thetaRad = pattern.boresight.theta * Math.PI / 180;
2546
- const phiRad = pattern.boresight.phi * Math.PI / 180;
2547
- seriesArray.push({ type: "line3D", name: `${pattern.name} Boresight`, coordinateSystem: "cartesian3D", data: [[0, 0, 0], [100 * Math.sin(thetaRad) * Math.cos(phiRad), 100 * Math.cos(thetaRad), 100 * Math.sin(thetaRad) * Math.sin(phiRad)]], lineStyle: { color: "#fff", width: 2 } });
2548
- }
2549
- });
2550
- return {
2551
- tooltip: {
2552
- show: true,
2553
- ...tooltipStyle,
2554
- formatter: (params) => {
2555
- const d = params.data || {};
2556
- return `<div style="font-weight:600;margin-bottom:4px">${params.seriesName}</div>${d.gain !== void 0 ? `<div style="color:#22d3ee">Gain: ${d.gain.toFixed(1)} dBi</div>` : ""}`;
2557
- }
2558
- },
2559
- legend: { show: patterns.length > 1, top: 10, ...legendStyle },
2560
- grid3D: { boxWidth: 100, boxHeight: 100, boxDepth: 100, viewControl: { autoRotate, autoRotateSpeed: 3, distance: 220, alpha: 20, beta: 45 }, light: { main: { intensity: 1.2 }, ambient: { intensity: 0.5 } }, postEffect: { enable: true, bloom: { enable: true, intensity: 0.08 } } },
2561
- xAxis3D: { type: "value", name: "X", min: -100, max: 100, axisLabel: { show: false }, splitLine: { show: false } },
2562
- yAxis3D: { type: "value", name: "Z", min: -100, max: 100, axisLabel: { show: false }, splitLine: { show: false } },
2563
- zAxis3D: { type: "value", name: "Y", min: -100, max: 100, axisLabel: { show: false }, splitLine: { show: false } },
2564
- series: seriesArray
2565
- };
2566
- }, [patterns, minGain, autoRotate, tooltipStyle, legendStyle]);
2567
- if (!glReady) return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading: true, className });
2568
- return /* @__PURE__ */ jsx(AstroChart, { ref, type: "scatter", series: [], title, width, height, loading, className, echartsOptions, export: exportOptions, infoTooltip });
2569
- }
2570
- ));
2571
- const WaterfallChart = memo(forwardRef(
2572
- function WaterfallChart2({
2573
- data = [],
2574
- title = "RF Spectrum Waterfall",
2575
- centerFrequency: _centerFrequency,
2576
- bandwidth: _bandwidth,
2577
- fftBins = 512,
2578
- colorMap = "viridis",
2579
- powerRange = [-120, -60],
2580
- timeWindow = 60,
2581
- markers: _markers = [],
2582
- showSpectrum: _showSpectrum = true,
2583
- width = "100%",
2584
- height = 400,
2585
- loading = false,
2586
- className = "",
2587
- export: exportOptions,
2588
- infoTooltip
2589
- }, ref) {
2590
- const { tokens } = useTheme();
2591
- const tooltipStyle = useChartTooltipStyle();
2592
- tokens.colors.text.primary;
2593
- tokens.colors.text.secondary;
2594
- const colorMaps = {
2595
- viridis: ["#440154", "#482777", "#3e4989", "#31688e", "#26828e", "#1f9e89", "#35b779", "#6ece58", "#b5de2b", "#fde725"],
2596
- plasma: ["#0d0887", "#46039f", "#7201a8", "#9c179e", "#bd3786", "#d8576b", "#ed7953", "#fb9f3a", "#fdca26", "#f0f921"],
2597
- inferno: ["#000004", "#1b0c41", "#4a0c6b", "#781c6d", "#a52c60", "#cf4446", "#ed6925", "#fb9b06", "#f7d13d", "#fcffa4"],
2598
- magma: ["#000004", "#180f3d", "#440f76", "#721f81", "#9e2f7f", "#cd4071", "#f1605d", "#fd9668", "#feca8d", "#fcfdbf"]
2599
- };
2600
- const echartsOptions = useMemo(() => {
2601
- if (!data.length) return {};
2602
- const heatmapData = [];
2603
- const timeLabels = [];
2604
- const freqLabels = [];
2605
- const firstPoint = data[0];
2606
- const freqMin = Math.min(...firstPoint.frequencies);
2607
- const freqMax = Math.max(...firstPoint.frequencies);
2608
- const freqStep = (freqMax - freqMin) / (fftBins - 1);
2609
- for (let i = 0; i < fftBins; i++) {
2610
- const freq = freqMin + i * freqStep;
2611
- freqLabels.push((freq / 1e6).toFixed(2));
2612
- }
2613
- data.slice(-timeWindow).forEach((point, tIdx) => {
2614
- const time = point.time instanceof Date ? point.time : new Date(point.time);
2615
- timeLabels.push(time.toLocaleTimeString());
2616
- point.powers.forEach((power, fIdx) => {
2617
- if (fIdx < fftBins) {
2618
- heatmapData.push([fIdx, tIdx, power]);
2619
- }
2620
- });
2621
- });
2622
- return {
2623
- tooltip: {
2624
- show: true,
2625
- ...tooltipStyle,
2626
- formatter: (params) => {
2627
- if (Array.isArray(params)) return "";
2628
- const [fIdx, tIdx, power] = params.data || [];
2629
- const freq = freqLabels[fIdx] || "N/A";
2630
- const time = timeLabels[tIdx] || "N/A";
2631
- return `<div style="font-weight:600">Spectrum</div>
2632
- <div>Frequency: ${freq} MHz</div>
2633
- <div>Time: ${time}</div>
2634
- <div>Power: ${(power == null ? void 0 : power.toFixed(1)) ?? "N/A"} dBm</div>`;
2635
- }
2636
- },
2637
- grid: { left: 60, right: 40, top: 40, bottom: 60 },
2638
- xAxis: { type: "category", data: freqLabels, name: "Frequency (MHz)", nameLocation: "middle", nameGap: 35 },
2639
- yAxis: { type: "category", data: timeLabels, name: "Time", nameLocation: "middle", nameGap: 45 },
2640
- visualMap: {
2641
- min: powerRange[0],
2642
- max: powerRange[1],
2643
- calculable: true,
2644
- orient: "horizontal",
2645
- left: "center",
2646
- bottom: 0,
2647
- // Enable hover linking - highlight only hovered range
2648
- hoverLink: true,
2649
- // Non-hovered regions get faded opacity
2650
- outOfRange: {
2651
- color: "rgba(128, 128, 128, 0.12)",
2652
- opacity: 0.15
2653
- },
2654
- inRange: { color: colorMaps[colorMap] || colorMaps.viridis },
2655
- text: [`${powerRange[1]} dBm`, `${powerRange[0]} dBm`],
2656
- textStyle: { color: "rgba(255, 255, 255, 0.7)" }
2657
- },
2658
- series: [{
2659
- type: "heatmap",
2660
- data: heatmapData,
2661
- emphasis: { itemStyle: { borderColor: "#fff", borderWidth: 1 } }
2662
- }]
2663
- };
2664
- }, [data, fftBins, colorMap, powerRange, timeWindow, tooltipStyle]);
2665
- return /* @__PURE__ */ jsx(
2666
- AstroChart,
2667
- {
2668
- ref,
2669
- type: "heatmap",
2670
- series: [],
2671
- title,
2672
- width,
2673
- height,
2674
- loading,
2675
- className,
2676
- echartsOptions,
2677
- export: exportOptions,
2678
- infoTooltip
2679
- }
2680
- );
2681
- }
2682
- ));
2683
- const DopplerTrackChart = memo(forwardRef(
2684
- function DopplerTrackChart2({
2685
- predicted = [],
2686
- measured = [],
2687
- carrierFrequency: _carrierFrequency,
2688
- passInfo,
2689
- showResiduals = false,
2690
- showElevation = true,
2691
- title,
2692
- width = "100%",
2693
- height = 300,
2694
- loading = false,
2695
- className = "",
2696
- export: exportOptions,
2697
- infoTooltip
2698
- }, ref) {
2699
- const tooltipStyle = useChartTooltipStyle();
2700
- const chartTitle = title || (passInfo ? `Doppler Track – ${passInfo.name}` : "Doppler Track");
2701
- const echartsOptions = useMemo(() => {
2702
- const series = [];
2703
- if (predicted.length > 0) {
2704
- series.push({
2705
- name: "Predicted",
2706
- type: "line",
2707
- data: predicted.map((p) => {
2708
- const time = p.time instanceof Date ? p.time.getTime() : p.time;
2709
- return [time, p.dopplerShift];
2710
- }),
2711
- lineStyle: { color: ASTRO_DATA_VIZ_COLORS.mixed[0], width: 2 },
2712
- symbol: "none",
2713
- smooth: true
2714
- });
2715
- }
2716
- if (measured.length > 0) {
2717
- series.push({
2718
- name: "Measured",
2719
- type: "scatter",
2720
- data: measured.map((p) => {
2721
- const time = p.time instanceof Date ? p.time.getTime() : p.time;
2722
- return [time, p.dopplerShift];
2723
- }),
2724
- itemStyle: { color: ASTRO_DATA_VIZ_COLORS.mixed[2] },
2725
- symbolSize: 4
2726
- });
2727
- }
2728
- if (showElevation && predicted.some((p) => p.elevation !== void 0)) {
2729
- series.push({
2730
- name: "Elevation",
2731
- type: "line",
2732
- yAxisIndex: 1,
2733
- data: predicted.filter((p) => p.elevation !== void 0).map((p) => {
2734
- const time = p.time instanceof Date ? p.time.getTime() : p.time;
2735
- return [time, p.elevation];
2736
- }),
2737
- lineStyle: { color: SOFT_STATUS_COLORS.normal, width: 1, type: "dashed" },
2738
- symbol: "none",
2739
- areaStyle: { color: `${STATUS_COLORS.normal}20` }
2740
- });
2741
- }
2742
- return {
2743
- tooltip: {
2744
- show: true,
2745
- trigger: "axis",
2746
- ...tooltipStyle,
2747
- formatter: (params) => {
2748
- if (!Array.isArray(params) || params.length === 0) return "";
2749
- const firstParam = params[0];
2750
- const time = new Date(firstParam.data[0]).toLocaleTimeString();
2751
- let html = `<div style="font-weight:600;margin-bottom:4px">${time}</div>`;
2752
- params.forEach((p) => {
2753
- var _a;
2754
- const value = p.seriesName === "Elevation" ? `${(_a = p.data[1]) == null ? void 0 : _a.toFixed(1)}°` : `${(p.data[1] / 1e3).toFixed(2)} kHz`;
2755
- html += `<div>${p.marker} ${p.seriesName}: ${value}</div>`;
2756
- });
2757
- return html;
2758
- }
2759
- },
2760
- legend: { show: true, top: 10 },
2761
- grid: { left: 60, right: 60, top: 50, bottom: 40 },
2762
- xAxis: { type: "time", name: "Time" },
2763
- yAxis: [
2764
- { type: "value", name: "Doppler (kHz)", axisLabel: { formatter: (v) => (v / 1e3).toFixed(1) } },
2765
- { type: "value", name: "Elevation (°)", position: "right", min: 0, max: 90, show: showElevation }
2766
- ],
2767
- series
2768
- };
2769
- }, [predicted, measured, showResiduals, showElevation, tooltipStyle]);
2770
- return /* @__PURE__ */ jsx(
2771
- AstroChart,
2772
- {
2773
- ref,
2774
- type: "line",
2775
- title: chartTitle,
2776
- series: [],
2777
- width,
2778
- height,
2779
- loading,
2780
- className,
2781
- echartsOptions,
2782
- export: exportOptions,
2783
- infoTooltip
2784
- }
2785
- );
2786
- }
2787
- ));
2788
- const LinkMarginChart = memo(forwardRef(
2789
- function LinkMarginChart2({
2790
- data = [],
2791
- minMargin,
2792
- mode = "both",
2793
- showRainFade: _showRainFade = false,
2794
- title = "Link Margin vs Elevation",
2795
- width = "100%",
2796
- height = 250,
2797
- loading = false,
2798
- className = "",
2799
- export: exportOptions,
2800
- infoTooltip
2801
- }, ref) {
2802
- const series = [];
2803
- if ((mode === "uplink" || mode === "both") && data.some((d) => d.uplinkMargin !== void 0)) {
2804
- series.push({
2805
- id: "uplink",
2806
- name: "Uplink Margin",
2807
- data: data.filter((d) => d.uplinkMargin !== void 0).map((d) => ({ x: d.elevation, y: d.uplinkMargin })),
2808
- color: ASTRO_DATA_VIZ_COLORS.mixed[0]
2809
- });
2810
- }
2811
- if ((mode === "downlink" || mode === "both") && data.some((d) => d.downlinkMargin !== void 0)) {
2812
- series.push({
2813
- id: "downlink",
2814
- name: "Downlink Margin",
2815
- data: data.filter((d) => d.downlinkMargin !== void 0).map((d) => ({ x: d.elevation, y: d.downlinkMargin })),
2816
- color: ASTRO_DATA_VIZ_COLORS.mixed[2]
2817
- });
2818
- }
2819
- const annotations = {
2820
- markLines: {
2821
- data: [{
2822
- yAxis: minMargin,
2823
- label: `Min Margin (${minMargin} dB)`,
2824
- color: SOFT_STATUS_COLORS.caution,
2825
- lineStyle: { type: "dashed" }
2826
- }]
2827
- },
2828
- markAreas: {
2829
- data: [[
2830
- { yAxis: 0, name: "Insufficient Margin" },
2831
- { yAxis: minMargin }
2832
- ]],
2833
- itemStyle: { color: `${STATUS_COLORS.critical}15` }
2834
- }
2835
- };
2836
- return /* @__PURE__ */ jsx(
2837
- AstroChart,
2838
- {
2839
- ref,
2840
- type: "line",
2841
- title,
2842
- series,
2843
- width,
2844
- height,
2845
- loading,
2846
- className,
2847
- xAxis: { type: "value", name: "Elevation (°)", min: 0, max: 90 },
2848
- yAxis: { type: "value", name: "Margin (dB)" },
2849
- tooltip: { trigger: "axis", crosshair: "x" },
2850
- legend: { show: mode === "both", position: "bottom" },
2851
- annotations,
2852
- export: exportOptions,
2853
- infoTooltip
2854
- }
2855
- );
2856
- }
2857
- ));
2858
- const ConstellationCoverageChart = memo(forwardRef(
2859
- function ConstellationCoverageChart2({
2860
- data = { coverage: [], latitudes: [], longitudes: [] },
2861
- title = "Constellation Coverage",
2862
- metricLabel = "Coverage",
2863
- metricUnit = "%",
2864
- colorMap = "viridis",
2865
- valueRange,
2866
- satellites = [],
2867
- groundStations = [],
2868
- width = "100%",
2869
- height = 400,
2870
- loading = false,
2871
- className = "",
2872
- export: exportOptions,
2873
- infoTooltip
2874
- }, ref) {
2875
- const { tokens } = useTheme();
2876
- const tooltipStyle = useChartTooltipStyle();
2877
- const labelPrimary = tokens.colors.text.primary;
2878
- const labelSecondary = tokens.colors.text.secondary;
2879
- const colorMaps = {
2880
- viridis: ["#440154", "#482777", "#3e4989", "#31688e", "#26828e", "#1f9e89", "#35b779", "#6ece58", "#b5de2b", "#fde725"],
2881
- jet: ["#00007f", "#0000ff", "#007fff", "#00ffff", "#7fff7f", "#ffff00", "#ff7f00", "#ff0000", "#7f0000"],
2882
- plasma: ["#0d0887", "#46039f", "#7201a8", "#9c179e", "#bd3786", "#d8576b", "#ed7953", "#fb9f3a", "#fdca26", "#f0f921"],
2883
- thermal: ["#000000", "#1a0a2e", "#3d1551", "#6b1d6a", "#a12568", "#d3405c", "#eb6841", "#f5a623", "#f7dc6f", "#ffffff"]
2884
- };
2885
- const echartsOptions = useMemo(() => {
2886
- if (!data.coverage.length || !data.latitudes.length || !data.longitudes.length) return {};
2887
- const heatmapData = [];
2888
- let minVal = Infinity;
2889
- let maxVal = -Infinity;
2890
- data.latitudes.forEach((_, latIdx) => {
2891
- data.longitudes.forEach((_2, lonIdx) => {
2892
- var _a;
2893
- const val = ((_a = data.coverage[latIdx]) == null ? void 0 : _a[lonIdx]) ?? 0;
2894
- heatmapData.push([lonIdx, latIdx, val]);
2895
- if (val < minVal) minVal = val;
2896
- if (val > maxVal) maxVal = val;
2897
- });
2898
- });
2899
- const range = valueRange || [minVal, maxVal];
2900
- const lonLabels = data.longitudes.map((v) => `${v.toFixed(0)}°`);
2901
- const latLabels = data.latitudes.map((v) => `${v.toFixed(0)}°`);
2902
- const seriesArray = [
2903
- {
2904
- type: "heatmap",
2905
- data: heatmapData,
2906
- emphasis: { itemStyle: { borderColor: "#fff", borderWidth: 1 } },
2907
- progressive: 5e3
2908
- }
2909
- ];
2910
- if (satellites.length > 0) {
2911
- seriesArray.push({
2912
- type: "scatter",
2913
- name: "Satellites",
2914
- coordinateSystem: "cartesian2d",
2915
- data: satellites.map((sat) => {
2916
- const lonIdx = data.longitudes.findIndex((v) => Math.abs(v - sat.lon) < data.longitudes[1] - data.longitudes[0]);
2917
- const latIdx = data.latitudes.findIndex((v) => Math.abs(v - sat.lat) < data.latitudes[1] - data.latitudes[0]);
2918
- return { value: [lonIdx >= 0 ? lonIdx : 0, latIdx >= 0 ? latIdx : 0], name: sat.name, itemStyle: { color: sat.color || "#fff" } };
2919
- }),
2920
- symbolSize: 8,
2921
- symbol: "triangle",
2922
- z: 10,
2923
- label: { show: true, formatter: (p) => {
2924
- var _a;
2925
- return ((_a = p.data) == null ? void 0 : _a.name) || "";
2926
- }, position: "top", color: labelPrimary, fontSize: 9 }
2927
- });
2928
- }
2929
- if (groundStations.length > 0) {
2930
- seriesArray.push({
2931
- type: "scatter",
2932
- name: "Ground Stations",
2933
- coordinateSystem: "cartesian2d",
2934
- data: groundStations.map((gs) => {
2935
- const lonIdx = data.longitudes.findIndex((v) => Math.abs(v - gs.lon) < data.longitudes[1] - data.longitudes[0]);
2936
- const latIdx = data.latitudes.findIndex((v) => Math.abs(v - gs.lat) < data.latitudes[1] - data.latitudes[0]);
2937
- return { value: [lonIdx >= 0 ? lonIdx : 0, latIdx >= 0 ? latIdx : 0], name: gs.name };
2938
- }),
2939
- symbolSize: 10,
2940
- symbol: "diamond",
2941
- itemStyle: { color: ASTRO_DATA_VIZ_COLORS.mixed[2] },
2942
- z: 10,
2943
- label: { show: true, formatter: (p) => {
2944
- var _a;
2945
- return ((_a = p.data) == null ? void 0 : _a.name) || "";
2946
- }, position: "bottom", color: labelSecondary, fontSize: 9 }
2947
- });
2948
- }
2949
- return {
2950
- tooltip: {
2951
- show: true,
2952
- ...tooltipStyle,
2953
- formatter: (params) => {
2954
- if (Array.isArray(params)) return "";
2955
- const d = params.data;
2956
- if (params.seriesType === "scatter") return `<div style="font-weight:600">${(d == null ? void 0 : d.name) || ""}</div>`;
2957
- const [lonIdx, latIdx, val] = d || [];
2958
- const lon = data.longitudes[lonIdx] ?? "N/A";
2959
- const lat = data.latitudes[latIdx] ?? "N/A";
2960
- return `<div style="font-weight:600">${metricLabel}</div>
2961
- <div>Lat: ${typeof lat === "number" ? lat.toFixed(1) : lat}°</div>
2962
- <div>Lon: ${typeof lon === "number" ? lon.toFixed(1) : lon}°</div>
2963
- <div>${metricLabel}: ${(val == null ? void 0 : val.toFixed(1)) ?? "N/A"} ${metricUnit}</div>`;
2964
- }
2965
- },
2966
- grid: { left: 60, right: 50, top: 40, bottom: 80 },
2967
- xAxis: { type: "category", data: lonLabels, name: "Longitude", nameLocation: "middle", nameGap: 30, axisLabel: { interval: Math.floor(lonLabels.length / 12) } },
2968
- yAxis: { type: "category", data: latLabels, name: "Latitude", nameLocation: "middle", nameGap: 40, axisLabel: { interval: Math.floor(latLabels.length / 6) } },
2969
- visualMap: {
2970
- min: range[0],
2971
- max: range[1],
2972
- calculable: true,
2973
- orient: "horizontal",
2974
- left: "center",
2975
- bottom: 0,
2976
- hoverLink: true,
2977
- outOfRange: { color: "rgba(128, 128, 128, 0.12)", opacity: 0.15 },
2978
- inRange: { color: colorMaps[colorMap] || colorMaps.viridis },
2979
- text: [`${range[1]} ${metricUnit}`, `${range[0]} ${metricUnit}`],
2980
- textStyle: { color: labelSecondary }
2981
- },
2982
- series: seriesArray
2983
- };
2984
- }, [data, satellites, groundStations, colorMap, valueRange, metricLabel, metricUnit, tooltipStyle, labelPrimary, labelSecondary]);
2985
- return /* @__PURE__ */ jsx(
2986
- AstroChart,
2987
- {
2988
- ref,
2989
- type: "heatmap",
2990
- series: [],
2991
- title,
2992
- width,
2993
- height,
2994
- loading,
2995
- className,
2996
- echartsOptions,
2997
- export: exportOptions,
2998
- infoTooltip
2999
- }
3000
- );
3001
- }
3002
- ));
3003
- const ConjunctionChart = memo(forwardRef(
3004
- function ConjunctionChart2({
3005
- events = [],
3006
- timeRange,
3007
- warningThreshold = 5,
3008
- criticalThreshold = 1,
3009
- minProbability: _minProbability,
3010
- showProbability = true,
3011
- title = "Conjunction Assessment",
3012
- width = "100%",
3013
- height = 350,
3014
- loading = false,
3015
- className = "",
3016
- export: exportOptions,
3017
- infoTooltip
3018
- }, ref) {
3019
- const tooltipStyle = useChartTooltipStyle();
3020
- const echartsOptions = useMemo(() => {
3021
- if (!events.length) return {};
3022
- const sorted = [...events].sort((a, b) => a.tca - b.tca);
3023
- const missData = sorted.map((evt) => {
3024
- const color = evt.missDistance < criticalThreshold ? STATUS_COLORS.critical : evt.missDistance < warningThreshold ? STATUS_COLORS.caution : STATUS_COLORS.normal;
3025
- return {
3026
- value: [evt.tca, evt.missDistance],
3027
- itemStyle: { color },
3028
- symbolSize: Math.max(6, Math.min(20, 22 - evt.missDistance * 2)),
3029
- ...evt
3030
- };
3031
- });
3032
- const seriesArray = [
3033
- {
3034
- name: "Miss Distance",
3035
- type: "scatter",
3036
- data: missData,
3037
- symbolSize: (val) => val.symbolSize || 10,
3038
- z: 10
3039
- }
3040
- ];
3041
- if (showProbability && sorted.some((e) => e.probability !== void 0)) {
3042
- seriesArray.push({
3043
- name: "Probability (Pc)",
3044
- type: "bar",
3045
- yAxisIndex: 1,
3046
- data: sorted.map((evt) => ({
3047
- value: [evt.tca, evt.probability ?? 0],
3048
- itemStyle: {
3049
- color: (evt.probability ?? 0) > 1e-4 ? `${STATUS_COLORS.critical}99` : (evt.probability ?? 0) > 1e-6 ? `${STATUS_COLORS.caution}99` : `${STATUS_COLORS.normal}60`
3050
- }
3051
- })),
3052
- barWidth: 8,
3053
- z: 5
3054
- });
3055
- }
3056
- return {
3057
- tooltip: {
3058
- show: true,
3059
- trigger: "item",
3060
- ...tooltipStyle,
3061
- formatter: (params) => {
3062
- var _a, _b, _c;
3063
- const d = params.data || {};
3064
- if (params.seriesName === "Probability (Pc)") {
3065
- return `<div>Pc: ${(((_a = d.value) == null ? void 0 : _a[1]) ?? 0).toExponential(2)}</div>`;
3066
- }
3067
- const mdColor = d.missDistance < criticalThreshold ? STATUS_COLORS.critical : d.missDistance < warningThreshold ? STATUS_COLORS.caution : STATUS_COLORS.normal;
3068
- const tca = new Date(((_b = d.value) == null ? void 0 : _b[0]) ?? d.tca);
3069
- return `<div style="font-weight:600;margin-bottom:4px">${d.primary} × ${d.secondary}</div>
3070
- <div>TCA: ${tca.toLocaleString()}</div>
3071
- <div style="color:${mdColor}">Miss Distance: ${(_c = d.missDistance) == null ? void 0 : _c.toFixed(3)} km</div>
3072
- ${d.probability !== void 0 ? `<div>Pc: ${(d.probability * 100).toExponential(2)}%</div>` : ""}
3073
- ${d.relativeVelocity ? `<div>Rel. Velocity: ${d.relativeVelocity.toFixed(2)} km/s</div>` : ""}`;
3074
- }
3075
- },
3076
- legend: { show: showProbability, top: 10 },
3077
- grid: { left: 60, right: showProbability ? 80 : 40, top: 50, bottom: 40 },
3078
- xAxis: {
3079
- type: "time",
3080
- name: "Time of Closest Approach",
3081
- ...timeRange ? { min: timeRange[0], max: timeRange[1] } : {}
3082
- },
3083
- yAxis: [
3084
- {
3085
- type: "value",
3086
- name: "Miss Distance (km)",
3087
- min: 0,
3088
- splitLine: { lineStyle: { color: "rgba(100, 116, 139, 0.15)" } }
3089
- },
3090
- {
3091
- type: "log",
3092
- name: showProbability ? "Probability" : void 0,
3093
- position: "right",
3094
- show: showProbability,
3095
- min: 1e-10,
3096
- max: 1,
3097
- axisLabel: { formatter: (v) => v.toExponential(0) },
3098
- splitLine: { show: false }
3099
- }
3100
- ],
3101
- // Threshold marklines
3102
- series: seriesArray.map((s, i) => ({
3103
- ...s,
3104
- ...i === 0 ? {
3105
- markLine: {
3106
- silent: true,
3107
- data: [
3108
- { yAxis: criticalThreshold, label: { formatter: `Critical (${criticalThreshold} km)`, color: STATUS_COLORS.critical }, lineStyle: { color: SOFT_STATUS_COLORS.critical, type: "dashed", width: 1 } },
3109
- { yAxis: warningThreshold, label: { formatter: `Warning (${warningThreshold} km)`, color: STATUS_COLORS.caution }, lineStyle: { color: SOFT_STATUS_COLORS.caution, type: "dashed", width: 1 } }
3110
- ]
3111
- },
3112
- markArea: {
3113
- silent: true,
3114
- data: [[{ yAxis: 0 }, { yAxis: criticalThreshold }]],
3115
- itemStyle: { color: `${STATUS_COLORS.critical}10` }
3116
- }
3117
- } : {}
3118
- }))
3119
- };
3120
- }, [events, timeRange, warningThreshold, criticalThreshold, showProbability, tooltipStyle]);
3121
- return /* @__PURE__ */ jsx(
3122
- AstroChart,
3123
- {
3124
- ref,
3125
- type: "scatter",
3126
- series: [],
3127
- title,
3128
- width,
3129
- height,
3130
- loading,
3131
- className,
3132
- echartsOptions,
3133
- export: exportOptions,
3134
- infoTooltip
3135
- }
3136
- );
3137
- }
3138
- ));
3139
- export {
3140
- AntennaPattern3DChart,
3141
- AttitudeChart,
3142
- AttitudeHistory3DChart,
3143
- Bar3DChart,
3144
- ConjunctionAssessment3DChart,
3145
- ConjunctionChart,
3146
- ConstellationCoverageChart,
3147
- ContactWindowChart,
3148
- DopplerTrackChart,
3149
- EclipseTimelineChart,
3150
- HeliocentricOrbitPlot,
3151
- LaunchCorridor3DChart,
3152
- Lines3DChart,
3153
- LinkBudgetChart,
3154
- LinkMarginChart,
3155
- ManeuverBudgetChart,
3156
- OrbitChart,
3157
- PowerChart,
3158
- RoseDiagram,
3159
- Scatter3DChart,
3160
- SpectrumChart,
3161
- SphericalRadar3DChart,
3162
- SubsystemGauge,
3163
- Surface3DChart,
3164
- ThermalHeatmapChart,
3165
- TransferOrbit3DChart,
3166
- WaterfallChart
3167
- };
3168
- //# sourceMappingURL=domain.js.map