Show which slide show hours is fetched
This commit is contained in:
@@ -27,12 +27,14 @@ object DataService {
|
|||||||
class DataService(log: Logger[IO]) {
|
class DataService(log: Logger[IO]) {
|
||||||
val BASE_FOLDER = "data"
|
val BASE_FOLDER = "data"
|
||||||
val GRIB_FOLDER = s"$BASE_FOLDER/grib"
|
val GRIB_FOLDER = s"$BASE_FOLDER/grib"
|
||||||
|
val TMP_FOLDER = s"$BASE_FOLDER/tmp"
|
||||||
|
|
||||||
def init: IO[Unit] = {
|
def init: IO[Unit] = {
|
||||||
for {
|
for {
|
||||||
_ <- fs2.io.file.Files[IO].createDirectories(fs2.io.file.Path(BASE_FOLDER))
|
_ <- fs2.io.file.Files[IO].createDirectories(fs2.io.file.Path(BASE_FOLDER))
|
||||||
_ <- fs2.io.file.Files[IO].createDirectories(fs2.io.file.Path(GRIB_FOLDER))
|
_ <- fs2.io.file.Files[IO].createDirectories(fs2.io.file.Path(GRIB_FOLDER))
|
||||||
_ <- log.info(s"Created directories: $BASE_FOLDER and $GRIB_FOLDER")
|
_ <- fs2.io.file.Files[IO].createDirectories(fs2.io.file.Path(TMP_FOLDER))
|
||||||
|
_ <- log.info(s"Created directories: $BASE_FOLDER, $GRIB_FOLDER, ${TMP_FOLDER}")
|
||||||
} yield ()
|
} yield ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class FetchService(dataService: DataService, log: Logger[IO]) {
|
|||||||
request = Request[IO](Method.GET, urlWithParams)
|
request = Request[IO](Method.GET, urlWithParams)
|
||||||
|
|
||||||
// TODO proly better to call dataService method than property
|
// TODO proly better to call dataService method than property
|
||||||
tmpPath = Path(s"${dataService.GRIB_FOLDER}/tmp.grib")
|
tmpPath = Path(s"${dataService.TMP_FOLDER}/tmp.grib")
|
||||||
_ <- client.stream(request)
|
_ <- client.stream(request)
|
||||||
.flatMap(_.body)
|
.flatMap(_.body)
|
||||||
.through(Files[IO].writeAll(tmpPath))
|
.through(Files[IO].writeAll(tmpPath))
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const Harmonie: Component<{}> = () => {
|
|||||||
const [getIsInterpolated, setIsInterpolated] = createSignal(true)
|
const [getIsInterpolated, setIsInterpolated] = createSignal(true)
|
||||||
const [getGribList, setGribList] = createSignal<GribMessage[]>([])
|
const [getGribList, setGribList] = createSignal<GribMessage[]>([])
|
||||||
const [getCanvas, setCanvas] = createSignal<HTMLCanvasElement>()
|
const [getCanvas, setCanvas] = createSignal<HTMLCanvasElement>()
|
||||||
const [getImgList, setImgList] = createSignal<[string, ImageBitmap][]>([])
|
const [getImgList, setImgList] = createSignal<[string, ImageBitmap | undefined][]>([])
|
||||||
|
|
||||||
const cachedMessagesSignal = createSignal<GribMessage[]>([])
|
const cachedMessagesSignal = createSignal<GribMessage[]>([])
|
||||||
const cachedBuffersSignal = createSignal<Uint8Array[]>([])
|
const cachedBuffersSignal = createSignal<Uint8Array[]>([])
|
||||||
@@ -70,7 +70,7 @@ export const Harmonie: Component<{}> = () => {
|
|||||||
getGribList={getGribList}
|
getGribList={getGribList}
|
||||||
getCanvas={getCanvas}
|
getCanvas={getCanvas}
|
||||||
options={{ getIsCrop: getIsCrop, getIsContour: getIsContour, getIsInterpolated: getIsInterpolated }}
|
options={{ getIsCrop: getIsCrop, getIsContour: getIsContour, getIsInterpolated: getIsInterpolated }}
|
||||||
setImgList={setImgList}
|
imgListSignal={[getImgList, setImgList]}
|
||||||
onClick={getAllGribStructure}
|
onClick={getAllGribStructure}
|
||||||
/>
|
/>
|
||||||
<ul class={styles.fileList}>
|
<ul class={styles.fileList}>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Accessor, Component, createSignal, resetErrorBoundaries, Setter } from 'solid-js'
|
import { Accessor, Component, createSignal, resetErrorBoundaries, Setter, Signal } from 'solid-js'
|
||||||
|
|
||||||
import { DrawOptions, GribMessage } from './interfaces'
|
import { DrawOptions, GribMessage } from './interfaces'
|
||||||
import { fetchGribBinaries } from './fetchGrib'
|
import { fetchGribBinaries } from './fetchGrib'
|
||||||
@@ -6,6 +6,7 @@ import { drawGrib } from './draw/drawGrib'
|
|||||||
import { CROP_BOUNDS } from './DrawView'
|
import { CROP_BOUNDS } from './DrawView'
|
||||||
|
|
||||||
import styles from './harmonie.module.css'
|
import styles from './harmonie.module.css'
|
||||||
|
import { handleProgressivePromises } from '../helpers/progressivePromises'
|
||||||
|
|
||||||
export const ReferenceTimes: Component<{
|
export const ReferenceTimes: Component<{
|
||||||
setIsLoading: Setter<boolean>,
|
setIsLoading: Setter<boolean>,
|
||||||
@@ -13,7 +14,7 @@ export const ReferenceTimes: Component<{
|
|||||||
getGribList: Accessor<GribMessage[]>,
|
getGribList: Accessor<GribMessage[]>,
|
||||||
getCanvas: Accessor<HTMLCanvasElement | undefined>,
|
getCanvas: Accessor<HTMLCanvasElement | undefined>,
|
||||||
options: DrawOptions,
|
options: DrawOptions,
|
||||||
setImgList: Setter<[string, ImageBitmap][]>,
|
imgListSignal: Signal<[string, ImageBitmap | undefined][]>,
|
||||||
onClick: () => void,
|
onClick: () => void,
|
||||||
}> = ({
|
}> = ({
|
||||||
setIsLoading,
|
setIsLoading,
|
||||||
@@ -21,7 +22,7 @@ export const ReferenceTimes: Component<{
|
|||||||
getGribList,
|
getGribList,
|
||||||
getCanvas,
|
getCanvas,
|
||||||
options,
|
options,
|
||||||
setImgList,
|
imgListSignal: [getImgList, setImgList],
|
||||||
onClick,
|
onClick,
|
||||||
}) => {
|
}) => {
|
||||||
const [getActiveDate, setActiveDate] = createSignal('')
|
const [getActiveDate, setActiveDate] = createSignal('')
|
||||||
@@ -40,16 +41,19 @@ export const ReferenceTimes: Component<{
|
|||||||
setActiveDate(newValue)
|
setActiveDate(newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getImgList(dateStr: string) {
|
async function fetchDrawImgList(refDateStr: string) {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
const canvas = getCanvas()!
|
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 === dateStr)
|
.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 === 0 && g.meteo.category === 1 && g.meteo.product === 192)
|
||||||
// .slice(0, 5) // TODO remove this
|
const emptyImgList: [string, undefined][] = forecastList
|
||||||
|
.map((grib): [string, undefined] => [grib.time.forecastTime, undefined])
|
||||||
|
.sort((a, b) => a[0] > b[0] ? 1 : -1)
|
||||||
|
setImgList(emptyImgList)
|
||||||
const promiseList = forecastList.map(async (grib): Promise<[string, ImageBitmap]> => {
|
const promiseList = forecastList.map(async (grib): Promise<[string, ImageBitmap]> => {
|
||||||
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)
|
||||||
@@ -59,17 +63,20 @@ export const ReferenceTimes: Component<{
|
|||||||
return [grib.time.forecastTime, img]
|
return [grib.time.forecastTime, img]
|
||||||
})
|
})
|
||||||
|
|
||||||
Promise.all(promiseList)
|
handleProgressivePromises(
|
||||||
.then(imgList => {
|
promiseList,
|
||||||
imgList.sort((a, b) => a[0] > b[0] ? 1 : -1)
|
([forecastDate, img]) => {
|
||||||
setImgList(imgList)
|
const udpdatedImgList = [...getImgList()]
|
||||||
})
|
const idx = udpdatedImgList.findIndex(([d]) => forecastDate === d)
|
||||||
.finally(() => {
|
if (idx >= 0) udpdatedImgList[idx][1] = img
|
||||||
const ctx = canvas.getContext('2d')!
|
setImgList(udpdatedImgList)
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
},
|
||||||
setIsLoading(false)
|
).finally(() => {
|
||||||
})
|
console.log("FINALLLY")
|
||||||
|
const ctx = canvas.getContext('2d')!
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||||
|
setIsLoading(false)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ul class={styles.dateList}>
|
return <ul class={styles.dateList}>
|
||||||
@@ -81,7 +88,7 @@ export const ReferenceTimes: Component<{
|
|||||||
<div
|
<div
|
||||||
class={styles.controls}
|
class={styles.controls}
|
||||||
style={{ display: getActiveDate() === dateStr ? 'block' : 'none'}}
|
style={{ display: getActiveDate() === dateStr ? 'block' : 'none'}}
|
||||||
onClick={() => getImgList(dateStr)}
|
onClick={() => fetchDrawImgList(dateStr)}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
getGribList().some(g => g.time.referenceTime === dateStr)
|
getGribList().some(g => g.time.referenceTime === dateStr)
|
||||||
|
|||||||
@@ -4,21 +4,23 @@ import styles from './harmonie.module.css'
|
|||||||
|
|
||||||
export const SlideShow: Component<{
|
export const SlideShow: Component<{
|
||||||
getCanvas: Accessor<HTMLCanvasElement | undefined>,
|
getCanvas: Accessor<HTMLCanvasElement | undefined>,
|
||||||
getImgList: Accessor<[string, ImageBitmap][]>,
|
getImgList: Accessor<[string, ImageBitmap | undefined][]>,
|
||||||
}> = ({
|
}> = ({
|
||||||
getCanvas,
|
getCanvas,
|
||||||
getImgList
|
getImgList
|
||||||
}) => {
|
}) => {
|
||||||
function draw(img: ImageBitmap) {
|
function draw(img: ImageBitmap | undefined) {
|
||||||
const canvas = getCanvas()!
|
const canvas = getCanvas()!
|
||||||
const ctx = canvas.getContext('2d')!
|
const ctx = canvas.getContext('2d')!
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||||
|
if (!img) return;
|
||||||
|
|
||||||
ctx.drawImage(img, 0, 0)
|
ctx.drawImage(img, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ul class={styles.slideShow}>
|
return <ul class={styles.slideShow}>
|
||||||
{ getImgList().map(([forecastDate, img]) =>
|
{ getImgList().map(([forecastDate, img]) =>
|
||||||
<li onClick={() => draw(img)}>
|
<li class={img ? styles.withImg : ''} onClick={() => draw(img)}>
|
||||||
{ format(forecastDate) }
|
{ format(forecastDate) }
|
||||||
</li>)}
|
</li>)}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -70,7 +70,17 @@
|
|||||||
padding: 10px 3px;
|
padding: 10px 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.slideShow {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.slideShow li {
|
.slideShow li {
|
||||||
display: inline;
|
display: inline;
|
||||||
|
font-size: 14px;
|
||||||
padding: 3px 3px;
|
padding: 3px 3px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.withImg {
|
||||||
|
background-color: rgb(187, 247, 187);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
export async function handleProgressivePromises<T>(
|
||||||
|
promises: Promise<T>[],
|
||||||
|
onProgress: (result: T) => void,
|
||||||
|
): Promise<(T | undefined)[]> {
|
||||||
|
const allPromises = promises.map(async promise => {
|
||||||
|
try {
|
||||||
|
const result = await promise;
|
||||||
|
onProgress(result)
|
||||||
|
return result
|
||||||
|
} catch (error) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const results = await Promise.allSettled(allPromises)
|
||||||
|
return results.map(result =>
|
||||||
|
result.status === 'fulfilled' ? result.value : undefined
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user