Global Live Earthquakes · 3D Globe
🌐 Global Live Earthquakes
Source: USGS · Past 7 days
…
earthquakes recorded
Magnitude (bigger & redder = stronger)
M 1–3 minor
M 3–5 moderate
M 5–7 strong
M 7+ major
Loading…
📰 Earthquake News
Click a card to read · 📍 to fly the globe there
' +
'
' + item.title + '
' +
'
' + (item.summary || "") + '
' +
'
' +
'Read full story →' +
(hasCoords ? '📍 View on globe' : '') +
'
';
// Click the card to open the article
card.addEventListener("click", function () {
window.open(item.url, "_blank");
});
// Click 📍 to fly the globe to the epicenter (only if we have coords)
if (hasCoords) {
card.querySelector(".news-pin").addEventListener("click", function (e) {
e.stopPropagation(); // don't also open the article
spinning = false; // stop the auto-rotation
spinBtn.textContent = "▶ Resume rotation";
view.goTo(
{ position: { longitude: item.lon, latitude: item.lat, z: 2500000 }, tilt: 45 },
{ duration: 2000 }
).catch(function () {});
});
}
list.appendChild(card);
});
}
// Decide: live mode (token set) or curated mode (token empty)?
if (GNEWS_TOKEN) {
statusEl.textContent = "Fetching live news…";
const realUrl = "https://gnews.io/api/v4/search?q=" + encodeURIComponent(NEWS_QUERY) +
"&lang=en&max=10&sortby=publishedAt&token=" + GNEWS_TOKEN;
const apiUrl = "https://api.allorigins.win/raw?url=" + encodeURIComponent(realUrl);
fetch(apiUrl)
.then(function (r) { return r.json(); })
.then(function (data) {
if (!data.articles || data.articles.length === 0) {
throw new Error("No articles returned");
}
// Map GNews fields to our card format (no coordinates available)
const items = data.articles.map(function (a) {
return {
source: a.source && a.source.name ? a.source.name : "News",
date: new Date(a.publishedAt).toLocaleDateString(),
title: a.title,
summary: a.description,
url: a.url
// GNews doesn't include lat/lon, so no 📍 button on live items
};
});
statusEl.textContent = "🟢 Live · updated " + new Date().toLocaleTimeString();
renderNews(items);
})
.catch(function (err) {
// If the live fetch fails, fall back to the curated list
statusEl.textContent = "⚠ Live fetch failed — showing curated news";
renderNews(curatedNews);
});
} else {
statusEl.textContent = "Curated news · add a GNews token for live updates";
renderNews(curatedNews);
}
// =================================================================
// GLOBE STATS + ROTATION
// =================================================================
function updateStats() {
quakeLayer.queryFeatureCount().then(function (n) {
document.getElementById("count").textContent = n.toLocaleString();
document.getElementById("updated").textContent =
"Updated at " + new Date().toLocaleTimeString();
});
}
view.when(function () {
updateStats();
quakeLayer.on("refresh", updateStats);
});
function spin() {
if (!spinning) return;
const cam = view.camera.clone();
cam.position.longitude += 0.15;
view.goTo(cam, { animate: false }).catch(function () {});
}
setInterval(spin, 50);
spinBtn.addEventListener("click", function () {
spinning = !spinning;
spinBtn.textContent = spinning ? "⏸ Pause rotation" : "▶ Resume rotation";
});
view.on("drag", function () {
if (spinning) {
spinning = false;
spinBtn.textContent = "▶ Resume rotation";
}
});
});