mirror of
https://github.com/smittix/intercept.git
synced 2026-07-07 17:18:11 -07:00
Merge branch 'upstream-shared-observer-location'
This commit is contained in:
@@ -74,6 +74,47 @@ The ADS-B history feature persists aircraft messages to Postgres for long-term a
|
|||||||
docker compose --profile history up -d
|
docker compose --profile history up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Set the following environment variables (for example in a `.env` file):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
INTERCEPT_ADSB_HISTORY_ENABLED=true
|
||||||
|
INTERCEPT_ADSB_DB_HOST=adsb_db
|
||||||
|
INTERCEPT_ADSB_DB_PORT=5432
|
||||||
|
INTERCEPT_ADSB_DB_NAME=intercept_adsb
|
||||||
|
INTERCEPT_ADSB_DB_USER=intercept
|
||||||
|
INTERCEPT_ADSB_DB_PASSWORD=intercept
|
||||||
|
```
|
||||||
|
|
||||||
|
### Other ADS-B Settings
|
||||||
|
|
||||||
|
Set these as environment variables for either local installs or Docker:
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| `INTERCEPT_ADSB_AUTO_START` | `false` | Auto-start ADS-B tracking when the dashboard loads |
|
||||||
|
| `INTERCEPT_SHARED_OBSERVER_LOCATION` | `true` | Share observer location across ADS-B/AIS/SSTV/Satellite modules |
|
||||||
|
|
||||||
|
**Local install example**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
INTERCEPT_ADSB_AUTO_START=true \
|
||||||
|
INTERCEPT_SHARED_OBSERVER_LOCATION=false \
|
||||||
|
python app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
**Docker example (.env)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
INTERCEPT_ADSB_AUTO_START=true
|
||||||
|
INTERCEPT_SHARED_OBSERVER_LOCATION=false
|
||||||
|
```
|
||||||
|
|
||||||
|
To store Postgres data on external storage, set `PGDATA_PATH` (defaults to `./pgdata`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PGDATA_PATH=/mnt/usbpi1/intercept/pgdata
|
||||||
|
```
|
||||||
|
|
||||||
Then open **/adsb/history** for the reporting dashboard.
|
Then open **/adsb/history** for the reporting dashboard.
|
||||||
|
|
||||||
### Open the Interface
|
### Open the Interface
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ from typing import Any
|
|||||||
|
|
||||||
from flask import Flask, render_template, jsonify, send_file, Response, request,redirect, url_for, flash, session
|
from flask import Flask, render_template, jsonify, send_file, Response, request,redirect, url_for, flash, session
|
||||||
from werkzeug.security import check_password_hash
|
from werkzeug.security import check_password_hash
|
||||||
from config import VERSION, CHANGELOG
|
from config import VERSION, CHANGELOG, SHARED_OBSERVER_LOCATION_ENABLED
|
||||||
from utils.dependencies import check_tool, check_all_dependencies, TOOL_DEPENDENCIES
|
from utils.dependencies import check_tool, check_all_dependencies, TOOL_DEPENDENCIES
|
||||||
from utils.process import cleanup_stale_processes
|
from utils.process import cleanup_stale_processes
|
||||||
from utils.sdr import SDRFactory
|
from utils.sdr import SDRFactory
|
||||||
@@ -279,7 +279,14 @@ def index() -> str:
|
|||||||
'rtlamr': check_tool('rtlamr')
|
'rtlamr': check_tool('rtlamr')
|
||||||
}
|
}
|
||||||
devices = [d.to_dict() for d in SDRFactory.detect_devices()]
|
devices = [d.to_dict() for d in SDRFactory.detect_devices()]
|
||||||
return render_template('index.html', tools=tools, devices=devices, version=VERSION, changelog=CHANGELOG)
|
return render_template(
|
||||||
|
'index.html',
|
||||||
|
tools=tools,
|
||||||
|
devices=devices,
|
||||||
|
version=VERSION,
|
||||||
|
changelog=CHANGELOG,
|
||||||
|
shared_observer_location=SHARED_OBSERVER_LOCATION_ENABLED,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/favicon.svg')
|
@app.route('/favicon.svg')
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ BT_UPDATE_INTERVAL = _get_env_float('BT_UPDATE_INTERVAL', 2.0)
|
|||||||
# ADS-B settings
|
# ADS-B settings
|
||||||
ADSB_SBS_PORT = _get_env_int('ADSB_SBS_PORT', 30003)
|
ADSB_SBS_PORT = _get_env_int('ADSB_SBS_PORT', 30003)
|
||||||
ADSB_UPDATE_INTERVAL = _get_env_float('ADSB_UPDATE_INTERVAL', 1.0)
|
ADSB_UPDATE_INTERVAL = _get_env_float('ADSB_UPDATE_INTERVAL', 1.0)
|
||||||
|
ADSB_AUTO_START = _get_env_bool('ADSB_AUTO_START', False)
|
||||||
ADSB_HISTORY_ENABLED = _get_env_bool('ADSB_HISTORY_ENABLED', False)
|
ADSB_HISTORY_ENABLED = _get_env_bool('ADSB_HISTORY_ENABLED', False)
|
||||||
ADSB_DB_HOST = _get_env('ADSB_DB_HOST', 'localhost')
|
ADSB_DB_HOST = _get_env('ADSB_DB_HOST', 'localhost')
|
||||||
ADSB_DB_PORT = _get_env_int('ADSB_DB_PORT', 5432)
|
ADSB_DB_PORT = _get_env_int('ADSB_DB_PORT', 5432)
|
||||||
@@ -149,6 +150,9 @@ ADSB_HISTORY_BATCH_SIZE = _get_env_int('ADSB_HISTORY_BATCH_SIZE', 500)
|
|||||||
ADSB_HISTORY_FLUSH_INTERVAL = _get_env_float('ADSB_HISTORY_FLUSH_INTERVAL', 1.0)
|
ADSB_HISTORY_FLUSH_INTERVAL = _get_env_float('ADSB_HISTORY_FLUSH_INTERVAL', 1.0)
|
||||||
ADSB_HISTORY_QUEUE_SIZE = _get_env_int('ADSB_HISTORY_QUEUE_SIZE', 50000)
|
ADSB_HISTORY_QUEUE_SIZE = _get_env_int('ADSB_HISTORY_QUEUE_SIZE', 50000)
|
||||||
|
|
||||||
|
# Observer location settings
|
||||||
|
SHARED_OBSERVER_LOCATION_ENABLED = _get_env_bool('SHARED_OBSERVER_LOCATION', True)
|
||||||
|
|
||||||
# Satellite settings
|
# Satellite settings
|
||||||
SATELLITE_UPDATE_INTERVAL = _get_env_int('SATELLITE_UPDATE_INTERVAL', 30)
|
SATELLITE_UPDATE_INTERVAL = _get_env_int('SATELLITE_UPDATE_INTERVAL', 30)
|
||||||
SATELLITE_TRAJECTORY_POINTS = _get_env_int('SATELLITE_TRAJECTORY_POINTS', 30)
|
SATELLITE_TRAJECTORY_POINTS = _get_env_int('SATELLITE_TRAJECTORY_POINTS', 30)
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ services:
|
|||||||
# - INTERCEPT_ADSB_DB_NAME=intercept_adsb
|
# - INTERCEPT_ADSB_DB_NAME=intercept_adsb
|
||||||
# - INTERCEPT_ADSB_DB_USER=intercept
|
# - INTERCEPT_ADSB_DB_USER=intercept
|
||||||
# - INTERCEPT_ADSB_DB_PASSWORD=intercept
|
# - INTERCEPT_ADSB_DB_PASSWORD=intercept
|
||||||
|
# ADS-B auto-start on dashboard load (default false)
|
||||||
|
- INTERCEPT_ADSB_AUTO_START=${INTERCEPT_ADSB_AUTO_START:-false}
|
||||||
|
# Shared observer location across modules
|
||||||
|
- INTERCEPT_SHARED_OBSERVER_LOCATION=${INTERCEPT_SHARED_OBSERVER_LOCATION:-true}
|
||||||
# Network mode for WiFi scanning (requires host network)
|
# Network mode for WiFi scanning (requires host network)
|
||||||
# network_mode: host
|
# network_mode: host
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -68,6 +72,10 @@ services:
|
|||||||
- INTERCEPT_ADSB_DB_NAME=intercept_adsb
|
- INTERCEPT_ADSB_DB_NAME=intercept_adsb
|
||||||
- INTERCEPT_ADSB_DB_USER=intercept
|
- INTERCEPT_ADSB_DB_USER=intercept
|
||||||
- INTERCEPT_ADSB_DB_PASSWORD=intercept
|
- INTERCEPT_ADSB_DB_PASSWORD=intercept
|
||||||
|
# ADS-B auto-start on dashboard load (default false)
|
||||||
|
- INTERCEPT_ADSB_AUTO_START=${INTERCEPT_ADSB_AUTO_START:-false}
|
||||||
|
# Shared observer location across modules
|
||||||
|
- INTERCEPT_SHARED_OBSERVER_LOCATION=${INTERCEPT_SHARED_OBSERVER_LOCATION:-true}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-sf", "http://localhost:5050/health"]
|
test: ["CMD", "curl", "-sf", "http://localhost:5050/health"]
|
||||||
|
|||||||
+34
-1
@@ -65,6 +65,8 @@ INTERCEPT automatically detects known trackers:
|
|||||||
- **Manual Entry** - Type coordinates directly
|
- **Manual Entry** - Type coordinates directly
|
||||||
- **Browser GPS** - Use browser's built-in geolocation (requires HTTPS)
|
- **Browser GPS** - Use browser's built-in geolocation (requires HTTPS)
|
||||||
- **USB GPS Dongle** - Connect a USB GPS receiver for continuous updates
|
- **USB GPS Dongle** - Connect a USB GPS receiver for continuous updates
|
||||||
|
- **Shared Location** - By default, the observer location is shared across modules
|
||||||
|
(disable with `INTERCEPT_SHARED_OBSERVER_LOCATION=false`)
|
||||||
4. **Start Tracking** - Click "Start Tracking" to begin ADS-B reception
|
4. **Start Tracking** - Click "Start Tracking" to begin ADS-B reception
|
||||||
5. **View Map** - Aircraft appear on the interactive Leaflet map
|
5. **View Map** - Aircraft appear on the interactive Leaflet map
|
||||||
6. **Click Aircraft** - Click markers for detailed information
|
6. **Click Aircraft** - Click markers for detailed information
|
||||||
@@ -72,6 +74,9 @@ INTERCEPT automatically detects known trackers:
|
|||||||
8. **Filter Aircraft** - Use dropdown to show all, military, civil, or emergency only
|
8. **Filter Aircraft** - Use dropdown to show all, military, civil, or emergency only
|
||||||
9. **Full Dashboard** - Click "Full Screen Dashboard" for dedicated radar view
|
9. **Full Dashboard** - Click "Full Screen Dashboard" for dedicated radar view
|
||||||
|
|
||||||
|
> Note: ADS-B auto-start is disabled by default. To enable auto-start on dashboard load,
|
||||||
|
> set `INTERCEPT_ADSB_AUTO_START=true`.
|
||||||
|
|
||||||
### Emergency Squawks
|
### Emergency Squawks
|
||||||
|
|
||||||
The system highlights aircraft transmitting emergency squawks:
|
The system highlights aircraft transmitting emergency squawks:
|
||||||
@@ -96,12 +101,40 @@ Set the following environment variables (Docker recommended):
|
|||||||
| `INTERCEPT_ADSB_DB_USER` | `intercept` | Database user |
|
| `INTERCEPT_ADSB_DB_USER` | `intercept` | Database user |
|
||||||
| `INTERCEPT_ADSB_DB_PASSWORD` | `intercept` | Database password |
|
| `INTERCEPT_ADSB_DB_PASSWORD` | `intercept` | Database password |
|
||||||
|
|
||||||
|
### Other ADS-B Settings
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| `INTERCEPT_ADSB_AUTO_START` | `false` | Auto-start ADS-B tracking when the dashboard loads |
|
||||||
|
| `INTERCEPT_SHARED_OBSERVER_LOCATION` | `true` | Share observer location across ADS-B/AIS/SSTV/Satellite modules |
|
||||||
|
|
||||||
|
**Local install example**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
INTERCEPT_ADSB_AUTO_START=true \
|
||||||
|
INTERCEPT_SHARED_OBSERVER_LOCATION=false \
|
||||||
|
python app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
**Docker example (.env)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
INTERCEPT_ADSB_AUTO_START=true
|
||||||
|
INTERCEPT_SHARED_OBSERVER_LOCATION=false
|
||||||
|
```
|
||||||
|
|
||||||
### Docker Setup
|
### Docker Setup
|
||||||
|
|
||||||
`docker-compose.yml` includes an `adsb_db` service and a persistent volume for history storage:
|
`docker-compose.yml` includes an `adsb_db` service and a persistent volume for history storage:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose up -d
|
docker compose --profile history up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
To store Postgres data on external storage, set `PGDATA_PATH` (defaults to `./pgdata`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PGDATA_PATH=/mnt/usbpi1/intercept/pgdata
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using the History Dashboard
|
### Using the History Dashboard
|
||||||
|
|||||||
+7
-1
@@ -33,7 +33,9 @@ from config import (
|
|||||||
ADSB_DB_PASSWORD,
|
ADSB_DB_PASSWORD,
|
||||||
ADSB_DB_PORT,
|
ADSB_DB_PORT,
|
||||||
ADSB_DB_USER,
|
ADSB_DB_USER,
|
||||||
|
ADSB_AUTO_START,
|
||||||
ADSB_HISTORY_ENABLED,
|
ADSB_HISTORY_ENABLED,
|
||||||
|
SHARED_OBSERVER_LOCATION_ENABLED,
|
||||||
)
|
)
|
||||||
from utils.logging import adsb_logger as logger
|
from utils.logging import adsb_logger as logger
|
||||||
from utils.validation import (
|
from utils.validation import (
|
||||||
@@ -812,7 +814,11 @@ def stream_adsb():
|
|||||||
@adsb_bp.route('/dashboard')
|
@adsb_bp.route('/dashboard')
|
||||||
def adsb_dashboard():
|
def adsb_dashboard():
|
||||||
"""Popout ADS-B dashboard."""
|
"""Popout ADS-B dashboard."""
|
||||||
return render_template('adsb_dashboard.html')
|
return render_template(
|
||||||
|
'adsb_dashboard.html',
|
||||||
|
shared_observer_location=SHARED_OBSERVER_LOCATION_ENABLED,
|
||||||
|
adsb_auto_start=ADSB_AUTO_START,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@adsb_bp.route('/history')
|
@adsb_bp.route('/history')
|
||||||
|
|||||||
+5
-1
@@ -15,6 +15,7 @@ from typing import Generator
|
|||||||
from flask import Blueprint, jsonify, request, Response, render_template
|
from flask import Blueprint, jsonify, request, Response, render_template
|
||||||
|
|
||||||
import app as app_module
|
import app as app_module
|
||||||
|
from config import SHARED_OBSERVER_LOCATION_ENABLED
|
||||||
from utils.logging import get_logger
|
from utils.logging import get_logger
|
||||||
from utils.validation import validate_device_index, validate_gain
|
from utils.validation import validate_device_index, validate_gain
|
||||||
from utils.sse import format_sse
|
from utils.sse import format_sse
|
||||||
@@ -480,4 +481,7 @@ def stream_ais():
|
|||||||
@ais_bp.route('/dashboard')
|
@ais_bp.route('/dashboard')
|
||||||
def ais_dashboard():
|
def ais_dashboard():
|
||||||
"""Popout AIS dashboard."""
|
"""Popout AIS dashboard."""
|
||||||
return render_template('ais_dashboard.html')
|
return render_template(
|
||||||
|
'ais_dashboard.html',
|
||||||
|
shared_observer_location=SHARED_OBSERVER_LOCATION_ENABLED,
|
||||||
|
)
|
||||||
|
|||||||
+6
-1
@@ -13,6 +13,8 @@ import requests
|
|||||||
|
|
||||||
from flask import Blueprint, jsonify, request, render_template, Response
|
from flask import Blueprint, jsonify, request, render_template, Response
|
||||||
|
|
||||||
|
from config import SHARED_OBSERVER_LOCATION_ENABLED
|
||||||
|
|
||||||
from data.satellites import TLE_SATELLITES
|
from data.satellites import TLE_SATELLITES
|
||||||
from utils.logging import satellite_logger as logger
|
from utils.logging import satellite_logger as logger
|
||||||
from utils.validation import validate_latitude, validate_longitude, validate_hours, validate_elevation
|
from utils.validation import validate_latitude, validate_longitude, validate_hours, validate_elevation
|
||||||
@@ -120,7 +122,10 @@ def _fetch_iss_realtime(observer_lat: Optional[float] = None, observer_lon: Opti
|
|||||||
@satellite_bp.route('/dashboard')
|
@satellite_bp.route('/dashboard')
|
||||||
def satellite_dashboard():
|
def satellite_dashboard():
|
||||||
"""Popout satellite tracking dashboard."""
|
"""Popout satellite tracking dashboard."""
|
||||||
return render_template('satellite_dashboard.html')
|
return render_template(
|
||||||
|
'satellite_dashboard.html',
|
||||||
|
shared_observer_location=SHARED_OBSERVER_LOCATION_ENABLED,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@satellite_bp.route('/predict', methods=['POST'])
|
@satellite_bp.route('/predict', methods=['POST'])
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ let muted = localStorage.getItem('audioMuted') === 'true';
|
|||||||
|
|
||||||
// Observer location (load from localStorage or default to London)
|
// Observer location (load from localStorage or default to London)
|
||||||
let observerLocation = (function() {
|
let observerLocation = (function() {
|
||||||
|
if (window.ObserverLocation && ObserverLocation.getForModule) {
|
||||||
|
return ObserverLocation.getForModule('observerLocation');
|
||||||
|
}
|
||||||
const saved = localStorage.getItem('observerLocation');
|
const saved = localStorage.getItem('observerLocation');
|
||||||
if (saved) {
|
if (saved) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
// Shared observer location helper for map-based modules.
|
||||||
|
// Default: shared location enabled unless explicitly disabled via config.
|
||||||
|
window.ObserverLocation = (function() {
|
||||||
|
const DEFAULT_LOCATION = { lat: 51.5074, lon: -0.1278 };
|
||||||
|
const SHARED_KEY = 'observerLocation';
|
||||||
|
const AIS_KEY = 'ais_observerLocation';
|
||||||
|
const LEGACY_LAT_KEY = 'observerLat';
|
||||||
|
const LEGACY_LON_KEY = 'observerLon';
|
||||||
|
|
||||||
|
function isSharedEnabled() {
|
||||||
|
return window.INTERCEPT_SHARED_OBSERVER_LOCATION !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalize(lat, lon) {
|
||||||
|
const latNum = parseFloat(lat);
|
||||||
|
const lonNum = parseFloat(lon);
|
||||||
|
if (Number.isNaN(latNum) || Number.isNaN(lonNum)) return null;
|
||||||
|
if (latNum < -90 || latNum > 90 || lonNum < -180 || lonNum > 180) return null;
|
||||||
|
return { lat: latNum, lon: lonNum };
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseLocation(raw) {
|
||||||
|
if (!raw) return null;
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
if (parsed && parsed.lat !== undefined && parsed.lon !== undefined) {
|
||||||
|
return normalize(parsed.lat, parsed.lon);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readKey(key) {
|
||||||
|
return parseLocation(localStorage.getItem(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
function readLegacyLatLon() {
|
||||||
|
const lat = localStorage.getItem(LEGACY_LAT_KEY);
|
||||||
|
const lon = localStorage.getItem(LEGACY_LON_KEY);
|
||||||
|
if (!lat || !lon) return null;
|
||||||
|
return normalize(lat, lon);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getShared() {
|
||||||
|
const current = readKey(SHARED_KEY);
|
||||||
|
if (current) return current;
|
||||||
|
|
||||||
|
const legacy = readKey(AIS_KEY) || readLegacyLatLon();
|
||||||
|
if (legacy) {
|
||||||
|
setShared(legacy);
|
||||||
|
return legacy;
|
||||||
|
}
|
||||||
|
return { ...DEFAULT_LOCATION };
|
||||||
|
}
|
||||||
|
|
||||||
|
function setShared(location, options = {}) {
|
||||||
|
if (!location) return;
|
||||||
|
localStorage.setItem(SHARED_KEY, JSON.stringify(location));
|
||||||
|
if (options.updateLegacy !== false) {
|
||||||
|
localStorage.setItem(LEGACY_LAT_KEY, location.lat.toString());
|
||||||
|
localStorage.setItem(LEGACY_LON_KEY, location.lon.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getForModule(moduleKey, options = {}) {
|
||||||
|
if (isSharedEnabled()) {
|
||||||
|
return getShared();
|
||||||
|
}
|
||||||
|
if (moduleKey) {
|
||||||
|
const moduleLocation = readKey(moduleKey);
|
||||||
|
if (moduleLocation) return moduleLocation;
|
||||||
|
}
|
||||||
|
if (options.fallbackToLatLon) {
|
||||||
|
const legacy = readLegacyLatLon();
|
||||||
|
if (legacy) return legacy;
|
||||||
|
}
|
||||||
|
return { ...DEFAULT_LOCATION };
|
||||||
|
}
|
||||||
|
|
||||||
|
function setForModule(moduleKey, location, options = {}) {
|
||||||
|
if (!location) return;
|
||||||
|
if (isSharedEnabled()) {
|
||||||
|
setShared(location, options);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (moduleKey) {
|
||||||
|
localStorage.setItem(moduleKey, JSON.stringify(location));
|
||||||
|
} else if (options.fallbackToLatLon) {
|
||||||
|
localStorage.setItem(LEGACY_LAT_KEY, location.lat.toString());
|
||||||
|
localStorage.setItem(LEGACY_LON_KEY, location.lon.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isSharedEnabled,
|
||||||
|
getShared,
|
||||||
|
setShared,
|
||||||
|
getForModule,
|
||||||
|
setForModule,
|
||||||
|
normalize,
|
||||||
|
DEFAULT_LOCATION: { ...DEFAULT_LOCATION }
|
||||||
|
};
|
||||||
|
})();
|
||||||
@@ -548,8 +548,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
* Load and display current observer location
|
* Load and display current observer location
|
||||||
*/
|
*/
|
||||||
function loadObserverLocation() {
|
function loadObserverLocation() {
|
||||||
const lat = localStorage.getItem('observerLat');
|
let lat = localStorage.getItem('observerLat');
|
||||||
const lon = localStorage.getItem('observerLon');
|
let lon = localStorage.getItem('observerLon');
|
||||||
|
if (window.ObserverLocation && ObserverLocation.isSharedEnabled()) {
|
||||||
|
const shared = ObserverLocation.getShared();
|
||||||
|
lat = shared.lat.toString();
|
||||||
|
lon = shared.lon.toString();
|
||||||
|
}
|
||||||
|
|
||||||
const latInput = document.getElementById('observerLatInput');
|
const latInput = document.getElementById('observerLatInput');
|
||||||
const lonInput = document.getElementById('observerLonInput');
|
const lonInput = document.getElementById('observerLonInput');
|
||||||
@@ -658,8 +663,12 @@ function saveObserverLocation() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorage.setItem('observerLat', lat.toString());
|
if (window.ObserverLocation && ObserverLocation.isSharedEnabled()) {
|
||||||
localStorage.setItem('observerLon', lon.toString());
|
ObserverLocation.setShared({ lat, lon });
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('observerLat', lat.toString());
|
||||||
|
localStorage.setItem('observerLon', lon.toString());
|
||||||
|
}
|
||||||
|
|
||||||
// Also update dashboard-specific location keys for ADS-B and AIS
|
// Also update dashboard-specific location keys for ADS-B and AIS
|
||||||
const locationObj = JSON.stringify({ lat: lat, lon: lon });
|
const locationObj = JSON.stringify({ lat: lat, lon: lon });
|
||||||
@@ -676,6 +685,11 @@ function saveObserverLocation() {
|
|||||||
showNotification('Location', 'Observer location saved');
|
showNotification('Location', 'Observer location saved');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window.observerLocation) {
|
||||||
|
window.observerLocation.lat = lat;
|
||||||
|
window.observerLocation.lon = lon;
|
||||||
|
}
|
||||||
|
|
||||||
// Refresh SSTV ISS schedule if available
|
// Refresh SSTV ISS schedule if available
|
||||||
if (typeof SSTV !== 'undefined' && typeof SSTV.loadIssSchedule === 'function') {
|
if (typeof SSTV !== 'undefined' && typeof SSTV.loadIssSchedule === 'function') {
|
||||||
SSTV.loadIssSchedule();
|
SSTV.loadIssSchedule();
|
||||||
|
|||||||
+19
-6
@@ -41,8 +41,13 @@ const SSTV = (function() {
|
|||||||
const latInput = document.getElementById('sstvObsLat');
|
const latInput = document.getElementById('sstvObsLat');
|
||||||
const lonInput = document.getElementById('sstvObsLon');
|
const lonInput = document.getElementById('sstvObsLon');
|
||||||
|
|
||||||
const storedLat = localStorage.getItem('observerLat');
|
let storedLat = localStorage.getItem('observerLat');
|
||||||
const storedLon = localStorage.getItem('observerLon');
|
let storedLon = localStorage.getItem('observerLon');
|
||||||
|
if (window.ObserverLocation && ObserverLocation.isSharedEnabled()) {
|
||||||
|
const shared = ObserverLocation.getShared();
|
||||||
|
storedLat = shared.lat.toString();
|
||||||
|
storedLon = shared.lon.toString();
|
||||||
|
}
|
||||||
|
|
||||||
if (latInput && storedLat) latInput.value = storedLat;
|
if (latInput && storedLat) latInput.value = storedLat;
|
||||||
if (lonInput && storedLon) lonInput.value = storedLon;
|
if (lonInput && storedLon) lonInput.value = storedLon;
|
||||||
@@ -64,8 +69,12 @@ const SSTV = (function() {
|
|||||||
|
|
||||||
if (!isNaN(lat) && lat >= -90 && lat <= 90 &&
|
if (!isNaN(lat) && lat >= -90 && lat <= 90 &&
|
||||||
!isNaN(lon) && lon >= -180 && lon <= 180) {
|
!isNaN(lon) && lon >= -180 && lon <= 180) {
|
||||||
localStorage.setItem('observerLat', lat.toString());
|
if (window.ObserverLocation && ObserverLocation.isSharedEnabled()) {
|
||||||
localStorage.setItem('observerLon', lon.toString());
|
ObserverLocation.setShared({ lat, lon });
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('observerLat', lat.toString());
|
||||||
|
localStorage.setItem('observerLon', lon.toString());
|
||||||
|
}
|
||||||
loadIssSchedule(); // Refresh pass predictions
|
loadIssSchedule(); // Refresh pass predictions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,8 +103,12 @@ const SSTV = (function() {
|
|||||||
if (latInput) latInput.value = lat;
|
if (latInput) latInput.value = lat;
|
||||||
if (lonInput) lonInput.value = lon;
|
if (lonInput) lonInput.value = lon;
|
||||||
|
|
||||||
localStorage.setItem('observerLat', lat);
|
if (window.ObserverLocation && ObserverLocation.isSharedEnabled()) {
|
||||||
localStorage.setItem('observerLon', lon);
|
ObserverLocation.setShared({ lat: parseFloat(lat), lon: parseFloat(lon) });
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('observerLat', lat);
|
||||||
|
localStorage.setItem('observerLon', lon);
|
||||||
|
}
|
||||||
|
|
||||||
btn.innerHTML = originalText;
|
btn.innerHTML = originalText;
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
|
|||||||
@@ -20,6 +20,11 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/adsb_dashboard.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/adsb_dashboard.css') }}">
|
||||||
|
<script>
|
||||||
|
window.INTERCEPT_SHARED_OBSERVER_LOCATION = {{ shared_observer_location | tojson }};
|
||||||
|
window.INTERCEPT_ADSB_AUTO_START = {{ adsb_auto_start | tojson }};
|
||||||
|
</script>
|
||||||
|
<script src="{{ url_for('static', filename='js/core/observer-location.js') }}"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="radar-bg"></div>
|
<div class="radar-bg"></div>
|
||||||
@@ -518,6 +523,9 @@
|
|||||||
|
|
||||||
// Observer location and range rings (load from localStorage or default to London)
|
// Observer location and range rings (load from localStorage or default to London)
|
||||||
let observerLocation = (function() {
|
let observerLocation = (function() {
|
||||||
|
if (window.ObserverLocation && ObserverLocation.getForModule) {
|
||||||
|
return ObserverLocation.getForModule('observerLocation');
|
||||||
|
}
|
||||||
const saved = localStorage.getItem('observerLocation');
|
const saved = localStorage.getItem('observerLocation');
|
||||||
if (saved) {
|
if (saved) {
|
||||||
try {
|
try {
|
||||||
@@ -1803,7 +1811,11 @@ ACARS: ${r.statistics.acarsMessages} messages`;
|
|||||||
observerLocation.lon = lon;
|
observerLocation.lon = lon;
|
||||||
|
|
||||||
// Save to localStorage for persistence
|
// Save to localStorage for persistence
|
||||||
localStorage.setItem('observerLocation', JSON.stringify(observerLocation));
|
if (window.ObserverLocation) {
|
||||||
|
ObserverLocation.setForModule('observerLocation', observerLocation);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('observerLocation', JSON.stringify(observerLocation));
|
||||||
|
}
|
||||||
|
|
||||||
if (radarMap) {
|
if (radarMap) {
|
||||||
radarMap.setView([lat, lon], radarMap.getZoom());
|
radarMap.setView([lat, lon], radarMap.getZoom());
|
||||||
@@ -1831,7 +1843,11 @@ ACARS: ${r.statistics.acarsMessages} messages`;
|
|||||||
observerLocation.lon = position.coords.longitude;
|
observerLocation.lon = position.coords.longitude;
|
||||||
|
|
||||||
// Save to localStorage for persistence
|
// Save to localStorage for persistence
|
||||||
localStorage.setItem('observerLocation', JSON.stringify(observerLocation));
|
if (window.ObserverLocation) {
|
||||||
|
ObserverLocation.setForModule('observerLocation', observerLocation);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('observerLocation', JSON.stringify(observerLocation));
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('obsLat').value = observerLocation.lat.toFixed(4);
|
document.getElementById('obsLat').value = observerLocation.lat.toFixed(4);
|
||||||
document.getElementById('obsLon').value = observerLocation.lon.toFixed(4);
|
document.getElementById('obsLon').value = observerLocation.lon.toFixed(4);
|
||||||
@@ -1925,6 +1941,9 @@ ACARS: ${r.statistics.acarsMessages} messages`;
|
|||||||
observerLocation.lon = position.longitude;
|
observerLocation.lon = position.longitude;
|
||||||
document.getElementById('obsLat').value = position.latitude.toFixed(4);
|
document.getElementById('obsLat').value = position.latitude.toFixed(4);
|
||||||
document.getElementById('obsLon').value = position.longitude.toFixed(4);
|
document.getElementById('obsLon').value = position.longitude.toFixed(4);
|
||||||
|
if (window.ObserverLocation && ObserverLocation.isSharedEnabled()) {
|
||||||
|
ObserverLocation.setShared({ lat: position.latitude, lon: position.longitude });
|
||||||
|
}
|
||||||
|
|
||||||
// Center map on GPS location (on first fix)
|
// Center map on GPS location (on first fix)
|
||||||
if (radarMap && !radarMap._gpsInitialized) {
|
if (radarMap && !radarMap._gpsInitialized) {
|
||||||
@@ -2537,9 +2556,13 @@ sudo make install</code>
|
|||||||
try {
|
try {
|
||||||
const response = await fetch('/adsb/session');
|
const response = await fetch('/adsb/session');
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
// No session info - try to auto-start if SDR available
|
// No session info - only auto-start if enabled
|
||||||
console.log('[ADS-B] No session found, attempting auto-start...');
|
if (window.INTERCEPT_ADSB_AUTO_START) {
|
||||||
await tryAutoStartLocal();
|
console.log('[ADS-B] No session found, attempting auto-start...');
|
||||||
|
await tryAutoStartLocal();
|
||||||
|
} else {
|
||||||
|
console.log('[ADS-B] No session found; auto-start disabled');
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
@@ -2581,15 +2604,21 @@ sudo make install</code>
|
|||||||
const statusEl = document.getElementById('trackingStatus');
|
const statusEl = document.getElementById('trackingStatus');
|
||||||
statusEl.textContent = 'TRACKING';
|
statusEl.textContent = 'TRACKING';
|
||||||
} else {
|
} else {
|
||||||
// Session not active - try to auto-start
|
// Session not active - only auto-start if enabled
|
||||||
console.log('[ADS-B] No active session, attempting auto-start...');
|
if (window.INTERCEPT_ADSB_AUTO_START) {
|
||||||
await tryAutoStartLocal();
|
console.log('[ADS-B] No active session, attempting auto-start...');
|
||||||
|
await tryAutoStartLocal();
|
||||||
|
} else {
|
||||||
|
console.log('[ADS-B] No active session; auto-start disabled');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('[ADS-B] Failed to sync tracking status:', err);
|
console.warn('[ADS-B] Failed to sync tracking status:', err);
|
||||||
// Try auto-start anyway
|
// Try auto-start only if enabled
|
||||||
await tryAutoStartLocal();
|
if (window.INTERCEPT_ADSB_AUTO_START) {
|
||||||
|
await tryAutoStartLocal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,10 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/ais_dashboard.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/ais_dashboard.css') }}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||||
|
<script>
|
||||||
|
window.INTERCEPT_SHARED_OBSERVER_LOCATION = {{ shared_observer_location | tojson }};
|
||||||
|
</script>
|
||||||
|
<script src="{{ url_for('static', filename='js/core/observer-location.js') }}"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Radar background effects -->
|
<!-- Radar background effects -->
|
||||||
@@ -219,7 +223,12 @@
|
|||||||
const MAX_TRAIL_POINTS = 50;
|
const MAX_TRAIL_POINTS = 50;
|
||||||
|
|
||||||
// Observer location
|
// Observer location
|
||||||
let observerLocation = { lat: 51.5074, lon: -0.1278 };
|
let observerLocation = (function() {
|
||||||
|
if (window.ObserverLocation && ObserverLocation.getForModule) {
|
||||||
|
return ObserverLocation.getForModule('ais_observerLocation');
|
||||||
|
}
|
||||||
|
return { lat: 51.5074, lon: -0.1278 };
|
||||||
|
})();
|
||||||
let rangeRingsLayer = null;
|
let rangeRingsLayer = null;
|
||||||
let observerMarker = null;
|
let observerMarker = null;
|
||||||
|
|
||||||
@@ -376,17 +385,9 @@
|
|||||||
|
|
||||||
// Initialize map
|
// Initialize map
|
||||||
function initMap() {
|
function initMap() {
|
||||||
// Load saved observer location
|
if (observerLocation) {
|
||||||
const saved = localStorage.getItem('ais_observerLocation');
|
document.getElementById('obsLat').value = observerLocation.lat;
|
||||||
if (saved) {
|
document.getElementById('obsLon').value = observerLocation.lon;
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(saved);
|
|
||||||
if (parsed.lat && parsed.lon) {
|
|
||||||
observerLocation = parsed;
|
|
||||||
document.getElementById('obsLat').value = parsed.lat;
|
|
||||||
document.getElementById('obsLon').value = parsed.lon;
|
|
||||||
}
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vesselMap = L.map('vesselMap', {
|
vesselMap = L.map('vesselMap', {
|
||||||
@@ -470,7 +471,11 @@
|
|||||||
const lon = parseFloat(document.getElementById('obsLon').value);
|
const lon = parseFloat(document.getElementById('obsLon').value);
|
||||||
if (!isNaN(lat) && !isNaN(lon) && lat >= -90 && lat <= 90 && lon >= -180 && lon <= 180) {
|
if (!isNaN(lat) && !isNaN(lon) && lat >= -90 && lat <= 90 && lon >= -180 && lon <= 180) {
|
||||||
observerLocation = { lat, lon };
|
observerLocation = { lat, lon };
|
||||||
localStorage.setItem('ais_observerLocation', JSON.stringify(observerLocation));
|
if (window.ObserverLocation) {
|
||||||
|
ObserverLocation.setForModule('ais_observerLocation', observerLocation);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('ais_observerLocation', JSON.stringify(observerLocation));
|
||||||
|
}
|
||||||
if (observerMarker) {
|
if (observerMarker) {
|
||||||
observerMarker.setLatLng([lat, lon]);
|
observerMarker.setLatLng([lat, lon]);
|
||||||
}
|
}
|
||||||
@@ -1058,7 +1063,11 @@
|
|||||||
drawRangeRings();
|
drawRangeRings();
|
||||||
|
|
||||||
// Save to localStorage
|
// Save to localStorage
|
||||||
localStorage.setItem('ais_observerLocation', JSON.stringify(observerLocation));
|
if (window.ObserverLocation) {
|
||||||
|
ObserverLocation.setForModule('ais_observerLocation', observerLocation);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('ais_observerLocation', JSON.stringify(observerLocation));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showGpsIndicator(show) {
|
function showGpsIndicator(show) {
|
||||||
|
|||||||
+19
-2
@@ -14,6 +14,10 @@
|
|||||||
window._showDisclaimerOnLoad = true;
|
window._showDisclaimerOnLoad = true;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<script>
|
||||||
|
window.INTERCEPT_SHARED_OBSERVER_LOCATION = {{ shared_observer_location | tojson }};
|
||||||
|
</script>
|
||||||
|
<script src="{{ url_for('static', filename='js/core/observer-location.js') }}"></script>
|
||||||
<!-- Fonts - Conditional CDN/Local loading -->
|
<!-- Fonts - Conditional CDN/Local loading -->
|
||||||
{% if offline_settings.fonts_source == 'local' %}
|
{% 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') }}">
|
||||||
@@ -2252,6 +2256,9 @@
|
|||||||
|
|
||||||
// Observer location for distance calculations (load from localStorage or default to London)
|
// Observer location for distance calculations (load from localStorage or default to London)
|
||||||
let observerLocation = (function () {
|
let observerLocation = (function () {
|
||||||
|
if (window.ObserverLocation && ObserverLocation.getForModule) {
|
||||||
|
return ObserverLocation.getForModule('observerLocation');
|
||||||
|
}
|
||||||
const saved = localStorage.getItem('observerLocation');
|
const saved = localStorage.getItem('observerLocation');
|
||||||
if (saved) {
|
if (saved) {
|
||||||
try {
|
try {
|
||||||
@@ -8375,8 +8382,15 @@
|
|||||||
if (navigator.geolocation) {
|
if (navigator.geolocation) {
|
||||||
navigator.geolocation.getCurrentPosition(
|
navigator.geolocation.getCurrentPosition(
|
||||||
position => {
|
position => {
|
||||||
document.getElementById('obsLat').value = position.coords.latitude.toFixed(4);
|
const lat = position.coords.latitude;
|
||||||
document.getElementById('obsLon').value = position.coords.longitude.toFixed(4);
|
const lon = position.coords.longitude;
|
||||||
|
document.getElementById('obsLat').value = lat.toFixed(4);
|
||||||
|
document.getElementById('obsLon').value = lon.toFixed(4);
|
||||||
|
observerLocation.lat = lat;
|
||||||
|
observerLocation.lon = lon;
|
||||||
|
if (window.ObserverLocation && ObserverLocation.isSharedEnabled()) {
|
||||||
|
ObserverLocation.setShared({ lat, lon });
|
||||||
|
}
|
||||||
showInfo('Location updated!');
|
showInfo('Location updated!');
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
@@ -8476,6 +8490,9 @@
|
|||||||
// Update observerLocation
|
// Update observerLocation
|
||||||
observerLocation.lat = position.latitude;
|
observerLocation.lat = position.latitude;
|
||||||
observerLocation.lon = position.longitude;
|
observerLocation.lon = position.longitude;
|
||||||
|
if (window.ObserverLocation && ObserverLocation.isSharedEnabled()) {
|
||||||
|
ObserverLocation.setShared({ lat: position.latitude, lon: position.longitude });
|
||||||
|
}
|
||||||
|
|
||||||
// Update APRS user location
|
// Update APRS user location
|
||||||
updateAprsUserLocation(position);
|
updateAprsUserLocation(position);
|
||||||
|
|||||||
@@ -20,6 +20,10 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/satellite_dashboard.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/satellite_dashboard.css') }}">
|
||||||
|
<script>
|
||||||
|
window.INTERCEPT_SHARED_OBSERVER_LOCATION = {{ shared_observer_location | tojson }};
|
||||||
|
</script>
|
||||||
|
<script src="{{ url_for('static', filename='js/core/observer-location.js') }}"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="grid-bg"></div>
|
<div class="grid-bg"></div>
|
||||||
@@ -313,15 +317,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applySharedObserverLocation() {
|
||||||
|
if (window.ObserverLocation && ObserverLocation.isSharedEnabled()) {
|
||||||
|
const shared = ObserverLocation.getShared();
|
||||||
|
if (shared) {
|
||||||
|
const latInput = document.getElementById('obsLat');
|
||||||
|
const lonInput = document.getElementById('obsLon');
|
||||||
|
if (latInput) latInput.value = shared.lat.toFixed(4);
|
||||||
|
if (lonInput) lonInput.value = shared.lon.toFixed(4);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
setupEmbeddedMode();
|
setupEmbeddedMode();
|
||||||
|
const usedShared = applySharedObserverLocation();
|
||||||
initGroundMap();
|
initGroundMap();
|
||||||
updateClock();
|
updateClock();
|
||||||
setInterval(updateClock, 1000);
|
setInterval(updateClock, 1000);
|
||||||
setInterval(updateCountdown, 1000);
|
setInterval(updateCountdown, 1000);
|
||||||
setInterval(updateRealTimePositions, 5000);
|
setInterval(updateRealTimePositions, 5000);
|
||||||
loadAgents();
|
loadAgents();
|
||||||
getLocation();
|
if (!usedShared) {
|
||||||
|
getLocation();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function loadAgents() {
|
async function loadAgents() {
|
||||||
@@ -380,6 +401,9 @@
|
|||||||
const gps = agentStatus.gps_position;
|
const gps = agentStatus.gps_position;
|
||||||
document.getElementById('obsLat').value = gps.lat.toFixed(4);
|
document.getElementById('obsLat').value = gps.lat.toFixed(4);
|
||||||
document.getElementById('obsLon').value = gps.lon.toFixed(4);
|
document.getElementById('obsLon').value = gps.lon.toFixed(4);
|
||||||
|
if (window.ObserverLocation && ObserverLocation.isSharedEnabled()) {
|
||||||
|
ObserverLocation.setShared({ lat: gps.lat, lon: gps.lon });
|
||||||
|
}
|
||||||
|
|
||||||
// Update observer marker label
|
// Update observer marker label
|
||||||
const agent = agents.find(a => a.id == agentId);
|
const agent = agents.find(a => a.id == agentId);
|
||||||
@@ -428,13 +452,24 @@
|
|||||||
subdomains: 'abcd'
|
subdomains: 'abcd'
|
||||||
}).addTo(groundMap);
|
}).addTo(groundMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lat = parseFloat(document.getElementById('obsLat')?.value);
|
||||||
|
const lon = parseFloat(document.getElementById('obsLon')?.value);
|
||||||
|
if (!Number.isNaN(lat) && !Number.isNaN(lon)) {
|
||||||
|
groundMap.setView([lat, lon], 3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLocation() {
|
function getLocation() {
|
||||||
if (navigator.geolocation) {
|
if (navigator.geolocation) {
|
||||||
navigator.geolocation.getCurrentPosition(pos => {
|
navigator.geolocation.getCurrentPosition(pos => {
|
||||||
document.getElementById('obsLat').value = pos.coords.latitude.toFixed(4);
|
const lat = pos.coords.latitude;
|
||||||
document.getElementById('obsLon').value = pos.coords.longitude.toFixed(4);
|
const lon = pos.coords.longitude;
|
||||||
|
document.getElementById('obsLat').value = lat.toFixed(4);
|
||||||
|
document.getElementById('obsLon').value = lon.toFixed(4);
|
||||||
|
if (window.ObserverLocation && ObserverLocation.isSharedEnabled()) {
|
||||||
|
ObserverLocation.setShared({ lat, lon });
|
||||||
|
}
|
||||||
calculatePasses();
|
calculatePasses();
|
||||||
}, () => {
|
}, () => {
|
||||||
calculatePasses();
|
calculatePasses();
|
||||||
|
|||||||
Reference in New Issue
Block a user