diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js
index e96686d..41a8113 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js
@@ -152,6 +152,8 @@ function setDisabled(disabled) {
let serverVersion = null;
let serverCallsign = null;
+let serverLat = null;
+let serverLon = null;
function updateTitle() {
let title = "trx-rs";
@@ -166,6 +168,8 @@ function render(update) {
if (update.info && update.info.model) rigName = update.info.model;
if (update.server_version) serverVersion = update.server_version;
if (update.server_callsign) serverCallsign = update.server_callsign;
+ if (update.server_latitude != null) serverLat = update.server_latitude;
+ if (update.server_longitude != null) serverLon = update.server_longitude;
updateTitle();
initialized = !!update.initialized;
@@ -637,6 +641,49 @@ document.querySelector(".tab-bar").addEventListener("click", (e) => {
connect();
+// --- Leaflet Map (lazy-initialized) ---
+let aprsMap = null;
+let aprsMapReceiverMarker = null;
+const stationMarkers = new Map();
+
+function initAprsMap() {
+ if (aprsMap) return;
+ const mapEl = document.getElementById("aprs-map");
+ if (!mapEl) return;
+
+ const hasLocation = serverLat != null && serverLon != null;
+ const center = hasLocation ? [serverLat, serverLon] : [20, 0];
+ const zoom = hasLocation ? 10 : 2;
+
+ aprsMap = L.map("aprs-map").setView(center, zoom);
+ L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
+ maxZoom: 19,
+ attribution: '© OpenStreetMap'
+ }).addTo(aprsMap);
+
+ if (hasLocation) {
+ const popupText = serverCallsign ? serverCallsign : "Receiver";
+ aprsMapReceiverMarker = L.circleMarker([serverLat, serverLon], {
+ radius: 8, color: "#3388ff", fillColor: "#3388ff", fillOpacity: 0.8
+ }).addTo(aprsMap).bindPopup(popupText);
+ }
+}
+
+window.aprsMapAddStation = function(call, lat, lon, info) {
+ if (!aprsMap) initAprsMap();
+ if (!aprsMap) return;
+ const existing = stationMarkers.get(call);
+ if (existing) {
+ existing.setLatLng([lat, lon]);
+ existing.setPopupContent(`${call}
${info}`);
+ } else {
+ const marker = L.circleMarker([lat, lon], {
+ radius: 6, color: "#00d17f", fillColor: "#00d17f", fillOpacity: 0.8
+ }).addTo(aprsMap).bindPopup(`${call}
${info}`);
+ stationMarkers.set(call, marker);
+ }
+};
+
// --- Sub-tab navigation (Plugins tab) ---
document.querySelectorAll(".sub-tab-bar").forEach((bar) => {
bar.addEventListener("click", (e) => {
@@ -647,6 +694,10 @@ document.querySelectorAll(".sub-tab-bar").forEach((bar) => {
const parent = bar.parentElement;
parent.querySelectorAll(".sub-tab-panel").forEach((p) => p.style.display = "none");
parent.querySelector(`#subtab-${btn.dataset.subtab}`).style.display = "";
+ if (btn.dataset.subtab === "map") {
+ initAprsMap();
+ if (aprsMap) setTimeout(() => aprsMap.invalidateSize(), 50);
+ }
});
});
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html
index abc42c9..5d632b9 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html
@@ -6,6 +6,8 @@
+
+