List of drawing meteo params, fix canvas race condition

This commit is contained in:
Guntis Smaukstelis
2025-02-24 19:35:49 +02:00
parent ee9fb0e5e9
commit 766d1c8395
3 changed files with 38 additions and 22 deletions
-1
View File
@@ -69,7 +69,6 @@ export const Harmonie: Component<{}> = () => {
setIsLoading={setIsLoading} setIsLoading={setIsLoading}
getFileList={getFileList} getFileList={getFileList}
getGribList={getGribList} getGribList={getGribList}
getCanvas={getCanvas}
options={{ getIsCrop: getIsCrop, getIsContour: getIsContour, getIsInterpolated: getIsInterpolated }} options={{ getIsCrop: getIsCrop, getIsContour: getIsContour, getIsInterpolated: getIsInterpolated }}
imgListSignal={[getImgList, setImgList]} imgListSignal={[getImgList, setImgList]}
setRefDate={setRefDate} setRefDate={setRefDate}
+21 -17
View File
@@ -1,6 +1,6 @@
import { Accessor, Component, createSignal, Setter, Signal } from 'solid-js' 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 { fetchGribBinaries } from './fetchGrib'
import { drawGrib } from './draw/drawGrib' import { drawGrib } from './draw/drawGrib'
import { CROP_BOUNDS } from './DrawView' import { CROP_BOUNDS } from './DrawView'
@@ -8,11 +8,19 @@ import { CROP_BOUNDS } from './DrawView'
import styles from './harmonie.module.css' import styles from './harmonie.module.css'
import { handleProgressivePromises } from '../helpers/progressivePromises' 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<{ export const ReferenceTimes: Component<{
setIsLoading: Setter<boolean>, setIsLoading: Setter<boolean>,
getFileList: Accessor<string[]>, getFileList: Accessor<string[]>,
getGribList: Accessor<GribMessage[]>, getGribList: Accessor<GribMessage[]>,
getCanvas: Accessor<HTMLCanvasElement | undefined>,
options: DrawOptions, options: DrawOptions,
imgListSignal: Signal<[string, ImageBitmap | undefined][]>, imgListSignal: Signal<[string, ImageBitmap | undefined][]>,
setRefDate: Setter<string>, setRefDate: Setter<string>,
@@ -21,7 +29,6 @@ export const ReferenceTimes: Component<{
setIsLoading, setIsLoading,
getFileList, getFileList,
getGribList, getGribList,
getCanvas,
options, options,
imgListSignal: [getImgList, setImgList], imgListSignal: [getImgList, setImgList],
setRefDate, setRefDate,
@@ -43,20 +50,20 @@ export const ReferenceTimes: Component<{
setActiveDate(newValue) setActiveDate(newValue)
} }
async function fetchDrawImgList(refDateStr: string) { async function fetchDrawImgList(refDateStr: string, param: MeteoParam) {
setIsLoading(true) setIsLoading(true)
const canvas = getCanvas()!
const cropBounds = options.getIsCrop() ? CROP_BOUNDS : undefined const cropBounds = options.getIsCrop() ? CROP_BOUNDS : undefined
const contour = options.getIsContour() const contour = options.getIsContour()
const isInterpolated = options.getIsInterpolated() const isInterpolated = options.getIsInterpolated()
const forecastList = getGribList() const forecastList = getGribList()
.filter(g => g.time.referenceTime === refDateStr) .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 const emptyImgList: [string, undefined][] = forecastList
.map((grib): [string, undefined] => [grib.time.forecastTime, undefined]) .map((grib): [string, undefined] => [grib.time.forecastTime, undefined])
.sort((a, b) => a[0] > b[0] ? 1 : -1) .sort((a, b) => a[0] > b[0] ? 1 : -1)
setImgList(emptyImgList) setImgList(emptyImgList)
const promiseList = forecastList.map(async (grib): Promise<[string, ImageBitmap]> => { const promiseList = forecastList.map(async (grib): Promise<[string, ImageBitmap]> => {
const canvas = document.createElement('canvas')
const [messages, buffers, bitmasks] = await fetchGribBinaries(grib, getGribList()) const [messages, buffers, bitmasks] = await fetchGribBinaries(grib, getGribList())
drawGrib(canvas, messages, buffers, bitmasks, cropBounds, contour, isInterpolated) drawGrib(canvas, messages, buffers, bitmasks, cropBounds, contour, isInterpolated)
// just to be sure that draws // just to be sure that draws
@@ -74,10 +81,7 @@ export const ReferenceTimes: Component<{
setImgList(udpdatedImgList) setImgList(udpdatedImgList)
}, },
).finally(() => { ).finally(() => {
console.log("FINALLLY")
setRefDate(refDateStr) setRefDate(refDateStr)
const ctx = canvas.getContext('2d')!
ctx.clearRect(0, 0, canvas.width, canvas.height)
setIsLoading(false) setIsLoading(false)
}) })
} }
@@ -86,18 +90,18 @@ export const ReferenceTimes: Component<{
{ dateList().map(([dateStr, count]) => { dateList().map(([dateStr, count]) =>
<li> <li>
<div onClick={() => onActiveDate(dateStr)}> <div onClick={() => onActiveDate(dateStr)}>
{ dateStr } ({ count }) <b>{ dateStr }</b> ({ count })
</div> </div>
<div <ul
class={styles.controls} class={styles.controls}
style={{ display: getActiveDate() === dateStr ? 'block' : 'none'}} style={{ display: getActiveDate() === dateStr ? 'block' : 'none'}}
onClick={() => fetchDrawImgList(dateStr)}
> >
{ { METEO_PARAMS.map(([paramName, param]) =>
getGribList().some(g => g.time.referenceTime === dateStr) <li onClick={() => fetchDrawImgList(dateStr, param)}>
&& <>TODO: download all forecasts</> { paramName }
} </li>
</div> )}
</ul>
</li>)} </li>)}
</ul> </ul>
} }
+17 -4
View File
@@ -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 styles from './harmonie.module.css'
import { downloadImagesAsZip } from '../helpers/download' import { downloadImagesAsZip } from '../helpers/download'
@@ -17,14 +17,27 @@ export const SlideShow: Component<{
const [getActive, setActive] = createSignal(-1) const [getActive, setActive] = createSignal(-1)
const [getIsPlaying, setIsPlaying] = createSignal(false) 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) { function draw(i: number) {
const canvas = getCanvas()! clearCanvas()
const ctx = canvas.getContext('2d')!
ctx.clearRect(0, 0, canvas.width, canvas.height)
setActive(i) setActive(i)
const img = getImgList()[i][1] const img = getImgList()[i][1]
if (!img) return; 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) ctx.drawImage(img, 0, 0)
} }