modular meteograms

This commit is contained in:
Vincent van der Wal
2026-07-22 19:28:57 +02:00
parent af9bf42d05
commit bac4759662
10 changed files with 1239 additions and 297 deletions
+56 -11
View File
@@ -165,6 +165,8 @@ export interface WeekForecastParams extends WeatherLocation, WeatherUnitParams {
model?: string;
forecast_days?: number;
past_days?: number;
/** Hourly API variables to request; defaults to the full core set */
hourlyVariables?: string[];
}
export interface WeekHourlyData {
@@ -178,6 +180,19 @@ export interface WeekHourlyData {
relative_humidity_2m: number[];
apparent_temperature: number[];
dew_point_2m: number[];
// Additional popular variables available for the customizable meteograms
wind_gusts_10m: number[];
pressure_msl: number[];
surface_pressure: number[];
rain: number[];
showers: number[];
snowfall: number[];
cloud_cover_low: number[];
cloud_cover_mid: number[];
cloud_cover_high: number[];
uv_index: number[];
visibility: number[];
cape: number[];
}
export interface WeekDailyData {
@@ -259,6 +274,9 @@ export interface EnsembleForecastResult {
// ─── Week Forecast Fetch ────────────────────────────────────────────────────────
// Fallback set when the caller does not specify which hourly variables it
// needs. Callers normally pass an explicit list so only shown variables are
// requested.
const WEEK_HOURLY_VARS = [
'temperature_2m',
'precipitation',
@@ -294,10 +312,16 @@ export async function fetchWeekForecast(params: WeekForecastParams): Promise<Wee
const pastDays = params.past_days ?? 0;
const modelParam = params.model && params.model !== 'best_match' ? params.model : undefined;
// Request only the variables the caller needs; fall back to the core set.
const hourlyVars =
params.hourlyVariables && params.hourlyVariables.length > 0
? [...new Set(params.hourlyVariables)]
: [...WEEK_HOURLY_VARS];
const apiParams: Record<string, string | number | undefined> = {
latitude: params.latitude,
longitude: params.longitude,
hourly: WEEK_HOURLY_VARS.join(','),
hourly: hourlyVars.join(','),
daily: WEEK_DAILY_VARS.join(','),
temperature_unit: params.temperature_unit ?? 'celsius',
wind_speed_unit: params.wind_speed_unit ?? 'kmh',
@@ -328,17 +352,38 @@ export async function fetchWeekForecast(params: WeekForecastParams): Promise<Wee
const hourlyTimestamps = getTimestamps(hourlyBlock);
const hourlyDates = hourlyTimestamps.map((t) => new Date(t));
// Values come back in the requested order; index them by API name so
// variables that were not requested resolve to empty arrays.
const byName: Record<string, number[]> = {};
hourlyVars.forEach((name, i) => {
const variable = hourlyBlock.variables(i);
byName[name] = variable ? getValues(variable) : [];
});
const g = (name: string): number[] => byName[name] ?? [];
const hourly: WeekHourlyData = {
temperature_2m: getValues(hourlyBlock.variables(0)!),
precipitation: getValues(hourlyBlock.variables(1)!),
precipitation_probability: getValues(hourlyBlock.variables(2)!),
weather_code: getValues(hourlyBlock.variables(3)!),
windspeed_10m: getValues(hourlyBlock.variables(4)!),
winddirection_10m: getValues(hourlyBlock.variables(5)!),
cloud_cover: getValues(hourlyBlock.variables(6)!),
relative_humidity_2m: getValues(hourlyBlock.variables(7)!),
apparent_temperature: getValues(hourlyBlock.variables(8)!),
dew_point_2m: getValues(hourlyBlock.variables(9)!)
temperature_2m: g('temperature_2m'),
precipitation: g('precipitation'),
precipitation_probability: g('precipitation_probability'),
weather_code: g('weather_code'),
windspeed_10m: g('wind_speed_10m'),
winddirection_10m: g('wind_direction_10m'),
cloud_cover: g('cloud_cover'),
relative_humidity_2m: g('relative_humidity_2m'),
apparent_temperature: g('apparent_temperature'),
dew_point_2m: g('dew_point_2m'),
wind_gusts_10m: g('wind_gusts_10m'),
pressure_msl: g('pressure_msl'),
surface_pressure: g('surface_pressure'),
rain: g('rain'),
showers: g('showers'),
snowfall: g('snowfall'),
cloud_cover_low: g('cloud_cover_low'),
cloud_cover_mid: g('cloud_cover_mid'),
cloud_cover_high: g('cloud_cover_high'),
uv_index: g('uv_index'),
visibility: g('visibility'),
cape: g('cape')
};
// Daily: variables are in the same order as WEEK_DAILY_VARS