From ba58ff893a5dd7a729d4d0a3aa27f3246f8b7ec7 Mon Sep 17 00:00:00 2001 From: Guntis Smaukstelis Date: Sat, 15 Mar 2025 22:34:33 +0200 Subject: [PATCH] Forecast table for two days --- web/src/assets/bg-table2-left.webp | Bin 0 -> 7082 bytes web/src/assets/bg-table2-right.webp | Bin 0 -> 7180 bytes .../table/{Table.tsx => TableFour.tsx} | 2 +- web/src/components/table/TableTwo.tsx | 115 ++++++++++++++++++ .../pages/lvgmc-forecast/LvgmcForecast.tsx | 24 ++-- web/src/pages/lvgmc-forecast/lvgmc.module.css | 6 + 6 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 web/src/assets/bg-table2-left.webp create mode 100644 web/src/assets/bg-table2-right.webp rename web/src/components/table/{Table.tsx => TableFour.tsx} (99%) create mode 100644 web/src/components/table/TableTwo.tsx create mode 100644 web/src/pages/lvgmc-forecast/lvgmc.module.css diff --git a/web/src/assets/bg-table2-left.webp b/web/src/assets/bg-table2-left.webp new file mode 100644 index 0000000000000000000000000000000000000000..b153b71f733a9a5b7779e85e88aa0f5ce8193f9a GIT binary patch literal 7082 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 literal 0 HcmV?d00001 diff --git a/web/src/assets/bg-table2-right.webp b/web/src/assets/bg-table2-right.webp new file mode 100644 index 0000000000000000000000000000000000000000..7f462495410c51a05e38d522a57f00f325706317 GIT binary patch literal 7180 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 VUl{oR$H3, }> = ({ getCsvLines, diff --git a/web/src/components/table/TableTwo.tsx b/web/src/components/table/TableTwo.tsx new file mode 100644 index 0000000..db7e88f --- /dev/null +++ b/web/src/components/table/TableTwo.tsx @@ -0,0 +1,115 @@ +import { Accessor, Component, createEffect } from 'solid-js' +import { codeToIcon } from '../weatherIcons/iconConsts' +import table2BgUrl from '../../assets/bg-table2-left.webp' +import arrowUrl from '../../assets/arrow.webp' +import { drawRotatedImage, getAngleFromString } from '../map/windAngles' + +type TableWeather = { + temperature: string, + windDirection: string, + windSpeed: string, + icon: string, +} + +export const TableTwo: Component<{ + getCsvLines: Accessor, +}> = ({ + getCsvLines, +}) => { + let canvas: HTMLCanvasElement | undefined + const table2Bg = new Image() + table2Bg.src = table2BgUrl + const arrowImg = new Image() + arrowImg.src = arrowUrl + + createEffect(() => { + const csvLines = getCsvLines() + if (csvLines.length <= 0) return; + const dateStr = csvLines[0].split(';')[0].split('.').reverse().join('.') + const weekDay = new Date(dateStr).getDay() + const weekDayLV = weekDaysLV.get(weekDay)?.toUpperCase() ?? '' + + const tempParts = csvLines[2].split(';') + const iconParts = csvLines[3].split(';') + const windDirParts = csvLines[4].split(';') + const windSpeedParts = csvLines[5].split(';') + + const data: TableWeather[] = [ + { + temperature: tempParts[2], + windDirection: windDirParts[2], + windSpeed: windSpeedParts[2], + icon: codeToIcon(Number(iconParts[2])), + }, + { + temperature: tempParts[5], + windDirection: windDirParts[5], + windSpeed: windSpeedParts[5], + icon: codeToIcon(Number(iconParts[5])), + }, + ] + + drawTable(canvas!, table2Bg, arrowImg, data, weekDayLV) + }) + + return <> + + +} + + +function drawTable( + canvas: HTMLCanvasElement, + rigaBg: HTMLImageElement, + arrowImg: HTMLImageElement, + data: TableWeather[], + title: string, +) { + if (!data.length) throw new Error('Empty data for drawing table!') + canvas.width = rigaBg.width + canvas.height = rigaBg.height + const ctx = canvas.getContext('2d')! + ctx.drawImage(rigaBg, 0, 0) + + ctx.textAlign = 'center' + ctx.textBaseline = 'middle' + ctx.font = 'bold 30px Rubik' + ctx.fillStyle = '#000000' + ctx.letterSpacing = '10px' + ctx.fillText(title, rigaBg.width/2, rigaBg.height*0.065) + + ctx.letterSpacing = '0px' + const colWidth = rigaBg.width / data.length + data.forEach((weather, i) => { + const midX = colWidth * (i + 0.5) + ctx.textAlign = 'center' + ctx.fillStyle = '#FFFFFF' + + ctx.font = `normal 240px Daira by LTV grafika` + ctx.fillText(weather.icon, midX, rigaBg.height * 0.4) + + ctx.font = 'normal 50px Rubik' + ctx.fillText(weather.temperature, midX, rigaBg.height * 0.7) + + const bottomLineY = rigaBg.height * 0.85 + ctx.font = 'bold 30px Rubik' + ctx.textAlign = 'center' + ctx.fillText(weather.windDirection, midX, bottomLineY) + const dirWidth = ctx.measureText(weather.windDirection).width + const windAngle = getAngleFromString(weather.windDirection) + ctx.textAlign = 'right' + drawRotatedImage(ctx, arrowImg, midX-dirWidth/2-arrowImg.width-10, bottomLineY-arrowImg.height/2, windAngle) + ctx.textAlign = 'left' + ctx.fillText(weather.windSpeed, midX+dirWidth/2+10, bottomLineY) + }) +} + +const weekDaysLV = new Map([ + [0, 'svētdiena'], + [1, 'pirmdiena'], + [2, 'otrdiena'], + [3, 'trešdiena'], + [4, 'ceturtdiena'], + [5, 'piektdiena'], + [6, 'sestdiena'], +]) \ No newline at end of file diff --git a/web/src/pages/lvgmc-forecast/LvgmcForecast.tsx b/web/src/pages/lvgmc-forecast/LvgmcForecast.tsx index 05f7057..59f5e51 100644 --- a/web/src/pages/lvgmc-forecast/LvgmcForecast.tsx +++ b/web/src/pages/lvgmc-forecast/LvgmcForecast.tsx @@ -1,11 +1,13 @@ -import { Component, createEffect, createSignal, Setter } from 'solid-js' +import { Component, createSignal, Setter } from 'solid-js' import dayBgMap from '../../assets/map_3840x1440_wind.webp' import nightBgMap from '../../assets/map_night_3840x1440_wind.webp' import { CsvMapData } from './CsvMapData' -import { Table } from '../../components/table/Table' +import { TableFour } from '../../components/table/TableFour' import { apiHost } from '../../consts' import { fetchText } from '../../helpers/fetch' +import { TableTwo } from '../../components/table/TableTwo' +import styles from './lvgmc.module.css' // Eiropa_LTV_pilsetas_nakama_dn.csv // Eiropa_LTV_pilsetas_tekosa_dn.csv @@ -27,13 +29,13 @@ export const LvgmcForecast: Component<{}> = () => { .catch(console.warn) ) - createEffect(() => { - console.log(getMorningLines()) - }) - - return <>

Vakara ēters

+ +
+ getEveningLines().slice(60, 67)} /> + getEveningLines().slice(69, 76)} /> +
getEveningLines().slice(4, 22)} getWindLine={() => getEveningLines()[26]} @@ -44,7 +46,7 @@ export const LvgmcForecast: Component<{}> = () => { getWindLine={() => getEveningLines()[57]} bgImgUrl={dayBgMap} /> - getEveningLines()} /> + getEveningLines()} />

Rīta ēters

= () => { getWindLine={() => getMorningLines()[23]} bgImgUrl={dayBgMap} /> -
getMorningLines()} /> + getMorningLines()} /> +
+ getMorningLines().slice(33, 40)} /> + getMorningLines().slice(42, 49)} /> +
} diff --git a/web/src/pages/lvgmc-forecast/lvgmc.module.css b/web/src/pages/lvgmc-forecast/lvgmc.module.css new file mode 100644 index 0000000..df32655 --- /dev/null +++ b/web/src/pages/lvgmc-forecast/lvgmc.module.css @@ -0,0 +1,6 @@ +.twoCanvas { + display: flex; + justify-content: space-between; + gap: 20px; + width: 1040px; +} \ No newline at end of file