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

98 lines
3.5 KiB
TypeScript
Raw Normal View History

import { Accessor, Component, createSignal, Setter } from 'solid-js'
2025-02-02 23:33:15 +02:00
import styles from './harmonie.module.css'
import { apiHost } from '../consts'
2025-02-03 23:33:28 +02:00
import { GribMessage } from './interfaces'
import { fetchBuffer } from '../helpers/fetch'
import { drawGrib } from './draw/drawGrib'
import { fetchWindData } from './draw/windDirection'
2025-02-03 23:33:28 +02:00
const CROP_BOUNDS = { x: 1906-1-400, y: 950, width: 400, height: 300 }
2025-02-02 23:33:15 +02:00
export const GribFile: Component<{
name: string,
isActive: Accessor<boolean>,
2025-02-03 23:33:28 +02:00
getCanvas: Accessor<HTMLCanvasElement | undefined>,
setIsLoading: Setter<boolean>,
2025-02-02 23:33:15 +02:00
onClick: (name: string) => void,
}> = ({
name,
isActive,
getCanvas,
setIsLoading,
onClick,
}) => {
const [getGribList, setGribList] = createSignal<GribMessage[]>([])
2025-02-03 23:33:28 +02:00
const isCrop = createSignal(false)
2025-02-02 23:33:15 +02:00
function onFileClick() {
onClick(name)
if (getGribList().length === 0) {
2025-02-02 23:33:15 +02:00
fetch(`${apiHost}/api/show/grib/${name}`)
.then(re => re.json())
.then(setGribList)
2025-02-02 23:33:15 +02:00
}
}
2025-02-03 23:33:28 +02:00
let cachedMessages: GribMessage[] = []
let cachedBuffers: Uint8Array[] = []
let cachedBitmasks: Uint8Array[] = []
function onParamClick(paramId: number) {
setIsLoading(true);
const grib = getGribList()[paramId]
2025-02-03 23:33:28 +02:00
const bitmaskSection = grib.sections.find(section => section.id === 6)
const binarySection = grib.sections.find(section => section.id === 7)
if (!bitmaskSection || !binarySection) return;
const bitmaskOffset = bitmaskSection.offset + 6
const bitmaskLength = bitmaskSection.size - 6
const bitmaskPromise = bitmaskSection.size > 6
? fetchBuffer(`${apiHost}/api/grib/binary-chunk/${bitmaskOffset}/${bitmaskLength}/${name}`).then(b=>[b])
: Promise.resolve([])
const binaryOffset = binarySection.offset + 5
const binaryLength = binarySection.size - 5
const fetchPromise: Promise<[GribMessage[], ArrayBuffer[], ArrayBuffer[]]> = grib.meteo.discipline === 0 && grib.meteo.category === 2 && grib.meteo.product === 192
? fetchWindData(grib, getGribList())
: Promise.all([
Promise.resolve([grib]),
2025-02-03 23:33:28 +02:00
fetchBuffer(`${apiHost}/api/grib/binary-chunk/${binaryOffset}/${binaryLength}/${name}`).then(b=>[b]),
bitmaskPromise,
])
fetchPromise.then(([messages, binaryBuffers, bitmasks]) => {
cachedMessages = messages
cachedBuffers = binaryBuffers.map(b => new Uint8Array(b))
cachedBitmasks = bitmasks.map(b => new Uint8Array(b))
const cropBounds = isCrop[0]() ? CROP_BOUNDS : undefined
drawGrib(getCanvas()!, cachedMessages, cachedBuffers, cachedBitmasks, cropBounds)
2025-02-03 23:33:28 +02:00
})
.catch(err => console.warn(err.message))
.finally(() => setIsLoading(false))
2025-02-03 23:33:28 +02:00
}
2025-02-02 23:33:15 +02:00
return <li
class={isActive() ? styles.active : ''}
onClick={onFileClick}
>
2025-02-03 20:24:20 +02:00
<div class={styles.name}>{ trimName(name) }</div>
2025-02-02 23:33:15 +02:00
<ul class={styles.meteoParams}>
{ getGribList()
2025-02-03 23:33:28 +02:00
.sort((a, b) => a.title > b.title ? 1 : -1)
.map((grib, i) =>
2025-02-04 21:59:39 +02:00
<li onClick={() => onParamClick(i)}>{ grib.title.replace('meteorology, ', '') }</li>
2025-02-02 23:33:15 +02:00
)}
</ul>
</li>
2025-02-03 20:24:20 +02:00
}
function trimName(title: string): string {
let result = title
result = result.replace('harmonie_', '')
result = result.replace('.grib', '')
return result
}