diff --git a/web/src/aggregator/map/MapView.tsx b/web/src/aggregator/map/MapView.tsx index 45aedb1..500ffd7 100644 --- a/web/src/aggregator/map/MapView.tsx +++ b/web/src/aggregator/map/MapView.tsx @@ -1,18 +1,38 @@ import { Component, createEffect, createSignal, onMount } from "solid-js"; + import { ResultKeyVal } from "../../consts"; import { cityCoords } from "./cityCoords"; +import { drawRotatedImage, getAngleFromString } from "./windAngles"; +import { WindInputs, WindSignals } from "./WindInputs"; + +const arrowImg = new Image(); +arrowImg.src = "src/assets/arrow.webp"; export const MapView: Component<{ data: () => ResultKeyVal[] }> = ({ data }) => { const [getCanvas, setCanvas] = createSignal(); const [getImg, setImg] = createSignal(new Image()); let lastCoords: [string, {x: number, y: number }, number][] = []; + const windSignals: WindSignals = { + direction: createSignal(""), + speed: createSignal(""), + gusts: createSignal(""), + } + + function getWindData(): [string, string, string] { + return [ + windSignals.direction[0](), + windSignals.speed[0](), + windSignals.gusts[0](), + ]; + } + onMount(() => { const ctx = getCanvas()!.getContext("2d")!; const img = new Image(); img.onload = () => { setImg(img); - drawOnMap(ctx, img, lastCoords); + drawOnMap(ctx, img, lastCoords, getWindData()); }; img.src = "src/assets/map_1920x1080.webp"; }); @@ -26,31 +46,65 @@ export const MapView: Component<{ data: () => ResultKeyVal[] }> = ({ data }) => typeof value === "number" ? value : -99, ]); lastCoords = coordsAndData; - drawOnMap(ctx, getImg(), coordsAndData); + drawOnMap(ctx, getImg(), coordsAndData, getWindData()); }); return ( - + <> + + + ); } function drawOnMap( ctx: CanvasRenderingContext2D, img: HTMLImageElement, - coords: [string, {x: number, y: number }, number][] + coords: [string, {x: number, y: number }, number][], + windData: [string, string, string], ): void { const size = 80; + + // bg + ctx.drawImage(img, 0, 0); + + // city boxes + ctx.fillStyle = "#FFFFFF"; + coords.forEach(([, {x, y}, value]) => { + ctx.rect(x, y, size, size); + }); + ctx.fill(); + + // weather values ctx.font = "bold 30px Arial"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; - - ctx.drawImage(img, 0, 0); + ctx.fillStyle = "#000000"; coords.forEach(([, {x, y}, value]) => { - ctx.beginPath(); - ctx.fillStyle = "#FFFFFF"; ctx.rect(x, y, size, size); - ctx.fill(); - ctx.fillStyle = "#000000"; ctx.fillText(`${value}`, x + size/2, y + size/2); }); + + // wind values + ctx.font = "bold 45px Arial"; + ctx.textAlign = "left"; + ctx.textBaseline = "top"; + ctx.fillStyle = "#FFFFFF"; + const boxMiddleX = 1675; + + const directionWidth = ctx.measureText(windData[0]).width; + ctx.fillText(windData[0], boxMiddleX - directionWidth / 2 + 30, 370); + const angleInDegrees = getAngleFromString(windData[0]); + drawRotatedImage(ctx, arrowImg, boxMiddleX - directionWidth / 2 - 30, 370, angleInDegrees); + + const speedWidth = ctx.measureText(windData[1]).width; + ctx.fillText(windData[1], boxMiddleX - speedWidth / 2 - 30, 575); + ctx.font = "bold 25px Arial"; + ctx.fillText("M/S", boxMiddleX + speedWidth / 2 - 22, 590); + + ctx.font = "bold 45px Arial"; + const gustsWidth = ctx.measureText(windData[2]).width; + ctx.fillText(windData[2], boxMiddleX - gustsWidth / 2 - 30, 790); + ctx.font = "bold 25px Arial"; + ctx.fillText("M/S", boxMiddleX + gustsWidth / 2 - 22, 805); } \ No newline at end of file diff --git a/web/src/aggregator/map/WindInputs.tsx b/web/src/aggregator/map/WindInputs.tsx new file mode 100644 index 0000000..7e33153 --- /dev/null +++ b/web/src/aggregator/map/WindInputs.tsx @@ -0,0 +1,32 @@ +import { Component, Signal } from "solid-js"; + +export interface WindSignals { + direction: Signal; + speed: Signal; + gusts: Signal; +} + +export const WindInputs: Component<{signals: WindSignals}> = ( + { signals: { + direction: [getDirection, setDirection], + speed: [getSpeed, setSpeed], + gusts: [getGusts, setGusts], + }} +) => { + return ( + <> +
+ setDirection(e.target.value)} /> + Vēja virziens +
+
+ setSpeed(e.target.value)} /> + Vēja ātrums +
+
+ setGusts(e.target.value)} /> + Brāzmas +
+ + ); +} \ No newline at end of file diff --git a/web/src/aggregator/map/windAngles.ts b/web/src/aggregator/map/windAngles.ts new file mode 100644 index 0000000..165bfbe --- /dev/null +++ b/web/src/aggregator/map/windAngles.ts @@ -0,0 +1,27 @@ +const windAngles: {[key: string]: number} = { + "R": 0, + "ZR": 45, + "Z": 90, + "ZA": 135, + "A": 180, + "DA": 225, + "D": 270, + "DR": 315, +} + +export function getAngleFromString(str: string): number { + return windAngles[str] ?? 0; +} + +export function drawRotatedImage( + ctx: CanvasRenderingContext2D, + img: HTMLImageElement, + x: number, + y: number, + angleInDegrees: number): void { + const angleInRadians = angleInDegrees * (Math.PI / 180); + ctx.translate(x + img.width / 2, y + img.height / 2); + ctx.rotate(angleInRadians); + ctx.drawImage(img, -img.width / 2, -img.height / 2, img.width, img.height); + ctx.setTransform(1, 0, 0, 1, 0, 0); +} diff --git a/web/src/aggregator/result/Result.tsx b/web/src/aggregator/result/Result.tsx index 4ac6acc..9640546 100644 --- a/web/src/aggregator/result/Result.tsx +++ b/web/src/aggregator/result/Result.tsx @@ -42,7 +42,7 @@ export const Result: Component<{ -
+
{ getResultView() === "text" ? cityData().map(([city, data]) =>