mirror of
https://github.com/netbymatt/ws4kp.git
synced 2026-04-14 15:49:31 -07:00
Compare commits
11 Commits
443114f555
...
v6.5.9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c07ebe8bdd | ||
|
|
a41b0da196 | ||
|
|
30887202c8 | ||
|
|
38d1455a4b | ||
|
|
30ec847ed5 | ||
|
|
11c54391b2 | ||
|
|
0b47cf79c1 | ||
|
|
ba36904477 | ||
|
|
dae5b20bc6 | ||
|
|
ccc936d81a | ||
|
|
5dc214c6a5 |
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2020-2025 Matt Walsh
|
Copyright (c) 2020-2026 Matt Walsh
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -8,13 +8,11 @@ import states from './stations-states.mjs';
|
|||||||
import chunk from './chunk.mjs';
|
import chunk from './chunk.mjs';
|
||||||
import overrides from './stations-overrides.mjs';
|
import overrides from './stations-overrides.mjs';
|
||||||
import postProcessor from './stations-postprocessor.mjs';
|
import postProcessor from './stations-postprocessor.mjs';
|
||||||
|
import { stationFilter } from '../server/scripts/modules/utils/string.mjs';
|
||||||
|
|
||||||
// check for cached flag
|
// check for cached flag
|
||||||
const USE_CACHE = process.argv.includes('--use-cache');
|
const USE_CACHE = process.argv.includes('--use-cache');
|
||||||
|
|
||||||
// skip stations starting with these letters
|
|
||||||
const skipStations = ['U', 'C', 'H', 'W', 'Y', 'T', 'S', 'M', 'O', 'L', 'A', 'F', 'B', 'N', 'V', 'R', 'D', 'E', 'I', 'G', 'J'];
|
|
||||||
|
|
||||||
// chunk the list of states
|
// chunk the list of states
|
||||||
const chunkStates = chunk(states, 3);
|
const chunkStates = chunk(states, 3);
|
||||||
|
|
||||||
@@ -41,10 +39,8 @@ if (!USE_CACHE) {
|
|||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
const stationsRaw = await https(next);
|
const stationsRaw = await https(next);
|
||||||
stations = JSON.parse(stationsRaw);
|
stations = JSON.parse(stationsRaw);
|
||||||
// filter stations for 4 letter identifiers
|
|
||||||
const stationsFiltered4 = stations.features.filter((station) => station.properties.stationIdentifier.match(/^[A-Z]{4}$/));
|
|
||||||
// filter against starting letter
|
// filter against starting letter
|
||||||
const stationsFiltered = stationsFiltered4.filter((station) => !skipStations.includes(station.properties.stationIdentifier.slice(0, 1)));
|
const stationsFiltered = stations.filter(stationFilter);
|
||||||
// add each resulting station to the output
|
// add each resulting station to the output
|
||||||
stationsFiltered.forEach((station) => {
|
stationsFiltered.forEach((station) => {
|
||||||
const id = station.properties.stationIdentifier;
|
const id = station.properties.stationIdentifier;
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "ws4kp",
|
"name": "ws4kp",
|
||||||
"version": "6.5.4",
|
"version": "6.5.9",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ws4kp",
|
"name": "ws4kp",
|
||||||
"version": "6.5.4",
|
"version": "6.5.9",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dotenv": "^17.0.1",
|
"dotenv": "^17.0.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ws4kp",
|
"name": "ws4kp",
|
||||||
"version": "6.5.4",
|
"version": "6.5.9",
|
||||||
"description": "Welcome to the WeatherStar 4000+ project page!",
|
"description": "Welcome to the WeatherStar 4000+ project page!",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ const init = async () => {
|
|||||||
if (!navigator.geolocation) btnGetGps.style.display = 'none';
|
if (!navigator.geolocation) btnGetGps.style.display = 'none';
|
||||||
|
|
||||||
document.querySelector('#divTwc').addEventListener('mousemove', () => {
|
document.querySelector('#divTwc').addEventListener('mousemove', () => {
|
||||||
if (document.fullscreenElement) updateFullScreenNavigate();
|
if (document.fullscreenElement || settings.kiosk?.value) updateFullScreenNavigate();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector('#btnGetLatLng').addEventListener('click', () => autoComplete.directFormSubmit());
|
document.querySelector('#btnGetLatLng').addEventListener('click', () => autoComplete.directFormSubmit());
|
||||||
@@ -384,7 +384,7 @@ const updateFullScreenNavigate = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
navigateFadeIntervalId = setTimeout(() => {
|
navigateFadeIntervalId = setTimeout(() => {
|
||||||
if (document.fullscreenElement) {
|
if (document.fullscreenElement || settings.kiosk?.value) {
|
||||||
divTwcBottom.classList.remove('visible');
|
divTwcBottom.classList.remove('visible');
|
||||||
divTwcBottom.classList.add('hidden');
|
divTwcBottom.classList.add('hidden');
|
||||||
document.querySelector('#divTwc').classList.add('no-cursor');
|
document.querySelector('#divTwc').classList.add('no-cursor');
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ import { debugFlag } from './utils/debug.mjs';
|
|||||||
import { isDataStale, enhanceObservationWithMapClick } from './utils/mapclick.mjs';
|
import { isDataStale, enhanceObservationWithMapClick } from './utils/mapclick.mjs';
|
||||||
import { DateTime } from '../vendor/auto/luxon.mjs';
|
import { DateTime } from '../vendor/auto/luxon.mjs';
|
||||||
|
|
||||||
// some stations prefixed do not provide all the necessary data
|
|
||||||
const skipStations = ['U', 'C', 'H', 'W', 'Y', 'T', 'S', 'M', 'O', 'L', 'A', 'F', 'B', 'N', 'V', 'R', 'D', 'E', 'I', 'G', 'J'];
|
|
||||||
|
|
||||||
class CurrentWeather extends WeatherDisplay {
|
class CurrentWeather extends WeatherDisplay {
|
||||||
constructor(navId, elemId) {
|
constructor(navId, elemId) {
|
||||||
super(navId, elemId, 'Current Conditions', true);
|
super(navId, elemId, 'Current Conditions', true);
|
||||||
@@ -29,8 +26,8 @@ class CurrentWeather extends WeatherDisplay {
|
|||||||
// note: current weather does not use old data on a silent refresh
|
// note: current weather does not use old data on a silent refresh
|
||||||
// this is deliberate because it can pull data from more than one station in sequence
|
// this is deliberate because it can pull data from more than one station in sequence
|
||||||
|
|
||||||
// filter for 4-letter observation stations, only those contain sky conditions and thus an icon
|
// get the available stations
|
||||||
const filteredStations = this.weatherParameters.stations.filter((station) => station?.properties?.stationIdentifier?.length === 4 && !skipStations.includes(station.properties.stationIdentifier.slice(0, 1)));
|
const { stations } = this.weatherParameters;
|
||||||
|
|
||||||
// Load the observations
|
// Load the observations
|
||||||
let observations;
|
let observations;
|
||||||
@@ -38,9 +35,9 @@ class CurrentWeather extends WeatherDisplay {
|
|||||||
|
|
||||||
// station number counter
|
// station number counter
|
||||||
let stationNum = 0;
|
let stationNum = 0;
|
||||||
while (!observations && stationNum < filteredStations.length) {
|
while (!observations && stationNum < stations.length) {
|
||||||
// get the station
|
// get the station
|
||||||
station = filteredStations[stationNum];
|
station = stations[stationNum];
|
||||||
const stationId = station.properties.stationIdentifier;
|
const stationId = station.properties.stationIdentifier;
|
||||||
|
|
||||||
stationNum += 1;
|
stationNum += 1;
|
||||||
@@ -104,7 +101,10 @@ class CurrentWeather extends WeatherDisplay {
|
|||||||
debugContext: 'currentweather',
|
debugContext: 'currentweather',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// copy enhanced data and restore the timestamp if it was overwritten by older data from mapclick
|
||||||
|
|
||||||
candidateObservation.features[0].properties = enhancedResult.data;
|
candidateObservation.features[0].properties = enhancedResult.data;
|
||||||
|
|
||||||
const { missingFields } = enhancedResult;
|
const { missingFields } = enhancedResult;
|
||||||
const missingRequired = missingFields.filter((fieldName) => {
|
const missingRequired = missingFields.filter((fieldName) => {
|
||||||
const field = requiredFields.find((f) => f.name === fieldName && f.required);
|
const field = requiredFields.find((f) => f.name === fieldName && f.required);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const changeEnable = (newValue) => {
|
|||||||
// hide the string entry
|
// hide the string entry
|
||||||
newDisplay = 'none';
|
newDisplay = 'none';
|
||||||
}
|
}
|
||||||
const stringEntry = document.getElementById('settings-customText-label');
|
const stringEntry = document.getElementById('settings-customText-string');
|
||||||
if (stringEntry) {
|
if (stringEntry) {
|
||||||
stringEntry.style.display = newDisplay;
|
stringEntry.style.display = newDisplay;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { safeJson } from './utils/fetch.mjs';
|
|||||||
import { getPoint } from './utils/weather.mjs';
|
import { getPoint } from './utils/weather.mjs';
|
||||||
import { debugFlag } from './utils/debug.mjs';
|
import { debugFlag } from './utils/debug.mjs';
|
||||||
import settings from './settings.mjs';
|
import settings from './settings.mjs';
|
||||||
|
import { stationFilter } from './utils/string.mjs';
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
init();
|
init();
|
||||||
@@ -85,7 +86,15 @@ const getWeather = async (latLon, haveDataCallback) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StationId = stations.features[0].properties.stationIdentifier;
|
// filter stations for proper format
|
||||||
|
const stationsFiltered = stations.features.filter(stationFilter);
|
||||||
|
// check for stations available after filtering
|
||||||
|
if (stationsFiltered.length === 0) {
|
||||||
|
console.warn('No observation stations left for location after filtering');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StationId = stationsFiltered[0].properties.stationIdentifier;
|
||||||
|
|
||||||
let { city } = point.properties.relativeLocation.properties;
|
let { city } = point.properties.relativeLocation.properties;
|
||||||
const { state } = point.properties.relativeLocation.properties;
|
const { state } = point.properties.relativeLocation.properties;
|
||||||
@@ -108,7 +117,7 @@ const getWeather = async (latLon, haveDataCallback) => {
|
|||||||
weatherParameters.timeZone = point.properties.timeZone;
|
weatherParameters.timeZone = point.properties.timeZone;
|
||||||
weatherParameters.forecast = point.properties.forecast;
|
weatherParameters.forecast = point.properties.forecast;
|
||||||
weatherParameters.forecastGridData = point.properties.forecastGridData;
|
weatherParameters.forecastGridData = point.properties.forecastGridData;
|
||||||
weatherParameters.stations = stations.features;
|
weatherParameters.stations = stationsFiltered;
|
||||||
weatherParameters.relativeLocation = point.properties.relativeLocation.properties;
|
weatherParameters.relativeLocation = point.properties.relativeLocation.properties;
|
||||||
|
|
||||||
// update the main process for display purposes
|
// update the main process for display purposes
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ const pixelToFile = (xPixel, yPixel) => {
|
|||||||
return `${yTile}-${xTile}`;
|
return `${yTile}-${xTile}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// convert a pixel location in the overall map to a pixel location on the tile
|
// convert a pixel location in the overall map to a pixel location on the tile set
|
||||||
const modTile = (xPixel, yPixel) => {
|
const modTile = (xPixel, yPixel) => {
|
||||||
const x = Math.round(xPixel) % TILE_SIZE.x;
|
// adjust for additional 1 tile when odd
|
||||||
const y = Math.round(yPixel) % TILE_SIZE.y;
|
const x = (Math.floor(xPixel) % (TILE_SIZE.x));
|
||||||
|
const y = (Math.floor(yPixel) % (TILE_SIZE.y));
|
||||||
|
|
||||||
return { x, y };
|
return { x, y };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,8 +48,8 @@ const setTiles = (data) => {
|
|||||||
// determine which tiles are used
|
// determine which tiles are used
|
||||||
const usedTiles = [
|
const usedTiles = [
|
||||||
true,
|
true,
|
||||||
TILE_SIZE.x - tileShift.x < RADAR_FINAL_SIZE.width,
|
tileShift.x + TILE_SIZE.x > RADAR_FINAL_SIZE.width,
|
||||||
TILE_SIZE.y - tileShift.y < RADAR_FINAL_SIZE.width,
|
tileShift.y + TILE_SIZE.y > RADAR_FINAL_SIZE.height,
|
||||||
];
|
];
|
||||||
// if we need t[1] and t[2] then we also need t[3]
|
// if we need t[1] and t[2] then we also need t[3]
|
||||||
usedTiles.push(usedTiles[1] && usedTiles[2]);
|
usedTiles.push(usedTiles[1] && usedTiles[2]);
|
||||||
|
|||||||
@@ -44,9 +44,11 @@ const kioskChange = (value) => {
|
|||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
body.classList.add('kiosk');
|
body.classList.add('kiosk');
|
||||||
|
document.querySelector('#divTwc')?.classList.add('no-cursor');
|
||||||
window.dispatchEvent(new Event('resize'));
|
window.dispatchEvent(new Event('resize'));
|
||||||
} else {
|
} else {
|
||||||
body.classList.remove('kiosk');
|
body.classList.remove('kiosk');
|
||||||
|
document.querySelector('#divTwc')?.classList.remove('no-cursor');
|
||||||
window.dispatchEvent(new Event('resize'));
|
window.dispatchEvent(new Event('resize'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -650,7 +650,7 @@ export const enhanceObservationWithMapClick = async (observationData, options =
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: mapClickProps,
|
data: { ...mapClickProps, timestamp: observationData.timestamp },
|
||||||
wasImproved: true,
|
wasImproved: true,
|
||||||
improvements,
|
improvements,
|
||||||
missingFields: [...mapClickMissingRequired, ...mapClickMissingOptional],
|
missingFields: [...mapClickMissingRequired, ...mapClickMissingOptional],
|
||||||
|
|||||||
@@ -13,7 +13,12 @@ const locationCleanup = (input) => {
|
|||||||
return regexes.reduce((value, regex) => value.replace(regex, ''), input);
|
return regexes.reduce((value, regex) => value.replace(regex, ''), input);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// stations must be 4 alpha characters and not start with the provided list
|
||||||
|
const skipStations = ['U', 'C', 'H', 'W', 'Y', 'T', 'S', 'M', 'O', 'L', 'A', 'F', 'B', 'N', 'V', 'R', 'D', 'E', 'I', 'G', 'J'];
|
||||||
|
const stationFilter = (station) => station.properties.stationIdentifier.match(/^[A-Z]{4}$/) && !skipStations.includes(station.properties.stationIdentifier.slice(0, 1));
|
||||||
|
|
||||||
export {
|
export {
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
|
||||||
locationCleanup,
|
locationCleanup,
|
||||||
|
stationFilter,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user