Files
protoloon/js/WsprSearchUiMapController.js
2026-04-02 17:39:02 -06:00

260 lines
7.5 KiB
JavaScript

/*
Copyright (c) 2023-forever Douglas Malnati. All rights reserved.
See the /faq/tos page for details.
(If this generated header is stamped on a file which is a 3rd party file or under a different license or copyright, then ignore this copyright statement and use that file's terms.)
*/
import * as utl from '/js/Utl.js';
import { Base } from './Base.js';
import { SpotMapAsyncLoader } from './SpotMapAsyncLoader.js';
import { TabularData } from '../../../../js/TabularData.js';
import { WSPREncoded } from '/js/WSPREncoded.js';
import { WsprSearchUiDataTableVisibility } from './WsprSearchUiDataTableVisibility.js';
import { WsprSearchUiDataTableColumnOrder } from './WsprSearchUiDataTableColumnOrder.js';
export class WsprSearchUiMapController
extends Base
{
constructor(cfg)
{
super();
this.cfg = cfg;
this.td = null;
this.mapDataToken = 0;
this.showEmptyMapRequested = false;
this.showControlHelpRequested = false;
this.ok = this.cfg.container;
// map gets async loaded
this.mapModule = null;
this.map = null;
SpotMapAsyncLoader.SetOnLoadCallback((module) => {
this.mapModule = module;
this.map = new this.mapModule.SpotMap({
container: this.ui,
});
this.map.SetDebug(this.debug);
if (this.showEmptyMapRequested)
{
this.map.SetSpotList([]);
this.showEmptyMapRequested = false;
}
else if (this.td)
{
this.ScheduleMapData();
}
if (this.showControlHelpRequested)
{
this.map.ShowControlHelpDialog();
this.showControlHelpRequested = false;
}
});
if (this.ok)
{
this.ui = this.MakeUI();
this.cfg.container.appendChild(this.ui);
}
}
SetDebug(tf)
{
super.SetDebug(tf);
this.t.SetCcGlobal(tf);
}
OnEvent(evt)
{
if (this.ok)
{
switch (evt.type) {
case "DATA_TABLE_RAW_READY": this.OnDataTableRawReady(evt); break;
case "DATA_TABLE_VISIBILITY_CHANGED": this.OnDataTableVisibilityChanged(evt); break;
case "SHOW_EMPTY_MAP": this.OnShowEmptyMap(evt); break;
case "SHOW_MAP_CONTROL_HELP": this.OnShowMapControlHelp(evt); break;
}
}
}
OnDataTableRawReady(evt)
{
// cache data
this.td = evt.tabularDataReadOnly;
// check if we can map immediately
if (this.mapModule != null)
{
this.ScheduleMapData();
}
}
OnDataTableVisibilityChanged(evt)
{
if (this.td && this.mapModule != null)
{
this.ScheduleMapData();
}
}
OnShowEmptyMap(evt)
{
this.td = null;
if (this.map)
{
this.map.SetSpotList([]);
}
else
{
this.showEmptyMapRequested = true;
}
}
OnShowMapControlHelp(evt)
{
if (this.map)
{
this.map.ShowControlHelpDialog();
}
else
{
this.showControlHelpRequested = true;
}
}
ScheduleMapData()
{
let token = ++this.mapDataToken;
let run = () => {
if (token != this.mapDataToken)
{
return;
}
this.MapData();
};
if (window.requestIdleCallback)
{
window.requestIdleCallback(() => {
window.requestAnimationFrame(run);
}, { timeout: 250 });
}
else
{
window.setTimeout(() => {
window.requestAnimationFrame(run);
}, 0);
}
}
MapData()
{
this.t.Reset();
this.t.Event(`WsprSearchUiMapController::MapData Start`);
let spotList = [];
if (this.td.Idx("Lat") != undefined && this.td.Idx("Lng") != undefined)
{
this.td.ForEach(row => {
let metaData = this.td.GetRowMetaData(row);
let locationSource = metaData?.overlap?.resolved?.sourceByFamily?.location ?? null;
let latResolved = this.td.Idx("Lat") != undefined ? this.td.Get(row, "Lat") : null;
let lngResolved = this.td.Idx("Lng") != undefined ? this.td.Get(row, "Lng") : null;
let lat = null;
let lng = null;
if (latResolved != null && lngResolved != null)
{
lat = latResolved;
lng = lngResolved;
}
if (lat != null && lng != null)
{
// get a list of all the reporting stations
let seenDataList = [];
for (let msg of metaData.slotMsgList)
{
if (msg)
{
for (let rxRecord of msg.rxRecordList)
{
let [lat, lng] = WSPREncoded.DecodeMaidenheadToDeg(rxRecord.rxGrid);
let seenData = {
sign: rxRecord.callsign,
lat,
lng,
grid: rxRecord.rxGrid,
};
seenDataList.push(seenData);
}
}
}
// send along a cut-down version of the data available
let tdSpot = new TabularData(this.td.MakeDataTableFromRow(row));
let popupVisibleColSet = new Set([
...WsprSearchUiDataTableVisibility.GetVisibleColumnsForStorageKey("dateTimeVisible"),
...WsprSearchUiDataTableVisibility.GetVisibleColumnsForStorageKey("resolvedVisible"),
]);
let popupColList = tdSpot.GetHeaderList().filter(col => popupVisibleColSet.has(col));
tdSpot.SetColumnOrder(popupColList);
WsprSearchUiDataTableColumnOrder.Apply(tdSpot);
tdSpot.DeleteEmptyColumns();
let spot = new this.mapModule.Spot({
lat: lat,
lng: lng,
grid: null,
accuracy:
(locationSource == "HRL" || locationSource == "EBT") ? "veryHigh" :
(locationSource == "BT") ? "high" :
"low",
dtLocal: tdSpot.Get(0, "DateTimeLocal"),
td: tdSpot,
seenDataList: seenDataList,
});
spotList.push(spot);
}
}, true);
}
// hand off even an empty spot list
this.map.SetSpotList(spotList);
this.t.Event(`WsprSearchUiMapController::MapData End`);
}
MakeUI()
{
let ui = document.createElement("div");
ui.style.boxSizing = "border-box";
ui.style.border = "1px solid black";
ui.style.width = "1210px";
ui.style.height = "550px";
ui.style.resize = "both";
ui.style.overflow = "hidden";
return ui;
}
}