日本列島を含む環太平洋火山帯(Ring of Fire)では、世界中の大地震の約8割が集中しています。地震大国に暮らす私たちにとって、地震情報は日々の生活の安心・安全を左右する死活問題です。
地球規模で発生する地震活動をWebブラウザ上の3D地球儀でリアルタイムに追跡する「QuakeViewer3D」では、アメリカ地質調査所(USGS: United States Geological Survey)が毎分更新・配信している公式オープンデータを、秒単位で取り込み瞬時に3D空間へマッピングする高可用リアルタイム処理パイプラインを構築しました。本記事では、GeoJSONフィードのインジェスチョン、新着差分検知(Diff Engine)、対数物理スケーリング、そして端末現在地からの大円距離計算アルゴリズムの全容を解説します。
1. USGS GeoJSON APIの定期フェッチとスマート差分検知(Diff Engine)
USGS Earthquake Hazards Programは、全世界の地震速報を「過去1時間」「過去1日」「過去7日間」「過去30日間」の4つの時間スパン、およびマグニチュード閾値(All, 1.0+, 2.5+, 4.5+)に分けてリアルタイムGeoJSONフィードとして配信しています。
QuakeViewer3Dでは、通信負荷と即時性のバランスを考慮し、最も鮮度の高い all_hour.geojson および all_day.geojson をバックグラウンドで60秒ごとに自動ポーリングしています。サーバーと端末の無駄なパケット消費を防ぐため、HTTPの If-Modified-Since ヘッダーを活用した304 Not Modifiedキャッシュ判定を導入しています。
フェッチした新規データから新着地震だけを抽出する差分検知エンジンのロジックは以下の通りです:
// 新着地震の差分検知と通知発火パイプライン
class QuakeDiffEngine {
constructor() {
this.knownQuakeIds = new Set();
}
processFeed(features) {
const newQuakes = [];
for (const feature of features) {
const id = feature.id;
if (!this.knownQuakeIds.has(id)) {
this.knownQuakeIds.add(id);
newQuakes.push(feature);
}
}
if (newQuakes.length > 0 && this.knownQuakeIds.size > newQuakes.length) {
// 初回ロード時を除き、新着地震が発生した場合にイベント発火
this.notifyNewEvents(newQuakes);
}
return newQuakes;
}
notifyNewEvents(quakes) {
quakes.forEach(q => {
const { mag, place } = q.properties;
console.log(`🚨 新着地震検知: M${mag} - ${place}`);
// Web Audio APIによるチャイム音再生とOS通知(Push API)
playAlertSound(mag);
showDesktopNotification(`M${mag} 地震発生`, place);
});
}
}
これにより、ユーザーがアプリを開いたまま作業している最中に新たな地震が発生した場合、わずか数十秒のタイムラグで自動的にチャイム音が鳴り、画面上のカメラが震源地へとスムーズにフライ(視点遷移)する体験を実現しました。
2. 震源球体の3D直交座標変換と認知工学的対数スケーリング
取得したGeoJSONの座標データは [経度, 緯度, 深さ(km)] の形式で格納されています。これをThree.jsの3D空間座標 $(X, Y, Z)$ に変換する計算式は以下の通りです:
// 地理座標から3Dデカルト座標への精密マッピング
function latLongDepthToVector3(lat, lon, depthKm) {
const r = (EARTH_RADIUS_KM - depthKm) * WORLD_SCALE;
const phi = (90 - lat) * (Math.PI / 180);
const theta = (lon + 180) * (Math.PI / 180);
const x = -(r * Math.sin(phi) * Math.cos(theta));
const z = (r * Math.sin(phi) * Math.sin(theta));
const y = (r * Math.cos(phi));
return new THREE.Vector3(x, y, z);
}
震源球体のサイズ(半径)の決定には、地震学の物理法則と認知心理学の調和が求められます。地震のエネルギー $E$ はマグニチュードが1増えるごとに約31.6倍($10^{1.5}$)に爆発的に増加します(グーテンベルグ・リヒターの関係式)。もしエネルギーに比例して球体の体積を描画すると、M3の地震が米粒サイズになる一方でM8の巨大地震が地球全体を覆い尽くしてしまい、地図としての可視性が崩壊します。
そこでQuakeViewer3Dでは、視認性を維持しながら揺れのスケール感を直感的に伝える対数指数スケーリングを採用しています:
$$Radius = R_{base} \times \exp(0.35 \times (M_w - 2.0))$$
また、球体の色相は震源の「深さ(Depth)」に応じて連続的に変化させ、浅い直下型(0〜30km)は鮮烈な赤・橙、中深度(30〜150km)は黄色、深発地震(300〜700km)は深海を思わせる青紫〜マゼンタにマッピングすることで、危険な浅い地震とエネルギーが拡散する深発地震を直感的に識別できるように設計しています。
3. ハバーサイン(Haversine)公式による現在地からの大円距離計算
ユーザーが関心を持つのは「世界で起きた地震」であると同時に、「自分のいる場所からどれくらい近い場所で起きたか」です。
QuakeViewer3Dでは、ブラウザの navigator.geolocation APIから取得した現在地座標と、各震源地の座標から、球面三角法に基づくハバーサイン(Haversine)の公式を用いて大円距離(地表面に沿った最短距離)を瞬時に計算します:
// 2地点間の大円距離(km)を求めるHaversine関数
function calculateHaversineDistance(lat1, lon1, lat2, lon2) {
const R = 6371; // 地球平均半径 (km)
const dLat = (lat2 - lat1) * Math.PI / 180;
const dLon = (lon2 - lon1) * Math.PI / 180;
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
この計算により、UI上の地震タイムラインをワンクリックで「現在地から近い順」にソートすることができ、遠方の海外地震に埋もれることなく身近な微小地震を即座に確認できます。
4. IndexedDBによるローカルキャッシュとThree.jsメモリリーク対策
数千個の地震オブジェクトを常時更新し続けるWebアプリケーションにおいて、最大の敵となるのがJavaScriptのメモリリークとヒープ肥大化です。
- Three.jsリソースの厳格な破棄: 期限切れ(過去30日を超過)した地震球体を破棄する際、
scene.remove()だけでなく、マテリアル(material.dispose())やテクスチャのGPU VRAM参照を完全に解放。 - IndexedDBによる高速復帰: 初回ロード時に取得した数千件のGeoJSONレコードをブラウザ内蔵のIndexedDBに保存。次回起動時はネットワーク通信の完了を待たずに数ミリ秒で過去の地震分布を瞬時に復元描画します。
5. まとめとオープンデータが拓くグローバル防災の未来
USGSが提供するオープンデータと最新のWeb技術(WebGL、Three.js、IndexedDB、Geolocation API)を掛け合わせることで、かつては研究機関や気象局の専用大型モニタでしか閲覧できなかった高度な地震情報が、手のひらのスマートフォンで誰でも自由に操作できるようになりました。
QuakeViewer3Dは、単なるビジュアライゼーションにとどまらず、世界中の市民が地球の鼓動を正しく恐れ、正しく備えるためのグローバル防災インフラとして今後も進化を続けてまいります。