mirror of
https://github.com/netbymatt/ws4kp.git
synced 2026-04-14 15:49:31 -07:00
weather displays complete
This commit is contained in:
135
server/scripts/modules/latestobservations.mjs
Normal file
135
server/scripts/modules/latestobservations.mjs
Normal file
@@ -0,0 +1,135 @@
|
||||
// current weather conditions display
|
||||
/* globals WeatherDisplay, navigation, StationInfo */
|
||||
import { distance as calcDistance, directionToNSEW } from './utils/calc.mjs';
|
||||
import { json } from './utils/fetch.mjs';
|
||||
import STATUS from './status.mjs';
|
||||
import { locationCleanup } from './utils/string.mjs';
|
||||
import { UNITS } from './config.mjs';
|
||||
import * as units from './utils/units.mjs';
|
||||
|
||||
class LatestObservations extends WeatherDisplay {
|
||||
constructor(navId, elemId) {
|
||||
super(navId, elemId, 'Latest Observations', true);
|
||||
|
||||
// constants
|
||||
this.MaximumRegionalStations = 7;
|
||||
}
|
||||
|
||||
async getData(_weatherParameters) {
|
||||
super.getData(_weatherParameters);
|
||||
const weatherParameters = _weatherParameters ?? this.weatherParameters;
|
||||
|
||||
// calculate distance to each station
|
||||
const stationsByDistance = Object.keys(StationInfo).map((key) => {
|
||||
const station = StationInfo[key];
|
||||
const distance = calcDistance(station.lat, station.lon, weatherParameters.latitude, weatherParameters.longitude);
|
||||
return { ...station, distance };
|
||||
});
|
||||
|
||||
// sort the stations by distance
|
||||
const sortedStations = stationsByDistance.sort((a, b) => a.distance - b.distance);
|
||||
// try up to 30 regional stations
|
||||
const regionalStations = sortedStations.slice(0, 30);
|
||||
|
||||
// get data for regional stations
|
||||
const allConditions = await Promise.all(regionalStations.map(async (station) => {
|
||||
try {
|
||||
const data = await json(`https://api.weather.gov/stations/${station.id}/observations/latest`);
|
||||
// test for temperature, weather and wind values present
|
||||
if (data.properties.temperature.value === null
|
||||
|| data.properties.textDescription === ''
|
||||
|| data.properties.windSpeed.value === null) return false;
|
||||
// format the return values
|
||||
return {
|
||||
...data.properties,
|
||||
StationId: station.id,
|
||||
city: station.city,
|
||||
};
|
||||
} catch (e) {
|
||||
console.log(`Unable to get latest observations for ${station.id}`);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
// remove and stations that did not return data
|
||||
const actualConditions = allConditions.filter((condition) => condition);
|
||||
// cut down to the maximum of 7
|
||||
this.data = actualConditions.slice(0, this.MaximumRegionalStations);
|
||||
|
||||
// test for at least one station
|
||||
if (this.data.length < 1) {
|
||||
this.setStatus(STATUS.noData);
|
||||
return;
|
||||
}
|
||||
this.setStatus(STATUS.loaded);
|
||||
}
|
||||
|
||||
async drawCanvas() {
|
||||
super.drawCanvas();
|
||||
const conditions = this.data;
|
||||
|
||||
// sort array by station name
|
||||
const sortedConditions = conditions.sort((a, b) => ((a.Name < b.Name) ? -1 : 1));
|
||||
|
||||
if (navigation.units() === UNITS.english) {
|
||||
this.elem.querySelector('.column-headers .temp.english').classList.add('show');
|
||||
this.elem.querySelector('.column-headers .temp.metric').classList.remove('show');
|
||||
} else {
|
||||
this.elem.querySelector('.column-headers .temp.english').classList.remove('show');
|
||||
this.elem.querySelector('.column-headers .temp.metric').classList.add('show');
|
||||
}
|
||||
|
||||
const lines = sortedConditions.map((condition) => {
|
||||
let Temperature = condition.temperature.value;
|
||||
let WindSpeed = condition.windSpeed.value;
|
||||
const windDirection = directionToNSEW(condition.windDirection.value);
|
||||
|
||||
if (navigation.units() === UNITS.english) {
|
||||
Temperature = units.celsiusToFahrenheit(Temperature);
|
||||
WindSpeed = units.kphToMph(WindSpeed);
|
||||
}
|
||||
WindSpeed = Math.round(WindSpeed);
|
||||
Temperature = Math.round(Temperature);
|
||||
|
||||
const fill = {};
|
||||
fill.location = locationCleanup(condition.city).substr(0, 14);
|
||||
fill.temp = Temperature;
|
||||
fill.weather = LatestObservations.shortenCurrentConditions(condition.textDescription).substr(0, 9);
|
||||
if (WindSpeed > 0) {
|
||||
fill.wind = windDirection + (Array(6 - windDirection.length - WindSpeed.toString().length).join(' ')) + WindSpeed.toString();
|
||||
} else if (WindSpeed === 'NA') {
|
||||
fill.wind = 'NA';
|
||||
} else {
|
||||
fill.wind = 'Calm';
|
||||
}
|
||||
|
||||
return this.fillTemplate('observation-row', fill);
|
||||
});
|
||||
|
||||
const linesContainer = this.elem.querySelector('.observation-lines');
|
||||
linesContainer.innerHTML = '';
|
||||
linesContainer.append(...lines);
|
||||
|
||||
this.finishDraw();
|
||||
}
|
||||
|
||||
static shortenCurrentConditions(_condition) {
|
||||
let condition = _condition;
|
||||
condition = condition.replace(/Light/, 'L');
|
||||
condition = condition.replace(/Heavy/, 'H');
|
||||
condition = condition.replace(/Partly/, 'P');
|
||||
condition = condition.replace(/Mostly/, 'M');
|
||||
condition = condition.replace(/Few/, 'F');
|
||||
condition = condition.replace(/Thunderstorm/, 'T\'storm');
|
||||
condition = condition.replace(/ in /, '');
|
||||
condition = condition.replace(/Vicinity/, '');
|
||||
condition = condition.replace(/ and /, ' ');
|
||||
condition = condition.replace(/Freezing Rain/, 'Frz Rn');
|
||||
condition = condition.replace(/Freezing/, 'Frz');
|
||||
condition = condition.replace(/Unknown Precip/, '');
|
||||
condition = condition.replace(/L Snow Fog/, 'L Snw/Fog');
|
||||
condition = condition.replace(/ with /, '/');
|
||||
return condition;
|
||||
}
|
||||
}
|
||||
|
||||
window.LatestObservations = LatestObservations;
|
||||
Reference in New Issue
Block a user