Files
WeatherTool/web/src/harmonie/ReferenceTimes.tsx
T

100 lines
3.9 KiB
TypeScript
Raw Normal View History

2025-02-23 20:21:11 +02:00
import { Accessor, Component, createSignal, resetErrorBoundaries, Setter, Signal } from 'solid-js'
2025-02-21 23:07:49 +02:00
import { DrawOptions, GribMessage } from './interfaces'
import { fetchGribBinaries } from './fetchGrib'
import { drawGrib } from './draw/drawGrib'
import { CROP_BOUNDS } from './DrawView'
import styles from './harmonie.module.css'
2025-02-23 20:21:11 +02:00
import { handleProgressivePromises } from '../helpers/progressivePromises'
export const ReferenceTimes: Component<{
2025-02-21 23:07:49 +02:00
setIsLoading: Setter<boolean>,
getFileList: Accessor<string[]>,
getGribList: Accessor<GribMessage[]>,
2025-02-21 23:07:49 +02:00
getCanvas: Accessor<HTMLCanvasElement | undefined>,
options: DrawOptions,
2025-02-23 20:21:11 +02:00
imgListSignal: Signal<[string, ImageBitmap | undefined][]>,
onClick: () => void,
}> = ({
2025-02-21 23:07:49 +02:00
setIsLoading,
getFileList,
getGribList,
2025-02-21 23:07:49 +02:00
getCanvas,
options,
2025-02-23 20:21:11 +02:00
imgListSignal: [getImgList, setImgList],
onClick,
}) => {
const [getActiveDate, setActiveDate] = createSignal('')
2025-02-23 17:30:37 +02:00
const dateList = (): [string, number][] => {
const datesStr = getFileList().map(f => f.replace('harmonie_', '').split('_')[0])
2025-02-23 17:30:37 +02:00
const uniqueDates = [...new Set(datesStr)]
return uniqueDates.map(dateStr => [
dateStr,
datesStr.filter(d => d === dateStr).length
])
}
function onActiveDate(date: string) {
onClick()
const newValue = getActiveDate() === date ? '' : date
setActiveDate(newValue)
}
2025-02-23 20:21:11 +02:00
async function fetchDrawImgList(refDateStr: string) {
2025-02-21 23:07:49 +02:00
setIsLoading(true)
const canvas = getCanvas()!
const cropBounds = options.getIsCrop() ? CROP_BOUNDS : undefined
const contour = options.getIsContour()
const isInterpolated = options.getIsInterpolated()
const forecastList = getGribList()
2025-02-23 20:21:11 +02:00
.filter(g => g.time.referenceTime === refDateStr)
2025-02-21 23:07:49 +02:00
.filter(g => g.meteo.discipline === 0 && g.meteo.category === 1 && g.meteo.product === 192)
2025-02-23 20:21:11 +02:00
const emptyImgList: [string, undefined][] = forecastList
.map((grib): [string, undefined] => [grib.time.forecastTime, undefined])
.sort((a, b) => a[0] > b[0] ? 1 : -1)
setImgList(emptyImgList)
2025-02-21 23:07:49 +02:00
const promiseList = forecastList.map(async (grib): Promise<[string, ImageBitmap]> => {
const [messages, buffers, bitmasks] = await fetchGribBinaries(grib, getGribList())
drawGrib(canvas, messages, buffers, bitmasks, cropBounds, contour, isInterpolated)
// just to be sure that draws
await new Promise(resolve => setTimeout(resolve))
const img = await createImageBitmap(canvas)
return [grib.time.forecastTime, img]
})
2025-02-23 20:21:11 +02:00
handleProgressivePromises(
promiseList,
([forecastDate, img]) => {
const udpdatedImgList = [...getImgList()]
const idx = udpdatedImgList.findIndex(([d]) => forecastDate === d)
if (idx >= 0) udpdatedImgList[idx][1] = img
setImgList(udpdatedImgList)
},
).finally(() => {
console.log("FINALLLY")
const ctx = canvas.getContext('2d')!
ctx.clearRect(0, 0, canvas.width, canvas.height)
setIsLoading(false)
})
2025-02-21 23:07:49 +02:00
}
return <ul class={styles.dateList}>
2025-02-23 17:30:37 +02:00
{ dateList().map(([dateStr, count]) =>
<li>
<div onClick={() => onActiveDate(dateStr)}>
2025-02-23 17:30:37 +02:00
{ dateStr } ({ count })
</div>
2025-02-21 23:07:49 +02:00
<div
class={styles.controls}
style={{ display: getActiveDate() === dateStr ? 'block' : 'none'}}
2025-02-23 20:21:11 +02:00
onClick={() => fetchDrawImgList(dateStr)}
2025-02-21 23:07:49 +02:00
>
{
getGribList().some(g => g.time.referenceTime === dateStr)
&& <>TODO: download all forecasts</>
}
</div>
</li>)}
</ul>
}