diff --git a/web/src/harmonie/DrawView.tsx b/web/src/harmonie/DrawView.tsx new file mode 100644 index 0000000..8466c5b --- /dev/null +++ b/web/src/harmonie/DrawView.tsx @@ -0,0 +1,43 @@ +import { Component, createEffect, createSignal, Signal } from 'solid-js' + +import { LoadingSpinner } from '../components/LoadingSpinner' +import { DrawOptions, GribMessage } from './interfaces' +import { drawGrib } from './draw/drawGrib' + +const CROP_BOUNDS = { x: 1906-1-440, y: 895, width: 440, height: 380 } + +export const DrawView: Component<{ + isLoadingSignal: Signal, + options: DrawOptions; + cachedMessagesSignal: Signal, + cachedBuffersSignal: Signal, + cachedBitmasksSignal: Signal, +}> = ({ + isLoadingSignal: [getIsLoading, setIsLoading], + options, + cachedMessagesSignal: [getCachedMessages], + cachedBuffersSignal: [getCachedBuffers], + cachedBitmasksSignal: [getCachedBitmasks], +}) => { + const [getCanvas, setCanvas] = createSignal() + + createEffect(async () => { + setIsLoading(true) + const canvas = getCanvas()! + const ctx = canvas.getContext('2d')! + ctx.clearRect(0, 0, canvas.width, canvas.height) + const cropBounds = options.getIsCrop() ? CROP_BOUNDS : undefined + const contour = options.getIsContour() + const isInterpolated = options.getIsInterpolated() + if (getCachedMessages().length === 0) return; + await new Promise(resolve => setTimeout(resolve, 100)) + // hack to show loading spinner + drawGrib(canvas, getCachedMessages(), getCachedBuffers(), getCachedBitmasks(), cropBounds, contour, isInterpolated) + setIsLoading(false) + }) + + return <> + { getIsLoading() && } + + +} diff --git a/web/src/harmonie/GribFile.tsx b/web/src/harmonie/GribFile.tsx index 27523bf..b67941d 100644 --- a/web/src/harmonie/GribFile.tsx +++ b/web/src/harmonie/GribFile.tsx @@ -1,50 +1,34 @@ -import { Accessor, Component, createEffect, createSignal, Setter } from 'solid-js' +import { Accessor, batch, Component, createSignal, Setter, Signal } from 'solid-js' import styles from './harmonie.module.css' import { apiHost } from '../consts' -import { DrawOptions, GribMessage } from './interfaces' +import { GribMessage } from './interfaces' import { fetchBuffer } from '../helpers/fetch' -import { drawGrib } from './draw/drawGrib' import { fetchWindData, isCalculatedWindDirection } from './draw/windDirection' import { fetchHourPrecipitationData, isCalculatedHourPrecipitation } from './draw/precipitation' -const CROP_BOUNDS = { x: 1906-1-440, y: 895, width: 440, height: 380 } - export const GribFile: Component<{ name: string, getCanvas: Accessor, setIsLoading: Setter, - getFileGribList: Accessor // specific reference and forecast time (in one file) - getAllGribLists: Accessor - options: DrawOptions; + getFileGribList: Accessor, // specific reference and forecast time (in one file) + getAllGribLists: Accessor, onClick: (name: string) => void, + cachedMessagesSignal: Signal, + cachedBuffersSignal: Signal, + cachedBitmasksSignal: Signal, }> = ({ name, - getCanvas, setIsLoading, getFileGribList, getAllGribLists, - options, onClick, + cachedMessagesSignal: [, setCachedMessages], + cachedBuffersSignal: [, setCachedBuffers], + cachedBitmasksSignal: [, setCachedBitmasks], }) => { - let cachedMessages: GribMessage[] = [] - let cachedBuffers: Uint8Array[] = [] - let cachedBitmasks: Uint8Array[] = [] - const [getIsActive, setIsActive] = createSignal(false) - createEffect(async () => { - setIsLoading(true) - const cropBounds = options.getIsCrop() ? CROP_BOUNDS : undefined - const contour = options.getIsContour() - const isInterpolated = options.getIsInterpolated() - // hack to show loading spinner - await new Promise(resolve => setTimeout(resolve, 100)) - if (cachedMessages.length === 0) return; - drawGrib(getCanvas()!, cachedMessages, cachedBuffers, cachedBitmasks, cropBounds, contour, isInterpolated) - setIsLoading(false) - }) - function onParamClick(paramId: number) { setIsLoading(true); const grib = getFileGribList()[paramId] @@ -70,11 +54,11 @@ export const GribFile: Component<{ if(isCalculatedHourPrecipitation(grib)) fetchPromise = fetchHourPrecipitationData(grib, getAllGribLists()) fetchPromise.then(([messages, binaryBuffers, bitmasks]) => { - cachedMessages = messages - cachedBuffers = binaryBuffers.map(b => new Uint8Array(b)) - cachedBitmasks = bitmasks.map(b => new Uint8Array(b)) - const cropBounds = options.getIsCrop() ? CROP_BOUNDS : undefined - drawGrib(getCanvas()!, cachedMessages, cachedBuffers, cachedBitmasks, cropBounds, options.getIsContour(), options.getIsInterpolated()) + batch(() => { + setCachedMessages(messages) + setCachedBuffers(binaryBuffers.map(b => new Uint8Array(b))) + setCachedBitmasks(bitmasks.map(b => new Uint8Array(b))) + }) }) .catch(err => console.warn(err.message)) .finally(() => setIsLoading(false)) diff --git a/web/src/harmonie/Harmonie.tsx b/web/src/harmonie/Harmonie.tsx index 8a34ee4..d31847a 100644 --- a/web/src/harmonie/Harmonie.tsx +++ b/web/src/harmonie/Harmonie.tsx @@ -3,11 +3,11 @@ import { Component, createSignal } from 'solid-js' import { apiHost } from '../consts' import styles from './harmonie.module.css' import { GribFile } from './GribFile' -import { LoadingSpinner } from '../components/LoadingSpinner' import { GribMessage } from './interfaces' import { fetchJson } from '../helpers/fetch' import { getFakeWindDirection, isWindSpeed } from './draw/windDirection' import { getFakeHourPrecipitation, isPrecipitation } from './draw/precipitation' +import { DrawView } from './DrawView' export const Harmonie: Component<{}> = () => { const [getFileList, setFileList] = createSignal([]) @@ -18,6 +18,10 @@ export const Harmonie: Component<{}> = () => { const [getIsInterpolated, setIsInterpolated] = createSignal(true) const [getGribList, setGribList] = createSignal([]) + const cachedMessagesSignal = createSignal([]) + const cachedBuffersSignal = createSignal([]) + const cachedBitmasksSignal = createSignal([]) + fetchJson(`${apiHost}/api/show/grib-list`) .then(fileList => { fileList.sort((a: string, b: string) => a < b ? 1 : -1) @@ -79,15 +83,22 @@ export const Harmonie: Component<{}> = () => { setIsLoading={setIsLoading} getFileGribList={() => getCurrentGribList(fileName)} getAllGribLists={getGribList} - options={{ getIsCrop: getIsCrop, getIsContour: getIsContour, getIsInterpolated: getIsInterpolated }} onClick={() => onGribMessageClick(fileName)} + cachedMessagesSignal={cachedMessagesSignal} + cachedBuffersSignal={cachedBuffersSignal} + cachedBitmasksSignal={cachedBitmasksSignal} /> )}
- { getIsLoading() && } - +
}