import FloorLevelInputElement from "../Input/FloorLevelInputElement"; import MapState, {GlobalFilter} from "../../Logic/State/MapState"; import {TagsFilter} from "../../Logic/Tags/TagsFilter"; import {RegexTag} from "../../Logic/Tags/RegexTag"; import {Or} from "../../Logic/Tags/Or"; import {Tag} from "../../Logic/Tags/Tag"; import Translations from "../i18n/Translations"; import Combine from "../Base/Combine"; import {OsmFeature} from "../../Models/OsmFeature"; import {BBox} from "../../Logic/BBox"; import {TagUtils} from "../../Logic/Tags/TagUtils"; import FeaturePipeline from "../../Logic/FeatureSource/FeaturePipeline"; import {Store} from "../../Logic/UIEventSource"; /*** * The element responsible for the level input element and picking the right level, showing and hiding at the right time, ... */ export default class LevelSelector extends Combine { constructor(state: MapState & { featurePipeline: FeaturePipeline }) { const levelsInView : Store< Record> = state.currentBounds.map(bbox => { if (bbox === undefined) { return {} } const allElementsUnfiltered: OsmFeature[] = [].concat(...state.featurePipeline.GetAllFeaturesAndMetaWithin(bbox).map(ff => ff.features)) const allElements = allElementsUnfiltered.filter(f => BBox.get(f).overlapsWith(bbox)) const allLevelsRaw: string[] = allElements.map(f => f.properties["level"]) const levels : Record = {"0": 0} for (const levelDescription of allLevelsRaw) { if(levelDescription === undefined){ levels["0"] ++ } for (const level of TagUtils.LevelsParser(levelDescription)) { levels[level] = (levels[level] ?? 0) + 1 } } return levels }) const levelSelect = new FloorLevelInputElement(levelsInView) state.globalFilters.data.push({ filter: { currentFilter: undefined, state: undefined, }, id: "level", onNewPoint: undefined }) const isShown = levelsInView.map(levelsInView => { if (state.locationControl.data.zoom <= 16) { return false; } if (Object.keys(levelsInView).length == 1) { return false; } return true; }, [state.locationControl]) function setLevelFilter() { console.log("Updating levels filter to ", levelSelect.GetValue().data, " is shown:", isShown.data) const filter: GlobalFilter = state.globalFilters.data.find(gf => gf.id === "level") if (!isShown.data) { filter.filter = { state: "*", currentFilter: undefined, } filter.onNewPoint = undefined state.globalFilters.ping(); return } const l = levelSelect.GetValue().data if(l === undefined){ return } let neededLevel: TagsFilter = new RegexTag("level", new RegExp("(^|;)" + l + "(;|$)")); if (l === "0") { neededLevel = new Or([neededLevel, new Tag("level", "")]) } filter.filter = { state: l, currentFilter: neededLevel } const t = Translations.t.general.levelSelection filter.onNewPoint = { confirmAddNew: t.confirmLevel.PartialSubs({level: l}), safetyCheck: t.addNewOnLevel.Subs({level: l}), tags: [new Tag("level", l)] } state.globalFilters.ping(); return; } isShown.addCallbackAndRun(shown => { console.log("Is level selector shown?", shown) setLevelFilter() if (shown) { levelSelect.RemoveClass("invisible") } else { levelSelect.SetClass("invisible") } }) levelsInView.addCallbackAndRun(levels => { if(!isShown.data){ return } const value = levelSelect.GetValue() if (!(levels[value.data] === undefined || levels[value.data] === 0)) { return; } // Nothing in view. Lets switch to a different level (the level with the most features) let mostElements = 0 let mostElementsLevel = undefined for (const level in levels) { const count = levels[level] if(mostElementsLevel === undefined || mostElements < count){ mostElementsLevel = level mostElements = count } } console.log("Force switching to a different level:", mostElementsLevel,"as it has",mostElements,"elements on that floor",levels,"(old level: "+value.data+")") value.setData(mostElementsLevel ) }) levelSelect.GetValue().addCallback(_ => setLevelFilter()) super([levelSelect]) } }