@zendir/ui 0.2.7 → 0.2.9

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.
@@ -217,6 +217,11 @@ export interface GroundTrackMapProps {
217
217
  * `enabled` is the new toggle state.
218
218
  */
219
219
  onLayerChange?: (layerId: string, enabled: boolean) => void;
220
+ /**
221
+ * Show sun and moon position markers on the map.
222
+ * Requires `showTerminator`. Default: true when terminator is enabled.
223
+ */
224
+ showCelestialMarkers?: boolean;
220
225
  }
221
- export declare function GroundTrackMap({ groundTrack, satellites, groundStations, accessMask, teamPaths, showTerminator, terminatorTime, showGrid, showLegend, showEquator, showRecenterButton, showMapStyleToggle, isLoading, emptyMessage, width, height, minHeight, defaultCenter, defaultZoom, className, onSatelliteClick, onStationClick, mapProvider, tileUrl, nightTileUrl, lightSources, pins, pinsEditable, onPinAdd, onPinUpdate, onPinRemove, customLayers, onLayerChange, }: GroundTrackMapProps): React.ReactElement;
226
+ export declare function GroundTrackMap({ groundTrack, satellites, groundStations, accessMask, teamPaths, showTerminator, terminatorTime, showGrid, showLegend, showEquator, showRecenterButton, showMapStyleToggle, isLoading, emptyMessage, width, height, minHeight, defaultCenter, defaultZoom, className, onSatelliteClick, onStationClick, mapProvider, tileUrl, nightTileUrl, lightSources, pins, pinsEditable, onPinAdd, onPinUpdate, onPinRemove, customLayers, onLayerChange, showCelestialMarkers, }: GroundTrackMapProps): React.ReactElement;
222
227
  export default GroundTrackMap;
@@ -78,11 +78,47 @@ function hexToRgb(hex) {
78
78
  }
79
79
  return [255, 238, 221];
80
80
  }
