diff --git a/server/scripts/modules/currentweather.mjs b/server/scripts/modules/currentweather.mjs index 51db3bb..ddcfeaa 100644 --- a/server/scripts/modules/currentweather.mjs +++ b/server/scripts/modules/currentweather.mjs @@ -153,10 +153,12 @@ class CurrentWeather extends WeatherDisplay { condition = shortConditions(condition); } + const wind = (typeof this.data.WindSpeed === 'number') ? this.data.WindDirection.padEnd(3, '') + this.data.WindSpeed.toString().padStart(3, ' ') : '-'; + const fill = { temp: this.data.Temperature + String.fromCharCode(176), condition, - wind: this.data.WindDirection.padEnd(3, '') + this.data.WindSpeed.toString().padStart(3, ' '), + wind, location: locationCleanup(this.data.station.properties.name).substr(0, 20), humidity: `${this.data.Humidity}%`, dewpoint: this.data.DewPoint + String.fromCharCode(176), @@ -243,7 +245,6 @@ const parseData = (data) => { data.WindSpeed = windConverter(observations.windSpeed.value); data.WindDirection = directionToNSEW(observations.windDirection.value); data.WindGust = windConverter(observations.windGust.value); - data.WindSpeed = windConverter(data.WindSpeed); data.WindUnit = windConverter.units; data.Humidity = Math.round(observations.relativeHumidity.value); data.Icon = getLargeIcon(observations.icon); diff --git a/server/scripts/modules/radar.mjs b/server/scripts/modules/radar.mjs index fa573c7..2ffc03e 100644 --- a/server/scripts/modules/radar.mjs +++ b/server/scripts/modules/radar.mjs @@ -8,8 +8,11 @@ import * as utils from './radar-utils.mjs'; import setTiles from './radar-tiles.mjs'; import processRadar from './radar-processor.mjs'; -// Use OVERRIDE_RADAR_HOST if provided, otherwise default to mesonet -const RADAR_HOST = (typeof OVERRIDES !== 'undefined' ? OVERRIDES?.RADAR_HOST : undefined) || 'mesonet.agron.iastate.edu'; +// store processed radar as dataURLs to avoid re-processing frames as they slide backwards in time +// this is cleared upon changing the location displayed +let processedRadars = []; + +const RADAR_HOST = 'mesonet.agron.iastate.edu'; class Radar extends WeatherDisplay { constructor(navId, elemId) { super(navId, elemId, 'Local Radar'); @@ -136,20 +139,43 @@ class Radar extends WeatherDisplay { elemId: this.elemId, }); - // Load the most recent doppler radar images. + const radarKey = `${radarSourceXY.x.toFixed(0)}-${radarSourceXY.y.toFixed(0)}`; + + // reset the "used" flag on pre-processed radars + // items that were not used during this process are deleted (either expired via time or change of location) + processedRadars.forEach((radar) => { radar.used = false; }); + try { const radarInfo = await Promise.all(urls.map(async (url) => { - const processedRadar = await processRadar({ + // store the time + const timeMatch = url.match(/_(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)\./); + const [, year, month, day, hour, minute] = timeMatch; + + const radarKeyedTimestamp = `${radarKey}:${year}${month}${day}${hour}${minute}`; + + // check for a pre-processed radar + const preProcessed = processedRadars.find((radar) => radar.key === radarKeyedTimestamp); + + // use the pre-processed radar, or get a new one + const processedRadar = preProcessed?.dataURL ?? await processRadar({ url, RADAR_HOST, OVERRIDES, radarSourceXY, }); - // store the time - const timeMatch = url.match(/_(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)\./); + // store the radar + if (!preProcessed) { + processedRadars.push({ + key: radarKeyedTimestamp, + dataURL: processedRadar, + used: true, + }); + } else { + // set used flag + preProcessed.used = true; + } - const [, year, month, day, hour, minute] = timeMatch; const time = DateTime.fromObject({ year, month, @@ -177,6 +203,9 @@ class Radar extends WeatherDisplay { this.times = radarInfo.map((radar) => radar.time); this.setStatus(STATUS.loaded); + + // clean up any unused stored radars + processedRadars = processedRadars.filter((radar) => radar.used); } catch (_error) { // Radar fetch failed - skip this display in animation by setting totalScreens = 0 this.timing.totalScreens = 0; @@ -187,7 +216,7 @@ class Radar extends WeatherDisplay { async drawCanvas() { super.drawCanvas(); const time = this.times[this.screenIndex].toLocaleString(DateTime.TIME_SIMPLE); - const timePadded = time.length >= 8 ? time : ` ${time}`; + const timePadded = time.length >= 8 ? time : ` ${time} `; this.elem.querySelector('.header .right .time').innerHTML = timePadded; // get image offset calculation