whycomeimsocool

CALENDAR JS - BACKUP

Jul 26th, 2025 (edited)
8
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 29.84 KB | None | 0 0
  1. // Current date state
  2. let currentMonth = new Date().getMonth(); // 0-based
  3. let currentYear = new Date().getFullYear();
  4.  
  5. // Timezone functionality
  6. let currentTimezoneOffset = -(new Date().getTimezoneOffset() / 60); // Convert to UTC offset
  7.  
  8. // Map quarter number to phase name and symbol
  9. const MOON_PHASES = [
  10. { name: "New Moon", symbol: '<svg> <use href="#moonnew" /> </svg>' },
  11. {
  12. name: "First Quarter",
  13. symbol: '<svg> <use href="#moonfirstquarter" /> </svg>',
  14. },
  15. { name: "Full Moon", symbol: '<svg> <use href="#moonfull" /> </svg>' },
  16. {
  17. name: "Last Quarter",
  18. symbol: '<svg> <use href="#moonlastquarter" /> </svg>',
  19. },
  20. ];
  21.  
  22. // Eclipse symbols by type - customize these as needed
  23. const ECLIPSE_SYMBOLS = {
  24. lunar: {
  25. penumbral: '<svg> <use href="#lunarpenumbral" /> </svg>',
  26. partial: '<svg> <use href="#lunarpartial" /> </svg>',
  27. total: '<svg> <use href="#lunartotal" /> </svg>',
  28. default: '<svg> <use href="#lunardefault" /> </svg>',
  29. },
  30. solar: {
  31. partial: '<svg> <use href="#solarpartial" /> </svg>',
  32. annular: '<svg> <use href="#solarannular" /> </svg>',
  33. total: '<svg> <use href="#solartotal" /> </svg>',
  34. hybrid: '<svg> <use href="#solarhybrid" /> </svg>',
  35. default: '<svg> <use href="#solardefault" /> </svg>',
  36. },
  37. };
  38.  
  39. // Location and astronomy functionality
  40. let currentLocation = { lat: 0, lon: 0, isUTC: true }; // Default to UTC (lat/lon 0,0)
  41.  
  42. function updateTimezoneDisplay() {
  43. const display = document.getElementById("timezoneDisplay");
  44. const sign = currentTimezoneOffset >= 0 ? "+" : "";
  45. display.textContent = `UTC${sign}${currentTimezoneOffset}`;
  46. }
  47.  
  48. function adjustTimezone(direction) {
  49. const newOffset = currentTimezoneOffset + direction;
  50.  
  51. // Limit timezone offset to valid range: -12 to +14
  52. if (newOffset >= -12 && newOffset <= 14) {
  53. currentTimezoneOffset = newOffset;
  54. updateTimezoneDisplay();
  55. renderCalendar();
  56. }
  57. }
  58.  
  59. // Helper function to convert UTC time to selected timezone
  60. function convertToSelectedTimezone(utcDate) {
  61. // Apply the timezone offset
  62. const adjustment = currentTimezoneOffset * 60 * 60 * 1000;
  63. const adjustedTimestamp = utcDate.getTime() + adjustment;
  64. const adjustedDate = new Date(adjustedTimestamp);
  65.  
  66. // Use UTC methods to get the correct date parts
  67. const result = {
  68. day: adjustedDate.getUTCDate(),
  69. month: adjustedDate.getUTCMonth(),
  70. year: adjustedDate.getUTCFullYear(),
  71. timestamp: adjustedTimestamp,
  72. originalDate: adjustedDate,
  73. };
  74.  
  75. return result;
  76. }
  77.  
  78. // Add this function to trigger the fade animation
  79. function triggerCalendarFade() {
  80. const calendarWrapper = document.querySelector(".calendar-wrapper");
  81.  
  82. // Remove the class if it exists (to restart animation)
  83. calendarWrapper.classList.remove("fade-in");
  84.  
  85. // Force a reflow to ensure the class removal is processed
  86. calendarWrapper.offsetHeight;
  87.  
  88. // Add the class to trigger the animation
  89. calendarWrapper.classList.add("fade-in");
  90. }
  91.  
  92. // Find all principal moon phases in the given month
  93. function getPrincipalMoonPhasesLocal(year, month) {
  94. const phases = [];
  95.  
  96. // Search a wider range to catch moon phases that might appear in different days due to timezone
  97. const searchStartUTC = new Date(Date.UTC(year, month, 1, 0, 0, 0));
  98. searchStartUTC.setUTCDate(searchStartUTC.getUTCDate() - 2);
  99.  
  100. const searchEndUTC = new Date(Date.UTC(year, month + 1, 0, 23, 59, 59));
  101. searchEndUTC.setUTCDate(searchEndUTC.getUTCDate() + 2);
  102.  
  103. try {
  104. let q = Astronomy.SearchMoonQuarter(searchStartUTC);
  105. let iterations = 0;
  106. const maxIterations = 50;
  107.  
  108. while (q && iterations < maxIterations) {
  109. const phaseUTC = q.time.date;
  110.  
  111. // Stop searching if we're way past our end date
  112. if (phaseUTC > searchEndUTC) {
  113. break;
  114. }
  115.  
  116. // Use the corrected conversion approach
  117. const phaseConverted = convertToSelectedTimezone(phaseUTC);
  118.  
  119. // Check if moon phase falls in target month
  120. if (phaseConverted.year === year && phaseConverted.month === month) {
  121. const phaseData = {
  122. day: phaseConverted.day,
  123. month: phaseConverted.month + 1,
  124. year: phaseConverted.year,
  125. quarter: q.quarter,
  126. name: MOON_PHASES[q.quarter].name,
  127. symbol: MOON_PHASES[q.quarter].symbol,
  128. exactTime: phaseConverted.originalDate,
  129. };
  130.  
  131. phases.push(phaseData);
  132. }
  133.  
  134. try {
  135. q = Astronomy.NextMoonQuarter(q);
  136. } catch (e) {
  137. break;
  138. }
  139. iterations++;
  140. }
  141. } catch (e) {
  142. console.warn("Error finding moon phases:", e);
  143. }
  144.  
  145. return phases;
  146. }
  147.  
  148. // Find solar eclipses in the given month
  149. function getSolarEclipsesLocal(year, month) {
  150. const eclipses = [];
  151.  
  152. // Search a wider range
  153. const searchStartUTC = new Date(Date.UTC(year, month, 1, 0, 0, 0));
  154. searchStartUTC.setUTCDate(searchStartUTC.getUTCDate() - 2);
  155.  
  156. const searchEndUTC = new Date(Date.UTC(year, month + 1, 0, 23, 59, 59));
  157. searchEndUTC.setUTCDate(searchEndUTC.getUTCDate() + 2);
  158.  
  159. try {
  160. let eclipse = Astronomy.SearchGlobalSolarEclipse(searchStartUTC);
  161. let iterations = 0;
  162. const maxIterations = 50;
  163.  
  164. while (eclipse && iterations < maxIterations) {
  165. const eclipseUTC = eclipse.peak.date;
  166.  
  167. if (eclipseUTC > searchEndUTC) {
  168. break;
  169. }
  170.  
  171. // Use the corrected conversion approach
  172. const eclipseConverted = convertToSelectedTimezone(eclipseUTC);
  173.  
  174. // Check if eclipse falls in target month
  175. if (eclipseConverted.year === year && eclipseConverted.month === month) {
  176. let typeDescription = "";
  177. switch (eclipse.kind) {
  178. case "partial":
  179. typeDescription = "Partial Solar Eclipse";
  180. break;
  181. case "annular":
  182. typeDescription = "Annular Solar Eclipse";
  183. break;
  184. case "total":
  185. typeDescription = "Total Solar Eclipse";
  186. break;
  187. case "hybrid":
  188. typeDescription = "Hybrid Solar Eclipse";
  189. break;
  190. default:
  191. typeDescription = "Solar Eclipse";
  192. }
  193.  
  194. const eclipseData = {
  195. day: eclipseConverted.day,
  196. month: eclipseConverted.month + 1,
  197. year: eclipseConverted.year,
  198. type: "solar",
  199. kind: eclipse.kind,
  200. description: typeDescription,
  201. exactTime: eclipseConverted.originalDate,
  202. };
  203.  
  204. eclipses.push(eclipseData);
  205. }
  206.  
  207. try {
  208. eclipse = Astronomy.NextGlobalSolarEclipse(eclipse.peak);
  209. } catch (e) {
  210. break;
  211. }
  212. iterations++;
  213. }
  214. } catch (e) {
  215. console.warn("Error finding solar eclipses:", e);
  216. }
  217.  
  218. return eclipses;
  219. }
  220.  
  221. // Find lunar eclipses in the given month
  222. function getLunarEclipsesLocal(year, month) {
  223. const eclipses = [];
  224.  
  225. // Search a wider range
  226. const searchStartUTC = new Date(Date.UTC(year, month, 1, 0, 0, 0));
  227. searchStartUTC.setUTCDate(searchStartUTC.getUTCDate() - 2);
  228.  
  229. const searchEndUTC = new Date(Date.UTC(year, month + 1, 0, 23, 59, 59));
  230. searchEndUTC.setUTCDate(searchEndUTC.getUTCDate() + 2);
  231.  
  232. try {
  233. let eclipse = Astronomy.SearchLunarEclipse(searchStartUTC);
  234. let iterations = 0;
  235. const maxIterations = 50;
  236.  
  237. while (eclipse && iterations < maxIterations) {
  238. const eclipseUTC = eclipse.peak.date;
  239.  
  240. if (eclipseUTC > searchEndUTC) {
  241. break;
  242. }
  243.  
  244. // Use the corrected conversion approach
  245. const eclipseConverted = convertToSelectedTimezone(eclipseUTC);
  246.  
  247. // Check if eclipse falls in target month
  248. if (eclipseConverted.year === year && eclipseConverted.month === month) {
  249. let typeDescription = "";
  250. switch (eclipse.kind) {
  251. case "penumbral":
  252. typeDescription = "Penumbral Lunar Eclipse";
  253. break;
  254. case "partial":
  255. typeDescription = "Partial Lunar Eclipse";
  256. break;
  257. case "total":
  258. typeDescription = "Total Lunar Eclipse";
  259. break;
  260. default:
  261. typeDescription = "Lunar Eclipse";
  262. }
  263.  
  264. const eclipseData = {
  265. day: eclipseConverted.day,
  266. month: eclipseConverted.month + 1,
  267. year: eclipseConverted.year,
  268. type: "lunar",
  269. kind: eclipse.kind,
  270. description: typeDescription,
  271. exactTime: eclipseConverted.originalDate,
  272. };
  273.  
  274. eclipses.push(eclipseData);
  275. }
  276.  
  277. try {
  278. eclipse = Astronomy.NextLunarEclipse(eclipse.peak);
  279. } catch (e) {
  280. break;
  281. }
  282. iterations++;
  283. }
  284. } catch (e) {
  285. console.warn("Error finding lunar eclipses:", e);
  286. }
  287.  
  288. return eclipses;
  289. }
  290.  
  291. function renderCalendar() {
  292. const monthNames = [
  293. "January",
  294. "February",
  295. "March",
  296. "April",
  297. "May",
  298. "June",
  299. "July",
  300. "August",
  301. "September",
  302. "October",
  303. "November",
  304. "December",
  305. ];
  306.  
  307. document.getElementById("monthYear").textContent = `${monthNames[currentMonth]} ${currentYear}`;
  308.  
  309. const firstDay = new Date(currentYear, currentMonth, 1).getDay();
  310. const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate();
  311.  
  312. // Get all principal phases for this month (in selected timezone)
  313. const phases = getPrincipalMoonPhasesLocal(currentYear, currentMonth);
  314. // Map day -> phase info
  315. const phaseByDay = {};
  316. for (const p of phases) {
  317. phaseByDay[p.day] = p;
  318. }
  319.  
  320. // Get eclipses for this month
  321. const solarEclipses = getSolarEclipsesLocal(currentYear, currentMonth);
  322. const lunarEclipses = getLunarEclipsesLocal(currentYear, currentMonth);
  323. const allEclipses = [...solarEclipses, ...lunarEclipses];
  324.  
  325. // Map day -> eclipse info
  326. const eclipseByDay = {};
  327. for (const e of allEclipses) {
  328. if (!eclipseByDay[e.day]) {
  329. eclipseByDay[e.day] = [];
  330. }
  331. eclipseByDay[e.day].push(e);
  332. }
  333.  
  334. let date = 1;
  335. const calendarBody = document.getElementById("calendarBody");
  336. calendarBody.innerHTML = "";
  337.  
  338. for (let i = 0; i < 6; i++) {
  339. const row = document.createElement("tr");
  340.  
  341. for (let j = 0; j < 7; j++) {
  342. const cell = document.createElement("td");
  343.  
  344. if (i === 0 && j < firstDay) {
  345. cell.textContent = "";
  346. } else if (date > daysInMonth) {
  347. cell.textContent = "";
  348. } else {
  349. let cellContent = `<div><strong>${date}</strong>`;
  350.  
  351. // Add moon phase if present
  352. if (phaseByDay[date]) {
  353. const { name, symbol } = phaseByDay[date];
  354. cellContent += `<span class="moon" data-phase="${name}" title="${name}">${symbol}</span></div>`;
  355.  
  356. // Add eclipses if present on the same day as moon phase
  357. if (eclipseByDay[date]) {
  358. for (const eclipse of eclipseByDay[date]) {
  359. const eclipseSymbol =
  360. ECLIPSE_SYMBOLS[eclipse.type][eclipse.kind] || ECLIPSE_SYMBOLS[eclipse.type].default;
  361. const eclipseClass = eclipse.type === "solar" ? "solar-eclipse" : "lunar-eclipse";
  362. const tooltipClass =
  363. eclipse.type === "solar" ? "solar-eclipse-tooltip" : "lunar-eclipse-tooltip";
  364.  
  365. cellContent += `<span class="${eclipseClass}" title="${eclipse.description}">${eclipseSymbol}<span class="${tooltipClass}">${eclipse.description}</span></span>`;
  366. }
  367. }
  368. } else if (eclipseByDay[date]) {
  369. // Add eclipses if present but no moon phase
  370. for (const eclipse of eclipseByDay[date]) {
  371. const eclipseSymbol =
  372. ECLIPSE_SYMBOLS[eclipse.type][eclipse.kind] || ECLIPSE_SYMBOLS[eclipse.type].default;
  373. const eclipseClass = eclipse.type === "solar" ? "solar-eclipse" : "lunar-eclipse";
  374. const tooltipClass =
  375. eclipse.type === "solar" ? "solar-eclipse-tooltip" : "lunar-eclipse-tooltip";
  376.  
  377. cellContent += `<span class="${eclipseClass}" title="${eclipse.description}">${eclipseSymbol}<span class="${tooltipClass}">${eclipse.description}</span></span>`;
  378. }
  379. }
  380.  
  381. cell.innerHTML = cellContent;
  382. date++;
  383. }
  384.  
  385. row.appendChild(cell);
  386. }
  387.  
  388. calendarBody.appendChild(row);
  389.  
  390. if (date > daysInMonth) break;
  391. }
  392.  
  393. // Apply hemisphere setting to the newly rendered calendar
  394. handleHemisphereChange();
  395.  
  396. // Trigger the fade animation
  397. triggerCalendarFade();
  398.  
  399. // Apply current toggle states
  400. document.getElementById("moonPhasesToggle").dispatchEvent(new Event("change"));
  401. document.getElementById("lunarEclipsesToggle").dispatchEvent(new Event("change"));
  402. document.getElementById("solarEclipsesToggle").dispatchEvent(new Event("change"));
  403. }
  404.  
  405. function handleHemisphereChange() {
  406. const isNorth = document.getElementById("northRadio").checked;
  407.  
  408. // Get all moon symbols
  409. const moonElements = document.querySelectorAll(".moon[data-phase]");
  410.  
  411. moonElements.forEach((moon) => {
  412. const phase = moon.getAttribute("data-phase");
  413.  
  414. if (phase === "First Quarter") {
  415. moon.innerHTML = isNorth ? MOON_PHASES[1].symbol : MOON_PHASES[3].symbol;
  416. } else if (phase === "Last Quarter") {
  417. moon.innerHTML = isNorth ? MOON_PHASES[3].symbol : MOON_PHASES[1].symbol;
  418. }
  419. // New Moon and Full Moon remain unchanged
  420. });
  421.  
  422. // Update legend symbols as well
  423. const legendFirstQuarter = document.getElementById("legend-first-quarter");
  424. const legendLastQuarter = document.getElementById("legend-last-quarter");
  425.  
  426. if (legendFirstQuarter) {
  427. legendFirstQuarter.innerHTML = isNorth ? MOON_PHASES[1].symbol : MOON_PHASES[3].symbol;
  428. }
  429. if (legendLastQuarter) {
  430. legendLastQuarter.innerHTML = isNorth ? MOON_PHASES[3].symbol : MOON_PHASES[1].symbol;
  431. }
  432. }
  433.  
  434. function requestPreciseLocation() {
  435. const btn = document.getElementById("preciseLocationBtn");
  436. const status = document.getElementById("locationStatus");
  437.  
  438. if (!navigator.geolocation) {
  439. updateLocationStatus("error", "Geolocation is not supported by this browser.");
  440. return;
  441. }
  442.  
  443. // Update UI to show we're requesting location
  444. btn.disabled = true;
  445. btn.textContent = "🔍 Getting Location...";
  446. updateLocationStatus("info", "Requesting your location...");
  447.  
  448. navigator.geolocation.getCurrentPosition(
  449. function (position) {
  450. // Success!
  451. currentLocation = {
  452. lat: position.coords.latitude,
  453. lon: position.coords.longitude,
  454. isUTC: false,
  455. accuracy: position.coords.accuracy,
  456. };
  457.  
  458. // Update UI
  459. btn.textContent = "✅ Location Set";
  460. btn.disabled = false;
  461.  
  462. const accuracy = Math.round(position.coords.accuracy);
  463. updateLocationStatus("success", `Location set! Accuracy: ±${accuracy}m. Times are now location-specific.`);
  464.  
  465. // Show coordinates
  466. const coordsDisplay = document.getElementById("coordinatesDisplay");
  467. if (coordsDisplay) {
  468. coordsDisplay.textContent = `Coordinates: ${currentLocation.lat.toFixed(
  469. 4
  470. )}°, ${currentLocation.lon.toFixed(4)}°`;
  471. }
  472.  
  473. // Recalculate times with precise location
  474. calculateSunMoonTimes();
  475. },
  476. function (error) {
  477. // Error handling
  478. let errorMsg = "Location request failed: ";
  479. switch (error.code) {
  480. case error.PERMISSION_DENIED:
  481. errorMsg += "Permission denied. You can still use UTC times.";
  482. break;
  483. case error.POSITION_UNAVAILABLE:
  484. errorMsg += "Location unavailable. Using UTC times.";
  485. break;
  486. case error.TIMEOUT:
  487. errorMsg += "Request timed out. Using UTC times.";
  488. break;
  489. default:
  490. errorMsg += "Unknown error. Using UTC times.";
  491. break;
  492. }
  493.  
  494. updateLocationStatus("warning", errorMsg);
  495. btn.textContent = "📍 Try Again";
  496. btn.disabled = false;
  497. },
  498. {
  499. enableHighAccuracy: true,
  500. timeout: 10000,
  501. maximumAge: 600000, // Cache for 10 minutes
  502. }
  503. );
  504. }
  505.  
  506. function updateLocationStatus(type, message) {
  507. const status = document.getElementById("locationStatus");
  508. if (status) {
  509. status.className = `location-status status-${type}`;
  510. status.textContent = message;
  511. }
  512. }
  513.  
  514. function calculateSunMoonTimes() {
  515. console.log("calculateSunMoonTimes called");
  516.  
  517. // Make sure Astronomy library is loaded
  518. if (typeof Astronomy === "undefined") {
  519. console.error("Astronomy library not loaded");
  520. return;
  521. }
  522.  
  523. console.log("Astronomy library is loaded, currentLocation:", currentLocation);
  524.  
  525. const today = new Date();
  526. console.log("Today:", today);
  527.  
  528. try {
  529. const observer = new Astronomy.Observer(currentLocation.lat, currentLocation.lon, 0);
  530. console.log("Observer created:", observer);
  531.  
  532. // Check what Direction constants are available
  533. console.log("Available Astronomy constants:", Object.keys(Astronomy));
  534.  
  535. // Try different ways to access Direction constants
  536. let riseDirection, setDirection;
  537.  
  538. if (Astronomy.Direction) {
  539. console.log("Direction object:", Astronomy.Direction);
  540. riseDirection = Astronomy.Direction.Rise;
  541. setDirection = Astronomy.Direction.Set;
  542. } else {
  543. // Try direct constants
  544. riseDirection = Astronomy.Rise || 1;
  545. setDirection = Astronomy.Set || -1;
  546. }
  547.  
  548. console.log("Rise direction:", riseDirection, "Set direction:", setDirection);
  549.  
  550. // Calculate sunrise/sunset
  551. console.log("Calculating sunrise...");
  552. const sunrise = Astronomy.SearchRiseSet(Astronomy.Body.Sun, observer, riseDirection, today, 1);
  553. console.log("Sunrise result:", sunrise);
  554.  
  555. console.log("Calculating sunset...");
  556. const sunset = Astronomy.SearchRiseSet(Astronomy.Body.Sun, observer, setDirection, today, 1);
  557. console.log("Sunset result:", sunset);
  558.  
  559. // Calculate moonrise/moonset
  560. console.log("Calculating moonrise...");
  561. const moonrise = Astronomy.SearchRiseSet(Astronomy.Body.Moon, observer, riseDirection, today, 1);
  562. console.log("Moonrise result:", moonrise);
  563.  
  564. console.log("Calculating moonset...");
  565. const moonset = Astronomy.SearchRiseSet(Astronomy.Body.Moon, observer, setDirection, today, 1);
  566. console.log("Moonset result:", moonset);
  567.  
  568. // Update the horizontal bar display
  569. const sunriseEl = document.getElementById("sunriseTime");
  570. const sunsetEl = document.getElementById("sunsetTime");
  571. const moonriseEl = document.getElementById("moonriseTime");
  572. const moonsetEl = document.getElementById("moonsetTime");
  573.  
  574. if (sunriseEl) sunriseEl.textContent = sunrise ? formatTime(sunrise.date) : "None";
  575. if (sunsetEl) sunsetEl.textContent = sunset ? formatTime(sunset.date) : "None";
  576. if (moonriseEl) moonriseEl.textContent = moonrise ? formatTime(moonrise.date) : "None";
  577. if (moonsetEl) moonsetEl.textContent = moonset ? formatTime(moonset.date) : "None";
  578.  
  579. // Update timezone note in the bar
  580. const timezoneNote = document.getElementById("timezoneNote");
  581. if (timezoneNote) {
  582. if (currentLocation.isUTC) {
  583. timezoneNote.textContent = "UTC Times";
  584. } else {
  585. timezoneNote.textContent = `Local Times (${currentLocation.lat.toFixed(
  586. 1
  587. )}°, ${currentLocation.lon.toFixed(1)}°)`;
  588. }
  589. }
  590. } catch (error) {
  591. console.error("Detailed astronomy calculation error:", error);
  592. console.error("Error stack:", error.stack);
  593.  
  594. // Show error in horizontal bar
  595. const sunriseEl = document.getElementById("sunriseTime");
  596. const sunsetEl = document.getElementById("sunsetTime");
  597. const moonriseEl = document.getElementById("moonriseTime");
  598. const moonsetEl = document.getElementById("moonsetTime");
  599.  
  600. if (sunriseEl) sunriseEl.textContent = "Error";
  601. if (sunsetEl) sunsetEl.textContent = "Error";
  602. if (moonriseEl) moonriseEl.textContent = "Error";
  603. if (moonsetEl) moonsetEl.textContent = "Error";
  604. }
  605. }
  606.  
  607. // Alternative approach if the above doesn't work
  608. function calculateSunMoonTimesAlternative() {
  609. console.log("calculateSunMoonTimesAlternative called");
  610.  
  611. if (typeof Astronomy === "undefined") {
  612. console.error("Astronomy library not loaded");
  613. return;
  614. }
  615.  
  616. const today = new Date();
  617.  
  618. try {
  619. const observer = new Astronomy.Observer(currentLocation.lat, currentLocation.lon, 0);
  620.  
  621. // Try using numeric constants directly (common in some versions)
  622. // 1 = Rise, -1 = Set (or vice versa depending on library version)
  623.  
  624. console.log("Trying with numeric direction constants...");
  625.  
  626. let sunrise, sunset, moonrise, moonset;
  627.  
  628. try {
  629. sunrise = Astronomy.SearchRiseSet(Astronomy.Body.Sun, observer, 1, today, 1);
  630. sunset = Astronomy.SearchRiseSet(Astronomy.Body.Sun, observer, -1, today, 1);
  631. moonrise = Astronomy.SearchRiseSet(Astronomy.Body.Moon, observer, 1, today, 1);
  632. moonset = Astronomy.SearchRiseSet(Astronomy.Body.Moon, observer, -1, today, 1);
  633. } catch (e1) {
  634. console.log("Trying reversed numeric constants...");
  635. // Try reversed if the first attempt fails
  636. sunrise = Astronomy.SearchRiseSet(Astronomy.Body.Sun, observer, -1, today, 1);
  637. sunset = Astronomy.SearchRiseSet(Astronomy.Body.Sun, observer, 1, today, 1);
  638. moonrise = Astronomy.SearchRiseSet(Astronomy.Body.Moon, observer, -1, today, 1);
  639. moonset = Astronomy.SearchRiseSet(Astronomy.Body.Moon, observer, 1, today, 1);
  640. }
  641.  
  642. // Update display
  643. const sunriseEl = document.getElementById("sunriseTime");
  644. const sunsetEl = document.getElementById("sunsetTime");
  645. const moonriseEl = document.getElementById("moonriseTime");
  646. const moonsetEl = document.getElementById("moonsetTime");
  647.  
  648. if (sunriseEl) sunriseEl.textContent = sunrise ? formatTime(sunrise.date) : "None";
  649. if (sunsetEl) sunsetEl.textContent = sunset ? formatTime(sunset.date) : "None";
  650. if (moonriseEl) moonriseEl.textContent = moonrise ? formatTime(moonrise.date) : "None";
  651. if (moonsetEl) moonsetEl.textContent = moonset ? formatTime(moonset.date) : "None";
  652.  
  653. const timezoneNote = document.getElementById("timezoneNote");
  654. if (timezoneNote) {
  655. if (currentLocation.isUTC) {
  656. timezoneNote.textContent = "UTC Times";
  657. } else {
  658. timezoneNote.textContent = `Local Times (${currentLocation.lat.toFixed(
  659. 1
  660. )}°, ${currentLocation.lon.toFixed(1)}°)`;
  661. }
  662. }
  663.  
  664. console.log("Alternative calculation completed successfully");
  665. } catch (error) {
  666. console.error("Alternative calculation failed:", error);
  667.  
  668. // Show error in display
  669. ["sunriseTime", "sunsetTime", "moonriseTime", "moonsetTime"].forEach((id) => {
  670. const el = document.getElementById(id);
  671. if (el) el.textContent = "Error";
  672. });
  673. }
  674. }
  675.  
  676. function formatTime(date) {
  677. // Format as HH:MM UTC
  678. return date.toISOString().substr(11, 5) + " UTC";
  679. }
  680.  
  681. function initCalendar() {
  682. // Initialize timezone display
  683. updateTimezoneDisplay();
  684.  
  685. renderCalendar();
  686.  
  687. // Add event listeners for navigation
  688. document.getElementById("yearPrev").addEventListener("click", () => {
  689. currentYear--;
  690. renderCalendar();
  691. });
  692.  
  693. document.getElementById("yearNext").addEventListener("click", () => {
  694. currentYear++;
  695. renderCalendar();
  696. });
  697.  
  698. document.getElementById("monthPrev").addEventListener("click", () => {
  699. currentMonth--;
  700. if (currentMonth < 0) {
  701. currentMonth = 11;
  702. currentYear--;
  703. }
  704. renderCalendar();
  705. });
  706.  
  707. document.getElementById("monthNext").addEventListener("click", () => {
  708. currentMonth++;
  709. if (currentMonth > 11) {
  710. currentMonth = 0;
  711. currentYear++;
  712. }
  713. renderCalendar();
  714. });
  715.  
  716. document.getElementById("resetButton").addEventListener("click", () => {
  717. const now = new Date();
  718. currentMonth = now.getMonth();
  719. currentYear = now.getFullYear();
  720. renderCalendar();
  721. });
  722.  
  723. // Timezone control event listeners
  724. document.getElementById("timezonePrev").addEventListener("click", () => adjustTimezone(-1));
  725. document.getElementById("timezoneNext").addEventListener("click", () => adjustTimezone(1));
  726.  
  727. // Timezone reset button
  728. document.getElementById("timezoneResetButton").addEventListener("click", () => {
  729. currentTimezoneOffset = -(new Date().getTimezoneOffset() / 60);
  730. updateTimezoneDisplay();
  731. renderCalendar();
  732. });
  733.  
  734. // Hemisphere change listeners
  735. document.getElementById("northRadio").addEventListener("change", handleHemisphereChange);
  736. document.getElementById("southRadio").addEventListener("change", handleHemisphereChange);
  737.  
  738. // Set up the precise location button
  739. const preciseLocationBtn = document.getElementById("preciseLocationBtn");
  740. if (preciseLocationBtn) {
  741. preciseLocationBtn.addEventListener("click", requestPreciseLocation);
  742. }
  743.  
  744. // Calculate initial UTC times
  745. calculateSunMoonTimes();
  746. }
  747.  
  748. initCalendar();
  749.  
  750. // Toggle visibility functionality
  751. document.getElementById("moonPhasesToggle").addEventListener("change", function () {
  752. const calendarWrapper = document.querySelector(".calendar-wrapper");
  753. const moonElements = document.querySelectorAll(".calendar-wrapper .moon");
  754. const eclipseElements = document.querySelectorAll(
  755. ".calendar-wrapper .solar-eclipse, .calendar-wrapper .lunar-eclipse"
  756. );
  757.  
  758. if (this.checked) {
  759. // Show moon phases
  760. calendarWrapper.classList.remove("moon-phases-hidden");
  761. moonElements.forEach((el) => {
  762. el.style.display = "block";
  763. el.classList.add("fade-in");
  764. });
  765. // Re-trigger fade-in for eclipses as they move down
  766. eclipseElements.forEach((el) => {
  767. el.classList.remove("fade-in");
  768. // Force reflow
  769. el.offsetHeight;
  770. el.classList.add("fade-in");
  771. });
  772. } else {
  773. // Hide moon phases
  774. calendarWrapper.classList.add("moon-phases-hidden");
  775. moonElements.forEach((el) => {
  776. el.style.display = "none";
  777. el.classList.remove("fade-in");
  778. });
  779. // Re-trigger fade-in for eclipses as they move up
  780. eclipseElements.forEach((el) => {
  781. el.classList.remove("fade-in");
  782. // Force reflow
  783. el.offsetHeight;
  784. el.classList.add("fade-in");
  785. });
  786. }
  787. });
  788.  
  789. document.getElementById("lunarEclipsesToggle").addEventListener("change", function () {
  790. const lunarEclipses = document.querySelectorAll(".calendar-wrapper .lunar-eclipse");
  791. lunarEclipses.forEach((el) => {
  792. if (this.checked) {
  793. el.style.display = "inline";
  794. el.classList.add("fade-in");
  795. } else {
  796. el.style.display = "none";
  797. el.classList.remove("fade-in");
  798. }
  799. });
  800. });
  801.  
  802. document.getElementById("solarEclipsesToggle").addEventListener("change", function () {
  803. const solarEclipses = document.querySelectorAll(".calendar-wrapper .solar-eclipse");
  804. solarEclipses.forEach((el) => {
  805. if (this.checked) {
  806. el.style.display = "inline";
  807. el.classList.add("fade-in");
  808. } else {
  809. el.style.display = "none";
  810. el.classList.remove("fade-in");
  811. }
  812. });
  813. });
  814.  
Advertisement
Add Comment
Please, Sign In to add comment