First version with working level selector

This commit is contained in:
Pieter Vander Vennet 2022-07-22 01:33:11 +02:00
parent 15e6fde194
commit 707961761c
9 changed files with 266 additions and 121 deletions

View file

@ -1,10 +1,9 @@
import {UIEventSource} from "../../UIEventSource";
import FilteredLayer from "../../../Models/FilteredLayer";
import {Store, UIEventSource} from "../../UIEventSource";
import FilteredLayer, {FilterState} from "../../../Models/FilteredLayer";
import {FeatureSourceForLayer, Tiled} from "../FeatureSource";
import {BBox} from "../../BBox";
import {ElementStorage} from "../../ElementStorage";
import {TagsFilter} from "../../Tags/TagsFilter";
import {tag} from "@turf/turf";
import {OsmFeature} from "../../../Models/OsmFeature";
export default class FilteringFeatureSource implements FeatureSourceForLayer, Tiled {
@ -16,7 +15,9 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
public readonly bbox: BBox
private readonly upstream: FeatureSourceForLayer;
private readonly state: {
locationControl: UIEventSource<{ zoom: number }>; selectedElement: UIEventSource<any>,
locationControl: Store<{ zoom: number }>;
selectedElement: Store<any>,
globalFilters: Store<{ filter: FilterState }[]>,
allElements: ElementStorage
};
private readonly _alreadyRegistered = new Set<UIEventSource<any>>();
@ -25,9 +26,10 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
constructor(
state: {
locationControl: UIEventSource<{ zoom: number }>,
selectedElement: UIEventSource<any>,
allElements: ElementStorage
locationControl: Store<{ zoom: number }>,
selectedElement: Store<any>,
allElements: ElementStorage,
globalFilters: Store<{ filter: FilterState }[]>
},
tileIndex,
upstream: FeatureSourceForLayer,
@ -60,6 +62,10 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
metataggingUpdated?.addCallback(_ => {
self._is_dirty.setData(true)
})
state.globalFilters.addCallback(_ => {
self.update()
})
this.update();
}
@ -69,6 +75,7 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
const layer = this.upstream.layer;
const features: { feature: OsmFeature; freshness: Date }[] = (this.upstream.features.data ?? []);
const includedFeatureIds = new Set<string>();
const globalFilters = self.state.globalFilters.data.map(f => f.filter);
const newFeatures = (features ?? []).filter((f) => {
self.registerCallback(f.feature)
@ -88,6 +95,14 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
}
}
for (const filter of globalFilters) {
const neededTags: TagsFilter = filter?.currentFilter
if (neededTags !== undefined && !neededTags.matchesProperties(f.feature.properties)) {
// Hidden by the filter on the layer itself - we want to hide it no matter what
return false;
}
}
includedFeatureIds.add(f.feature.properties.id)
return true;
});

View file

