Themes: add toilet layers automatically if toilet information is included

This commit is contained in:
Pieter Vander Vennet 2025-04-27 23:45:09 +02:00
parent cf7e005fd1
commit af2636bfaa
8 changed files with 72 additions and 22 deletions

View file

@ -3358,6 +3358,19 @@
"en": "Has no toilets", "en": "Has no toilets",
"nl": "Heeft geenad toiletten" "nl": "Heeft geenad toiletten"
} }
},
{
"if": "toilets=separate",
"then": {
"en": "The toilets are marked separately on the map",
"nl": "De toiletten zijn als alleenstaand punt op de kaart aangeduid"
}
}
],
"requiredLayers": [
{
"id": "toilet",
"minzoom": 18
} }
] ]
} }

View file

@ -565,6 +565,9 @@
"12": { "12": {
"then": "Woodcarving" "then": "Woodcarving"
}, },
"13": {
"then": "Poem"
},
"2": { "2": {
"then": "Painting" "then": "Painting"
}, },
@ -9333,6 +9336,9 @@
}, },
"1": { "1": {
"then": "Has no toilets" "then": "Has no toilets"
},
"2": {
"then": "The toilets are marked separately on the map"
} }
}, },
"question": "Has {title()} toilets?" "question": "Has {title()} toilets?"
@ -14563,4 +14569,4 @@
"render": "wind turbine" "render": "wind turbine"
} }
} }
} }

View file

@ -551,6 +551,9 @@
"12": { "12": {
"then": "Houtsculptuur" "then": "Houtsculptuur"
}, },
"13": {
"then": "Gedicht"
},
"2": { "2": {
"then": "Schilderij" "then": "Schilderij"
}, },
@ -7954,6 +7957,9 @@
}, },
"1": { "1": {
"then": "Heeft geenad toiletten" "then": "Heeft geenad toiletten"
},
"2": {
"then": "De toiletten zijn als alleenstaand punt op de kaart aangeduid"
} }
}, },
"question": "Heeft {title()} toiletten?" "question": "Heeft {title()} toiletten?"
@ -11558,4 +11564,4 @@
"render": "windturbine" "render": "windturbine"
} }
} }
} }

View file

@ -805,9 +805,7 @@ class LayerOverviewUtils extends Script {
const sourcePath = `./assets/layers/${id}/${id}.json` const sourcePath = `./assets/layers/${id}/${id}.json`
const targetPath = `./public/assets/generated/layers/${id}.json` const targetPath = `./public/assets/generated/layers/${id}.json`
if (id === "questions") { if (LayerOverviewUtils.shouldBeUpdated(sourcePath, targetPath)) {
layerState.set(id, "clean")
} else if (LayerOverviewUtils.shouldBeUpdated(sourcePath, targetPath)) {
layerState.set(id, "changed") layerState.set(id, "changed")
} else { } else {
layerState.set(id, "clean") layerState.set(id, "clean")
@ -816,10 +814,10 @@ class LayerOverviewUtils extends Script {
const state = layerState.get(id) const state = layerState.get(id)
if (state !== "clean") { if (state !== "clean") {
allClean = false allClean = false
console.log(`- ${id} (${state}; ${dirtyDeps.map(dd => dd + "*").join(", ")})`) console.log(`- ${id} (${state}; ${dirtyDeps.map(dd => dd + "*").join(", ")})`)
} }
} }
if (allClean) { if (!allClean) {
console.log("\n") console.log("\n")
} }
} }

View file

