From 766d1c8395cdca510e79a2e246f06cd58d1192f2 Mon Sep 17 00:00:00 2001 From: Guntis Smaukstelis Date: Mon, 24 Feb 2025 19:35:49 +0200 Subject: [PATCH] List of drawing meteo params, fix canvas race condition --- web/src/harmonie/Harmonie.tsx | 1 - web/src/harmonie/ReferenceTimes.tsx | 38 ++++++++++++++++------------- web/src/harmonie/SlideShow.tsx | 21 +++++++++++++--- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/web/src/harmonie/Harmonie.tsx b/web/src/harmonie/Harmonie.tsx index 78bd6de..a9483a1 100644 --- a/web/src/harmonie/Harmonie.tsx +++ b/web/src/harmonie/Harmonie.tsx @@ -69,7 +69,6 @@ export const Harmonie: Component<{}> = () => { setIsLoading={setIsLoading} getFileList={getFileList} getGribList={getGribList} - getCanvas={getCanvas} options={{ getIsCrop: getIsCrop, getIsContour: getIsContour, getIsInterpolated: getIsInterpolated }} imgListSignal={[getImgList, setImgList]} setRefDate={setRefDate} diff --git a/web/src/harmonie/ReferenceTimes.tsx b/web/src/harmonie/ReferenceTimes.tsx index de9ccf8..f06f4a9 100644 --- a/web/src/harmonie/ReferenceTimes.tsx +++ b/web/src/harmonie/ReferenceTimes.tsx @@ -1,6 +1,6 @@ import { Accessor, Component, createSignal, Setter, Signal } from 'solid-js' -import { DrawOptions, GribMessage } from './interfaces' +import { DrawOptions, GribMessage, MeteoParam } from './interfaces' import { fetchGribBinaries } from './fetchGrib' import { drawGrib } from './draw/drawGrib' import { CROP_BOUNDS } from './DrawView' @@ -8,11 +8,19 @@ import { CROP_BOUNDS } from './DrawView' import styles from './harmonie.module.css' import { handleProgressivePromises } from '../helpers/progressivePromises' +const METEO_PARAMS: [string, MeteoParam][] = [ + ['temperature', { discipline: 0, category: 0, product: 0, levelType: -1, levelValue: -1, subType: 'now' }], + ['precipitation', { discipline: 0, category: 1, product: 236, levelType: -1, levelValue: -1, subType: 'now' }], + ['categorical precipitation', { discipline: 0, category: 1, product: 192, levelType: -1, levelValue: -1, subType: 'now' }], + ['wind speed', { discipline: 0, category: 2, product: 1, levelType: -1, levelValue: -1, subType: 'now' }], + ['wind speed gust', { discipline: 0, category: 2, product: 22, levelType: -1, levelValue: -1, subType: 'now' }], + ['wind direction', { discipline: 0, category: 2, product: 192, levelType: -1, levelValue: -1, subType: 'now' }], +] + export const ReferenceTimes: Component<{ setIsLoading: Setter, getFileList: Accessor, getGribList: Accessor, - getCanvas: Accessor, options: DrawOptions, imgListSignal: Signal<[string, ImageBitmap | undefined][]>, setRefDate: Setter, @@ -21,7 +29,6 @@ export const ReferenceTimes: Component<{ setIsLoading, getFileList, getGribList, - getCanvas, options, imgListSignal: [getImgList, setImgList], setRefDate, @@ -43,20 +50,20 @@ export const ReferenceTimes: Component<{ setActiveDate(newValue) } - async function fetchDrawImgList(refDateStr: string) { + async function fetchDrawImgList(refDateStr: string, param: MeteoParam) { setIsLoading(true) - const canvas = getCanvas()! const cropBounds = options.getIsCrop() ? CROP_BOUNDS : undefined const contour = options.getIsContour() const isInterpolated = options.getIsInterpolated() const forecastList = getGribList() .filter(g => g.time.referenceTime === refDateStr) - .filter(g => g.meteo.discipline === 0 && g.meteo.category === 1 && g.meteo.product === 192) + .filter(g => g.meteo.discipline === param.discipline && g.meteo.category === param.category && g.meteo.product === param.product) const emptyImgList: [string, undefined][] = forecastList .map((grib): [string, undefined] => [grib.time.forecastTime, undefined]) .sort((a, b) => a[0] > b[0] ? 1 : -1) setImgList(emptyImgList) const promiseList = forecastList.map(async (grib): Promise<[string, ImageBitmap]> => { + const canvas = document.createElement('canvas') const [messages, buffers, bitmasks] = await fetchGribBinaries(grib, getGribList()) drawGrib(canvas, messages, buffers, bitmasks, cropBounds, contour, isInterpolated) // just to be sure that draws @@ -74,10 +81,7 @@ export const ReferenceTimes: Component<{ setImgList(udpdatedImgList) }, ).finally(() => { - console.log("FINALLLY") setRefDate(refDateStr) - const ctx = canvas.getContext('2d')! - ctx.clearRect(0, 0, canvas.width, canvas.height) setIsLoading(false) }) } @@ -86,18 +90,18 @@ export const ReferenceTimes: Component<{ { dateList().map(([dateStr, count]) =>
  • onActiveDate(dateStr)}> - { dateStr } ({ count }) + { dateStr } ({ count })
    -
    fetchDrawImgList(dateStr)} > - { - getGribList().some(g => g.time.referenceTime === dateStr) - && <>TODO: download all forecasts - } -
    + { METEO_PARAMS.map(([paramName, param]) => +
  • fetchDrawImgList(dateStr, param)}> + { paramName } +
  • + )} + )} } \ No newline at end of file diff --git a/web/src/harmonie/SlideShow.tsx b/web/src/harmonie/SlideShow.tsx index 97b0e35..7be8863 100644 --- a/web/src/harmonie/SlideShow.tsx +++ b/web/src/harmonie/SlideShow.tsx @@ -1,4 +1,4 @@ -import { Accessor, Component, createSignal } from 'solid-js' +import { Accessor, Component, createEffect, createSignal, onMount } from 'solid-js' import styles from './harmonie.module.css' import { downloadImagesAsZip } from '../helpers/download' @@ -17,14 +17,27 @@ export const SlideShow: Component<{ const [getActive, setActive] = createSignal(-1) const [getIsPlaying, setIsPlaying] = createSignal(false) + let canvas: HTMLCanvasElement + let ctx: CanvasRenderingContext2D + function clearCanvas() { ctx.clearRect(0, 0, canvas.width, canvas.height) } + + onMount(() => { + canvas = getCanvas()! + ctx = canvas.getContext('2d')! + }) + createEffect(() => getImgList() && clearCanvas()) + function draw(i: number) { - const canvas = getCanvas()! - const ctx = canvas.getContext('2d')! - ctx.clearRect(0, 0, canvas.width, canvas.height) + clearCanvas() setActive(i) const img = getImgList()[i][1] if (!img) return; + if (img.width !== canvas.width && img.height !== canvas.height) { + canvas.width = img.width + canvas.height = img.height + } + ctx.drawImage(img, 0, 0) }