@ -8,6 +8,7 @@ import {FixedUiElement} from "../UI/Base/FixedUiElement";
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
import {CountryCoder} from "latlon2country"
import Constants from "../Models/Constants";
import {TagUtils} from "./Tags/TagUtils";
export class SimpleMetaTagger {
@ -32,7 +33,7 @@ export class SimpleMetaTagger {
if (!docs.cleanupRetagger) {
for (const key of docs.keys) {
if (!key.startsWith('_') && key.toLowerCase().indexOf("theme") < 0) {
throw `Incorrect metakey ${key}: it should start with underscore (_)`
throw `Incorrect key for a calculated meta value '${key}': it should start with underscore (_)`
}
}
}
@ -211,6 +212,27 @@ export default class SimpleMetaTaggers {
return true;
})
);
private static levels = new SimpleMetaTagger(
{
doc: "Extract the 'level'-tag into a normalized, ';'-separated value",
keys: ["_level"]
},
((feature) => {
if (feature.properties["level"] === undefined) {
return false;
}
const l = feature.properties["level"]
const newValue = TagUtils.LevelsParser(l).join(";")
if(l === newValue) {
return false;
}
feature.properties["level"] = newValue
return true
})
)
private static canonicalize = new SimpleMetaTagger(
{
doc: "If 'units' is defined in the layoutConfig, then this metatagger will rewrite the specified keys to have the canonical form (e.g. `1meter` will be rewritten to `1m`)",
@ -218,7 +240,7 @@ export default class SimpleMetaTaggers {
},
((feature, _, __, state) => {
const units = Utils.NoNull([].concat(...state?.layoutToUse?.layers?.map(layer => layer.units )?? []));
const units = Utils.NoNull([].concat(...state?.layoutToUse?.layers?.map(layer => layer.units) ?? []));
if (units.length == 0) {
return;
}
@ -317,7 +339,7 @@ export default class SimpleMetaTaggers {
country_code: tags._country.toLowerCase(),
state: undefined
}
}, <any> {tag_key: "opening_hours"});
}, <any>{tag_key: "opening_hours"});
// Recalculate!
return oh.getState() ? "yes" : "no";
@ -327,12 +349,12 @@ export default class SimpleMetaTaggers {
delete tags._isOpen
tags["_isOpen"] = "parse_error";
}
}});
}
});
const tagsSource = state.allElements.getEventSourceById(feature.properties.id);
})
)
@ -400,7 +422,8 @@ export default class SimpleMetaTaggers {
SimpleMetaTaggers.currentTime,
SimpleMetaTaggers.objectMetaInfo,
SimpleMetaTaggers.noBothButLeftRight,
SimpleMetaTaggers.geometryType
SimpleMetaTaggers.geometryType,
SimpleMetaTaggers.levels
];
public static readonly lazyTags: string[] = [].concat(...SimpleMetaTaggers.metatags.filter(tagger => tagger.isLazy)

View file

@ -127,7 +127,7 @@ export class TagUtils {
* }
* ]})
* TagUtils.FlattenMultiAnswer([tag]) // => TagUtils.Tag({and:["x=a;b", "y=0;1;2;3"] })
*
*
* TagUtils.FlattenMultiAnswer(([new Tag("x","y"), new Tag("a","b")])) // => new And([new Tag("x","y"), new Tag("a","b")])
* TagUtils.FlattenMultiAnswer(([new Tag("x","")])) // => new And([new Tag("x","")])
*/
@ -240,7 +240,7 @@ export class TagUtils {
*
* TagUtils.Tag("xyz<5").matchesProperties({xyz: 4}) // => true
* TagUtils.Tag("xyz<5").matchesProperties({xyz: 5}) // => false
*
*
* // RegexTags must match values with newlines
* TagUtils.Tag("note~.*aed.*").matchesProperties({note: "Hier bevindt zich wss een defibrillator. \\n\\n De aed bevindt zich op de 5de verdieping"}) // => true
* TagUtils.Tag("note~i~.*aed.*").matchesProperties({note: "Hier bevindt zich wss een defibrillator. \\n\\n De AED bevindt zich op de 5de verdieping"}) // => true
@ -264,13 +264,13 @@ export class TagUtils {
* @constructor
*/
public static TagD(json?: TagConfigJson, context: string = ""): TagsFilter | undefined {
if(json === undefined){
if (json === undefined) {
return undefined
}
return TagUtils.Tag(json, context)
}
/**
* INLINE sort of the given list
*/
@ -581,4 +581,38 @@ export class TagUtils {
return listToFilter.some(tf => guards.some(guard => guard.shadows(tf)))
}
/**
* Parses a level specifier to the various available levels
*
* TagUtils.LevelsParser("0") // => ["0"]
* TagUtils.LevelsParser("1") // => ["1"]
* TagUtils.LevelsParser("0;2") // => ["0","2"]
* TagUtils.LevelsParser("0-5") // => ["0","1","2","3","4","5"]
* TagUtils.LevelsParser("0") // => ["0"]
* TagUtils.LevelsParser("-1") // => ["-1"]
* TagUtils.LevelsParser("0;-1") // => ["0", "-1"]
*/
public static LevelsParser(level: string): string[] {
let spec = Utils.NoNull([level])
spec = [].concat(...spec.map(s => s?.split(";")))
spec = [].concat(...spec.map(s => {
s = s.trim()
if (s.indexOf("-") < 0 || s.startsWith("-")) {
return s
}
const [start, end] = s.split("-").map(s => Number(s.trim()))
if (isNaN(start) || isNaN(end)) {
return undefined
}
const values = []
for (let i = start; i <= end; i++) {
values.push(i + "")
}
return values
}))
return Utils.NoNull(spec);
}
}