Select city on canvas

This commit is contained in:
Guntis Smaukstelis
2024-01-06 23:48:23 +02:00
parent cb3e525fc2
commit d6707b7bb0
6 changed files with 82 additions and 32 deletions
+4 -1
View File
@@ -4,8 +4,8 @@ import { QueryResult } from "./result/QueryResult";
import { SelectCity } from "../components/SelectCity"; import { SelectCity } from "../components/SelectCity";
import { SelectTimeRange } from "../components/SelectTimeRange"; import { SelectTimeRange } from "../components/SelectTimeRange";
import { SelectField } from "../components/SelectField";
import { SelectField } from "./SelectField";
import { SelectGranularity } from "./SelectGranularity"; import { SelectGranularity } from "./SelectGranularity";
import { SelectKey } from "./SelectKey"; import { SelectKey } from "./SelectKey";
@@ -36,7 +36,10 @@ export function Cities() {
/> />
</div> </div>
<div> <div>
<div>
<h4>Select field</h4>
<SelectField getField={getField} setField={setField} /> <SelectField getField={getField} setField={setField} />
</div>
<SelectKey getKey={getKey} setKey={setKey} /> <SelectKey getKey={getKey} setKey={setKey} />
<SelectGranularity getGranularity={getGranularity} setGranularity={setGranularity} /> <SelectGranularity getGranularity={getGranularity} setGranularity={setGranularity} />
</div> </div>
-22
View File
@@ -1,22 +0,0 @@
import { Accessor, Component, Setter } from "solid-js";
import { weatherField } from "../consts";
export const SelectField: Component<{
getField: Accessor<string>,
setField: Setter<string>,
}> = (props) => {
return (
<div>
<h4>Select field</h4>
<select onChange={(e) => props.setField(e.target.value)}>
{ weatherField.map(field =>
<option
value={field}
selected={field === props.getField() ? true : false}
>{field}</option>
)}
</select>
</div>
);
}
+19
View File
@@ -0,0 +1,19 @@
import { Accessor, Component, Setter } from "solid-js";
import { weatherField } from "../consts";
export const SelectField: Component<{
getField: Accessor<string>,
setField: Setter<string>,
}> = (props) => {
return (
<select onChange={(e) => props.setField(e.target.value)}>
{ weatherField.map(field =>
<option
value={field}
selected={field === props.getField() ? true : false}
>{field}</option>
)}
</select>
);
}
+9
View File
@@ -0,0 +1,9 @@
import { Accessor, Component } from "solid-js";
export const Result: Component<{ getCity: Accessor<string|undefined>}> = ({ getCity }) => {
return (
<div>
{ getCity() }
</div>
);
}
+33 -8
View File
@@ -1,21 +1,42 @@
import { Component, createEffect, createSignal, onMount } from "solid-js"; import { Component, createEffect, createSignal, onMount } from "solid-js";
import moment from "moment";
import mapUrl from "../assets/map_1000x570.webp";
import "../css/station.css"
import { cityCoords } from "./cityCoords"; import { cityCoords } from "./cityCoords";
import { SelectCity } from "../components/SelectCity"; import { SelectCity } from "../components/SelectCity";
import mapUrl from "../assets/map_1000x570.webp";
import "../css/station.css"
import { SelectField } from "../components/SelectField";
import { coordToCity } from "./coordToCity";
import { Result } from "./Result";
export const Station: Component<{}> = () => { export const Station: Component<{}> = () => {
const [getCanvas, setCanvas] = createSignal<HTMLCanvasElement>(); const [getCanvas, setCanvas] = createSignal<HTMLCanvasElement>();
const [getImg, setImg] = createSignal(new Image()); const [getImg, setImg] = createSignal(new Image());
const [getShowCities, setShowCities] = createSignal(false); const [getShowCities, setShowCities] = createSignal(false);
const [getCities, setCities] = createSignal<Set<string>>(new Set(["Rīga", "Rēzekne", "Liepāja"])); const [getCities, setCities] = createSignal<Set<string>>(new Set(["Ainaži", "Rīga", "Rēzekne", "Liepāja", "Daugavpils", "Ventspils", "Madona"]));
const [getDate, setDate] = createSignal(moment());
const [getField, setField] = createSignal("tempMax");
const [getCity, setCity] = createSignal<string | undefined>(undefined);
let ctx: CanvasRenderingContext2D | undefined; let ctx: CanvasRenderingContext2D | undefined;
onMount(() => { onMount(() => {
ctx = getCanvas()!.getContext("2d")!; const canvas = getCanvas()!;
canvas.addEventListener("click", event => {
const rect = canvas.getBoundingClientRect();
const scaleX = canvas.width / rect.width;
const scaleY = canvas.height / rect.height;
const x = Math.round((event.clientX - rect.left) * scaleX);
const y = Math.round((event.clientY - rect.top) * scaleY);
const selectedCityCoords = Object.entries(cityCoords).filter(([city]) => getCities().has(city));
const optionalCity = coordToCity(x, y, selectedCityCoords);
setCity(optionalCity);
});
ctx = canvas.getContext("2d")!;
const img = new Image(); const img = new Image();
img.onload = () => setImg(img); img.onload = () => setImg(img);
@@ -41,6 +62,8 @@ export const Station: Component<{}> = () => {
value="Select stations" value="Select stations"
onClick={() => setShowCities(!getShowCities())} onClick={() => setShowCities(!getShowCities())}
/> />
<input type="date" value={getDate().format("YYYY-MM-DD")} />
<SelectField getField={getField} setField={setField} />
</div> </div>
<div class={"cities " + (getShowCities() ? "visible" : "hidden")}> <div class={"cities " + (getShowCities() ? "visible" : "hidden")}>
<SelectCity getCities={getCities} setCities={setCities} /> <SelectCity getCities={getCities} setCities={setCities} />
@@ -48,7 +71,7 @@ export const Station: Component<{}> = () => {
<canvas ref={setCanvas} width={1000} height={570} /> <canvas ref={setCanvas} width={1000} height={570} />
</div> </div>
<div class="column"> <div class="column">
3rd <Result getCity={getCity} />
</div> </div>
</div> </div>
</div> </div>
@@ -60,7 +83,6 @@ function drawOnMap(
imgArr: [HTMLImageElement], imgArr: [HTMLImageElement],
cities: Set<string>, cities: Set<string>,
): void { ): void {
console.log("Draw cities");
ctx.drawImage(imgArr[0], 0, 0); ctx.drawImage(imgArr[0], 0, 0);
ctx.fillStyle = "red"; ctx.fillStyle = "red";
ctx.font = "18px serif"; ctx.font = "18px serif";
@@ -69,9 +91,12 @@ function drawOnMap(
if (!coord) return; if (!coord) return;
ctx.beginPath(); ctx.beginPath();
ctx.arc(coord.x, coord.y, 6, 0, 2 * Math.PI); ctx.arc(coord.x, coord.y, 4, 0, 2 * Math.PI);
const cityTextSize = ctx.measureText(city); const cityTextSize = ctx.measureText(city);
ctx.fillText(city, coord.x - cityTextSize.width/2, coord.y - 6); ctx.fillText(city, coord.x - cityTextSize.width/2, coord.y - 6);
ctx.fill(); ctx.fill();
// const boxWidth = 60;
// const boxHeight = 30;
// ctx.strokeRect(coord.x-boxWidth/2, coord.y-boxHeight/2, boxWidth, boxHeight);
}); });
} }
+16
View File
@@ -0,0 +1,16 @@
export function coordToCity(
x: number,
y: number,
cityCoords: [string, { x: number, y: number}][],
boxWidth = 60,
boxHeight = 30,
): string | undefined {
const optionalCity = cityCoords.find(([city, coord]) =>
coord.x >= x-boxWidth/2
&& coord.x <= x+boxWidth/2
&& coord.y >= y-boxHeight/2
&& coord.y <= y+boxHeight/2
);
return optionalCity && optionalCity[0];
}