420 lines
No EOL
24 KiB
HTML
420 lines
No EOL
24 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>SkyView - Multi-Source ADS-B Aircraft Tracker</title>
|
|
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
|
|
|
<!-- Leaflet CSS -->
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
|
|
<!-- Chart.js -->
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js"></script>
|
|
|
|
<!-- Three.js for 3D radar (ES modules) -->
|
|
<script type="importmap">
|
|
{
|
|
"imports": {
|
|
"three": "https://cdn.jsdelivr.net/npm/three@0.158.0/build/three.module.js",
|
|
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.158.0/examples/jsm/"
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<!-- Custom CSS -->
|
|
<link rel="stylesheet" href="/static/css/style.css">
|
|
</head>
|
|
<body>
|
|
<div id="app">
|
|
<header class="header">
|
|
<h1>SkyView <span class="version-info">v0.0.11</span>
|
|
<a href="https://kode.naiv.no/olemd/skyview" target="_blank" class="repo-link" title="Project Repository">⚙</a>
|
|
<a href="/database" class="repo-link" title="Database Status">📊</a>
|
|
</h1>
|
|
|
|
<!-- Status indicators -->
|
|
<div class="status-section">
|
|
<div class="clock-display">
|
|
<div class="clock" id="utc-clock">
|
|
<div class="clock-face">
|
|
<div class="clock-hand hour-hand" id="utc-hour"></div>
|
|
<div class="clock-hand minute-hand" id="utc-minute"></div>
|
|
</div>
|
|
<div class="clock-label">UTC</div>
|
|
</div>
|
|
<div class="clock" id="update-clock">
|
|
<div class="clock-face">
|
|
<div class="clock-hand hour-hand" id="update-hour"></div>
|
|
<div class="clock-hand minute-hand" id="update-minute"></div>
|
|
</div>
|
|
<div class="clock-label">Last Update</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Summary stats -->
|
|
<div class="stats-summary">
|
|
<span id="aircraft-count">0 aircraft</span>
|
|
<span id="position-summary">0 positioned</span>
|
|
<span id="sources-count">0 sources</span>
|
|
<span id="active-clients">1 viewer</span>
|
|
<span id="connection-status" class="connection-status disconnected">Connecting...</span>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="main-content">
|
|
<!-- View selection tabs -->
|
|
<div class="view-toggle">
|
|
<button id="map-view-btn" class="view-btn active">Map</button>
|
|
<button id="table-view-btn" class="view-btn">Table</button>
|
|
<button id="stats-view-btn" class="view-btn">Statistics</button>
|
|
<button id="coverage-view-btn" class="view-btn">Coverage</button>
|
|
<button id="radar3d-view-btn" class="view-btn">3D Radar</button>
|
|
</div>
|
|
|
|
<!-- Map View -->
|
|
<div id="map-view" class="view active">
|
|
<div id="map"></div>
|
|
|
|
<!-- Map controls -->
|
|
<div class="map-controls">
|
|
<button id="center-map" title="Center on aircraft">Center Map</button>
|
|
<button id="reset-map" title="Reset to origin">Reset Map</button>
|
|
<button id="toggle-trails" title="Show/hide aircraft trails">Show Trails</button>
|
|
<button id="toggle-sources" title="Show/hide source locations">Show Sources</button>
|
|
<button id="toggle-dark-mode" title="Toggle dark/light mode">🌙 Night Mode</button>
|
|
</div>
|
|
|
|
<!-- Options -->
|
|
<div class="display-options">
|
|
<h4 class="collapsible-header collapsed" id="display-options-header">
|
|
<span>Options</span>
|
|
<span class="collapse-indicator">▼</span>
|
|
</h4>
|
|
<div class="option-group collapsible-content collapsed" id="display-options-content">
|
|
<label>
|
|
<input type="checkbox" id="show-site-positions" checked>
|
|
<span>Site Positions</span>
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" id="show-range-rings" checked>
|
|
<span>Range Rings</span>
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" id="show-selected-trail">
|
|
<span>Selected Aircraft Trail</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Legend -->
|
|
<div class="legend">
|
|
<h4>ADS-B Categories</h4>
|
|
<div class="legend-item">
|
|
<span class="legend-icon light">
|
|
<svg width="24" height="24" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg">
|
|
<g transform="translate(14,14)">
|
|
<path d="M0,-10 L-1,-9 L-1,5 L-0.5,7 L0,8 L0.5,7 L1,5 L1,-9 Z" fill="currentColor"/>
|
|
<path d="M-1,-1 L-8,1 L-8,2.5 L-1,1 Z" fill="currentColor"/>
|
|
<path d="M1,-1 L8,1 L8,2.5 L1,1 Z" fill="currentColor"/>
|
|
<path d="M-0.5,5 L-3,6 L-3,6.5 L-0.5,6 Z" fill="currentColor"/>
|
|
<path d="M0.5,5 L3,6 L3,6.5 L0.5,6 Z" fill="currentColor"/>
|
|
<path d="M0,4 L-0.3,4 L-1,7 L0,7 L1,7 L0.3,4 Z" fill="currentColor"/>
|
|
<ellipse cx="0" cy="-9.5" rx="1" ry="1.5" fill="currentColor"/>
|
|
</g>
|
|
</svg>
|
|
</span>
|
|
<span>Light < 7000kg</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<span class="legend-icon medium">
|
|
<svg width="24" height="24" viewBox="0 0 30 30" xmlns="http://www.w3.org/2000/svg">
|
|
<g transform="translate(15,15)">
|
|
<path d="M0,-12 L-1.2,-11 L-1.2,6 L-0.8,8 L0,9 L0.8,8 L1.2,6 L1.2,-11 Z" fill="currentColor"/>
|
|
<path d="M-1.2,-0.5 L-10,2 L-10,3.5 L-1.2,2 Z" fill="currentColor"/>
|
|
<path d="M1.2,-0.5 L10,2 L10,3.5 L1.2,2 Z" fill="currentColor"/>
|
|
<path d="M-0.7,6.5 L-4,7.5 L-4,8.2 L-0.7,7.5 Z" fill="currentColor"/>
|
|
<path d="M0.7,6.5 L4,7.5 L4,8.2 L0.7,7.5 Z" fill="currentColor"/>
|
|
<path d="M0,5 L-0.4,5 L-1.5,9 L0,9 L1.5,9 L0.4,5 Z" fill="currentColor"/>
|
|
<ellipse cx="0" cy="-11.5" rx="1.2" ry="1.8" fill="currentColor"/>
|
|
<ellipse cx="-3" cy="1.5" rx="0.8" ry="1.5" fill="currentColor"/>
|
|
<ellipse cx="3" cy="1.5" rx="0.8" ry="1.5" fill="currentColor"/>
|
|
</g>
|
|
</svg>
|
|
</span>
|
|
<span>Medium 7000-34000kg</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<span class="legend-icon large">
|
|
<svg width="24" height="24" viewBox="0 0 34 34" xmlns="http://www.w3.org/2000/svg">
|
|
<g transform="translate(17,17)">
|
|
<path d="M0,-15 L-2,-13 L-2,8 L-1.2,11 L0,12 L1.2,11 L2,8 L2,-13 Z" fill="currentColor"/>
|
|
<path d="M-2,0 L-14,3.5 L-14,5.5 L-2,3 Z" fill="currentColor"/>
|
|
<path d="M2,0 L14,3.5 L14,5.5 L2,3 Z" fill="currentColor"/>
|
|
<path d="M-14,3.5 L-15,2.5 L-15,4 L-14,5 Z" fill="currentColor"/>
|
|
<path d="M14,3.5 L15,2.5 L15,4 L14,5 Z" fill="currentColor"/>
|
|
<path d="M-1,9 L-6,10.5 L-6,11.5 L-1,10.5 Z" fill="currentColor"/>
|
|
<path d="M1,9 L6,10.5 L6,11.5 L1,10.5 Z" fill="currentColor"/>
|
|
<path d="M0,7 L-0.6,7 L-2.5,12 L0,12 L2.5,12 L0.6,7 Z" fill="currentColor"/>
|
|
<ellipse cx="0" cy="-14" rx="2" ry="2.5" fill="currentColor"/>
|
|
<ellipse cx="-5" cy="2.5" rx="1.2" ry="2.5" fill="currentColor"/>
|
|
<ellipse cx="5" cy="2.5" rx="1.2" ry="2.5" fill="currentColor"/>
|
|
</g>
|
|
</svg>
|
|
</span>
|
|
<span>Large 34000-136000kg</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<span class="legend-icon high-vortex">
|
|
<svg width="24" height="24" viewBox="0 0 34 34" xmlns="http://www.w3.org/2000/svg">
|
|
<g transform="translate(17,17)">
|
|
<path d="M0,-15 L-2,-13 L-2,8 L-1.2,11 L0,12 L1.2,11 L2,8 L2,-13 Z" fill="currentColor"/>
|
|
<path d="M-2,0 L-14,3.5 L-14,5.5 L-2,3 Z" fill="currentColor"/>
|
|
<path d="M2,0 L14,3.5 L14,5.5 L2,3 Z" fill="currentColor"/>
|
|
<path d="M-14,3.5 L-15,2.5 L-15,4 L-14,5 Z" fill="currentColor"/>
|
|
<path d="M14,3.5 L15,2.5 L15,4 L14,5 Z" fill="currentColor"/>
|
|
<path d="M-1,9 L-6,10.5 L-6,11.5 L-1,10.5 Z" fill="currentColor"/>
|
|
<path d="M1,9 L6,10.5 L6,11.5 L1,10.5 Z" fill="currentColor"/>
|
|
<path d="M0,7 L-0.6,7 L-2.5,12 L0,12 L2.5,12 L0.6,7 Z" fill="currentColor"/>
|
|
<ellipse cx="0" cy="-14" rx="2" ry="2.5" fill="currentColor"/>
|
|
<ellipse cx="-5" cy="2.5" rx="1.2" ry="2.5" fill="currentColor"/>
|
|
<ellipse cx="5" cy="2.5" rx="1.2" ry="2.5" fill="currentColor"/>
|
|
</g>
|
|
</svg>
|
|
</span>
|
|
<span>High Vortex Large</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<span class="legend-icon heavy">
|
|
<svg width="24" height="24" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
|
|
<g transform="translate(18,18)">
|
|
<path d="M0,-16 L-2.5,-14 L-2.5,9 L-1.5,12 L0,13 L1.5,12 L2.5,9 L2.5,-14 Z" fill="currentColor"/>
|
|
<path d="M-2.5,0.5 L-16,4 L-16,6.5 L-2.5,3.5 Z" fill="currentColor"/>
|
|
<path d="M2.5,0.5 L16,4 L16,6.5 L2.5,3.5 Z" fill="currentColor"/>
|
|
<path d="M-16,4 L-17.5,2.5 L-17.5,5 L-16,6.5 Z" fill="currentColor"/>
|
|
<path d="M16,4 L17.5,2.5 L17.5,5 L16,6.5 Z" fill="currentColor"/>
|
|
<path d="M-1.2,10 L-7,11.8 L-7,13 L-1.2,11.5 Z" fill="currentColor"/>
|
|
<path d="M1.2,10 L7,11.8 L7,13 L1.2,11.5 Z" fill="currentColor"/>
|
|
<path d="M0,8 L-0.8,8 L-3,13.5 L0,13.5 L3,13.5 L0.8,8 Z" fill="currentColor"/>
|
|
<ellipse cx="0" cy="-15" rx="2.5" ry="3" fill="currentColor"/>
|
|
<ellipse cx="-6" cy="3" rx="1.5" ry="3" fill="currentColor"/>
|
|
<ellipse cx="6" cy="3" rx="1.5" ry="3" fill="currentColor"/>
|
|
<ellipse cx="-4" cy="4" rx="1" ry="2" fill="currentColor"/>
|
|
<ellipse cx="4" cy="4" rx="1" ry="2" fill="currentColor"/>
|
|
</g>
|
|
</svg>
|
|
</span>
|
|
<span>Heavy > 136000kg</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<span class="legend-icon helicopter">
|
|
<svg width="24" height="24" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
|
<g transform="translate(16,16)">
|
|
<!-- Main rotor disc -->
|
|
<ellipse cx="0" cy="-2" rx="11" ry="1" fill="currentColor" opacity="0.2"/>
|
|
<path d="M-11,-2 L11,-2" stroke="currentColor" stroke-width="0.5" opacity="0.4"/>
|
|
<!-- Main fuselage -->
|
|
<path d="M0,-8 C-3,-8 -4,-6 -4,-3 L-4,4 C-4,6 -3,7 -1,7 L1,7 C3,7 4,6 4,4 L4,-3 C4,-6 3,-8 0,-8 Z" fill="currentColor"/>
|
|
<!-- Cockpit windscreen -->
|
|
<path d="M0,-8 C-2,-8 -3,-7 -3,-5 L-3,-3 L3,-3 L3,-5 C3,-7 2,-8 0,-8 Z" fill="currentColor" opacity="0.7"/>
|
|
<!-- Tail boom -->
|
|
<rect x="-1" y="6" width="2" height="8" fill="currentColor"/>
|
|
<!-- Tail rotor -->
|
|
<ellipse cx="0" cy="13" rx="1" ry="3" fill="currentColor"/>
|
|
<path d="M-3,13 L3,13" stroke="currentColor" stroke-width="0.8"/>
|
|
<!-- Landing skids -->
|
|
<path d="M-3,7 L-3,9 L-1,9" stroke="currentColor" stroke-width="1" fill="none"/>
|
|
<path d="M3,7 L3,9 L1,9" stroke="currentColor" stroke-width="1" fill="none"/>
|
|
<!-- Rotor hub -->
|
|
<circle cx="0" cy="-2" r="1" fill="currentColor"/>
|
|
</g>
|
|
</svg>
|
|
</span>
|
|
<span>Rotorcraft</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<span class="legend-icon ga">
|
|
<svg width="24" height="24" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg">
|
|
<g transform="translate(14,14)">
|
|
<path d="M0,-8 L-0.8,-7.5 L-0.8,4 L-0.4,5.5 L0,6 L0.4,5.5 L0.8,4 L0.8,-7.5 Z" fill="currentColor"/>
|
|
<path d="M-0.8,-0.5 L-6,1 L-6,2 L-0.8,1 Z" fill="currentColor"/>
|
|
<path d="M0.8,-0.5 L6,1 L6,2 L0.8,1 Z" fill="currentColor"/>
|
|
<path d="M-0.4,4 L-2.5,4.8 L-2.5,5.2 L-0.4,4.8 Z" fill="currentColor"/>
|
|
<path d="M0.4,4 L2.5,4.8 L2.5,5.2 L0.4,4.8 Z" fill="currentColor"/>
|
|
<path d="M0,3 L-0.2,3 L-0.8,6 L0,6 L0.8,6 L0.2,3 Z" fill="currentColor"/>
|
|
<ellipse cx="0" cy="-7.5" rx="0.8" ry="1" fill="currentColor"/>
|
|
</g>
|
|
</svg>
|
|
</span>
|
|
<span>Glider/Ultralight</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<span class="legend-icon ground">
|
|
<svg width="24" height="24" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
|
<g transform="translate(16,16)">
|
|
<path d="M-6,-2 L6,-2 L8,0 L8,2 L-8,2 L-8,0 Z" fill="currentColor"/>
|
|
<ellipse cx="-4" cy="4" rx="2" ry="2" fill="currentColor"/>
|
|
<ellipse cx="4" cy="4" rx="2" ry="2" fill="currentColor"/>
|
|
<path d="M-2,-2 L2,-2 L2,-6 L-2,-6 Z" fill="currentColor"/>
|
|
<path d="M-1,-6 L1,-6 L1,-8 L-1,-8 Z" fill="currentColor"/>
|
|
</g>
|
|
</svg>
|
|
</span>
|
|
<span>Surface Vehicle</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<span class="legend-icon military">
|
|
<svg width="24" height="24" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
|
<g transform="translate(16,16)">
|
|
<path d="M0,-14 L-1.2,-12 L-1.2,6 L-0.8,9 L0,10 L0.8,9 L1.2,6 L1.2,-12 Z" fill="currentColor"/>
|
|
<path d="M-1.2,-1 L-11,2 L-11,3.5 L-1.2,2 Z" fill="currentColor"/>
|
|
<path d="M1.2,-1 L11,2 L11,3.5 L1.2,2 Z" fill="currentColor"/>
|
|
<path d="M-0.7,7 L-4.5,8 L-4.5,8.8 L-0.7,8 Z" fill="currentColor"/>
|
|
<path d="M0.7,7 L4.5,8 L4.5,8.8 L0.7,8 Z" fill="currentColor"/>
|
|
<path d="M0,5.5 L-0.4,5.5 L-1.8,10 L0,10 L1.8,10 L0.4,5.5 Z" fill="currentColor"/>
|
|
<ellipse cx="0" cy="-13" rx="1.2" ry="2" fill="currentColor"/>
|
|
<ellipse cx="-3.5" cy="1.8" rx="0.8" ry="1.8" fill="currentColor"/>
|
|
<ellipse cx="3.5" cy="1.8" rx="0.8" ry="1.8" fill="currentColor"/>
|
|
</g>
|
|
</svg>
|
|
</span>
|
|
<span>Military</span>
|
|
</div>
|
|
|
|
<h4>Sources</h4>
|
|
<div id="sources-legend"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Table View -->
|
|
<div id="table-view" class="view">
|
|
<div class="table-controls">
|
|
<input type="text" id="search-input" placeholder="Search by flight, ICAO, or squawk...">
|
|
<select id="sort-select">
|
|
<option value="distance">Distance</option>
|
|
<option value="altitude">Altitude</option>
|
|
<option value="speed">Speed</option>
|
|
<option value="flight">Flight</option>
|
|
<option value="icao">ICAO</option>
|
|
<option value="squawk">Squawk</option>
|
|
<option value="signal">Signal</option>
|
|
<option value="age">Age</option>
|
|
</select>
|
|
<select id="source-filter">
|
|
<option value="">All Sources</option>
|
|
</select>
|
|
</div>
|
|
<div class="table-container">
|
|
<table id="aircraft-table">
|
|
<thead>
|
|
<tr>
|
|
<th>ICAO</th>
|
|
<th>Flight</th>
|
|
<th>Squawk</th>
|
|
<th>Altitude</th>
|
|
<th>Speed</th>
|
|
<th>Distance</th>
|
|
<th>Track</th>
|
|
<th>Sources</th>
|
|
<th>Signal</th>
|
|
<th>Age</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="aircraft-tbody">
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Statistics View -->
|
|
<div id="stats-view" class="view">
|
|
<div class="stats-grid">
|
|
<div class="stat-card">
|
|
<h3>Total Aircraft</h3>
|
|
<div class="stat-value" id="total-aircraft">0</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Active Sources</h3>
|
|
<div class="stat-value" id="active-sources">0</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Active Viewers</h3>
|
|
<div class="stat-value" id="active-viewers">1</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Messages/sec</h3>
|
|
<div class="stat-value" id="messages-sec">0</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Max Range</h3>
|
|
<div class="stat-value" id="max-range">0 km</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Aircraft with Position</h3>
|
|
<div class="stat-value" id="aircraft-with-position">0</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Aircraft without Position</h3>
|
|
<div class="stat-value" id="aircraft-without-position">0</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Charts -->
|
|
<div class="charts-container">
|
|
<div class="chart-card">
|
|
<h3>Aircraft Count Timeline</h3>
|
|
<canvas id="aircraft-chart"></canvas>
|
|
</div>
|
|
<div class="chart-card">
|
|
<h3>Message Rate by Source <span class="under-construction">🚧 Under Construction</span></h3>
|
|
<canvas id="message-chart"></canvas>
|
|
<div class="construction-notice">This chart is planned but not yet implemented</div>
|
|
</div>
|
|
<div class="chart-card">
|
|
<h3>Signal Strength Distribution <span class="under-construction">🚧 Under Construction</span></h3>
|
|
<canvas id="signal-chart"></canvas>
|
|
<div class="construction-notice">This chart is planned but not yet implemented</div>
|
|
</div>
|
|
<div class="chart-card">
|
|
<h3>Altitude Distribution <span class="under-construction">🚧 Under Construction</span></h3>
|
|
<canvas id="altitude-chart"></canvas>
|
|
<div class="construction-notice">This chart is planned but not yet implemented</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Coverage View -->
|
|
<div id="coverage-view" class="view">
|
|
<div class="coverage-controls">
|
|
<select id="coverage-source">
|
|
<option value="">Select Source</option>
|
|
</select>
|
|
<button id="toggle-heatmap">Toggle Heatmap</button>
|
|
</div>
|
|
<div id="coverage-map"></div>
|
|
</div>
|
|
|
|
<!-- 3D Radar View -->
|
|
<div id="radar3d-view" class="view">
|
|
<div class="radar3d-controls">
|
|
<div class="construction-notice">🚧 3D Controls Under Construction</div>
|
|
<button id="radar3d-reset" disabled>Reset View</button>
|
|
<button id="radar3d-auto-rotate" disabled>Auto Rotate</button>
|
|
<label>
|
|
<input type="range" id="radar3d-range" min="10" max="500" value="100" disabled>
|
|
Range: <span id="radar3d-range-value">100</span> km
|
|
</label>
|
|
</div>
|
|
<div id="radar3d-container"></div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<!-- Leaflet JS -->
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
|
|
<!-- Custom JS -->
|
|
<script type="module" src="/static/js/app.js?v=4"></script>
|
|
</body>
|
|
</html> |