ESC
科技 2 分钟阅读

2026年日食网络摄像头直播地图

一个交互式地图展示了2026年8月12日即将发生的日全食路径,并标注了沿途网络摄像头的位置,提供实时倒计时,方便用户观看日食直播。

来源:Hacker News

2026年日全食网络摄像头直播

body { padding: 0; margin: 0; } html, body, #map { height: 100%; width: 100%; } #countdowns { position: absolute; top: 10px; right: 10px; z-index: 1000; background: rgba(255, 255, 255, 0.9); border-radius: 0; box-shadow: 0 1px 5px rgba(0,0,0,0.4); padding: 8px 12px; font-family: sans-serif; font-size: 13px; line-height: 1.4; } #countdowns .label { color: #333; } #countdowns .time { font-weight: bold; font-family: monospace; } #countdowns .credit { margin-top: 8px; text-align: right; }

🌑 全食开始于…

📹 到达首个网络摄像头…

由 jonty 制作

var umbra_polygons; var umbra_layer;

var eclipse_start_time = new Date(‘2026-08-12T17:02:00Z’); var eclipse_end_time = new Date(‘2026-08-12T18:32:00Z’); var first_webcam_time = new Date(‘2026-08-12T17:42:20Z’); var last_webcam_time = new Date(‘2026-08-12T18:31:20Z’);

var map = L.map(‘map’).setView([54, -12], 4);

L.tileLayer(‘https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png’, { attribution: ‘© OpenStreetMap contributors | Made by jonty’ }).addTo(map);

function pathStyle(feature) { switch (feature.properties.title) { case ‘Path of totality’: return { color: ‘#333’, weight: 1, fillColor: ‘#666’, fillOpacity: 0.25 }; default: return { color: ‘#7f7fff’, weight: 1, fillOpacity: 0 }; } }

fetch(’eclipse_2026_path.geojson’) .then(function(response) { return response.json(); }) .then(function(data) { L.geoJson(data, { style: pathStyle, onEachFeature: function(feature, layer) { if (feature.properties && feature.properties.title && feature.properties.url) { layer.bindPopup(’’ + feature.properties.title + ‘\n打开网络摄像头 📹’); } } }).addTo(map); });

fetch(‘umbra_polygons.geojson’) .then(function(response) { return response.json(); }) .then(function(data) { umbra_polygons = data.features; update_umbra(); });

update_countdowns(); setInterval(update_countdowns, 1000);

function format_countdown(target) { var diff = target.getTime() - new Date().getTime(); var totalSeconds = Math.floor(Math.abs(diff) / 1000); var hours = Math.floor(totalSeconds / 3600); var minutes = Math.floor((totalSeconds % 3600) / 60); var seconds = totalSeconds % 60; return hours + ‘h ’ + minutes.toString().padStart(2, ‘0’) + ’m ’ + seconds.toString().padStart(2, ‘0’) + ’s’; }

function update_countdowns() { var now = new Date();

if (eclipse_start_time && now < eclipse_start_time) { document.getElementById(‘countdown-eclipse’).innerText = format_countdown(eclipse_start_time); } else { document.getElementById(‘countdown-eclipse’).innerText = ‘正在进行中’; }

if (first_webcam_time && now < first_webcam_time) { document.getElementById(‘countdown-webcam’).innerText = format_countdown(first_webcam_time); } else if (last_webcam_time && now < last_webcam_time) { document.getElementById(‘countdown-webcam’).innerText = ‘正在直播’; } else { document.getElementById(‘countdown-webcam’).innerText = ‘已结束’; } }

function polystyle(feature) { return { color: ‘#000’, weight: 1, fillColor: ‘#ff0000’, fillOpacity: 0.2 }; }

function update_umbra() { var now = new Date(); var UTCTime = now.toISOString().slice(0, 19).replace(‘T’, ’ ‘);

var filteredFeatures = umbra_polygons.filter(feature => feature.properties.UTCTime == UTCTime); if (umbra_layer != null) { map.removeLayer(umbra_layer); } umbra_layer = L.geoJSON(filteredFeatures, {style: polystyle}).addTo(map);

setTimeout(update_umbra, 1000*10); }