[feat](trx-frontend-http): add FT4 as map source
- Add ft4 to DEFAULT_MAP_SOURCE_FILTER (visible by default) - Add ft4 hue to locatorThemeHues (peakHue + 30° offset from FT8) - Propagate ft4 through locatorSourceLabel, locatorFilterColor, locatorHueForEntry, isLocatorOverlay, applyMapFilter, ensureDecodeLocatorMarker, pruneLocatorEntry, rebuildDecodeContactPaths, clearMapMarkersByType, markerSearchText, navigateToMapLocator, and the source items chip row - ft8MapAddLocator now maps type="ft4" to markerType="ft4" so FT4 locators get their own distinct marker colour and filter chip - ft4.js: pass "ft4" (not "ft8") to ft8MapAddLocator Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
This commit is contained in:
@@ -3986,7 +3986,7 @@ const locatorMarkers = new Map();
|
||||
const decodeContactPaths = new Map();
|
||||
let selectedMapQsoKey = null;
|
||||
const mapMarkers = new Set();
|
||||
const DEFAULT_MAP_SOURCE_FILTER = { ais: true, vdes: true, aprs: true, bookmark: false, ft8: true, wspr: true };
|
||||
const DEFAULT_MAP_SOURCE_FILTER = { ais: true, vdes: true, aprs: true, bookmark: false, ft8: true, ft4: true, wspr: true };
|
||||
const mapFilter = { ...DEFAULT_MAP_SOURCE_FILTER };
|
||||
const mapLocatorFilter = { phase: "band", bands: new Set() };
|
||||
let mapSearchFilter = "";
|
||||
@@ -4163,7 +4163,7 @@ function ensureVdesMarker(key, entry) {
|
||||
}
|
||||
|
||||
function ensureDecodeLocatorMarker(entry) {
|
||||
if (!aprsMap || !entry || entry.marker || !entry.grid || (entry.sourceType !== "ft8" && entry.sourceType !== "wspr")) return;
|
||||
if (!aprsMap || !entry || entry.marker || !entry.grid || (entry.sourceType !== "ft8" && entry.sourceType !== "ft4" && entry.sourceType !== "wspr")) return;
|
||||
const bounds = maidenheadToBounds(entry.grid);
|
||||
if (!bounds) return;
|
||||
const count = Math.max(entry.stationDetails?.size || 0, entry.stations?.size || 0, 1);
|
||||
@@ -4245,7 +4245,7 @@ function pruneAisEntry(key, entry, cutoffMs) {
|
||||
|
||||
function pruneLocatorEntry(key, entry, cutoffMs) {
|
||||
const canRenderMap = !!aprsMap && !decodeHistoryReplayActive;
|
||||
if (!entry || (entry.sourceType !== "ft8" && entry.sourceType !== "wspr")) return true;
|
||||
if (!entry || (entry.sourceType !== "ft8" && entry.sourceType !== "ft4" && entry.sourceType !== "wspr")) return true;
|
||||
if (!(entry.allStationDetails instanceof Map)) {
|
||||
entry.allStationDetails = entry.stationDetails instanceof Map
|
||||
? new Map(entry.stationDetails)
|
||||
@@ -4330,6 +4330,7 @@ function pruneMapHistory() {
|
||||
function locatorSourceLabel(type) {
|
||||
if (type === "bookmark") return "Bookmarks";
|
||||
if (type === "wspr") return "WSPR";
|
||||
if (type === "ft4") return "FT4";
|
||||
return "FT8";
|
||||
}
|
||||
|
||||
@@ -4345,7 +4346,7 @@ function locatorFilterColor(type) {
|
||||
const light = lightTheme ? 42 : 56;
|
||||
const hue = type === "bookmark"
|
||||
? hues.bookmark
|
||||
: (type === "wspr" ? hues.wspr : hues.ft8);
|
||||
: (type === "wspr" ? hues.wspr : (type === "ft4" ? hues.ft4 : hues.ft8));
|
||||
return `hsl(${hue.toFixed(1)} ${sat}% ${light}%)`;
|
||||
}
|
||||
|
||||
@@ -4470,6 +4471,7 @@ function locatorThemeHues() {
|
||||
return {
|
||||
bookmark: wrapHue(baseHue),
|
||||
ft8: wrapHue(peakHue),
|
||||
ft4: wrapHue(peakHue + 30),
|
||||
wspr: wrapHue((waveHue + baseHue) / 2),
|
||||
bandBase: wrapHue((baseHue * 0.65) + (peakHue * 0.35)),
|
||||
};
|
||||
@@ -4519,6 +4521,7 @@ function locatorHueForEntry(entry) {
|
||||
}
|
||||
if (entry?.sourceType === "bookmark") return hues.bookmark;
|
||||
if (entry?.sourceType === "wspr") return hues.wspr;
|
||||
if (entry?.sourceType === "ft4") return hues.ft4;
|
||||
return hues.ft8;
|
||||
}
|
||||
|
||||
@@ -4785,7 +4788,7 @@ function setSelectedLocatorMarker(marker) {
|
||||
|
||||
function isLocatorOverlay(marker) {
|
||||
const type = marker?.__trxType;
|
||||
return type === "bookmark" || type === "ft8" || type === "wspr";
|
||||
return type === "bookmark" || type === "ft8" || type === "ft4" || type === "wspr";
|
||||
}
|
||||
|
||||
function sendLocatorOverlayToBack(marker) {
|
||||
@@ -4916,7 +4919,7 @@ function rebuildMapLocatorFilters() {
|
||||
for (const entry of locatorMarkers.values()) {
|
||||
const sourceType = entry?.sourceType;
|
||||
if (!sourceType) continue;
|
||||
if ((sourceType === "ft8" || sourceType === "wspr") && !entry?.visibleInHistoryWindow) continue;
|
||||
if ((sourceType === "ft8" || sourceType === "ft4" || sourceType === "wspr") && !entry?.visibleInHistoryWindow) continue;
|
||||
availableSources.add(sourceType);
|
||||
const meta = entry?.bandMeta instanceof Map ? entry.bandMeta : new Map();
|
||||
for (const [label, hz] of meta.entries()) {
|
||||
@@ -4944,7 +4947,7 @@ function rebuildMapLocatorFilters() {
|
||||
if (!bandMap.has(key)) mapLocatorFilter.bands.delete(key);
|
||||
}
|
||||
|
||||
const sourceItems = ["ais", "vdes", "aprs", "bookmark", "ft8", "wspr"]
|
||||
const sourceItems = ["ais", "vdes", "aprs", "bookmark", "ft8", "ft4", "wspr"]
|
||||
.filter((key) => availableSources.has(key))
|
||||
.map((key) => ({
|
||||
key,
|
||||
@@ -4986,7 +4989,7 @@ function markerPassesLocatorFilters(marker) {
|
||||
|
||||
function markerSearchText(marker) {
|
||||
const type = marker?.__trxType;
|
||||
if (type === "bookmark" || type === "ft8" || type === "wspr") {
|
||||
if (type === "bookmark" || type === "ft8" || type === "ft4" || type === "wspr") {
|
||||
const entry = locatorEntryForMarker(marker);
|
||||
const parts = [];
|
||||
if (entry?.grid) parts.push(entry.grid);
|
||||
@@ -5132,7 +5135,7 @@ window.clearMapMarkersByType = function(type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "ft8" || type === "wspr") {
|
||||
if (type === "ft8" || type === "ft4" || type === "wspr") {
|
||||
const prefix = `${type}:`;
|
||||
for (const [key, entry] of locatorMarkers.entries()) {
|
||||
if (!key.startsWith(prefix)) continue;
|
||||
@@ -5379,7 +5382,7 @@ function initAprsMap() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (marker.__trxType === "bookmark" || marker.__trxType === "ft8" || marker.__trxType === "wspr") {
|
||||
if (marker.__trxType === "bookmark" || marker.__trxType === "ft8" || marker.__trxType === "ft4" || marker.__trxType === "wspr") {
|
||||
const center = locatorMarkerCenter(marker);
|
||||
if (center) {
|
||||
setSelectedLocatorMarker(marker);
|
||||
@@ -5618,10 +5621,10 @@ window.navigateToMapLocator = function(grid, preferredType = null) {
|
||||
sizeAprsMapToViewport();
|
||||
if (!aprsMap) return false;
|
||||
|
||||
const pref = preferredType === "wspr" ? "wspr" : (preferredType === "ft8" ? "ft8" : null);
|
||||
const pref = preferredType === "wspr" ? "wspr" : (preferredType === "ft4" ? "ft4" : (preferredType === "ft8" ? "ft8" : null));
|
||||
const keys = pref
|
||||
? [`${pref}:${normalizedGrid}`, `ft8:${normalizedGrid}`, `wspr:${normalizedGrid}`, `bookmark:${normalizedGrid}`]
|
||||
: [`ft8:${normalizedGrid}`, `wspr:${normalizedGrid}`, `bookmark:${normalizedGrid}`];
|
||||
? [`${pref}:${normalizedGrid}`, `ft8:${normalizedGrid}`, `ft4:${normalizedGrid}`, `wspr:${normalizedGrid}`, `bookmark:${normalizedGrid}`]
|
||||
: [`ft8:${normalizedGrid}`, `ft4:${normalizedGrid}`, `wspr:${normalizedGrid}`, `bookmark:${normalizedGrid}`];
|
||||
let entry = null;
|
||||
for (const key of keys) {
|
||||
entry = locatorMarkers.get(key);
|
||||
@@ -6160,6 +6163,7 @@ function applyMapFilter() {
|
||||
(type === "vdes" && mapFilter.vdes) ||
|
||||
(type === "aprs" && mapFilter.aprs) ||
|
||||
(type === "ft8" && mapFilter.ft8) ||
|
||||
(type === "ft4" && mapFilter.ft4) ||
|
||||
(type === "wspr" && mapFilter.wspr)
|
||||
);
|
||||
const onMap = aprsMap.hasLayer(marker);
|
||||
@@ -6271,7 +6275,7 @@ function rebuildDecodeContactPaths() {
|
||||
const stationLocators = new Map();
|
||||
const directedMessages = [];
|
||||
for (const entry of locatorMarkers.values()) {
|
||||
if (!entry || (entry.sourceType !== "ft8" && entry.sourceType !== "wspr")) continue;
|
||||
if (!entry || (entry.sourceType !== "ft8" && entry.sourceType !== "ft4" && entry.sourceType !== "wspr")) continue;
|
||||
const grid = String(entry.grid || "").trim().toUpperCase();
|
||||
if (!grid || !(entry.stationDetails instanceof Map)) continue;
|
||||
for (const detail of entry.stationDetails.values()) {
|
||||
@@ -6520,7 +6524,7 @@ window.syncBookmarkMapLocators = function(bookmarks) {
|
||||
|
||||
window.ft8MapAddLocator = function(message, grids, type = "ft8", station = null, details = null) {
|
||||
if (!Array.isArray(grids) || grids.length === 0) return;
|
||||
const markerType = type === "wspr" ? "wspr" : "ft8";
|
||||
const markerType = type === "wspr" ? "wspr" : (type === "ft4" ? "ft4" : "ft8");
|
||||
const unique = [...new Set(grids.map((g) => String(g).toUpperCase()))];
|
||||
const stationId = station && String(station).trim() ? String(station).trim().toUpperCase() : "";
|
||||
const locatorDetails = new Map();
|
||||
|
||||
@@ -132,7 +132,7 @@ window.onServerFt4Batch = function(messages) {
|
||||
for (const msg of messages) {
|
||||
const next = normalizeServerFt4Message(msg);
|
||||
if (next.grids.length > 0 && window.ft8MapAddLocator) {
|
||||
window.ft8MapAddLocator(next.raw, next.grids, "ft8", next.station, { ...msg, freq_hz: next.rfHz, locator_details: next.locatorDetails });
|
||||
window.ft8MapAddLocator(next.raw, next.grids, "ft4", next.station, { ...msg, freq_hz: next.rfHz, locator_details: next.locatorDetails });
|
||||
}
|
||||
next.history._tsMs = Number.isFinite(next.history?.ts_ms) ? Number(next.history.ts_ms) : Date.now();
|
||||
normalized.push(next.history);
|
||||
@@ -183,7 +183,7 @@ window.onServerFt4 = function(msg) {
|
||||
if (ft4Status) ft4Status.textContent = ft4Paused ? "Paused" : "Receiving";
|
||||
const next = normalizeServerFt4Message(msg);
|
||||
if (next.grids.length > 0 && window.ft8MapAddLocator) {
|
||||
window.ft8MapAddLocator(next.raw, next.grids, "ft8", next.station, { ...msg, freq_hz: next.rfHz, locator_details: next.locatorDetails });
|
||||
window.ft8MapAddLocator(next.raw, next.grids, "ft4", next.station, { ...msg, freq_hz: next.rfHz, locator_details: next.locatorDetails });
|
||||
}
|
||||
addFt4Message(next.history);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user