diff --git a/web/src/assets/bg-riga.webp b/web/src/assets/bg-riga.webp new file mode 100644 index 0000000..35d4c60 Binary files /dev/null and b/web/src/assets/bg-riga.webp differ diff --git a/web/src/components/map/windAngles.ts b/web/src/components/map/windAngles.ts index 165bfbe..c3e3bd7 100644 --- a/web/src/components/map/windAngles.ts +++ b/web/src/components/map/windAngles.ts @@ -18,7 +18,8 @@ export function drawRotatedImage( img: HTMLImageElement, x: number, y: number, - angleInDegrees: number): void { + angleInDegrees: number, +): void { const angleInRadians = angleInDegrees * (Math.PI / 180); ctx.translate(x + img.width / 2, y + img.height / 2); ctx.rotate(angleInRadians); diff --git a/web/src/components/table/Table.tsx b/web/src/components/table/Table.tsx new file mode 100644 index 0000000..09386e7 --- /dev/null +++ b/web/src/components/table/Table.tsx @@ -0,0 +1,114 @@ +import { Component } from 'solid-js' +import { fetchText } from '../../helpers/fetch' +import { apiHost } from '../../consts' +import { codeToIcon } from '../weatherIcons/iconConsts' +import rigaBgUrl from '../../assets/bg-riga.webp' +import arrowUrl from '../../assets/arrow.webp' +import { drawRotatedImage, getAngleFromString } from '../map/windAngles' + +type TableWeather = { + hour: string, + temperature: string, + windDirection: string, + windSpeed: string, + icon: string, +} + +export const Table: Component<{ + csvUrl: string, +}> = ({ + csvUrl, +}) => { + let canvas: HTMLCanvasElement | undefined + const rigaBg = new Image() + rigaBg.src = rigaBgUrl + const arrowImg = new Image() + arrowImg.src = arrowUrl + + fetchText(`${apiHost}/api/show/lvgmc-forecast/${csvUrl}`) + .then(csv => { + const csvLines = csv.split('\n') + const dateStr = csvLines[2].split(';')[0].split('.').reverse().join('.') + const weekDay = new Date(dateStr).getDay() + const weekDayLV = weekDaysLV.get(weekDay)?.toUpperCase() ?? '' + const dayOrNight = csvLines[2].split(';')[1] + const rigaOffset = dayOrNight === 'DIENA' ? 24 : 51 + const data: TableWeather[] = csvLines + .slice(rigaOffset, rigaOffset+4) + .map((line): TableWeather => { + const parts = line.split(';') + const hour = parts[0].slice(6, 11).replace(':', '.') + const temperature = parts[1] + const windDirection = parts[3] + const windSpeed = parts[5] + const iconCode = Number(parts[7]) + const icon = codeToIcon(iconCode) + + return { hour, temperature, windDirection, windSpeed, icon } + }) + drawTable(canvas!, rigaBg, 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.font = 'bold 20px Rubik' + ctx.fillStyle = '#FFFFFF' + ctx.fillText(weather.hour, midX, rigaBg.height * 0.2) + + ctx.font = `normal 240px Daira by LTV grafika` + ctx.fillText(weather.icon, midX, rigaBg.height * 0.5) + + ctx.font = 'normal 50px Rubik' + ctx.fillText(weather.temperature, midX, rigaBg.height * 0.75) + + const bottomLineY = rigaBg.height * 0.9 + 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([ + [1, 'pirmdiena'], + [2, 'otrdiena'], + [3, 'trešdiena'], + [4, 'ceturtdiena'], + [5, 'piektdiena'], + [6, 'sestdiena'], + [7, 'svētdiena'], +]) \ No newline at end of file diff --git a/web/src/pages/lvgmc-forecast/CsvMapData.tsx b/web/src/pages/lvgmc-forecast/CsvMapData.tsx index ae62f58..8c1ef94 100644 --- a/web/src/pages/lvgmc-forecast/CsvMapData.tsx +++ b/web/src/pages/lvgmc-forecast/CsvMapData.tsx @@ -23,7 +23,7 @@ export const CsvMapData: Component<{ .then(csv => { const csvLines = csv.split('\n') const dayOrNight = csvLines[2].split(';')[1] - console.log(csvLines) + // console.log(csvLines) const citiesOffset = 4 const cityData: CityData[] = csvCityListInOrder .map((city, i): CityData => { diff --git a/web/src/pages/lvgmc-forecast/LvgmcForecast.tsx b/web/src/pages/lvgmc-forecast/LvgmcForecast.tsx index 17153b3..e8c03c6 100644 --- a/web/src/pages/lvgmc-forecast/LvgmcForecast.tsx +++ b/web/src/pages/lvgmc-forecast/LvgmcForecast.tsx @@ -3,6 +3,7 @@ import { Component } 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' // Eiropa_LTV_pilsetas_nakama_dn.csv // Eiropa_LTV_pilsetas_tekosa_dn.csv @@ -12,6 +13,13 @@ import { CsvMapData } from './CsvMapData' export const LvgmcForecast: Component<{}> = () => { return <> +
Night