Add distance column for spots

This commit is contained in:
Ian Renton
2026-08-13 14:49:15 +01:00
parent d1a9af9932
commit 186f03a233
11 changed files with 69 additions and 19 deletions
+14
View File
@@ -20,6 +20,20 @@ function calcBearing(lat1, lon1, lat2, lon2) {
return bearing;
}
function calcDistanceKm(lat1, lon1, lat2, lon2) {
const EARTH_RADIUS_KM = 6371;
lat1 *= Math.PI / 180;
lon1 *= Math.PI / 180;
lat2 *= Math.PI / 180;
lon2 *= Math.PI / 180;
const latDelta = lat2 - lat1;
const lonDelta = lon2 - lon1;
const a = Math.sin(latDelta / 2) ** 2 +
Math.cos(lat1) * Math.cos(lat2) * Math.sin(lonDelta / 2) ** 2;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return EARTH_RADIUS_KM * c;
}
// Convert a Maidenhead grid reference of arbitrary precision to the lat/long of the centre point of the square.
// Returns null if the grid format is invalid.
function latLonForGridCentre(grid) {
+33 -4
View File
@@ -115,6 +115,7 @@ function updateTable() {
const showMode = $("#tableShowMode")[0].checked;
const showComment = $("#tableShowComment")[0].checked;
const showBearing = $("#tableShowBearing")[0].checked && userPos != null;
const showDistance = $("#tableShowDistance")[0].checked && userPos != null;
const showType = $("#tableShowType")[0].checked;
const showRef = $("#tableShowRef")[0].checked;
const showDE = $("#tableShowDE")[0].checked;
@@ -141,6 +142,9 @@ function updateTable() {
if (showBearing) {
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Bearing</th>`);
}
if (showDistance) {
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Distance</th>`);
}
if (showType) {
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Type</th>`);
}
@@ -191,6 +195,7 @@ function createNewTableRowsForSpot(s, highlightNew) {
const showMode = $("#tableShowMode")[0].checked;
const showComment = $("#tableShowComment")[0].checked;
const showBearing = $("#tableShowBearing")[0].checked && userPos != null;
const showDistance = $("#tableShowDistance")[0].checked && userPos != null;
const showType = $("#tableShowType")[0].checked;
const showRef = $("#tableShowRef")[0].checked;
const showDE = $("#tableShowDE")[0].checked;
@@ -280,13 +285,27 @@ function createNewTableRowsForSpot(s, highlightNew) {
bearingText = bearing.toFixed(0).padStart(3, '0') + "°";
if (s["dx_location_good"] == null || s["dx_location_good"] === false) {
if (s["dx_location_source"] === "HOME QTH") {
bearingText = bearingText + "<span class='bearing-q hideonmobile'><i class='fa-solid fa-circle-question' title='The position was not reported via the spotting service. We had to fall back to a QRZ \"home\" location for a portable/mobile/alternative spot, so this bearing may not be accurate if the DX is close to you..'></i></span>";
bearingText = bearingText + "<span class='bearing-q hideonmobile'><i class='fa-solid fa-circle-question' title='The position was not reported via the spotting service. We had to fall back to a QRZ \"home\" location for a portable/mobile/alternative spot, so this bearing may not be accurate if the DX is close to you.'></i></span>";
} else {
bearingText = bearingText + "<span class='bearing-q hideonmobile'><i class='fa-solid fa-circle-question' title='The position was not reported via the spotting service. We had to fall back to just using the centre of a DXCC entity, so this bearing may not be accurate if the DX is close to you.'></i></span>";
}
}
}
// Format distance text
let distanceText = "---<span class='bearing-q hideonmobile'><i class='fa-solid fa-circle-question' title='The position was not reported via the spotting service, and we could not determine one. A distance to this DX is not available.'></i></span>";
if (userPos != null && s["dx_latitude"] != null && s["dx_longitude"] != null) {
const distance = calcDistanceKm(userPos[0], userPos[1], s["dx_latitude"], s["dx_longitude"]);
distanceText = distance.toFixed(0) + " km";
if (s["dx_location_good"] == null || s["dx_location_good"] === false) {
if (s["dx_location_source"] === "HOME QTH") {
distanceText = distanceText + "<span class='bearing-q hideonmobile'><i class='fa-solid fa-circle-question' title='The position was not reported via the spotting service. We had to fall back to a QRZ \"home\" location for a portable/mobile/alternative spot, so this distance may not be accurate if the DX is close to you.'></i></span>";
} else {
distanceText = distanceText + "<span class='bearing-q hideonmobile'><i class='fa-solid fa-circle-question' title='The position was not reported via the spotting service. We had to fall back to just using the centre of a DXCC entity, so this distance may not be accurate if the DX is close to you.'></i></span>";
}
}
}
// Format "type" (Sig or fallback to source)
let typeText = s["source"];
if (s["sig"]) {
@@ -354,6 +373,9 @@ function createNewTableRowsForSpot(s, highlightNew) {
if (showBearing) {
$tr.append(`<td class='nowrap hideonmobile'>${bearingText}</td>`);
}
if (showDistance) {
$tr.append(`<td class='nowrap hideonmobile'>${distanceText}</td>`);
}
if (showType) {
$tr.append(`<td class='nowrap hideonmobile'><span class='icon-wrapper'><i class='fa-solid ${sigToIcon(s["sig"], "fa-tower-cell")}'></i></span> ${typeText}</td>`);
}
@@ -394,6 +416,9 @@ function createNewTableRowsForSpot(s, highlightNew) {
if (showBearing) {
$td2floatright.append(`${bearingText} &nbsp;`);
}
if (showDistance) {
$td2floatright.append(`${distanceText} &nbsp;`);
}
if (showDE) {
$td2floatright.append(` de ${de_call} &nbsp;`);
}
@@ -443,12 +468,14 @@ function loadOptions() {
// Load settings from settings storage now all the controls are available
loadSettings();
// Extra setting - the toggle for the "bearing" column is disabled if the user has not entered a valid grid, and
// normally this logic is handled on user input to the grid field, but we might have just loaded a value direct
// into the field, so apply the same logic here.
// Extra setting - the toggle for the "bearing" & "distance" columns are disabled if the user has not entered a
// valid grid, and normally this logic is handled on user input to the grid field, but we might have just loaded
// a value direct into the field, so apply the same logic here.
$("#tableShowBearing").prop('disabled', !isUserGridValid());
$("#tableShowDistance").prop('disabled', !isUserGridValid());
if (!isUserGridValid()) {
$("#tableShowBearing").prop('checked', false);
$("#tableShowDistance").prop('checked', false);
}
// Load spots (this will also set up the SSE connection to update them too)
@@ -470,8 +497,10 @@ function userGridUpdated() {
}
// Enable/disable bearing column depending on grid validity
$("#tableShowBearing").prop('disabled', !userGridValid);
$("#tableShowDistance").prop('disabled', !userGridValid);
if (!userGridValid) {
$("#tableShowBearing").prop('checked', false);
$("#tableShowDistance").prop('checked', false);
}
// Save settings even if not a valid grid, this allows the user to clear their grid and have it save.
saveSettings();
+1 -1
View File
@@ -76,7 +76,7 @@
</div>
<script src="/static/js/add-spot.js?v=1786601585"></script>
<script src="/static/js/add-spot.js?v=1786628955"></script>
<script>$(document).ready(function () {
$("#nav-link-add-spot").addClass("active");
}); <!-- highlight active page in nav --></script>
+1 -1
View File
@@ -82,7 +82,7 @@
</div>
<script src="/static/js/alerts.js?v=1786601585"></script>
<script src="/static/js/alerts.js?v=1786628955"></script>
<script>$(document).ready(function () {
$("#nav-link-alerts").addClass("active");
}); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -79,8 +79,8 @@
</div>
<script src="/static/js/spotsbandsandmap.js?v=1786601585"></script>
<script src="/static/js/bands.js?v=1786601585"></script>
<script src="/static/js/spotsbandsandmap.js?v=1786628955"></script>
<script src="/static/js/bands.js?v=1786628955"></script>
<script>$(document).ready(function () {
$("#nav-link-bands").addClass("active");
}); <!-- highlight active page in nav --></script>
+5 -5
View File
@@ -1,6 +1,6 @@
{% extends "skeleton.html" %}
{% block head_extra %}
<link rel="stylesheet" href="/static/css/style.css?v=1786601585" type="text/css">
<link rel="stylesheet" href="/static/css/style.css?v=1786628955" type="text/css">
<link href="/static/vendor/css/bootstrap-5.3.8.min.css" rel="stylesheet">
<link href="/static/vendor/css/fontawesome-6.7.2.min.css" rel="stylesheet">
<link href="/static/vendor/css/solid-6.7.2.min.css" rel="stylesheet">
@@ -10,10 +10,10 @@
<script src="/static/vendor/js/bootstrap-5.3.8.bundle.min.js"></script>
<script src="/static/vendor/js/tinycolor2-1.6.0.min.js"></script>
<script src="/static/js/utils.js?v=1786601585"></script>
<script src="/static/js/ui-ham.js?v=1786601585"></script>
<script src="/static/js/geo.js?v=1786601585"></script>
<script src="/static/js/common.js?v=1786601585"></script>
<script src="/static/js/utils.js?v=1786628955"></script>
<script src="/static/js/ui-ham.js?v=1786628955"></script>
<script src="/static/js/geo.js?v=1786628955"></script>
<script src="/static/js/common.js?v=1786628955"></script>
{% end %}
{% block body %}
<div class="container">
+7
View File
@@ -44,6 +44,13 @@
<label class="form-check-label" for="tableShowBearing">Bearing</label>
</div>
</div>
<div class="col">
<div class="form-check">
<input class="form-check-input storeable-checkbox" type="checkbox" id="tableShowDistance"
value="tableShowDistance" oninput="columnsUpdated();">
<label class="form-check-label" for="tableShowDistance">Distance</label>
</div>
</div>
<div class="col">
<div class="form-check">
<input class="form-check-input storeable-checkbox" type="checkbox" id="tableShowType"
+1 -1
View File
@@ -284,7 +284,7 @@
</div>
<script src="/static/vendor/js/chart-4.4.9.umd.min.js"></script>
<script src="/static/js/conditions.js?v=1786601585"></script>
<script src="/static/js/conditions.js?v=1786628955"></script>
<script>$(document).ready(function () {
$("#nav-link-conditions").addClass("active");
}); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -112,8 +112,8 @@
<script src="/static/vendor/js/leaflet-cqzones.js"></script>
<script src="/static/vendor/js/leaflet-workedallbritainireland.js" type="module"></script>
<script src="/static/js/spotsbandsandmap.js?v=1786601585"></script>
<script src="/static/js/map.js?v=1786601585"></script>
<script src="/static/js/spotsbandsandmap.js?v=1786628955"></script>
<script src="/static/js/map.js?v=1786628955"></script>
<script>$(document).ready(function () {
$("#nav-link-map").addClass("active");
}); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -118,8 +118,8 @@
</div>
<script src="/static/js/spotsbandsandmap.js?v=1786601585"></script>
<script src="/static/js/spots.js?v=1786601585"></script>
<script src="/static/js/spotsbandsandmap.js?v=1786628955"></script>
<script src="/static/js/spots.js?v=1786628955"></script>
<script>$(document).ready(function () {
$("#nav-link-spots").addClass("active");
}); <!-- highlight active page in nav --></script>
+1 -1
View File
@@ -86,7 +86,7 @@
</div>
</div>
<script src="/static/js/status.js?v=1786601585"></script>
<script src="/static/js/status.js?v=1786628955"></script>
<script>
$(document).ready(function () {
$("#nav-link-status").addClass("active");