Refactor isShown into a tagsfilter

This commit is contained in:
pietervdvn 2022-07-18 02:00:32 +02:00
parent dab0565a8b
commit b8bca0287d
13 changed files with 64 additions and 123 deletions

View file

@ -4,6 +4,8 @@ import {FeatureSourceForLayer, Tiled} from "../FeatureSource";
import {BBox} from "../../BBox"; import {BBox} from "../../BBox";
import {ElementStorage} from "../../ElementStorage"; import {ElementStorage} from "../../ElementStorage";
import {TagsFilter} from "../../Tags/TagsFilter"; import {TagsFilter} from "../../Tags/TagsFilter";
import {tag} from "@turf/turf";
import {OsmFeature} from "../../../Models/OsmFeature";
export default class FilteringFeatureSource implements FeatureSourceForLayer, Tiled { export default class FilteringFeatureSource implements FeatureSourceForLayer, Tiled {
public features: UIEventSource<{ feature: any; freshness: Date }[]> = public features: UIEventSource<{ feature: any; freshness: Date }[]> =
@ -65,22 +67,17 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
private update() { private update() {
const self = this; const self = this;
const layer = this.upstream.layer; const layer = this.upstream.layer;
const features: { feature: any; freshness: Date }[] = (this.upstream.features.data ?? []); const features: { feature: OsmFeature; freshness: Date }[] = (this.upstream.features.data ?? []);
const includedFeatureIds = new Set<string>(); const includedFeatureIds = new Set<string>();
const newFeatures = (features ?? []).filter((f) => { const newFeatures = (features ?? []).filter((f) => {
self.registerCallback(f.feature) self.registerCallback(f.feature)
const isShown = layer.layerDef.isShown; const isShown: TagsFilter = layer.layerDef.isShown;
const tags = f.feature.properties; const tags = f.feature.properties;
if (isShown.IsKnown(tags)) { if (isShown !== undefined && !isShown.matchesProperties(tags) ) {
const result = layer.layerDef.isShown.GetRenderValue(
f.feature.properties
).txt;
if (result !== "yes") {
return false; return false;
} }
}
const tagsFilter = Array.from(layer.appliedFilters?.data?.values() ?? []) const tagsFilter = Array.from(layer.appliedFilters?.data?.values() ?? [])
for (const filter of tagsFilter) { for (const filter of tagsFilter) {

View file

@ -257,6 +257,20 @@ export class TagUtils {
} }
} }
/**
* Same as `.Tag`, except that this will return undefined if the json is undefined
* @param json
* @param context
* @constructor
*/
public static TagD(json?: TagConfigJson, context: string = ""): TagsFilter | undefined {
if(json === undefined){
return undefined
}
return TagUtils.Tag(json, context)
}
/** /**
* INLINE sort of the given list * INLINE sort of the given list
*/ */

View file

@ -16,7 +16,7 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
super([ super([
"Advanced conversion which deducts a layer showing all notes that are 'importable' (i.e. a note that contains a link to some MapComplete theme, with hash '#import').", "Advanced conversion which deducts a layer showing all notes that are 'importable' (i.e. a note that contains a link to some MapComplete theme, with hash '#import').",
"The import buttons and matches will be based on the presets of the given theme", "The import buttons and matches will be based on the presets of the given theme",
].join("\n\n"), [],"CreateNoteImportLayer") ].join("\n\n"), [], "CreateNoteImportLayer")
this._includeClosedNotesDays = includeClosedNotesDays; this._includeClosedNotesDays = includeClosedNotesDays;
} }
@ -43,18 +43,18 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
const pointRenderings = (layerJson.mapRendering ?? []).filter(r => r !== null && r["location"] !== undefined); const pointRenderings = (layerJson.mapRendering ?? []).filter(r => r !== null && r["location"] !== undefined);
const firstRender = <PointRenderingConfigJson>(pointRenderings [0]) const firstRender = <PointRenderingConfigJson>(pointRenderings [0])
if(firstRender === undefined){ if (firstRender === undefined) {
throw `Layer ${layerJson.id} does not have a pointRendering: `+context throw `Layer ${layerJson.id} does not have a pointRendering: ` + context
} }
const title = layer.presets[0].title const title = layer.presets[0].title
const importButton = {} const importButton = {}
{ {
const translations = trs(t.importButton,{layerId: layer.id, title: layer.presets[0].title}) const translations = trs(t.importButton, {layerId: layer.id, title: layer.presets[0].title})
for (const key in translations) { for (const key in translations) {
if(key !== "_context"){ if (key !== "_context") {
importButton[key] = "{" + translations[key] + "}" importButton[key] = "{" + translations[key] + "}"
}else{ } else {
importButton[key] = translations[key] importButton[key] = translations[key]
} }
} }
@ -69,18 +69,18 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
return result return result
} }
function tr(translation: Translation){ function tr(translation: Translation) {
return{ ...translation.translations, "_context": translation.context} return {...translation.translations, "_context": translation.context}
} }
function trs<T>(translation: TypedTranslation<T>, subs: T) : object{ function trs<T>(translation: TypedTranslation<T>, subs: T): object {
return {...translation.Subs(subs).translations, "_context": translation.context} return {...translation.Subs(subs).translations, "_context": translation.context}
} }
const result: LayerConfigJson = { const result: LayerConfigJson = {
"id": "note_import_" + layer.id, "id": "note_import_" + layer.id,
// By disabling the name, the import-layers won't pollute the filter view "name": t.layerName.Subs({title: layer.title.render}).translations, // By disabling the name, the import-layers won't pollute the filter view "name": t.layerName.Subs({title: layer.title.render}).translations,
"description": trs(t.description , {title: layer.title.render}), "description": trs(t.description, {title: layer.title.render}),
"source": { "source": {
"osmTags": { "osmTags": {
"and": [ "and": [
@ -93,7 +93,7 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
}, },
"minzoom": Math.min(12, layerJson.minzoom - 2), "minzoom": Math.min(12, layerJson.minzoom - 2),
"title": { "title": {
"render": trs( t.popupTitle, {title}) "render": trs(t.popupTitle, {title})
}, },
"calculatedTags": [ "calculatedTags": [
"_first_comment=feat.get('comments')[0].text.toLowerCase()", "_first_comment=feat.get('comments')[0].text.toLowerCase()",
@ -103,23 +103,11 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
"_tags=(() => {let lines = feat.get('comments')[0].text.split('\\n').map(l => l.trim()); lines.splice(0, feat.get('_trigger_index') + 1); lines = lines.filter(l => l != ''); return lines.join(';');})()" "_tags=(() => {let lines = feat.get('comments')[0].text.split('\\n').map(l => l.trim()); lines.splice(0, feat.get('_trigger_index') + 1); lines = lines.filter(l => l != ''); return lines.join(';');})()"
], ],
"isShown": { "isShown": {
"render": "no",
"mappings": [
{
"if": "comments!~.*https://mapcomplete.osm.be.*",
"then": "no"
},
{
"if": {
and: and:
["_trigger_index~*", ["_trigger_index~*",
{or: isShownIfAny} {or: isShownIfAny}
] ]
}, },
"then": "yes"
}
]
},
"titleIcons": [ "titleIcons": [
{ {
"render": "<a href='https://openstreetmap.org/note/{id}' target='_blank'><img src='./assets/svg/osm-logo-us.svg'></a>" "render": "<a href='https://openstreetmap.org/note/{id}' target='_blank'><img src='./assets/svg/osm-logo-us.svg'></a>"
@ -165,7 +153,7 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
"render": "{add_image_to_note()}" "render": "{add_image_to_note()}"
}, },
{ {
"id":"nearby_images", "id": "nearby_images",
render: tr(t.nearbyImagesIntro) render: tr(t.nearbyImagesIntro)
} }

View file

@ -357,7 +357,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
for (const layerConfig of alreadyLoaded) { for (const layerConfig of alreadyLoaded) {
try { try {
const layerDeps = DependencyCalculator.getLayerDependencies(new LayerConfig(layerConfig)) const layerDeps = DependencyCalculator.getLayerDependencies(new LayerConfig(layerConfig, themeId+"(dependencies)"))
dependencies.push(...layerDeps) dependencies.push(...layerDeps)
} catch (e) { } catch (e) {
console.error(e) console.error(e)

View file

@ -549,6 +549,10 @@ export class ValidateLayer extends DesugaringStep<LayerConfigJson> {
if (json["hideUnderlayingFeaturesMinPercentage"] !== undefined) { if (json["hideUnderlayingFeaturesMinPercentage"] !== undefined) {
errors.push(context + ": layer " + json.id + " contains an old 'hideUnderlayingFeaturesMinPercentage'") errors.push(context + ": layer " + json.id + " contains an old 'hideUnderlayingFeaturesMinPercentage'")
} }
if(json.isShown !== undefined && (json.isShown["render"] !== undefined || json.isShown["mappings"] !== undefined)){
warnings.push(context + " has a tagRendering as `isShown`")
}
} }
{ {
// Check location of layer file // Check location of layer file

View file

@ -135,7 +135,7 @@ export interface LayerConfigJson {
doNotDownload?: boolean; doNotDownload?: boolean;
/** /**
* This tag rendering should either be 'yes' or 'no'. If 'no' is returned, then the feature will be hidden from view. * If set, only features matching this extra tag will be shown.
* This is useful to hide certain features from view. * This is useful to hide certain features from view.
* *
* Important: hiding features does not work dynamically, but is only calculated when the data is first renders. * Important: hiding features does not work dynamically, but is only calculated when the data is first renders.
@ -143,7 +143,7 @@ export interface LayerConfigJson {
* *
* The default value is 'yes' * The default value is 'yes'
*/ */
isShown?: TagRenderingConfigJson; isShown?: TagConfigJson;
/** /**
* Advanced option - might be set by the theme compiler * Advanced option - might be set by the theme compiler

View file

@ -39,7 +39,7 @@ export default class LayerConfig extends WithContextLoader {
public readonly calculatedTags: [string, string, boolean][]; public readonly calculatedTags: [string, string, boolean][];
public readonly doNotDownload: boolean; public readonly doNotDownload: boolean;
public readonly passAllFeatures: boolean; public readonly passAllFeatures: boolean;
public readonly isShown: TagRenderingConfig; public readonly isShown: TagsFilter;
public minzoom: number; public minzoom: number;
public minzoomVisible: number; public minzoomVisible: number;
public readonly maxzoom: number; public readonly maxzoom: number;
@ -302,7 +302,7 @@ export default class LayerConfig extends WithContextLoader {
}); });
this.title = this.tr("title", undefined); this.title = this.tr("title", undefined);
this.isShown = this.tr("isShown", "yes"); this.isShown = TagUtils.TagD(json.isShown, context+".isShown")
this.deletion = null; this.deletion = null;
if (json.deletion === true) { if (json.deletion === true) {
@ -478,7 +478,7 @@ export default class LayerConfig extends WithContextLoader {
} }
AllTagRenderings(): TagRenderingConfig[] { AllTagRenderings(): TagRenderingConfig[] {
return Utils.NoNull([...this.tagRenderings, ...this.titleIcons, this.title, this.isShown]) return Utils.NoNull([...this.tagRenderings, ...this.titleIcons, this.title])
} }
public isLeftRightSensitive(): boolean { public isLeftRightSensitive(): boolean {

View file

@ -21,17 +21,9 @@
"_is_enclosed=feat.properties._enclosing != '[]'" "_is_enclosed=feat.properties._enclosing != '[]'"
], ],
"isShown": { "isShown": {
"render": "yes", "or": [
"mappings": [ "building=",
{ "_is_enclosed!=true"
"if": {
"and": [
"building~*",
"_is_enclosed=true"
]
},
"then": "no"
}
] ]
}, },
"tagRenderings": [ "tagRenderings": [

View file

@ -34,7 +34,9 @@
"osmTags": { "osmTags": {
"or": [ "or": [
"leisure=nature_reserve", "leisure=nature_reserve",
"boundary=protected_area" {
"and": ["boundary=protected_area","protect_class!=22"]
}
] ]
} }
}, },
@ -149,15 +151,7 @@
"_overlapWithUpperLayers=Math.max(...feat.overlapWith('nature_reserve_buurtnatuur').map(o => o.overlap))/feat.area", "_overlapWithUpperLayers=Math.max(...feat.overlapWith('nature_reserve_buurtnatuur').map(o => o.overlap))/feat.area",
"_tooMuchOverlap=Number(feat.properties._overlapWithUpperLayers) > 0.1 ? 'yes' :'no'" "_tooMuchOverlap=Number(feat.properties._overlapWithUpperLayers) > 0.1 ? 'yes' :'no'"
], ],
"isShown": { "isShown": "_tooMuchOverlap!=yes",
"render": "yes",
"mappings": [
{
"if": "_tooMuchOverlap=yes",
"then": "no"
}
]
},
"title": { "title": {
"render": { "render": {
"nl": "Park" "nl": "Park"
@ -257,15 +251,7 @@
"_overlapWithUpperLayers=Math.max(...feat.overlapWith('parks','nature_reserve_buurtnatuur').map(o => o.overlap))/feat.area", "_overlapWithUpperLayers=Math.max(...feat.overlapWith('parks','nature_reserve_buurtnatuur').map(o => o.overlap))/feat.area",
"_tooMuchOverlap=Number(feat.properties._overlapWithUpperLayers) > 0.1 ? 'yes' : 'no'" "_tooMuchOverlap=Number(feat.properties._overlapWithUpperLayers) > 0.1 ? 'yes' : 'no'"
], ],
"isShown": { "isShown": "_tooMuchOverlap!=yes",
"render": "yes",
"mappings": [
{
"if": "_tooMuchOverlap=yes",
"then": "no"
}
]
},
"title": { "title": {
"render": { "render": {
"nl": "Bos" "nl": "Bos"

View file

@ -73,15 +73,7 @@
] ]
} }
}, },
"isShown": { "isShown": "id~way/.*",
"render": "yes",
"mappings": [
{
"if": "id!~way/.*",
"then": "no"
}
]
},
"description": { "description": {
"nl": "Een fietsstraat is een straat waar gemotoriseerd verkeer een fietser niet mag inhalen", "nl": "Een fietsstraat is een straat waar gemotoriseerd verkeer een fietser niet mag inhalen",
"en": "A cyclestreet is a street where motorized traffic is not allowed to overtake a cyclist", "en": "A cyclestreet is a street where motorized traffic is not allowed to overtake a cyclist",

View file

@ -630,18 +630,10 @@
} }
} }
], ],
"isShown": { "isShown":{
"render": "yes", "or": [
"mappings": [ "_imported_osm_object_found!=true",
{ "_imported_osm_still_fresh!=true"
"if": {
"and": [
"_imported_osm_object_found=true",
"_imported_osm_still_fresh=true"
]
},
"then": "no"
}
] ]
}, },
"mapRendering": [ "mapRendering": [

View file

@ -117,15 +117,7 @@
"dashArray": "8 8" "dashArray": "8 8"
} }
], ],
"isShown": { "isShown": "_country=be"
"render": "yes",
"mappings": [
{
"if": "_country!=be",
"then": "no"
}
]
}
}, },
{ {
"id": "wrong_postal_code", "id": "wrong_postal_code",
@ -196,15 +188,7 @@
] ]
} }
], ],
"isShown": { "isShown": "_country=be"
"render": "yes",
"mappings": [
{
"if": "_country!=be",
"then": "no"
}
]
}
} }
] ]
} }

View file

@ -288,14 +288,6 @@
"then": "./assets/themes/speelplekken/youtube.svg" "then": "./assets/themes/speelplekken/youtube.svg"
} }
], ],
"isShown": { "isShown":"_is_shadowed!=yes"
"render": "yes",
"mappings": [
{
"if": "_is_shadowed=yes",
"then": "no"
}
]
}
} }
} }