Refactor isShown into a tagsfilter
This commit is contained in:
		
							parent
							
								
									dab0565a8b
								
							
						
					
					
						commit
						b8bca0287d
					
				
					 13 changed files with 64 additions and 123 deletions
				
			
		|  | @ -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,21 +67,16 @@ 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( |                 return false; | ||||||
|                     f.feature.properties |  | ||||||
|                 ).txt; |  | ||||||
|                 if (result !== "yes") { |  | ||||||
|                     return false; |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             const tagsFilter = Array.from(layer.appliedFilters?.data?.values() ?? []) |             const tagsFilter = Array.from(layer.appliedFilters?.data?.values() ?? []) | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|  | @ -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] | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -68,19 +68,19 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L | ||||||
|             result["_context"] = translation.context |             result["_context"] = translation.context | ||||||
|             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,22 +103,10 @@ 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", |                 and: | ||||||
|                 "mappings": [ |                     ["_trigger_index~*", | ||||||
|                     { |                         {or: isShownIfAny} | ||||||
|                         "if": "comments!~.*https://mapcomplete.osm.be.*", |                     ] | ||||||
|                         "then": "no" |  | ||||||
|                     }, |  | ||||||
|                     { |  | ||||||
|                         "if": { |  | ||||||
|                             and: |  | ||||||
|                                 ["_trigger_index~*", |  | ||||||
|                                     {or: isShownIfAny} |  | ||||||
|                                 ] |  | ||||||
|                         }, |  | ||||||
|                         "then": "yes" |  | ||||||
|                     } |  | ||||||
|                 ] |  | ||||||
|             }, |             }, | ||||||
|             "titleIcons": [ |             "titleIcons": [ | ||||||
|                 { |                 { | ||||||
|  | @ -165,9 +153,9 @@ 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) | ||||||
|                          | 
 | ||||||
|                 } |                 } | ||||||
|             ], |             ], | ||||||
|             "mapRendering": [ |             "mapRendering": [ | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
|  |  | ||||||
|  | @ -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
 | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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 { | ||||||
|  |  | ||||||
|  | @ -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": [ | ||||||
|  |  | ||||||
|  | @ -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" | ||||||
|  |  | ||||||
|  | @ -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", | ||||||
|  |  | ||||||
|  | @ -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": [ | ||||||
|  |  | ||||||
|  | @ -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" |  | ||||||
|           } |  | ||||||
|         ] |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|   ] |   ] | ||||||
| } | } | ||||||
|  | @ -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" |  | ||||||
|         } |  | ||||||
|       ] |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue