whycomeimsocool

CALENDAR JS - CURRENT

Jul 26th, 2025 (edited)
7
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.50 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(
  308. "monthYear"
  309. ).textContent = `${monthNames[currentMonth]} ${currentYear}`;
  310.  
  311. const firstDay = new Date(currentYear, currentMonth, 1).getDay();
  312. const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate();
  313.  
  314. // Get all principal phases for this month (in selected timezone)
  315. const phases = getPrincipalMoonPhasesLocal(currentYear, currentMonth);
  316. // Map day -> phase info
  317. const phaseByDay = {};
  318. for (const p of phases) {
  319. phaseByDay[p.day] = p;
  320. }
  321.  
  322. // Get eclipses for this month
  323. const solarEclipses = getSolarEclipsesLocal(currentYear, currentMonth);
  324. const lunarEclipses = getLunarEclipsesLocal(currentYear, currentMonth);
  325. const allEclipses = [...solarEclipses, ...lunarEclipses];
  326.  
  327. // Map day -> eclipse info
  328. const eclipseByDay = {};
  329. for (const e of allEclipses) {
  330. if (!eclipseByDay[e.day]) {
  331. eclipseByDay[e.day] = [];
  332. }
  333. eclipseByDay[e.day].push(e);
  334. }
  335.  
  336. let date = 1;
  337. const calendarBody = document.getElementById("calendarBody");
  338. calendarBody.innerHTML = "";
  339.  
  340. for (let i = 0; i < 6; i++) {
  341. const row = document.createElement("tr");
  342.  
  343. for (let j = 0; j < 7; j++) {
  344. const cell = document.createElement("td");
  345.  
  346. if (i === 0 && j < firstDay) {
  347. cell.textContent = "";
  348. } else if (date > daysInMonth) {
  349. cell.textContent = "";
  350. } else {
  351. let cellContent = `<div><strong>${date}</strong>`;
  352.  
  353. // Add moon phase if present
  354. if (phaseByDay[date]) {
  355. const { name, symbol } = phaseByDay[date];
  356. cellContent += `<span class="moon" data-phase="${name}" title="${name}">${symbol}</span></div>`;
  357.  
  358. // Add eclipses if present on the same day as moon phase
  359. if (eclipseByDay[date]) {
  360. for (const eclipse of eclipseByDay[date]) {
  361. const eclipseSymbol =
  362. ECLIPSE_SYMBOLS[eclipse.type][eclipse.kind] ||
  363. ECLIPSE_SYMBOLS[eclipse.type].default;
  364. const eclipseClass =
  365. eclipse.type === "solar" ? "solar-eclipse" : "lunar-eclipse";
  366. const tooltipClass =
  367. eclipse.type === "solar"
  368. ? "solar-eclipse-tooltip"
  369. : "lunar-eclipse-tooltip";
  370.  
  371. cellContent += `<span class="${eclipseClass}" title="${eclipse.description}">${eclipseSymbol}<span class="${tooltipClass}">${eclipse.description}</span></span>`;
  372. }
  373. }
  374. } else if (eclipseByDay[date]) {
  375. // Add eclipses if present but no moon phase
  376. for (const eclipse of eclipseByDay[date]) {
  377. const eclipseSymbol =
  378. ECLIPSE_SYMBOLS[eclipse.type][eclipse.kind] ||
  379. ECLIPSE_SYMBOLS[eclipse.type].default;
  380. const eclipseClass =
  381. eclipse.type === "solar" ? "solar-eclipse" : "lunar-eclipse";
  382. const tooltipClass =
  383. eclipse.type === "solar"
  384. ? "solar-eclipse-tooltip"
  385. : "lunar-eclipse-tooltip";
  386.  
  387. cellContent += `<span class="${eclipseClass}" title="${eclipse.description}">${eclipseSymbol}<span class="${tooltipClass}">${eclipse.description}</span></span>`;
  388. }
  389. }
  390.  
  391. cell.innerHTML = cellContent;
  392. date++;
  393. }
  394.  
  395. row.appendChild(cell);
  396. }
  397.  
  398. calendarBody.appendChild(row);
  399.  
  400. if (date > daysInMonth) break;
  401. }
  402.  
  403. // Apply hemisphere setting to the newly rendered calendar
  404. handleHemisphereChange();
  405.  
  406. // Trigger the fade animation
  407. triggerCalendarFade();
  408.  
  409. // Apply current toggle states
  410. document
  411. .getElementById("moonPhasesToggle")
  412. .dispatchEvent(new Event("change"));
  413. document
  414. .getElementById("lunarEclipsesToggle")
  415. .dispatchEvent(new Event("change"));
  416. document
  417. .getElementById("solarEclipsesToggle")
  418. .dispatchEvent(new Event("change"));
  419. }
  420.  
  421. function handleHemisphereChange() {
  422. const isNorth = document.getElementById("northRadio").checked;
  423.  
  424. // Get all moon symbols
  425. const moonElements = document.querySelectorAll(".moon[data-phase]");
  426.  
  427. moonElements.forEach((moon) => {
  428. const phase = moon.getAttribute("data-phase");
  429.  
  430. if (phase === "First Quarter") {
  431. moon.innerHTML = isNorth ? MOON_PHASES[1].symbol : MOON_PHASES[3].symbol;
  432. } else if (phase === "Last Quarter") {
  433. moon.innerHTML = isNorth ? MOON_PHASES[3].symbol : MOON_PHASES[1].symbol;
  434. }
  435. // New Moon and Full Moon remain unchanged
  436. });
  437.  
  438. // Update legend symbols as well
  439. const legendFirstQuarter = document.getElementById("legend-first-quarter");
  440. const legendLastQuarter = document.getElementById("legend-last-quarter");
  441.  
  442. if (legendFirstQuarter) {
  443. legendFirstQuarter.innerHTML = isNorth
  444. ? MOON_PHASES[1].symbol
  445. : MOON_PHASES[3].symbol;
  446. }
  447. if (legendLastQuarter) {
  448. legendLastQuarter.innerHTML = isNorth
  449. ? MOON_PHASES[3].symbol
  450. : MOON_PHASES[1].symbol;
  451. }
  452. }
  453.  
  454. function requestPreciseLocation() {
  455. const btn = document.getElementById("preciseLocationBtn");
  456. const status = document.getElementById("locationStatus");
  457.  
  458. if (!navigator.geolocation) {
  459. updateLocationStatus(
  460. "error",
  461. "Geolocation is not supported by this browser."
  462. );
  463. return;
  464. }
  465.  
  466. // Update UI to show we're requesting location
  467. btn.disabled = true;
  468. btn.textContent = "🔍 Getting Location...";
  469. updateLocationStatus("info", "Requesting your location...");
  470.  
  471. navigator.geolocation.getCurrentPosition(
  472. function (position) {
  473. // Success!
  474. currentLocation = {
  475. lat: position.coords.latitude,
  476. lon: position.coords.longitude,
  477. isUTC: false,
  478. accuracy: position.coords.accuracy,
  479. };
  480.  
  481. // Update UI
  482. btn.textContent = "✅ Location Set";
  483. btn.disabled = false;
  484.  
  485. const accuracy = Math.round(position.coords.accuracy);
  486. updateLocationStatus(
  487. "success",
  488. `Location set! Accuracy: ±${accuracy}m. Times are now location-specific.`
  489. );
  490.  
  491. // Show coordinates
  492. const coordsDisplay = document.getElementById("coordinatesDisplay");
  493. if (coordsDisplay) {
  494. coordsDisplay.textContent = `Coordinates: ${currentLocation.lat.toFixed(
  495. 4
  496. )}°, ${currentLocation.lon.toFixed(4)}°`;
  497. }
  498.  
  499. // Recalculate times with precise location
  500. calculateSunMoonTimes();
  501. },
  502. function (error) {
  503. // Error handling
  504. let errorMsg = "Location request failed: ";
  505. switch (error.code) {
  506. case error.PERMISSION_DENIED:
  507. errorMsg += "Permission denied. You can still use UTC times.";
  508. break;
  509. case error.POSITION_UNAVAILABLE:
  510. errorMsg += "Location unavailable. Using UTC times.";
  511. break;
  512. case error.TIMEOUT:
  513. errorMsg += "Request timed out. Using UTC times.";
  514. break;
  515. default:
  516. errorMsg += "Unknown error. Using UTC times.";
  517. break;
  518. }
  519.  
  520. updateLocationStatus("warning", errorMsg);
  521. btn.textContent = "📍 Try Again";
  522. btn.disabled = false;
  523. },
  524. {
  525. enableHighAccuracy: true,
  526. timeout: 10000,
  527. maximumAge: 600000, // Cache for 10 minutes
  528. }
  529. );
  530. }
  531.  
  532. function updateLocationStatus(type, message) {
  533. const status = document.getElementById("locationStatus");
  534. if (status) {
  535. status.className = `location-status status-${type}`;
  536. status.textContent = message;
  537. }
  538. }
  539.  
  540. function calculateSunMoonTimes() {
  541. console.log("calculateSunMoonTimes called");
  542.  
  543. // Make sure Astronomy library is loaded
  544. if (typeof Astronomy === "undefined") {
  545. console.error("Astronomy library not loaded");
  546. return;
  547. }
  548.  
  549. console.log("Astronomy library is loaded, currentLocation:", currentLocation);
  550.  
  551. const today = new Date();
  552. console.log("Today:", today);
  553.  
  554. try {
  555. const observer = new Astronomy.Observer(
  556. currentLocation.lat,
  557. currentLocation.lon,
  558. 0
  559. );
  560. console.log("Observer created:", observer);
  561.  
  562. // Check what Direction constants are available
  563. console.log("Available Astronomy constants:", Object.keys(Astronomy));
  564.  
  565. // Try different ways to access Direction constants
  566. let riseDirection, setDirection;
  567.  
  568. if (Astronomy.Direction) {
  569. console.log("Direction object:", Astronomy.Direction);
  570. riseDirection = Astronomy.Direction.Rise;
  571. setDirection = Astronomy.Direction.Set;
  572. } else {
  573. // Try direct constants
  574. riseDirection = Astronomy.Rise || 1;
  575. setDirection = Astronomy.Set || -1;
  576. }
  577.  
  578. console.log(
  579. "Rise direction:",
  580. riseDirection,
  581. "Set direction:",
  582. setDirection
  583. );
  584.  
  585. // Calculate sunrise/sunset
  586. console.log("Calculating sunrise...");
  587. const sunrise = Astronomy.SearchRiseSet(
  588. Astronomy.Body.Sun,
  589. observer,
  590. riseDirection,
  591. today,
  592. 1
  593. );
  594. console.log("Sunrise result:", sunrise);
  595.  
  596. console.log("Calculating sunset...");
  597. const sunset = Astronomy.SearchRiseSet(
  598. Astronomy.Body.Sun,
  599. observer,
  600. setDirection,
  601. today,
  602. 1
  603. );
  604. console.log("Sunset result:", sunset);
  605.  
  606. // Calculate moonrise/moonset
  607. console.log("Calculating moonrise...");
  608. const moonrise = Astronomy.SearchRiseSet(
  609. Astronomy.Body.Moon,
  610. observer,
  611. riseDirection,
  612. today,
  613. 1
  614. );
  615. console.log("Moonrise result:", moonrise);
  616.  
  617. console.log("Calculating moonset...");
  618. const moonset = Astronomy.SearchRiseSet(
  619. Astronomy.Body.Moon,
  620. observer,
  621. setDirection,
  622. today,
  623. 1
  624. );
  625. console.log("Moonset result:", moonset);
  626.  
  627. // Update the horizontal bar display
  628. const sunriseEl = document.getElementById("sunriseTime");
  629. const sunsetEl = document.getElementById("sunsetTime");
  630. const moonriseEl = document.getElementById("moonriseTime");
  631. const moonsetEl = document.getElementById("moonsetTime");
  632.  
  633. if (sunriseEl)
  634. sunriseEl.textContent = sunrise ? formatTime(sunrise.date) : "None";
  635. if (sunsetEl)
  636. sunsetEl.textContent = sunset ? formatTime(sunset.date) : "None";
  637. if (moonriseEl)
  638. moonriseEl.textContent = moonrise ? formatTime(moonrise.date) : "None";
  639. if (moonsetEl)
  640. moonsetEl.textContent = moonset ? formatTime(moonset.date) : "None";
  641.  
  642. // Update timezone note in the bar
  643. const timezoneNote = document.getElementById("timezoneNote");
  644. if (timezoneNote) {
  645. if (currentLocation.isUTC) {
  646. timezoneNote.textContent = "UTC Times";
  647. } else {
  648. timezoneNote.textContent = `Local Times (${currentLocation.lat.toFixed(
  649. 1
  650. )}°, ${currentLocation.lon.toFixed(1)}°)`;
  651. }
  652. }
  653. } catch (error) {
  654. console.error("Detailed astronomy calculation error:", error);
  655. console.error("Error stack:", error.stack);
  656.  
  657. // Show error in horizontal bar
  658. const sunriseEl = document.getElementById("sunriseTime");
  659. const sunsetEl = document.getElementById("sunsetTime");
  660. const moonriseEl = document.getElementById("moonriseTime");
  661. const moonsetEl = document.getElementById("moonsetTime");
  662.  
  663. if (sunriseEl) sunriseEl.textContent = "Error";
  664. if (sunsetEl) sunsetEl.textContent = "Error";
  665. if (moonriseEl) moonriseEl.textContent = "Error";
  666. if (moonsetEl) moonsetEl.textContent = "Error";
  667. }
  668. }
  669.  
  670. // Alternative approach if the above doesn't work
  671. function calculateSunMoonTimesAlternative() {
  672. console.log("calculateSunMoonTimesAlternative called");
  673.  
  674. if (typeof Astronomy === "undefined") {
  675. console.error("Astronomy library not loaded");
  676. return;
  677. }
  678.  
  679. const today = new Date();
  680.  
  681. try {
  682. const observer = new Astronomy.Observer(
  683. currentLocation.lat,
  684. currentLocation.lon,
  685. 0
  686. );
  687.  
  688. // Try using numeric constants directly (common in some versions)
  689. // 1 = Rise, -1 = Set (or vice versa depending on library version)
  690.  
  691. console.log("Trying with numeric direction constants...");
  692.  
  693. let sunrise, sunset, moonrise, moonset;
  694.  
  695. try {
  696. sunrise = Astronomy.SearchRiseSet(
  697. Astronomy.Body.Sun,
  698. observer,
  699. 1,
  700. today,
  701. 1
  702. );
  703. sunset = Astronomy.SearchRiseSet(
  704. Astronomy.Body.Sun,
  705. observer,
  706. -1,
  707. today,
  708. 1
  709. );
  710. moonrise = Astronomy.SearchRiseSet(
  711. Astronomy.Body.Moon,
  712. observer,
  713. 1,
  714. today,
  715. 1
  716. );
  717. moonset = Astronomy.SearchRiseSet(
  718. Astronomy.Body.Moon,
  719. observer,
  720. -1,
  721. today,
  722. 1
  723. );
  724. } catch (e1) {
  725. console.log("Trying reversed numeric constants...");
  726. // Try reversed if the first attempt fails
  727. sunrise = Astronomy.SearchRiseSet(
  728. Astronomy.Body.Sun,
  729. observer,
  730. -1,
  731. today,
  732. 1
  733. );
  734. sunset = Astronomy.SearchRiseSet(
  735. Astronomy.Body.Sun,
  736. observer,
  737. 1,
  738. today,
  739. 1
  740. );
  741. moonrise = Astronomy.SearchRiseSet(
  742. Astronomy.Body.Moon,
  743. observer,
  744. -1,
  745. today,
  746. 1
  747. );
  748. moonset = Astronomy.SearchRiseSet(
  749. Astronomy.Body.Moon,
  750. observer,
  751. 1,
  752. today,
  753. 1
  754. );
  755. }
  756.  
  757. // Update display
  758. const sunriseEl = document.getElementById("sunriseTime");
  759. const sunsetEl = document.getElementById("sunsetTime");
  760. const moonriseEl = document.getElementById("moonriseTime");
  761. const moonsetEl = document.getElementById("moonsetTime");
  762.  
  763. if (sunriseEl)
  764. sunriseEl.textContent = sunrise ? formatTime(sunrise.date) : "None";
  765. if (sunsetEl)
  766. sunsetEl.textContent = sunset ? formatTime(sunset.date) : "None";
  767. if (moonriseEl)
  768. moonriseEl.textContent = moonrise ? formatTime(moonrise.date) : "None";
  769. if (moonsetEl)
  770. moonsetEl.textContent = moonset ? formatTime(moonset.date) : "None";
  771.  
  772. const timezoneNote = document.getElementById("timezoneNote");
  773. if (timezoneNote) {
  774. if (currentLocation.isUTC) {
  775. timezoneNote.textContent = "UTC Times";
  776. } else {
  777. timezoneNote.textContent = `Local Times (${currentLocation.lat.toFixed(
  778. 1
  779. )}°, ${currentLocation.lon.toFixed(1)}°)`;
  780. }
  781. }
  782.  
  783. console.log("Alternative calculation completed successfully");
  784. } catch (error) {
  785. console.error("Alternative calculation failed:", error);
  786.  
  787. // Show error in display
  788. ["sunriseTime", "sunsetTime", "moonriseTime", "moonsetTime"].forEach(
  789. (id) => {
  790. const el = document.getElementById(id);
  791. if (el) el.textContent = "Error";
  792. }
  793. );
  794. }
  795. }
  796.  
  797. function formatTime(date) {
  798. // Format as HH:MM UTC
  799. return date.toISOString().substr(11, 5) + " UTC";
  800. }
  801.  
  802. function initCalendar() {
  803. // Initialize timezone display
  804. updateTimezoneDisplay();
  805.  
  806. renderCalendar();
  807.  
  808. // Add event listeners for navigation
  809. document.getElementById("yearPrev").addEventListener("click", () => {
  810. currentYear--;
  811. renderCalendar();
  812. });
  813.  
  814. document.getElementById("yearNext").addEventListener("click", () => {
  815. currentYear++;
  816. renderCalendar();
  817. });
  818.  
  819. document.getElementById("monthPrev").addEventListener("click", () => {
  820. currentMonth--;
  821. if (currentMonth < 0) {
  822. currentMonth = 11;
  823. currentYear--;
  824. }
  825. renderCalendar();
  826. });
  827.  
  828. document.getElementById("monthNext").addEventListener("click", () => {
  829. currentMonth++;
  830. if (currentMonth > 11) {
  831. currentMonth = 0;
  832. currentYear++;
  833. }
  834. renderCalendar();
  835. });
  836.  
  837. document.getElementById("resetButton").addEventListener("click", () => {
  838. const now = new Date();
  839. currentMonth = now.getMonth();
  840. currentYear = now.getFullYear();
  841. renderCalendar();
  842. });
  843.  
  844. // Timezone control event listeners
  845. document
  846. .getElementById("timezonePrev")
  847. .addEventListener("click", () => adjustTimezone(-1));
  848. document
  849. .getElementById("timezoneNext")
  850. .addEventListener("click", () => adjustTimezone(1));
  851.  
  852. // Timezone reset button
  853. document
  854. .getElementById("timezoneResetButton")
  855. .addEventListener("click", () => {
  856. currentTimezoneOffset = -(new Date().getTimezoneOffset() / 60);
  857. updateTimezoneDisplay();
  858. renderCalendar();
  859. });
  860.  
  861. // Hemisphere change listeners
  862. document
  863. .getElementById("northRadio")
  864. .addEventListener("change", handleHemisphereChange);
  865. document
  866. .getElementById("southRadio")
  867. .addEventListener("change", handleHemisphereChange);
  868.  
  869. // Set up the precise location button
  870. const preciseLocationBtn = document.getElementById("preciseLocationBtn");
  871. if (preciseLocationBtn) {
  872. preciseLocationBtn.addEventListener("click", requestPreciseLocation);
  873. }
  874.  
  875. // Calculate initial UTC times
  876. calculateSunMoonTimes();
  877. }
  878.  
  879. initCalendar();
  880.  
  881. // Toggle visibility functionality
  882. document;
  883. /* --- Replace the last 3 event listeners in calendar.js with this code --- */
  884.  
  885. // Toggle visibility functionality
  886. document
  887. .getElementById("moonPhasesToggle")
  888. .addEventListener("change", function () {
  889. document
  890. .querySelector(".calendar-wrapper")
  891. .classList.toggle("moon-phases-hidden", !this.checked);
  892. });
  893.  
  894. document
  895. .getElementById("lunarEclipsesToggle")
  896. .addEventListener("change", function () {
  897. document
  898. .querySelector(".calendar-wrapper")
  899. .classList.toggle("lunar-eclipses-hidden", !this.checked);
  900. });
  901.  
  902. document
  903. .getElementById("solarEclipsesToggle")
  904. .addEventListener("change", function () {
  905. document
  906. .querySelector(".calendar-wrapper")
  907. .classList.toggle("solar-eclipses-hidden", !this.checked);
  908. });
  909.  
  910. document
  911. .getElementById("lunarEclipsesToggle")
  912. .addEventListener("change", function () {
  913. const lunarEclipses = document.querySelectorAll(
  914. ".calendar-wrapper .lunar-eclipse"
  915. );
  916. lunarEclipses.forEach((el) => {
  917. if (this.checked) {
  918. el.style.display = "inline";
  919. el.classList.add("fade-in");
  920. } else {
  921. el.style.display = "none";
  922. el.classList.remove("fade-in");
  923. }
  924. });
  925. });
  926.  
  927. document
  928. .getElementById("solarEclipsesToggle")
  929. .addEventListener("change", function () {
  930. const solarEclipses = document.querySelectorAll(
  931. ".calendar-wrapper .solar-eclipse"
  932. );
  933. solarEclipses.forEach((el) => {
  934. if (this.checked) {
  935. el.style.display = "inline";
  936. el.classList.add("fade-in");
  937. } else {
  938. el.style.display = "none";
  939. el.classList.remove("fade-in");
  940. }
  941. });
  942. });
  943.  
Advertisement
Add Comment
Please, Sign In to add comment