[feat](trx-frontend-http): default map filtering to band
Co-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -3755,7 +3755,7 @@ const decodeContactPaths = new Map();
|
|||||||
const mapMarkers = new Set();
|
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, wspr: true };
|
||||||
const mapFilter = { ...DEFAULT_MAP_SOURCE_FILTER };
|
const mapFilter = { ...DEFAULT_MAP_SOURCE_FILTER };
|
||||||
const mapLocatorFilter = { phase: "type", bands: new Set() };
|
const mapLocatorFilter = { phase: "band", bands: new Set() };
|
||||||
let mapSearchFilter = "";
|
let mapSearchFilter = "";
|
||||||
const APRS_TRACK_MAX_POINTS = 64;
|
const APRS_TRACK_MAX_POINTS = 64;
|
||||||
const AIS_TRACK_MAX_POINTS = 64;
|
const AIS_TRACK_MAX_POINTS = 64;
|
||||||
@@ -4303,11 +4303,30 @@ function renderMapLocatorPhaseRow(container, phase) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderMapBandLegend(items) {
|
||||||
|
const legendEl = document.getElementById("map-band-legend");
|
||||||
|
if (!legendEl) return;
|
||||||
|
const bandItems = Array.isArray(items) ? items : [];
|
||||||
|
if (bandItems.length === 0) {
|
||||||
|
legendEl.classList.add("is-empty");
|
||||||
|
legendEl.innerHTML = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
legendEl.classList.remove("is-empty");
|
||||||
|
const rows = bandItems
|
||||||
|
.map((item) => {
|
||||||
|
const label = escapeMapHtml(item.label);
|
||||||
|
const color = escapeMapHtml(item.color);
|
||||||
|
return `<span class="map-band-legend-item"><span class="map-band-legend-swatch" style="--legend-color:${color};"></span><span class="map-band-legend-text">${label}</span></span>`;
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
legendEl.innerHTML = `<div class="map-band-legend-title">Band Colors</div><div class="map-band-legend-list">${rows}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
function rebuildMapLocatorFilters() {
|
function rebuildMapLocatorFilters() {
|
||||||
const phaseEl = document.getElementById("map-locator-phase");
|
const phaseEl = document.getElementById("map-locator-phase");
|
||||||
const choiceEl = document.getElementById("map-locator-choice-filter");
|
const choiceEl = document.getElementById("map-locator-choice-filter");
|
||||||
const choiceLabelEl = document.getElementById("map-locator-choice-label");
|
const choiceLabelEl = document.getElementById("map-locator-choice-label");
|
||||||
if (!phaseEl || !choiceEl || !choiceLabelEl) return;
|
|
||||||
|
|
||||||
const availableSources = new Set();
|
const availableSources = new Set();
|
||||||
if (aisMarkers.size > 0) availableSources.add("ais");
|
if (aisMarkers.size > 0) availableSources.add("ais");
|
||||||
@@ -4360,6 +4379,9 @@ function rebuildMapLocatorFilters() {
|
|||||||
const bandItems = Array.from(bandMap.values())
|
const bandItems = Array.from(bandMap.values())
|
||||||
.sort((a, b) => (b.sortHz - a.sortHz) || a.label.localeCompare(b.label));
|
.sort((a, b) => (b.sortHz - a.sortHz) || a.label.localeCompare(b.label));
|
||||||
|
|
||||||
|
renderMapBandLegend(bandItems);
|
||||||
|
if (!phaseEl || !choiceEl || !choiceLabelEl) return;
|
||||||
|
|
||||||
renderMapLocatorPhaseRow(phaseEl, mapLocatorFilter.phase);
|
renderMapLocatorPhaseRow(phaseEl, mapLocatorFilter.phase);
|
||||||
if (mapLocatorFilter.phase === "band") {
|
if (mapLocatorFilter.phase === "band") {
|
||||||
choiceLabelEl.textContent = "Visible Bands";
|
choiceLabelEl.textContent = "Visible Bands";
|
||||||
|
|||||||
@@ -698,6 +698,7 @@
|
|||||||
<button type="button" id="map-fullscreen-btn" class="map-fullscreen-btn">Fullscreen</button>
|
<button type="button" id="map-fullscreen-btn" class="map-fullscreen-btn">Fullscreen</button>
|
||||||
<button type="button" id="map-overlay-toggle-btn" class="map-overlay-toggle-btn">Hide Filters</button>
|
<button type="button" id="map-overlay-toggle-btn" class="map-overlay-toggle-btn">Hide Filters</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="map-band-legend" class="map-band-legend" aria-label="Band color legend"></div>
|
||||||
<div id="aprs-map"></div>
|
<div id="aprs-map"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1314,6 +1314,61 @@ small { color: var(--text-muted); }
|
|||||||
border-color: color-mix(in srgb, var(--accent-green) 34%, var(--border-light));
|
border-color: color-mix(in srgb, var(--accent-green) 34%, var(--border-light));
|
||||||
color: var(--text-heading);
|
color: var(--text-heading);
|
||||||
}
|
}
|
||||||
|
.map-band-legend {
|
||||||
|
position: absolute;
|
||||||
|
left: 0.7rem;
|
||||||
|
bottom: 0.7rem;
|
||||||
|
z-index: 410;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.45rem;
|
||||||
|
width: min(14rem, calc(100% - 5.8rem));
|
||||||
|
max-height: min(40%, 18rem);
|
||||||
|
padding: 0.65rem 0.7rem;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
border: 1px solid color-mix(in srgb, var(--border-light) 74%, transparent);
|
||||||
|
background: color-mix(in srgb, var(--card-bg) 78%, transparent);
|
||||||
|
box-shadow: 0 16px 30px rgba(0, 0, 0, 0.2);
|
||||||
|
backdrop-filter: blur(14px);
|
||||||
|
-webkit-backdrop-filter: blur(14px);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.map-band-legend.is-empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.map-band-legend-title {
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
.map-band-legend-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(5.4rem, 1fr));
|
||||||
|
gap: 0.35rem 0.55rem;
|
||||||
|
}
|
||||||
|
.map-band-legend-item {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.4rem;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.map-band-legend-swatch {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: 0.78rem;
|
||||||
|
height: 0.78rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: var(--legend-color, var(--accent-green));
|
||||||
|
box-shadow: 0 0 0 1px color-mix(in srgb, var(--legend-color, var(--accent-green)) 44%, rgba(255, 255, 255, 0.18));
|
||||||
|
}
|
||||||
|
.map-band-legend-text {
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 0.76rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
#map-stage:fullscreen,
|
#map-stage:fullscreen,
|
||||||
#map-stage:-webkit-full-screen,
|
#map-stage:-webkit-full-screen,
|
||||||
#map-stage.map-fake-fullscreen {
|
#map-stage.map-fake-fullscreen {
|
||||||
@@ -2321,6 +2376,17 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
|||||||
top: 0.55rem;
|
top: 0.55rem;
|
||||||
right: 0.55rem;
|
right: 0.55rem;
|
||||||
}
|
}
|
||||||
|
.map-band-legend {
|
||||||
|
left: 0.55rem;
|
||||||
|
bottom: 0.55rem;
|
||||||
|
width: min(12rem, calc(100% - 1.1rem));
|
||||||
|
max-height: min(36%, 13rem);
|
||||||
|
padding: 0.55rem 0.6rem;
|
||||||
|
border-radius: 0.7rem;
|
||||||
|
}
|
||||||
|
.map-band-legend-list {
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(4.8rem, 1fr));
|
||||||
|
}
|
||||||
.map-locator-filter-group {
|
.map-locator-filter-group {
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user