Fix double drawing by taking out canvas from gribfile.tsx

This commit is contained in:
Guntis Smaukstelis
2025-02-18 23:08:31 +02:00
parent ea776991cc
commit 8cf4cc826d
3 changed files with 73 additions and 35 deletions
+43
View File
@@ -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<boolean>,
options: DrawOptions;
cachedMessagesSignal: Signal<GribMessage[]>,
cachedBuffersSignal: Signal<Uint8Array[]>,
cachedBitmasksSignal: Signal<Uint8Array[]>,
}> = ({
isLoadingSignal: [getIsLoading, setIsLoading],
options,
cachedMessagesSignal: [getCachedMessages],
cachedBuffersSignal: [getCachedBuffers],
cachedBitmasksSignal: [getCachedBitmasks],
}) => {
const [getCanvas, setCanvas] = createSignal<HTMLCanvasElement>()
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() && <LoadingSpinner text='' />}
<canvas ref={setCanvas} style={{ display: getIsLoading() ? 'none' : 'block' }} />
</>
}
+15 -31
View File
@@ -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<HTMLCanvasElement | undefined>,
setIsLoading: Setter<boolean>,
getFileGribList: Accessor<GribMessage[]> // specific reference and forecast time (in one file)
getAllGribLists: Accessor<GribMessage[]>
options: DrawOptions;
getFileGribList: Accessor<GribMessage[]>, // specific reference and forecast time (in one file)
getAllGribLists: Accessor<GribMessage[]>,
onClick: (name: string) => void,
cachedMessagesSignal: Signal<GribMessage[]>,
cachedBuffersSignal: Signal<Uint8Array[]>,
cachedBitmasksSignal: Signal<Uint8Array[]>,
}> = ({
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))
+15 -4
View File
@@ -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<string[]>([])
@@ -18,6 +18,10 @@ export const Harmonie: Component<{}> = () => {
const [getIsInterpolated, setIsInterpolated] = createSignal(true)
const [getGribList, setGribList] = createSignal<GribMessage[]>([])
const cachedMessagesSignal = createSignal<GribMessage[]>([])
const cachedBuffersSignal = createSignal<Uint8Array[]>([])
const cachedBitmasksSignal = createSignal<Uint8Array[]>([])
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}
/>
)}
</ul>
</div>
<div class={styles.column}>
{ getIsLoading() && <LoadingSpinner text='' />}
<canvas ref={setCanvas} style={{ display: getIsLoading() ? 'none' : 'block' }} />
<DrawView
isLoadingSignal={[getIsLoading, setIsLoading]}
options={{ getIsCrop: getIsCrop, getIsContour: getIsContour, getIsInterpolated: getIsInterpolated }}
cachedMessagesSignal={cachedMessagesSignal}
cachedBuffersSignal={cachedBuffersSignal}
cachedBitmasksSignal={cachedBitmasksSignal}
/>
</div>
</div>
}