From 2113f8269423932fa76ae4f822f77a07dd703266 Mon Sep 17 00:00:00 2001 From: Petri Hienonen Date: Thu, 13 Nov 2025 13:23:25 +0200 Subject: Refactor, add light rail and tram stops --- app/components.js | 58 +++---- app/dom.js | 12 +- app/geometry.js | 8 +- app/main.js | 209 +++++++++---------------- app/map.js | 456 +++++++++++++++++++++--------------------------------- app/models.js | 270 +++++++++++++++++++++++++++----- 6 files changed, 516 insertions(+), 497 deletions(-) (limited to 'app') diff --git a/app/components.js b/app/components.js index bb11138..6531206 100644 --- a/app/components.js +++ b/app/components.js @@ -1,6 +1,5 @@ import { Dom, DomOptions, ToastType } from "dom"; -import { AreaColorParameter, ColorParameter } from "map"; -import { District, Filters, House, Weights } from "models"; +import { AreaParam, District, Filters, House, HouseParameter, Weights } from "models"; export class Widgets { /** @@ -193,7 +192,7 @@ export class Sidebar { * @returns {HTMLElement} */ #render() { - const sidebar = Dom.div( + return Dom.div( new DomOptions({ children: [ // Toggle button @@ -256,10 +255,10 @@ export class Sidebar { }, new DomOptions({ children: [ - Dom.option(ColorParameter.price, "Price"), - Dom.option(ColorParameter.score, "Score"), - Dom.option(ColorParameter.year, "Construction Year"), - Dom.option(ColorParameter.area, "Living Area"), + Dom.option(HouseParameter.price, "Price"), + Dom.option(HouseParameter.score, "Score"), + Dom.option(HouseParameter.year, "Construction Year"), + Dom.option(HouseParameter.area, "Living Area"), ], id: "color-parameter", styles: { @@ -300,20 +299,11 @@ export class Sidebar { }, new DomOptions({ children: [ - Dom.option(AreaColorParameter.none, "None"), - Dom.option( - AreaColorParameter.foreignSpeakers, - "Foreign speakers", - ), - Dom.option( - AreaColorParameter.unemploymentRate, - "Unemployment rate", - ), - Dom.option(AreaColorParameter.averageIncome, "Average income"), - Dom.option( - AreaColorParameter.higherEducation, - "Higher education", - ), + Dom.option(AreaParam.none, "None"), + Dom.option(AreaParam.foreignSpeakers, "Foreign speakers"), + Dom.option(AreaParam.unemploymentRate, "Unemployment rate"), + Dom.option(AreaParam.averageIncome, "Average income"), + Dom.option(AreaParam.higherEducation, "Higher education"), ], id: "area-color-parameter", styles: { @@ -520,7 +510,6 @@ export class Sidebar { }, }), ); - return sidebar; } /** @@ -545,7 +534,6 @@ export class Sidebar { } } - /** Toggle sidebar visibility */ toggle() { this.#collapsed = !this.#collapsed; const sidebarContent = this.#rootElement.querySelector("#sidebar-content"); @@ -572,11 +560,10 @@ export class Sidebar { /** * Update district options in the multi-select - * @param {District[]} districts * @param {House[]} houses */ - updateDistricts(districts, houses) { - const districtOptions = this.#renderDistrictOptions(districts, houses); + updateDistricts(houses) { + const districtOptions = this.#renderDistrictOptions(houses); const districtSelect = this.#rootElement.querySelector("#district-select"); if (districtSelect) { districtSelect.append(...districtOptions); @@ -596,11 +583,10 @@ export class Sidebar { /** * Render district options for multi-select - * @param {District[]} _districts * @param {House[]} houses * @returns {HTMLOptionElement[]} */ - #renderDistrictOptions(_districts, houses) { + #renderDistrictOptions(houses) { const houseDistricts = [...new Set(houses.map((h) => h.district).filter((d) => d))].sort(); return houseDistricts.map((districtName) => Dom.option(districtName, districtName)); } @@ -615,8 +601,6 @@ export class Modal { #timer; /** @type {boolean} */ #persistent; - /** @type {House} */ - #house; /** @type {() => void} */ #onHide; /** @type {() => void} */ @@ -682,12 +666,6 @@ export class Modal { { label: "Living Area", value: `${house.livingArea} m²` }, { label: "District", value: house.district }, { label: "Rooms", value: house.rooms?.toString() ?? "N/A" }, - { label: "Price", value: `${house.price} €` }, - { label: "Building Type", value: house.buildingType }, - { label: "Construction Year", value: house.constructionYear?.toString() ?? "N/A" }, - { label: "Living Area", value: `${house.livingArea} m²` }, - { label: "District", value: house.district }, - { label: "Rooms", value: house.rooms?.toString() ?? "N/A" }, ]; for (const { label, value } of details) { const item = Dom.div( @@ -696,7 +674,12 @@ export class Modal { Dom.span( label, new DomOptions({ - styles: { fontSize: "14px", fontWeight: "bold", marginBottom: "4px" }, + styles: { + fontSize: "14px", + fontWeight: "bold", + marginBottom: "4px", + marginRight: "4px", + }, }), ), Dom.span(value, new DomOptions({ styles: { color: "#333", fontSize: "14px" } })), @@ -771,7 +754,6 @@ export class Modal { * @param {() => void} onClearMapTimer */ constructor(house, persistent, positionStyles, onHide, onClearMapTimer) { - this.#house = house; this.#persistent = persistent; this.#onHide = onHide; this.#onClearMapTimer = onClearMapTimer; diff --git a/app/dom.js b/app/dom.js index 508636a..4419205 100644 --- a/app/dom.js +++ b/app/dom.js @@ -38,7 +38,7 @@ export class Dom { * @param {DomOptions} options * @returns {HTMLDivElement} */ - static div(options) { + static div(options = new DomOptions()) { const div = document.createElement("div"); Object.assign(div.style, options.styles); if (options.id) div.id = options.id; @@ -109,6 +109,16 @@ export class Dom { return input; } + /** + * Create a `` + * @param {string} text + */ + static strong(text) { + const strong = document.createElement("strong"); + strong.textContent = text; + return strong; + } + /** * Create a `