@ -303,7 +303,8 @@ class AddDependencyLayersToTheme extends DesugaringStep<ThemeConfigJson> {
neededLayer: string neededLayer: string
neededBy: string neededBy: string
reason: string reason: string
context?: string context?: string,
minzoom?: number
}[] = [] }[] = []
do { do {
const dependencies: { const dependencies: {
@ -311,7 +312,8 @@ class AddDependencyLayersToTheme extends DesugaringStep<ThemeConfigJson> {
reason: string reason: string
context?: string context?: string
neededBy: string neededBy: string
checkHasSnapName: boolean checkHasSnapName: boolean,
minzoom?: number
}[] = [] }[] = []
for (const layerConfig of alreadyLoaded) { for (const layerConfig of alreadyLoaded) {
@ -382,6 +384,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<ThemeConfigJson> {
dep.forceLoad = true dep.forceLoad = true
dep.passAllFeatures = true dep.passAllFeatures = true
dep.description = reason dep.description = reason
dep.minzoom = unmetDependency.minzoom ?? dep.minzoom
dependenciesToAdd.unshift({ dependenciesToAdd.unshift({
config: dep, config: dep,
reason, reason,
@ -400,6 +403,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<ThemeConfigJson> {
const state = this._state const state = this._state
const allKnownLayers: Map<string, LayerConfigJson> = state.sharedLayers const allKnownLayers: Map<string, LayerConfigJson> = state.sharedLayers
const knownTagRenderings: Map<string, TagRenderingConfigJson> = state.tagRenderings const knownTagRenderings: Map<string, TagRenderingConfigJson> = state.tagRenderings
// Current layers in the theme
const layers: LayerConfigJson[] = <LayerConfigJson[]>theme.layers // Layers should be expanded at this point const layers: LayerConfigJson[] = <LayerConfigJson[]>theme.layers // Layers should be expanded at this point
knownTagRenderings.forEach((value, key) => { knownTagRenderings.forEach((value, key) => {

View file

@ -5,11 +5,19 @@ import { SpecialVisualization } from "../../UI/SpecialVisualization"
import SpecialVisualizations from "../../UI/SpecialVisualizations" import SpecialVisualizations from "../../UI/SpecialVisualizations"
export default class DependencyCalculator { export default class DependencyCalculator {
public static GetTagRenderingDependencies(tr: TagRenderingConfig): string[] { public static GetTagRenderingDependencies(tr: TagRenderingConfig): {
id: string,
minzoom?: number,
neededBy: string
}[] {
if (tr === undefined) { if (tr === undefined) {
throw "Got undefined tag rendering in getTagRenderingDependencies" throw "Got undefined tag rendering in getTagRenderingDependencies"
} }
const deps: string[] = [] const deps: { id: string, minZoom?: number, neededBy: string }[] = []
if (tr.requiredLayers) {
deps.push(...tr.requiredLayers.map(req => ({ ...req, neededBy: tr.id })))
}
// All translated snippets // All translated snippets
const parts: string[] = [].concat(...tr.EnumerateTranslations().map((tr) => tr.AllValues())) const parts: string[] = [].concat(...tr.EnumerateTranslations().map((tr) => tr.AllValues()))
@ -21,7 +29,7 @@ export default class DependencyCalculator {
.map((p) => <{ func: SpecialVisualization; args: string[] }>p) .map((p) => <{ func: SpecialVisualization; args: string[] }>p)
.filter((o) => o?.func?.getLayerDependencies !== undefined) .filter((o) => o?.func?.getLayerDependencies !== undefined)
for (const specialViz of specialVizs) { for (const specialViz of specialVizs) {
deps.push(...specialViz.func.getLayerDependencies(specialViz.args)) deps.push(...specialViz.func.getLayerDependencies(specialViz.args).map(id => ({ id, neededBy: tr.id })))
} }
} }
return deps return deps
@ -43,7 +51,8 @@ export default class DependencyCalculator {
reason: string reason: string
context?: string context?: string
neededBy: string neededBy: string
checkHasSnapName: boolean checkHasSnapName: boolean,
minzoom?: number
}[] = [] }[] = []
for (let i = 0; layer.presets !== undefined && i < layer.presets.length; i++) { for (let i = 0; layer.presets !== undefined && i < layer.presets.length; i++) {
@ -68,8 +77,9 @@ export default class DependencyCalculator {
for (const tr of layer.AllTagRenderings()) { for (const tr of layer.AllTagRenderings()) {
for (const dep of DependencyCalculator.GetTagRenderingDependencies(tr)) { for (const dep of DependencyCalculator.GetTagRenderingDependencies(tr)) {
deps.push({ deps.push({
neededLayer: dep, neededLayer: dep.id,
reason: "a tagrendering needs this layer", reason: `tagrendering ${dep.neededBy} needs this layer`,
minzoom: dep.minzoom,
context: tr.id, context: tr.id,
neededBy: layer.id, neededBy: layer.id,
checkHasSnapName: false, checkHasSnapName: false,
@ -91,8 +101,8 @@ export default class DependencyCalculator {
let currentKey = undefined let currentKey = undefined
let currentLine = undefined let currentLine = undefined
const params: ExtraFuncParams = { const params: ExtraFuncParams = {
getFeatureById: (_) => undefined, getFeatureById: () => undefined,
getFeaturesWithin: (layerId, _) => { getFeaturesWithin: (layerId) => {
if (layerId === "*") { if (layerId === "*") {
// This is a wildcard // This is a wildcard
return [] return []
@ -128,7 +138,9 @@ export default class DependencyCalculator {
) )
const result = func(obj, helpers) const result = func(obj, helpers)
obj.properties[key] = JSON.stringify(result) obj.properties[key] = JSON.stringify(result)
} catch (e) {} } catch (e) {
// pass
}
} }
} }

View file

@ -236,4 +236,15 @@ export interface TagRenderingConfigJson {
* group: hidden * group: hidden
*/ */
_definedIn?: [string, string] _definedIn?: [string, string]
/**
* question: what layers should always be included in the theme if this question is set?
*
* Some items (e.g. toilets, bicycle pumps) can be added as separate node or as prefixed values.
* In this case, we'll always want to include the relevant layer, on a high zoom level
* This can be forced by setting this.
* Note: if the theme already has a layer with this ID, the value is ignored
* group: hidden
*/
requiredLayers: { id: string, minzoom?: number }[]
} }

View file

@ -5,10 +5,7 @@ import { TagUtils } from "../../Logic/Tags/TagUtils"
import { And } from "../../Logic/Tags/And" import { And } from "../../Logic/Tags/And"
import { Utils } from "../../Utils" import { Utils } from "../../Utils"
import { Tag } from "../../Logic/Tags/Tag" import { Tag } from "../../Logic/Tags/Tag"
import { import { MappingConfigJson, QuestionableTagRenderingConfigJson } from "./Json/QuestionableTagRenderingConfigJson"
MappingConfigJson,
QuestionableTagRenderingConfigJson,
} from "./Json/QuestionableTagRenderingConfigJson"
import Validators, { ValidatorType } from "../../UI/InputElement/Validators" import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson" import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
import { RegexTag } from "../../Logic/Tags/RegexTag" import { RegexTag } from "../../Logic/Tags/RegexTag"
@ -68,6 +65,8 @@ export default class TagRenderingConfig {
*/ */
public readonly _definedIn: [string, string] = undefined public readonly _definedIn: [string, string] = undefined
public readonly requiredLayers: { id: string, minzoom?: number }[]
public readonly freeform?: { public readonly freeform?: {
readonly key: string readonly key: string
readonly type: ValidatorType readonly type: ValidatorType
@ -174,6 +173,7 @@ export default class TagRenderingConfig {
translationKey + ".editButtonAriaLabel" translationKey + ".editButtonAriaLabel"
) )
this.requiredLayers = json.requiredLayers ?? []
this.condition = TagUtils.Tag(json.condition ?? { and: [] }, `${context}.condition`) this.condition = TagUtils.Tag(json.condition ?? { and: [] }, `${context}.condition`)
this.invalidValues = json["invalidValues"] this.invalidValues = json["invalidValues"]
? TagUtils.Tag(json["invalidValues"], `${context}.invalidValues`) ? TagUtils.Tag(json["invalidValues"], `${context}.invalidValues`)