diff --git a/templates/about.html b/templates/about.html index f2ebdcb..039c098 100644 --- a/templates/about.html +++ b/templates/about.html @@ -69,7 +69,7 @@

This software is dedicated to the memory of Tom G1PJB, SK, a friend and colleague who sadly passed away around the time I started writing it in Autumn 2025. I was looking forward to showing it to you when it was done.

- + {% end %} \ No newline at end of file diff --git a/templates/add_spot.html b/templates/add_spot.html index eed98a5..afaff68 100644 --- a/templates/add_spot.html +++ b/templates/add_spot.html @@ -69,8 +69,8 @@ - - + + {% end %} \ No newline at end of file diff --git a/templates/alerts.html b/templates/alerts.html index e49e0be..1ebace6 100644 --- a/templates/alerts.html +++ b/templates/alerts.html @@ -70,8 +70,8 @@ - - + + {% end %} \ No newline at end of file diff --git a/templates/bands.html b/templates/bands.html index 568e75d..3b14bb7 100644 --- a/templates/bands.html +++ b/templates/bands.html @@ -76,9 +76,9 @@ - - - + + + {% end %} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index 6d2bb8c..fe4bdde 100644 --- a/templates/base.html +++ b/templates/base.html @@ -24,7 +24,7 @@ Spothole - + @@ -52,9 +52,9 @@ integrity="sha384-L1eE4eD41kpBIWe2I0eHy+GnEUC4RIpcvibVW2JCminuPlTl+2Bc528iPdVMg5Dn" crossorigin="anonymous"> - - - + + + diff --git a/templates/conditions.html b/templates/conditions.html index b728c80..62f11ce 100644 --- a/templates/conditions.html +++ b/templates/conditions.html @@ -249,8 +249,8 @@ - - + + diff --git a/templates/map.html b/templates/map.html index da43c0c..62aa4ea 100644 --- a/templates/map.html +++ b/templates/map.html @@ -94,9 +94,9 @@ - - - + + + {% end %} \ No newline at end of file diff --git a/templates/spots.html b/templates/spots.html index f0c0c03..42b80b2 100644 --- a/templates/spots.html +++ b/templates/spots.html @@ -104,9 +104,9 @@ - - - + + + {% end %} \ No newline at end of file diff --git a/templates/status.html b/templates/status.html index d581a0e..b424407 100644 --- a/templates/status.html +++ b/templates/status.html @@ -59,8 +59,8 @@ - - + + diff --git a/webassets/js/conditions.js b/webassets/js/conditions.js index 30ab86e..f5ee08b 100644 --- a/webassets/js/conditions.js +++ b/webassets/js/conditions.js @@ -376,6 +376,8 @@ function populateIonosondeDropdown(data) { // Render the foF2/MUF data and line chart for the currently selected station function renderIonosondeData() { + // First make sure that we have some data, that a station entry is selected in the drop-down box, and that the + // data contains an entry for that station. If not, bail out at this point. if (!ionosondeData) return; const ursi = $('#ionosonde-station').val(); if (!ursi) return; @@ -384,12 +386,15 @@ function renderIonosondeData() { }); if (!station) return; + // Set up some styles, matching the k-index chart. We use Bootstrap's "primary" and "danger" colours not for any + // real reason but just to get a suitable blue and red that match the other colours Spothole uses const style = getComputedStyle(document.documentElement); const fof2Color = style.getPropertyValue('--bs-primary').trim(); const mufColor = style.getPropertyValue('--bs-danger').trim(); const textColor = style.getPropertyValue('--bs-body-color').trim() || '#666'; const gridColor = style.getPropertyValue('--bs-border-color').trim() || 'rgba(128,128,128,0.3)'; + // Utility function to convert the dict of timestamp-to-value into just a value array in timestamp key order function toSeries(dict) { if (!dict) return []; return Object.entries(dict) @@ -405,10 +410,11 @@ function renderIonosondeData() { // Populate latest values summary (visible on all screen sizes) const latestFof2 = fof2Entries.length ? fof2Entries[fof2Entries.length - 1].val : null; const latestMuf = mufEntries.length ? mufEntries[mufEntries.length - 1].val : null; - const latestTs = allTs.length ? Math.max(...allTs) : null; - var latestTimeStr = ''; - if (latestTs != null) { - const latestDate = moment.utc(latestTs * 1000); + const minTs = allTs.length ? Math.min(...allTs) : null; + const maxTs = allTs.length ? Math.max(...allTs) : null; + let latestTimeStr = ''; + if (maxTs != null) { + const latestDate = moment.utc(maxTs * 1000); latestTimeStr = latestDate.format('DD MMM YYYY HH:mm [UTC]') + ' (' + latestDate.fromNow() + ')'; } $('#ionosonde-latest').html( @@ -424,9 +430,6 @@ function renderIonosondeData() { ionosondeChart.destroy(); } - const minTs = Math.min(...allTs); - const maxTs = Math.max(...allTs); - // Compute tick positions at 3-hour UTC boundaries so midnight always lands on a tick, which triggers the date being // printed, and in general looks nicer than arbitrary ticks based on min & max timestamp const tickStep = 3 * 3600; @@ -437,6 +440,7 @@ function renderIonosondeData() { } tickValues.push(maxTs); + // Build time axis const timeAxis = { type: 'linear', min: minTs, @@ -450,6 +454,8 @@ function renderIonosondeData() { maxRotation: 45, minRotation: 0, callback(value) { + // Use the same type of display as in the k-index chart, where the labels on the axis are just HH:mm + // unless that's 00:00, in which case add the short date as well. const dt = new Date(value * 1000); const h = dt.getUTCHours(); const m = dt.getUTCMinutes(); @@ -463,6 +469,8 @@ function renderIonosondeData() { grid: {color: gridColor}, }; + // Build frequency axis. This is pretty normal except there's no grid, because we draw extra horizontal lines for + // the amateur radio bands which function as grid lines for the frequency axis. const freqAxis = { min: 0, title: {display: true, text: 'Frequency (MHz)', color: textColor}, @@ -470,6 +478,7 @@ function renderIonosondeData() { grid: {display: false}, }; + // List of ham bands for drawing horizontal lines const AMATEUR_BANDS = [ {label: '160m', freq: 1.8}, {label: '80m', freq: 3.5}, @@ -483,6 +492,7 @@ function renderIonosondeData() { {label: '10m', freq: 28.0}, ]; + // Build the horizontal lines for each ham band, including a label on the right-hand side. const bandLinesPlugin = { id: 'bandLines', beforeDatasetsDraw(chart) { @@ -492,6 +502,8 @@ function renderIonosondeData() { ctx.strokeStyle = gridColor; ctx.lineWidth = 1; ctx.setLineDash([]); + // Add an extra vertical line for 30MHz, which should correspond to the top of the chart and avoid having + // no top "border" gridline const y30 = scales.y.getPixelForValue(30); if (y30 >= chartArea.top && y30 <= chartArea.bottom) { ctx.beginPath(); @@ -501,6 +513,7 @@ function renderIonosondeData() { } ctx.font = '10px sans-serif'; ctx.fillStyle = textColor; + // Add the ham band "grid lines" AMATEUR_BANDS.forEach(({label, freq}) => { const y = scales.y.getPixelForValue(freq); if (y < chartArea.top || y > chartArea.bottom) return; @@ -516,6 +529,7 @@ function renderIonosondeData() { } }; + // Create the chart itself ionosondeChart = new Chart(document.getElementById('ionosonde-chart'), { type: 'line', data: {