PageSourceSearch

https://aurora-c9c22.web.app/js/loadingAnimation.js

js aurora-c9c22.web.app collected 2026-10-03 12:18:50 UTC 4,920 bytes, 147 lines download raw bytes

1// loadingAnimation.js - Beautiful aurora-themed loading animations
2
3/**
4 * Creates a beautiful aurora-themed loading animation
5 * @param {string} containerId - The ID of the container to add the loader to
6 * @param {string} message - The loading message to display
7 * @param {string} type - Type of loader: 'globe' or 'population'
8 * @returns {HTMLElement} The loader element
9 */
10export function createLoadingAnimation(containerId, message = 'Loading...', type = 'globe') {
11  const container = document.getElementById(containerId);
12  if (!container) {
13    console.error(`Container ${containerId} not found`);
14    return null;
15  }
16
17  // Create loader wrapper
18  const loaderWrapper = document.createElement('div');
19  loaderWrapper.className = `aurora-loader ${type}-loader`;
20  loaderWrapper.id = `${type}-loader`;
21
22  // Different animations based on type
23  let loaderContent = '';
24  
25  if (type === 'globe') {
26    loaderContent = `
27      <div class="aurora-loader-content">
28        <div class="aurora-globe-spinner">
29          <div class="globe-ring ring-1"></div>
30          <div class="globe-ring ring-2"></div>
31          <div class="globe-ring ring-3"></div>
32          <div class="globe-core"></div>
33        </div>
34        <div class="aurora-loader-text">
35          <div class="loader-message">${message}</div>
36          <div class="loader-submessage">Preparing your view of Earth...</div>
37        </div>
38        <div class="aurora-particles">
39          ${Array.from({ length: 20 }, (_, i) => `<div class="particle particle-${i}"></div>`).join('')}
40        </div>
41      </div>
42    `;
43  } else if (type === 'population') {
44    loaderContent = `
45      <div class="aurora-loader-content population-content">
46        <div class="aurora-wave-spinner">
47          <div class="wave-bar bar-1"></div>
48          <div class="wave-bar bar-2"></div>
49          <div class="wave-bar bar-3"></div>
50          <div class="wave-bar bar-4"></div>
51          <div class="wave-bar bar-5"></div>
52        </div>
53        <div class="aurora-loader-text">
54          <div class="loader-message">${message}</div>
55          <div class="loader-submessage">Analyzing global aurora visibility...</div>
56        </div>
57      </div>
58    `;
59  }
60
61  loaderWrapper.innerHTML = loaderContent;
62  container.appendChild(loaderWrapper);
63
64  // Trigger fade-in animation
65  requestAnimationFrame(() => {
66    loaderWrapper.classList.add('fade-in');
67  });
68
69  return loaderWrapper;
70}
71
72/**
73 * Shows the loading animation
74 * @param {string} type - Type of loader to show
75 */
76export function showLoader(type = 'globe') {
77  const loader = document.getElementById(`${type}-loader`);
78  if (loader) {
79    loader.style.display = 'flex';
80    loader.classList.add('fade-in');
81  }
82}
83
84/**
85 * Hides and removes the loading animation with a fade-out effect
86 * @param {string} type - Type of loader to hide
87 */
88export function hideLoader(type = 'globe') {
89  const loader = document.getElementById(`${type}-loader`);
90  if (loader) {
91    clearLoaderWatchdog(type);
92    loader.classList.add('fade-out');
93    // Stop swallowing clicks the moment we start fading; the controls beneath
94    // are already live and a half-second of dead input feels broken.
95    loader.style.pointerEvents = 'none';
96    setTimeout(() => {
97      if (loader && loader.parentNode) {
98        loader.parentNode.removeChild(loader);
99      }
100    }, 250); // Match the fade-out animation in loading-animation.css
101  }
102}
103
104// The globe loader is a full-viewport overlay, so anything that prevents
105// hideLoader() from running leaves the whole UI unclickable. Tile loading
106// depends on a third-party imagery host and `tilesLoaded` may simply never
107// fire, so every loader gets a bounded lifetime.
108const LOADER_MAX_MS = 20000;
109const watchdogs = new Map();
110
111export function armLoaderWatchdog(type = 'globe', maxMs = LOADER_MAX_MS) {
112  clearLoaderWatchdog(type);
113  watchdogs.set(type, setTimeout(() => {
114    const loader = document.getElementById(`${type}-loader`);
115    if (loader) {
116      console.warn(`[loader] ${type} loader exceeded ${maxMs}ms; dismissing so the UI stays usable.`);
117      hideLoader(type);
118    }
119  }, maxMs));
120}
121
122export function clearLoaderWatchdog(type = 'globe') {
123  const timer = watchdogs.get(type);
124  if (timer) {
125    clearTimeout(timer);
126    watchdogs.delete(type);
127  }
128}
129
130/**
131 * Updates the loading message
132 * @param {string} type - Type of loader
133 * @param {string} message - New message
134 * @param {string} submessage - New submessage (optional)
135 */
136export function updateLoaderMessage(type, message, submessage = null) {
137  const loader = document.getElementById(`${type}-loader`);
138  if (loader) {
139    const messageEl = loader.querySelector('.loader-message');
140    if (messageEl) messageEl.textContent = message;
141    
142    if (submessage !== null) {
143      const submessageEl = loader.querySelector('.loader-submessage');
144      if (submessageEl) submessageEl.textContent = submessage;
145    }
146  }
147}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.