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,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) {
|
||||||
|
|
|
@ -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]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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…
Reference in a new issue