From b3188237ca703425819abed3fa73075a9fc9283f Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Mon, 24 Aug 2026 21:56:04 +0200 Subject: [PATCH 1/2] refactor(windy-plugin): minor refactoring --- libs/windy-sounding/src/components/skewt.tsx | 10 +++---- .../src/containers/containers.tsx | 2 +- .../src/redux/forecast-slice.ts | 27 +++++++------------ 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/libs/windy-sounding/src/components/skewt.tsx b/libs/windy-sounding/src/components/skewt.tsx index de465c06..d7ddf558 100644 --- a/libs/windy-sounding/src/components/skewt.tsx +++ b/libs/windy-sounding/src/components/skewt.tsx @@ -12,7 +12,7 @@ export type SkewTProps = { yPointer: number | undefined; levels: number[]; temps: number[]; - dewpoints: number[]; + dewPoints: number[]; ghs: number[]; seaLevelPressure: number; minPressure: number; @@ -38,7 +38,7 @@ export function SkewT(props: SkewTProps) { levels, temps, ghs, - dewpoints, + dewPoints, minPressure, maxPressure, seaLevelPressure, @@ -207,10 +207,10 @@ export function SkewT(props: SkewTProps) { {parcel && } - + ), - [parcel, width, height, pathGenerator, pressureToPxScale, formatAltitude, temps, dewpoints, levels], + [parcel, width, height, pathGenerator, pressureToPxScale, formatAltitude, temps, dewPoints, levels], ); let tempAtCursor = 0; @@ -219,7 +219,7 @@ export function SkewT(props: SkewTProps) { let cursorClass = 'top'; if (yPointer !== undefined) { tempAtCursor = math.sampleAt(levels, temps, pressureToPxScale.invert(yPointer)); - dewPointAtCursor = math.sampleAt(levels, dewpoints, pressureToPxScale.invert(yPointer)); + dewPointAtCursor = math.sampleAt(levels, dewPoints, pressureToPxScale.invert(yPointer)); if (yPointer > height / 2) { yOffsetCursor = -4; cursorClass = 'bottom'; diff --git a/libs/windy-sounding/src/containers/containers.tsx b/libs/windy-sounding/src/containers/containers.tsx index 83a6055f..34030ab7 100644 --- a/libs/windy-sounding/src/containers/containers.tsx +++ b/libs/windy-sounding/src/containers/containers.tsx @@ -430,7 +430,7 @@ const ConnectedSkewT = memo(function ConnectedSkewT(props: ChildGraphProps) { return { levels: periodValues.levels, temps: timeValues.temp, - dewpoints: timeValues.dewpoint, + dewPoints: timeValues.dewPoint, ghs: timeValues.gh, seaLevelPressure: timeValues.seaLevelPressure, minTemp, diff --git a/libs/windy-sounding/src/redux/forecast-slice.ts b/libs/windy-sounding/src/redux/forecast-slice.ts index 490362c5..bbf49cef 100644 --- a/libs/windy-sounding/src/redux/forecast-slice.ts +++ b/libs/windy-sounding/src/redux/forecast-slice.ts @@ -4,13 +4,7 @@ import type { LatLon } from '@windy/interfaces'; import type { AnyMeteogramLevels, DataHash2, SoundingDataHash2, WeatherDataPayload2 } from '@windy/node-forecast-v3'; import type { ParcelData } from '../util/atmosphere'; -import { - dewpoint, - getElevation, - getPressureToGhScale, - parcelTrajectory, - saturationVaporPressure, -} from '../util/atmosphere'; +import { getElevation, getPressureToGhScale, parcelTrajectory } from '../util/atmosphere'; import type { Scale } from '../util/math'; import { lerpAngleDegree, sampleAt, scaleLinear } from '../util/math'; import { latLon2Str } from '../util/utils'; @@ -35,7 +29,7 @@ export enum FetchStatus { } // Those properties varies with the altitude level. -const _levelProps = ['temp', 'dewpoint', 'gh', 'wind', 'windDir', 'rh', 'cloud'] as const; +const _levelProps = ['temp', 'dewPoint', 'gh', 'wind', 'windDir', 'rh', 'cloud'] as const; type LevelProp = (typeof _levelProps)[number]; type LevelPropByTime = `${LevelProp}ByTime`; @@ -243,7 +237,7 @@ function isWindyDataCached(state: ForecastState, key: string) { * and approximates geopotential height (gh) from the barometric formula if omitted by the model. * * @param sounding - Sounding data payload. - * @param paramName - Parameter to extract ('temp', 'dewpoint', 'gh', 'rh', 'wind', or 'windDir'). + * @param paramName - Parameter to extract ('temp', 'dewPoint', 'gh', 'rh', 'wind', or 'windDir'). * @param levels - Pressure levels in descending order (in hPa). * @param tsIndex - Timestamp index in the time series. * @returns Array of parameter values corresponding to each level. @@ -257,17 +251,16 @@ function extractSoundingParamByLevel( return levels.map((level: number): number => { const levelKey = `${level}h` as AnyMeteogramLevels; - if (paramName === 'dewpoint') { + if (paramName === 'dewPoint') { const dew = sounding[`dewPoint-${levelKey}`]?.[tsIndex]; if (dew != null) { + // As of Aug 2026, windy does not provide the dew point for meteoblue AI return dew; } const temp = sounding[`temp-${levelKey}`]?.[tsIndex]; const rh = sounding[`rh-${levelKey}`]?.[tsIndex]; if (temp != null && rh != null) { - return typeof windyUtils.computeDewPointKelvin === 'function' - ? windyUtils.computeDewPointKelvin(rh, temp) - : dewpoint(saturationVaporPressure(temp) * (rh / 100)); + return windyUtils.computeDewPointKelvin(rh, temp); } } @@ -323,7 +316,7 @@ function computePeriodValues( let maxSeaLevelPressure: number = Number.MIN_VALUE; const values: Record & Record = { - dewpointByTime: [], + dewPointByTime: [], ghByTime: [], rhByTime: [], tempByTime: [], @@ -342,7 +335,7 @@ function computePeriodValues( const seaLevelPressure = sampleAt(soundingTimeMs, windyData.forecast.data.pressure, timeMs) / 100; maxSeaLevelPressure = Math.max(maxSeaLevelPressure, seaLevelPressure); values.tempByTime.push(tempByLevel); - values.dewpointByTime.push(extractSoundingParamByLevel(soundingData, 'dewpoint', levels, tsIndex)); + values.dewPointByTime.push(extractSoundingParamByLevel(soundingData, 'dewPoint', levels, tsIndex)); values.ghByTime.push(extractSoundingParamByLevel(soundingData, 'gh', levels, tsIndex)); values.rhByTime.push(extractSoundingParamByLevel(soundingData, 'rh', levels, tsIndex)); values.windByTime.push(extractSoundingParamByLevel(soundingData, 'wind', levels, tsIndex)); @@ -511,7 +504,7 @@ export const selValuesAt = createSelector( timeMs = Math.max(timeMs, windyData.forecast.sounding?.ts?.[0] ?? timesMs[0], windyData.forecast.data.ts[0]); return { temp: sampleAt(timesMs, periodValues.tempByTime, timeMs), - dewpoint: sampleAt(timesMs, periodValues.dewpointByTime, timeMs), + dewPoint: sampleAt(timesMs, periodValues.dewPointByTime, timeMs), gh: sampleAt(timesMs, periodValues.ghByTime, timeMs), rh: sampleAt(timesMs, periodValues.rhByTime, timeMs), wind: sampleAt(timesMs, periodValues.windByTime, timeMs), @@ -552,7 +545,7 @@ export const selParcel = createSelector( selPressureToGhScale, selElevation, (timeValues, periodValues, pressureToGhScale, elevation): ParcelData => { - const pressureToDewpointScale = scaleLinear(periodValues.levels, timeValues.dewpoint); + const pressureToDewpointScale = scaleLinear(periodValues.levels, timeValues.dewPoint); return parcelTrajectory( periodValues.levels, timeValues.gh, From 923676b282a90912a7117ea3c6037ab05efb3c35 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Mon, 24 Aug 2026 22:12:50 +0200 Subject: [PATCH 2/2] fix(windy-plugin): update level on cursor move only for layer with levels --- libs/windy-sounding/src/containers/containers.tsx | 6 +++++- libs/windy-sounding/src/env.d.ts | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libs/windy-sounding/src/containers/containers.tsx b/libs/windy-sounding/src/containers/containers.tsx index 34030ab7..6575739e 100644 --- a/libs/windy-sounding/src/containers/containers.tsx +++ b/libs/windy-sounding/src/containers/containers.tsx @@ -345,8 +345,12 @@ function Graph({ width, height, skewTWidthPercent }: { width: number; height: nu } else { setYpointer(y); + // Only update the active map level for overlays that support multiple altitude levels + // (e.g. wind, temp) to avoid unnecessary or invalid level changes on surface-only layers (e.g. rain, radar). + const overlay = W.store.get('overlay') as keyof typeof W.overlays; + const supportsLevels = W.overlays[overlay].hasMoreLevels; const availLevels = W.store.get('availLevels'); - if (availLevels && availLevels.length > 1) { + if (supportsLevels && availLevels.length > 1) { const { levels, ghs, seaLevelPressure, minPressure, maxPressure, height } = cursorContextRef.current; const pressureToGhScale = atm.getPressureToGhScale(levels, ghs, seaLevelPressure); const ghMeterToPxScale = math.scaleLinear( diff --git a/libs/windy-sounding/src/env.d.ts b/libs/windy-sounding/src/env.d.ts index c2e740da..c3778945 100644 --- a/libs/windy-sounding/src/env.d.ts +++ b/libs/windy-sounding/src/env.d.ts @@ -21,5 +21,6 @@ declare const W: { broadcast: typeof import('@windy/client/broadcast').default; http: typeof import('@windy/client/http'); user: typeof import('@windy/client/user'); + overlays: typeof import('@windy/client/overlays').default; }; /* eslint-enable */