81
+ function calculateSubSolarPoint(date) {
82
+ const dayOfYear = Math.floor((date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 864e5);
83
+ const declination = -23.44 * Math.cos(2 * Math.PI / 365 * (dayOfYear + 10));
84
+ const B = 2 * Math.PI / 365 * (dayOfYear - 81);
85
+ const eotMinutes = 9.87 * Math.sin(2 * B) - 7.53 * Math.cos(B) - 1.5 * Math.sin(B);
86
+ const utcHours = date.getUTCHours() + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600;
87
+ const solarHours = utcHours + eotMinutes / 60;
88
+ const lon = -(solarHours - 12) * 15;
89
+ return [declination, (lon + 540) % 360 - 180];
90
+ }
91
+ function calculateSubLunarPoint(date) {
92
+ const J2000 = Date.UTC(2e3, 0, 1, 12, 0, 0);
93
+ const d = (date.getTime() - J2000) / 864e5;
94
+ const DEG = Math.PI / 180;
95
+ const L = (218.316 + 13.176396 * d) % 360;
96
+ const M = (134.963 + 13.064993 * d) % 360;
97
+ const F = (93.272 + 13.22935 * d) % 360;
98
+ const lon_ecl = L + 6.289 * Math.sin(M * DEG);
99
+ const lat_ecl = 5.128 * Math.sin(F * DEG);
100
+ const obliquity = 23.439 - 36e-8 * d;
101
+ const sinRA = Math.sin(lon_ecl * DEG) * Math.cos(obliquity * DEG) - Math.tan(lat_ecl * DEG) * Math.sin(obliquity * DEG);
102
+ const cosRA = Math.cos(lon_ecl * DEG);
103
+ let RA = Math.atan2(sinRA, cosRA) / DEG;
104
+ if (RA < 0) RA += 360;
105
+ const dec = Math.asin(
106
+ Math.sin(lat_ecl * DEG) * Math.cos(obliquity * DEG) + Math.cos(lat_ecl * DEG) * Math.sin(obliquity * DEG) * Math.sin(lon_ecl * DEG)
107
+ ) / DEG;
108
+ const GMST = (280.46061837 + 360.98564736629 * d) % 360;
109
+ let geoLon = RA - GMST;
110
+ geoLon = (geoLon + 540) % 360 - 180;
111
+ return [dec, geoLon];
112
+ }
81
113
  function calculateTerminatorContinuous(date, depressionDeg = 0, numPoints = 360) {
82
114
  const dayOfYear = Math.floor((date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 864e5);
83
115
  const declination = -23.44 * Math.cos(2 * Math.PI / 365 * (dayOfYear + 10));
84
116
  const decRad = declination * Math.PI / 180;
85
- const hourAngle = (date.getUTCHours() + date.getUTCMinutes() / 60) / 24 * 360 - 180;
117
+ const B = 2 * Math.PI / 365 * (dayOfYear - 81);
118
+ const eotMinutes = 9.87 * Math.sin(2 * B) - 7.53 * Math.cos(B) - 1.5 * Math.sin(B);
119
+ const utcHours = date.getUTCHours() + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600;
120
+ const solarHours = utcHours + eotMinutes / 60;
121
+ const hourAngle = solarHours / 24 * 360 - 180;
86
122
  const depRad = depressionDeg * Math.PI / 180;
87
123
  const sunset = [];
88
124
  const sunrise = [];
@@ -143,7 +179,8 @@ function GroundTrackMap({
143
179
  onPinUpdate,
144
180
  onPinRemove,
145
181
  customLayers,
146
- onLayerChange
182
+ onLayerChange,
183
+ showCelestialMarkers
147
184
  }) {
148
185
  const { tokens } = useTheme();
149
186
  const canvasRef = useRef(null);
@@ -309,6 +346,54 @@ function GroundTrackMap({
309
346
  }
310
347
  ctx.restore();
311
348
  }
349
+ const celestialEnabled = showCelestialMarkers !== void 0 ? showCelestialMarkers : true;
350
+ if (celestialEnabled) {
351
+ const [sunLat, sunLon] = calculateSubSolarPoint(now);
352
+ const sx = lonToX(sunLon, W), sy = latToY(sunLat, H);
353
+ ctx.save();
354
+ ctx.shadowColor = "rgba(255, 179, 0, 0.5)";
355
+ ctx.shadowBlur = 8;
356
+ ctx.fillStyle = "#FFB300";
357
+ ctx.strokeStyle = "#FF8F00";
358
+ ctx.lineWidth = 1.2;
359
+ ctx.beginPath();
360
+ ctx.arc(sx, sy, 6, 0, Math.PI * 2);
361
+ ctx.fill();
362
+ ctx.stroke();
363
+ ctx.shadowBlur = 0;
364
+ ctx.strokeStyle = "rgba(255, 179, 0, 0.85)";
365
+ ctx.lineWidth = 1.4;
366
+ for (let a = 0; a < 360; a += 45) {
367
+ const rad = a * Math.PI / 180;
368
+ ctx.beginPath();
369
+ ctx.moveTo(sx + 8 * Math.cos(rad), sy + 8 * Math.sin(rad));
370
+ ctx.lineTo(sx + 12 * Math.cos(rad), sy + 12 * Math.sin(rad));
371
+ ctx.stroke();
372
+ }
373
+ ctx.restore();
374
+ const [moonLat, moonLon] = calculateSubLunarPoint(now);
375
+ const mx = lonToX(moonLon, W), my = latToY(moonLat, H);
376
+ ctx.save();
377
+ ctx.shadowColor = "rgba(224, 224, 224, 0.4)";
378
+ ctx.shadowBlur = 6;
379
+ ctx.fillStyle = "#e0e0e0";
380
+ ctx.strokeStyle = "#9e9e9e";
381
+ ctx.lineWidth = 0.8;
382
+ ctx.beginPath();
383
+ ctx.arc(mx, my, 5.5, 0, Math.PI * 2);
384
+ ctx.fill();
385
+ ctx.stroke();
386
+ ctx.shadowBlur = 0;
387
+ ctx.fillStyle = "rgba(189, 189, 189, 0.5)";
388
+ ctx.beginPath();
389
+ ctx.arc(mx - 1.5, my - 1, 1.4, 0, Math.PI * 2);
390
+ ctx.fill();
391
+ ctx.fillStyle = "rgba(189, 189, 189, 0.4)";
392
+ ctx.beginPath();
393
+ ctx.arc(mx + 2, my + 1.5, 0.9, 0, Math.PI * 2);
394
+ ctx.fill();
395
+ ctx.restore();
396
+ }
312
397
  }
313
398
  ctx.fillStyle = COLORS.land;
314
399
  ctx.strokeStyle = "rgba(100, 120, 160, 0.25)";
@@ -1015,7 +1100,8 @@ function GroundTrackMap({
1015
1100
  onPinUpdate,
1016
1101
  onPinRemove,
1017
1102
  customLayers,
1018
- onLayerChange
1103
+ onLayerChange,
1104
+ showCelestialMarkers
1019
1105
  }
1020
1106
  )
1021
1107
  }