City selection with display on a map
This commit is contained in:
+1
-1
@@ -17,7 +17,7 @@ const App: Component = () => {
|
|||||||
["latvia", () => <Country />],
|
["latvia", () => <Country />],
|
||||||
["database", () => <Database />],
|
["database", () => <Database />],
|
||||||
];
|
];
|
||||||
const [getPageTitle, setPageTitle] = createSignal("cities");
|
const [getPageTitle, setPageTitle] = createSignal("station");
|
||||||
|
|
||||||
const getPageContent = () => {
|
const getPageContent = () => {
|
||||||
const page = pages.find(p => p[0] === getPageTitle());
|
const page = pages.find(p => p[0] === getPageTitle());
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
@@ -2,11 +2,12 @@ import moment from "moment";
|
|||||||
import { createSignal } from "solid-js";
|
import { createSignal } from "solid-js";
|
||||||
import { QueryResult } from "./result/QueryResult";
|
import { QueryResult } from "./result/QueryResult";
|
||||||
|
|
||||||
import { SelectCity } from "./SelectCity";
|
import { SelectCity } from "../components/SelectCity";
|
||||||
|
import { SelectTimeRange } from "../components/SelectTimeRange";
|
||||||
|
|
||||||
import { SelectField } from "./SelectField";
|
import { SelectField } from "./SelectField";
|
||||||
import { SelectGranularity } from "./SelectGranularity";
|
import { SelectGranularity } from "./SelectGranularity";
|
||||||
import { SelectKey } from "./SelectKey";
|
import { SelectKey } from "./SelectKey";
|
||||||
import { SelectTimeRange } from "../components/SelectTimeRange";
|
|
||||||
|
|
||||||
const nowRounded = new Date(new Date().setMinutes(30));
|
const nowRounded = new Date(new Date().setMinutes(30));
|
||||||
const dayAgo = moment(nowRounded).subtract(1, "days").subtract(30, "minutes").toDate();
|
const dayAgo = moment(nowRounded).subtract(1, "days").subtract(30, "minutes").toDate();
|
||||||
@@ -21,7 +22,6 @@ export function Cities() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="aggregator">
|
<div class="aggregator">
|
||||||
<h2>Cities</h2>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<SelectCity getCities={getCities} setCities={setCities} />
|
<SelectCity getCities={getCities} setCities={setCities} />
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ export function Country() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="fileManager">
|
<div class="fileManager">
|
||||||
<h2>Latvia</h2>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<MultiSelectField
|
<MultiSelectField
|
||||||
|
|||||||
@@ -24,18 +24,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
position: absolute;
|
padding: 8px 20px;
|
||||||
top: 0px;
|
text-align: right;
|
||||||
left: 0px;
|
|
||||||
padding-left: 20px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu li{
|
.menu li{
|
||||||
display: inline;
|
display: inline;
|
||||||
padding: 10px 0 10px 10px;
|
padding: 10px 0 10px 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
line-height: 40px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu li:not(:first-child)::before {
|
.menu li:not(:first-child)::before {
|
||||||
|
|||||||
@@ -54,3 +54,11 @@ table tr:nth-child(odd) {
|
|||||||
table tr:hover {
|
table tr:hover {
|
||||||
background: #c0c0c0;
|
background: #c0c0c0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
.stationWrapper .container {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stationWrapper .container .column {
|
||||||
|
flex: 1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stationWrapper .container .column:nth-child(1) {
|
||||||
|
padding: 0;
|
||||||
|
flex-basis: 20%;
|
||||||
|
background-color: white;
|
||||||
|
min-width: 1000px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stationWrapper .container .column:nth-child(2) {
|
||||||
|
padding: 10px;
|
||||||
|
flex-basis: 80%;
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stationWrapper .cities {
|
||||||
|
width: 200px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10;
|
||||||
|
background-color: white;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stationWrapper .submenu {
|
||||||
|
padding: 5px 10px;
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
@@ -15,7 +15,6 @@ export function Database() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="fileManager">
|
<div class="fileManager">
|
||||||
<h2>Database</h2>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<DateList getDate={getDate} setDate={setDate} />
|
<DateList getDate={getDate} setDate={setDate} />
|
||||||
|
|||||||
@@ -1,15 +1,51 @@
|
|||||||
import { Component } from "solid-js";
|
import { Component, createEffect, createSignal, onMount } from "solid-js";
|
||||||
|
|
||||||
|
import mapUrl from "../assets/map_1000x570.webp";
|
||||||
|
|
||||||
|
import "../css/station.css"
|
||||||
|
import { cityCoords } from "./cityCoords";
|
||||||
|
import { SelectCity } from "../components/SelectCity";
|
||||||
|
|
||||||
|
export const Station: Component<{}> = () => {
|
||||||
|
const [getCanvas, setCanvas] = createSignal<HTMLCanvasElement>();
|
||||||
|
const [getImg, setImg] = createSignal(new Image());
|
||||||
|
const [getShowCities, setShowCities] = createSignal(false);
|
||||||
|
const [getCities, setCities] = createSignal<Set<string>>(new Set(["Rīga", "Rēzekne", "Liepāja"]));
|
||||||
|
|
||||||
|
let ctx: CanvasRenderingContext2D | undefined;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
ctx = getCanvas()!.getContext("2d")!;
|
||||||
|
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => setImg(img);
|
||||||
|
img.src = mapUrl;
|
||||||
|
});
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (!ctx || !getImg()) return;
|
||||||
|
drawOnMap(
|
||||||
|
ctx!,
|
||||||
|
[getImg()],
|
||||||
|
getCities(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
export const Station: Component<{}> = (props) => {
|
|
||||||
return (
|
return (
|
||||||
<div class="fileManager">
|
<div class="stationWrapper">
|
||||||
<h2>Station</h2>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
1st
|
<div class="submenu">
|
||||||
|
<input
|
||||||
|
type="button"
|
||||||
|
value="Select stations"
|
||||||
|
onClick={() => setShowCities(!getShowCities())}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class={"cities " + (getShowCities() ? "visible" : "hidden")}>
|
||||||
2nd
|
<SelectCity getCities={getCities} setCities={setCities} />
|
||||||
|
</div>
|
||||||
|
<canvas ref={setCanvas} width={1000} height={570} />
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
3rd
|
3rd
|
||||||
@@ -18,3 +54,24 @@ export const Station: Component<{}> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function drawOnMap(
|
||||||
|
ctx: CanvasRenderingContext2D,
|
||||||
|
imgArr: [HTMLImageElement],
|
||||||
|
cities: Set<string>,
|
||||||
|
): void {
|
||||||
|
console.log("Draw cities");
|
||||||
|
ctx.drawImage(imgArr[0], 0, 0);
|
||||||
|
ctx.fillStyle = "red";
|
||||||
|
ctx.font = "18px serif";
|
||||||
|
cities.forEach(city => {
|
||||||
|
const coord = cityCoords[city];
|
||||||
|
if (!coord) return;
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(coord.x, coord.y, 6, 0, 2 * Math.PI);
|
||||||
|
const cityTextSize = ctx.measureText(city);
|
||||||
|
ctx.fillText(city, coord.x - cityTextSize.width/2, coord.y - 6);
|
||||||
|
ctx.fill();
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
export const cityCoords: {[key: string]: { x: number, y: number}} = {
|
||||||
|
"Ainaži": { x: 467, y: 77 },
|
||||||
|
"Alūksne": { x: 812, y: 145 },
|
||||||
|
"Bauska": { x: 470, y: 405 },
|
||||||
|
"Dagda": { x: 902, y: 450 },
|
||||||
|
"Daugavgrīva": { x: 435, y: 250 },
|
||||||
|
"Daugavpils": { x: 780, y: 508 },
|
||||||
|
"Dobele": { x: 340, y: 365 },
|
||||||
|
"Gulbene": { x: 770, y: 215 },
|
||||||
|
"Jelgava": { x: 410, y: 350 },
|
||||||
|
"Kalnciems": { x: 390, y: 310 },
|
||||||
|
"Kolka": { x: 250, y: 87 },
|
||||||
|
"Kuldīga": { x: 180, y: 277 },
|
||||||
|
"Lielpēči": { x: 530, y: 310 },
|
||||||
|
"Liepāja": { x: 55, y: 375 },
|
||||||
|
"Madona": { x: 720, y: 280 },
|
||||||
|
"Mērsrags": { x: 320, y: 185 },
|
||||||
|
"Pāvilosta": { x: 80, y: 295 },
|
||||||
|
"Piedruja": { x: 895, y: 520 },
|
||||||
|
"Priekuļi": { x: 590, y: 195 },
|
||||||
|
"Rēzekne": { x: 870, y: 350 },
|
||||||
|
"Rīga": { x: 455, y: 275 },
|
||||||
|
"Rucava": { x: 75, y: 470 },
|
||||||
|
"Rūjiena": { x: 590, y: 60 },
|
||||||
|
"Saldus": { x: 240, y: 350 },
|
||||||
|
"Sigulda": { x: 540, y: 230 },
|
||||||
|
"Sīļi": { x: 720, y: 410 },
|
||||||
|
"Skrīveri": { x: 580, y: 340 },
|
||||||
|
"Skulte": { x: 485, y: 195 },
|
||||||
|
"Stende": { x: 250, y: 235 },
|
||||||
|
"Ventspils": { x: 123, y: 175 },
|
||||||
|
"Vičaki": { x: 155, y: 142},
|
||||||
|
"Zīlāni": { x: 690, y: 370 },
|
||||||
|
"Zosēni": { x: 650, y: 250 },
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user