mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
Harden dashboard loading against network stalls
This commit is contained in:
@@ -4,27 +4,10 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>AIRCRAFT RADAR // INTERCEPT - See the Invisible</title>
|
<title>AIRCRAFT RADAR // INTERCEPT - See the Invisible</title>
|
||||||
<!-- Preconnect hints -->
|
<!-- Dedicated dashboards always use bundled assets so navigation is not
|
||||||
{% if offline_settings.assets_source != 'local' %}
|
blocked by external CDN reachability. -->
|
||||||
<link rel="preconnect" href="https://unpkg.com" crossorigin>
|
|
||||||
{% endif %}
|
|
||||||
{% if offline_settings.fonts_source != 'local' %}
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
{% endif %}
|
|
||||||
<link rel="preconnect" href="https://cartodb-basemaps-a.global.ssl.fastly.net" crossorigin>
|
|
||||||
<!-- Fonts - Conditional CDN/Local loading -->
|
|
||||||
{% if offline_settings.fonts_source == 'local' %}
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts-local.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts-local.css') }}">
|
||||||
{% else %}
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
|
||||||
{% endif %}
|
|
||||||
<!-- Leaflet CSS -->
|
|
||||||
{% if offline_settings.assets_source == 'local' %}
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='vendor/leaflet/leaflet.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='vendor/leaflet/leaflet.css') }}">
|
||||||
{% else %}
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
||||||
{% endif %}
|
|
||||||
<!-- Core CSS -->
|
<!-- Core CSS -->
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/variables.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/variables.css') }}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||||
@@ -39,11 +22,7 @@
|
|||||||
window.INTERCEPT_DEFAULT_LAT = {{ default_latitude | tojson }};
|
window.INTERCEPT_DEFAULT_LAT = {{ default_latitude | tojson }};
|
||||||
window.INTERCEPT_DEFAULT_LON = {{ default_longitude | tojson }};
|
window.INTERCEPT_DEFAULT_LON = {{ default_longitude | tojson }};
|
||||||
</script>
|
</script>
|
||||||
{% if offline_settings.assets_source == 'local' %}
|
|
||||||
<script defer src="{{ url_for('static', filename='vendor/leaflet/leaflet.js') }}"></script>
|
<script defer src="{{ url_for('static', filename='vendor/leaflet/leaflet.js') }}"></script>
|
||||||
{% else %}
|
|
||||||
<script defer src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
||||||
{% endif %}
|
|
||||||
<script defer src="{{ url_for('static', filename='js/core/observer-location.js') }}"></script>
|
<script defer src="{{ url_for('static', filename='js/core/observer-location.js') }}"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -2100,6 +2079,47 @@ sudo make install</code>
|
|||||||
now.toISOString().substring(11, 19) + ' UTC';
|
now.toISOString().substring(11, 19) + ' UTC';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createFallbackGridLayer() {
|
||||||
|
const layer = L.gridLayer({
|
||||||
|
tileSize: 256,
|
||||||
|
updateWhenIdle: true,
|
||||||
|
attribution: 'Local fallback grid'
|
||||||
|
});
|
||||||
|
layer.createTile = function(coords) {
|
||||||
|
const tile = document.createElement('canvas');
|
||||||
|
tile.width = 256;
|
||||||
|
tile.height = 256;
|
||||||
|
const ctx = tile.getContext('2d');
|
||||||
|
|
||||||
|
ctx.fillStyle = '#08121c';
|
||||||
|
ctx.fillRect(0, 0, 256, 256);
|
||||||
|
|
||||||
|
ctx.strokeStyle = 'rgba(0, 212, 255, 0.14)';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0, 0);
|
||||||
|
ctx.lineTo(256, 0);
|
||||||
|
ctx.moveTo(0, 0);
|
||||||
|
ctx.lineTo(0, 256);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.strokeStyle = 'rgba(0, 212, 255, 0.08)';
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(128, 0);
|
||||||
|
ctx.lineTo(128, 256);
|
||||||
|
ctx.moveTo(0, 128);
|
||||||
|
ctx.lineTo(256, 128);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.fillStyle = 'rgba(160, 220, 255, 0.28)';
|
||||||
|
ctx.font = '11px "JetBrains Mono", monospace';
|
||||||
|
ctx.fillText(`Z${coords.z} X${coords.x} Y${coords.y}`, 12, 22);
|
||||||
|
|
||||||
|
return tile;
|
||||||
|
};
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
async function initMap() {
|
async function initMap() {
|
||||||
// Guard against double initialization (e.g. bfcache restore)
|
// Guard against double initialization (e.g. bfcache restore)
|
||||||
const container = document.getElementById('radarMap');
|
const container = document.getElementById('radarMap');
|
||||||
@@ -2115,13 +2135,9 @@ sudo make install</code>
|
|||||||
// Use settings manager for tile layer (allows runtime changes)
|
// Use settings manager for tile layer (allows runtime changes)
|
||||||
window.radarMap = radarMap;
|
window.radarMap = radarMap;
|
||||||
|
|
||||||
// Add fallback tiles immediately so the map is never blank
|
// Use a zero-network fallback so dashboard navigation stays fast even
|
||||||
const fallbackTiles = L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png', {
|
// when internet map providers are slow or unreachable.
|
||||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OSM</a> © <a href="https://carto.com/">CARTO</a>',
|
const fallbackTiles = createFallbackGridLayer().addTo(radarMap);
|
||||||
maxZoom: 19,
|
|
||||||
subdomains: 'abcd',
|
|
||||||
className: 'tile-layer-cyan'
|
|
||||||
}).addTo(radarMap);
|
|
||||||
|
|
||||||
// Draw range rings after map is ready
|
// Draw range rings after map is ready
|
||||||
setTimeout(() => drawRangeRings(), 100);
|
setTimeout(() => drawRangeRings(), 100);
|
||||||
|
|||||||
@@ -4,27 +4,10 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>VESSEL RADAR // INTERCEPT - See the Invisible</title>
|
<title>VESSEL RADAR // INTERCEPT - See the Invisible</title>
|
||||||
<!-- Preconnect hints -->
|
<!-- Dedicated dashboards always use bundled assets so navigation is not
|
||||||
{% if offline_settings.assets_source != 'local' %}
|
blocked by external CDN reachability. -->
|
||||||
<link rel="preconnect" href="https://unpkg.com" crossorigin>
|
|
||||||
{% endif %}
|
|
||||||
{% if offline_settings.fonts_source != 'local' %}
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
{% endif %}
|
|
||||||
<link rel="preconnect" href="https://cartodb-basemaps-a.global.ssl.fastly.net" crossorigin>
|
|
||||||
<!-- Fonts - Conditional CDN/Local loading -->
|
|
||||||
{% if offline_settings.fonts_source == 'local' %}
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts-local.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts-local.css') }}">
|
||||||
{% else %}
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
|
||||||
{% endif %}
|
|
||||||
<!-- Leaflet CSS -->
|
|
||||||
{% if offline_settings.assets_source == 'local' %}
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='vendor/leaflet/leaflet.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='vendor/leaflet/leaflet.css') }}">
|
||||||
{% else %}
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
||||||
{% endif %}
|
|
||||||
<!-- Core CSS -->
|
<!-- Core CSS -->
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/variables.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/variables.css') }}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/ais_dashboard.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/ais_dashboard.css') }}">
|
||||||
@@ -38,11 +21,7 @@
|
|||||||
window.INTERCEPT_DEFAULT_LAT = {{ default_latitude | tojson }};
|
window.INTERCEPT_DEFAULT_LAT = {{ default_latitude | tojson }};
|
||||||
window.INTERCEPT_DEFAULT_LON = {{ default_longitude | tojson }};
|
window.INTERCEPT_DEFAULT_LON = {{ default_longitude | tojson }};
|
||||||
</script>
|
</script>
|
||||||
{% if offline_settings.assets_source == 'local' %}
|
|
||||||
<script defer src="{{ url_for('static', filename='vendor/leaflet/leaflet.js') }}"></script>
|
<script defer src="{{ url_for('static', filename='vendor/leaflet/leaflet.js') }}"></script>
|
||||||
{% else %}
|
|
||||||
<script defer src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
||||||
{% endif %}
|
|
||||||
<script defer src="{{ url_for('static', filename='js/core/observer-location.js') }}"></script>
|
<script defer src="{{ url_for('static', filename='js/core/observer-location.js') }}"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -409,6 +388,47 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Initialize map
|
// Initialize map
|
||||||
|
function createFallbackGridLayer() {
|
||||||
|
const layer = L.gridLayer({
|
||||||
|
tileSize: 256,
|
||||||
|
updateWhenIdle: true,
|
||||||
|
attribution: 'Local fallback grid'
|
||||||
|
});
|
||||||
|
layer.createTile = function(coords) {
|
||||||
|
const tile = document.createElement('canvas');
|
||||||
|
tile.width = 256;
|
||||||
|
tile.height = 256;
|
||||||
|
const ctx = tile.getContext('2d');
|
||||||
|
|
||||||
|
ctx.fillStyle = '#07131c';
|
||||||
|
ctx.fillRect(0, 0, 256, 256);
|
||||||
|
|
||||||
|
ctx.strokeStyle = 'rgba(0, 212, 255, 0.12)';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0, 0);
|
||||||
|
ctx.lineTo(256, 0);
|
||||||
|
ctx.moveTo(0, 0);
|
||||||
|
ctx.lineTo(0, 256);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.strokeStyle = 'rgba(34, 197, 94, 0.10)';
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(128, 0);
|
||||||
|
ctx.lineTo(128, 256);
|
||||||
|
ctx.moveTo(0, 128);
|
||||||
|
ctx.lineTo(256, 128);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.fillStyle = 'rgba(160, 220, 255, 0.28)';
|
||||||
|
ctx.font = '11px "JetBrains Mono", monospace';
|
||||||
|
ctx.fillText(`Z${coords.z} X${coords.x} Y${coords.y}`, 12, 22);
|
||||||
|
|
||||||
|
return tile;
|
||||||
|
};
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
async function initMap() {
|
async function initMap() {
|
||||||
// Guard against double initialization (e.g. bfcache restore)
|
// Guard against double initialization (e.g. bfcache restore)
|
||||||
const container = document.getElementById('vesselMap');
|
const container = document.getElementById('vesselMap');
|
||||||
@@ -428,13 +448,9 @@
|
|||||||
// Use settings manager for tile layer (allows runtime changes)
|
// Use settings manager for tile layer (allows runtime changes)
|
||||||
window.vesselMap = vesselMap;
|
window.vesselMap = vesselMap;
|
||||||
|
|
||||||
// Add fallback tile layer immediately so the map is never blank
|
// Use a zero-network fallback so dashboard navigation stays fast even
|
||||||
const fallbackTiles = L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png', {
|
// when internet map providers are slow or unreachable.
|
||||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OSM</a> © <a href="https://carto.com/">CARTO</a>',
|
const fallbackTiles = createFallbackGridLayer().addTo(vesselMap);
|
||||||
maxZoom: 19,
|
|
||||||
subdomains: 'abcd',
|
|
||||||
className: 'tile-layer-cyan'
|
|
||||||
}).addTo(vesselMap);
|
|
||||||
|
|
||||||
// Then try to upgrade tiles via Settings (non-blocking)
|
// Then try to upgrade tiles via Settings (non-blocking)
|
||||||
if (typeof Settings !== 'undefined') {
|
if (typeof Settings !== 'undefined') {
|
||||||
|
|||||||
@@ -4,20 +4,11 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>SATELLITE COMMAND // iNTERCEPT - See the Invisible</title>
|
<title>SATELLITE COMMAND // iNTERCEPT - See the Invisible</title>
|
||||||
<!-- Fonts - Conditional CDN/Local loading -->
|
<!-- Dedicated dashboards always use bundled assets so navigation is not
|
||||||
{% if offline_settings.fonts_source == 'local' %}
|
blocked by external CDN reachability. -->
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts-local.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts-local.css') }}">
|
||||||
{% else %}
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
|
||||||
{% endif %}
|
|
||||||
<!-- Leaflet.js - Conditional CDN/Local loading -->
|
|
||||||
{% if offline_settings.assets_source == 'local' %}
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='vendor/leaflet/leaflet.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='vendor/leaflet/leaflet.css') }}">
|
||||||
<script src="{{ url_for('static', filename='vendor/leaflet/leaflet.js') }}"></script>
|
<script src="{{ url_for('static', filename='vendor/leaflet/leaflet.js') }}"></script>
|
||||||
{% else %}
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
||||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
||||||
{% endif %}
|
|
||||||
<!-- Core CSS variables -->
|
<!-- Core CSS variables -->
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/variables.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/variables.css') }}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||||
@@ -903,6 +894,47 @@
|
|||||||
now.toISOString().substring(11, 19) + ' UTC';
|
now.toISOString().substring(11, 19) + ' UTC';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createFallbackGridLayer() {
|
||||||
|
const layer = L.gridLayer({
|
||||||
|
tileSize: 256,
|
||||||
|
updateWhenIdle: true,
|
||||||
|
attribution: 'Local fallback grid'
|
||||||
|
});
|
||||||
|
layer.createTile = function(coords) {
|
||||||
|
const tile = document.createElement('canvas');
|
||||||
|
tile.width = 256;
|
||||||
|
tile.height = 256;
|
||||||
|
const ctx = tile.getContext('2d');
|
||||||
|
|
||||||
|
ctx.fillStyle = '#08121c';
|
||||||
|
ctx.fillRect(0, 0, 256, 256);
|
||||||
|
|
||||||
|
ctx.strokeStyle = 'rgba(0, 212, 255, 0.12)';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0, 0);
|
||||||
|
ctx.lineTo(256, 0);
|
||||||
|
ctx.moveTo(0, 0);
|
||||||
|
ctx.lineTo(0, 256);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.strokeStyle = 'rgba(255, 255, 255, 0.06)';
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(128, 0);
|
||||||
|
ctx.lineTo(128, 256);
|
||||||
|
ctx.moveTo(0, 128);
|
||||||
|
ctx.lineTo(256, 128);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.fillStyle = 'rgba(160, 220, 255, 0.28)';
|
||||||
|
ctx.font = '11px "JetBrains Mono", monospace';
|
||||||
|
ctx.fillText(`Z${coords.z} X${coords.x} Y${coords.y}`, 12, 22);
|
||||||
|
|
||||||
|
return tile;
|
||||||
|
};
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
async function initGroundMap() {
|
async function initGroundMap() {
|
||||||
groundMap = L.map('groundMap', {
|
groundMap = L.map('groundMap', {
|
||||||
center: [20, 0],
|
center: [20, 0],
|
||||||
@@ -914,13 +946,9 @@
|
|||||||
|
|
||||||
window.groundMap = groundMap;
|
window.groundMap = groundMap;
|
||||||
|
|
||||||
// Add fallback tiles immediately so the map is visible instantly
|
// Use a zero-network fallback so dashboard navigation stays fast even
|
||||||
const fallbackTiles = L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png', {
|
// when internet map providers are slow or unreachable.
|
||||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OSM</a> © <a href="https://carto.com/">CARTO</a>',
|
const fallbackTiles = createFallbackGridLayer().addTo(groundMap);
|
||||||
maxZoom: 19,
|
|
||||||
subdomains: 'abcd',
|
|
||||||
className: 'tile-layer-cyan'
|
|
||||||
}).addTo(groundMap);
|
|
||||||
|
|
||||||
// Upgrade tiles in background via Settings (with timeout fallback)
|
// Upgrade tiles in background via Settings (with timeout fallback)
|
||||||
if (typeof Settings !== 'undefined') {
|
if (typeof Settings !== 'undefined') {
|
||||||
|
|||||||
Reference in New Issue
Block a user