forked from MapComplete/MapComplete
		
	Merge develop
This commit is contained in:
		
						commit
						f7370d0ae9
					
				
					 25 changed files with 452 additions and 64 deletions
				
			
		| 
						 | 
					@ -1 +1,2 @@
 | 
				
			||||||
["file-overview.json","missing_editor.json","stats.2020-10.json","stats.2020-11.json","stats.2020-12.json","stats.2020-5.json","stats.2020-6.json","stats.2020-7.json","stats.2020-8.json","stats.2020-9.json","stats.2021-1.json","stats.2021-10.json","stats.2021-11.json","stats.2021-12.json","stats.2021-2.json","stats.2021-3.json","stats.2021-4.json","stats.2021-5.json","stats.2021-6.json","stats.2021-7.json","stats.2021-8.json","stats.2021-9.json","stats.2022-1.json","stats.2022-2.json","stats.2022-3.json","stats.2022-4.json","stats.2022-5.json","stats.2022-6.json","stats.2022-7.json","stats.2022-8.json","stats.2022-9-01.day.json","stats.2022-9-02.day.json","stats.2022-9-03.day.json","stats.2022-9-04.day.json","stats.2022-9-05.day.json","stats.2022-9-06.day.json","stats.2022-9-07.day.json","stats.2022-9-08.day.json","stats.2022-9-09.day.json","stats.2022-9-10.day.json","stats.2022-9-11.day.json","stats.2022-9-12.day.json","stats.2022-9-13.day.json","stats.2022-9-14.day.json","stats.2022-9-15.day.json","stats.2022-9-16.day.json","stats.2022-9-17.day.json","stats.2022-9-18.day.json","stats.2022-9-19.day.json","stats.2022-9-20.day.json","stats.2022-9-21.day.json","stats.2022-9-22.day.json","stats.2022-9-23.day.json"]
 | 
					["file-overview.json","missing_editor.json","stats.2020-10.json","stats.2020-11.json","stats.2020-12.json","stats.2020-5.json","stats.2020-6.json","stats.2020-7.json","stats.2020-8.json","stats.2020-9.json","stats.2021-1.json","stats.2021-10.json","stats.2021-11.json","stats.2021-12.json","stats.2021-2.json","stats.2021-3.json","stats.2021-4.json","stats.2021-5.json","stats.2021-6.json","stats.2021-7.json","stats.2021-8.json","stats.2021-9.json","stats.2022-1.json","stats.2022-2.json","stats.2022-3.json","stats.2022-4.json","stats.2022-5.json","stats.2022-6.json","stats.2022-7.json","stats.2022-8.json","stats.2022-9-01.day.json","stats.2022-9-02.day.json","stats.2022-9-03.day.json","stats.2022-9-04.day.json","stats.2022-9-05.day.json","stats.2022-9-06.day.json","stats.2022-9-07.day.json","stats.2022-9-08.day.json","stats.2022-9-09.day.json","stats.2022-9-10.day.json","stats.2022-9-11.day.json","stats.2022-9-12.day.json","stats.2022-9-13.day.json","stats.2022-9-14.day.json","stats.2022-9-15.day.json","stats.2022-9-16.day.json","stats.2022-9-17.day.json","stats.2022-9-18.day.json","stats.2022-9-19.day.json","stats.2022-9-20.day.json","stats.2022-9-21.day.json","stats.2022-9-22.day.json","stats.2022-9-23.day.json","stats.2022-9-24.day.json","stats.2022-9-25.day.json"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								Docs/Tools/stats/stats.2022-9-24.day.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Docs/Tools/stats/stats.2022-9-24.day.json
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								Docs/Tools/stats/stats.2022-9-25.day.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Docs/Tools/stats/stats.2022-9-25.day.json
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
					@ -137,10 +137,13 @@ export default class AvailableBaseLayersImplementation implements AvailableBaseL
 | 
				
			||||||
            l("Stamen.TonerBackground", "Toner Background - no labels (by Stamen)"),
 | 
					            l("Stamen.TonerBackground", "Toner Background - no labels (by Stamen)"),
 | 
				
			||||||
            l("Stamen.Watercolor", "Watercolor (by Stamen)"),
 | 
					            l("Stamen.Watercolor", "Watercolor (by Stamen)"),
 | 
				
			||||||
            l("Stadia.OSMBright", "Osm Bright (by Stadia)"),
 | 
					            l("Stadia.OSMBright", "Osm Bright (by Stadia)"),
 | 
				
			||||||
 | 
					            l("Stadia.AlidadeSmoothDark", "Alidade Smooth Dark (by Stadia)"),
 | 
				
			||||||
            l("CartoDB.Positron", "Positron (by CartoDB)"),
 | 
					            l("CartoDB.Positron", "Positron (by CartoDB)"),
 | 
				
			||||||
            l("CartoDB.PositronNoLabels", "Positron  - no labels (by CartoDB)"),
 | 
					            l("CartoDB.PositronNoLabels", "Positron  - no labels (by CartoDB)"),
 | 
				
			||||||
            l("CartoDB.Voyager", "Voyager (by CartoDB)"),
 | 
					            l("CartoDB.Voyager", "Voyager (by CartoDB)"),
 | 
				
			||||||
            l("CartoDB.VoyagerNoLabels", "Voyager  - no labels (by CartoDB)"),
 | 
					            l("CartoDB.VoyagerNoLabels", "Voyager  - no labels (by CartoDB)"),
 | 
				
			||||||
 | 
					            l("CartoDB.DarkMatter", "Dark Matter (by CartoDB)"),
 | 
				
			||||||
 | 
					            l("CartoDB.DarkMatterNoLabels", "Dark Matter  - no labels (by CartoDB)"),
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
        return Utils.NoNull(layers)
 | 
					        return Utils.NoNull(layers)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@ import {
 | 
				
			||||||
    Polygon,
 | 
					    Polygon,
 | 
				
			||||||
    Properties,
 | 
					    Properties,
 | 
				
			||||||
} from "@turf/turf"
 | 
					} from "@turf/turf"
 | 
				
			||||||
import {GeoJSON, LineString} from "geojson";
 | 
					import {GeoJSON, LineString, Point} from "geojson";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class GeoOperations {
 | 
					export class GeoOperations {
 | 
				
			||||||
    private static readonly _earthRadius = 6378137
 | 
					    private static readonly _earthRadius = 6378137
 | 
				
			||||||
| 
						 | 
					@ -27,8 +27,8 @@ export class GeoOperations {
 | 
				
			||||||
     * Converts a GeoJson feature to a point GeoJson feature
 | 
					     * Converts a GeoJson feature to a point GeoJson feature
 | 
				
			||||||
     * @param feature
 | 
					     * @param feature
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    static centerpoint(feature: any) {
 | 
					    static centerpoint(feature: any): Feature<Point> {
 | 
				
			||||||
        const newFeature = turf.center(feature)
 | 
					        const newFeature : Feature<Point> = turf.center(feature)
 | 
				
			||||||
        newFeature.properties = feature.properties
 | 
					        newFeature.properties = feature.properties
 | 
				
			||||||
        newFeature.id = feature.id
 | 
					        newFeature.id = feature.id
 | 
				
			||||||
        return newFeature
 | 
					        return newFeature
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@ import LayerConfig from "../Models/ThemeConfig/LayerConfig"
 | 
				
			||||||
import { CountryCoder } from "latlon2country"
 | 
					import { CountryCoder } from "latlon2country"
 | 
				
			||||||
import Constants from "../Models/Constants"
 | 
					import Constants from "../Models/Constants"
 | 
				
			||||||
import { TagUtils } from "./Tags/TagUtils"
 | 
					import { TagUtils } from "./Tags/TagUtils"
 | 
				
			||||||
 | 
					import {Feature, LineString} from "geojson";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class SimpleMetaTagger {
 | 
					export class SimpleMetaTagger {
 | 
				
			||||||
    public readonly keys: string[]
 | 
					    public readonly keys: string[]
 | 
				
			||||||
| 
						 | 
					@ -420,6 +421,38 @@ export default class SimpleMetaTaggers {
 | 
				
			||||||
            return true
 | 
					            return true
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static directionCenterpoint = new SimpleMetaTagger(
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            keys:["_direction:centerpoint"],
 | 
				
			||||||
 | 
					            isLazy: true,
 | 
				
			||||||
 | 
					            doc: "_direction:centerpoint is the direction of the linestring (in degrees) if one were standing at the projected centerpoint."
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        (feature: Feature) => {
 | 
				
			||||||
 | 
					            if(feature.geometry.type !== "LineString"){
 | 
				
			||||||
 | 
					                return false
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const ls = <Feature<LineString>> feature;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Object.defineProperty(feature.properties, "_direction:centerpoint", {
 | 
				
			||||||
 | 
					                enumerable: false,
 | 
				
			||||||
 | 
					                configurable: true,
 | 
				
			||||||
 | 
					                get: () => {
 | 
				
			||||||
 | 
					                    const centroid = GeoOperations.centerpoint(feature)
 | 
				
			||||||
 | 
					                    const projected = GeoOperations.nearestPoint(ls, <[number,number]> centroid.geometry.coordinates)
 | 
				
			||||||
 | 
					                    const nextPoint = ls.geometry.coordinates[projected.properties.index + 1]
 | 
				
			||||||
 | 
					                    const bearing = GeoOperations.bearing(projected.geometry.coordinates, nextPoint)
 | 
				
			||||||
 | 
					                    delete feature.properties["_direction:centerpoint"]
 | 
				
			||||||
 | 
					                    feature.properties["_direction:centerpoint"] = bearing
 | 
				
			||||||
 | 
					                    return bearing
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static currentTime = new SimpleMetaTagger(
 | 
					    private static currentTime = new SimpleMetaTagger(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            keys: ["_now:date", "_now:datetime", "_loaded:date", "_loaded:_datetime"],
 | 
					            keys: ["_now:date", "_now:datetime", "_loaded:date", "_loaded:_datetime"],
 | 
				
			||||||
| 
						 | 
					@ -457,6 +490,7 @@ export default class SimpleMetaTaggers {
 | 
				
			||||||
        SimpleMetaTaggers.country,
 | 
					        SimpleMetaTaggers.country,
 | 
				
			||||||
        SimpleMetaTaggers.isOpen,
 | 
					        SimpleMetaTaggers.isOpen,
 | 
				
			||||||
        SimpleMetaTaggers.directionSimplified,
 | 
					        SimpleMetaTaggers.directionSimplified,
 | 
				
			||||||
 | 
					        SimpleMetaTaggers.directionCenterpoint,
 | 
				
			||||||
        SimpleMetaTaggers.currentTime,
 | 
					        SimpleMetaTaggers.currentTime,
 | 
				
			||||||
        SimpleMetaTaggers.objectMetaInfo,
 | 
					        SimpleMetaTaggers.objectMetaInfo,
 | 
				
			||||||
        SimpleMetaTaggers.noBothButLeftRight,
 | 
					        SimpleMetaTaggers.noBothButLeftRight,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -371,7 +371,7 @@ export default class LayerConfig extends WithContextLoader {
 | 
				
			||||||
            throw "Error in " + context + ": use 'filter' instead of 'filters'"
 | 
					            throw "Error in " + context + ": use 'filter' instead of 'filters'"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.titleIcons = this.ParseTagRenderings(<TagRenderingConfigJson[]>json.titleIcons, {
 | 
					        this.titleIcons = this.ParseTagRenderings(<TagRenderingConfigJson[]>json.titleIcons ?? [], {
 | 
				
			||||||
            readOnlyMode: true,
 | 
					            readOnlyMode: true,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -148,7 +148,7 @@ export default abstract class BaseUIElement {
 | 
				
			||||||
        } catch (e) {
 | 
					        } catch (e) {
 | 
				
			||||||
            const domExc = e as DOMException
 | 
					            const domExc = e as DOMException
 | 
				
			||||||
            if (domExc) {
 | 
					            if (domExc) {
 | 
				
			||||||
                console.log("An exception occured", domExc.code, domExc.message, domExc.name)
 | 
					                console.error("An exception occured", domExc.code, domExc.message, domExc.name, domExc)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            console.error(e)
 | 
					            console.error(e)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ import Translations from "../i18n/Translations";
 | 
				
			||||||
export class CheckBox extends InputElementMap<number[], boolean> {
 | 
					export class CheckBox extends InputElementMap<number[], boolean> {
 | 
				
			||||||
    constructor(el: (BaseUIElement | string), defaultValue?: boolean) {
 | 
					    constructor(el: (BaseUIElement | string), defaultValue?: boolean) {
 | 
				
			||||||
        super(
 | 
					        super(
 | 
				
			||||||
            new CheckBoxes([Translations.T(el)]),
 | 
					            new CheckBoxes([Translations.W(el)]),
 | 
				
			||||||
            (x0, x1) => x0 === x1,
 | 
					            (x0, x1) => x0 === x1,
 | 
				
			||||||
            (t) => t.length > 0,
 | 
					            (t) => t.length > 0,
 | 
				
			||||||
            (x) => (x ? [0] : [])
 | 
					            (x) => (x ? [0] : [])
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,16 +10,15 @@ import Toggle from "./Input/Toggle"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class LanguagePicker extends Toggle {
 | 
					export default class LanguagePicker extends Toggle {
 | 
				
			||||||
    constructor(languages: string[], label: string | BaseUIElement = "") {
 | 
					    constructor(languages: string[], label: string | BaseUIElement = "") {
 | 
				
			||||||
 | 
					        console.log("Constructing a language pîcker for languages", languages)
 | 
				
			||||||
        if (languages === undefined || languages.length <= 1) {
 | 
					        if (languages === undefined || languages.length <= 1) {
 | 
				
			||||||
            super(undefined, undefined, undefined)
 | 
					            super(undefined, undefined, undefined)
 | 
				
			||||||
            return undefined
 | 
					        }else {
 | 
				
			||||||
 | 
					            const normalPicker = LanguagePicker.dropdownFor(languages, label)
 | 
				
			||||||
 | 
					            const fullPicker = new Lazy(() => LanguagePicker.dropdownFor(allLanguages, label))
 | 
				
			||||||
 | 
					            super(fullPicker, normalPicker, Locale.showLinkToWeblate)
 | 
				
			||||||
 | 
					            const allLanguages: string[] = used_languages.languages
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        const allLanguages: string[] = used_languages.languages
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const normalPicker = LanguagePicker.dropdownFor(languages, label)
 | 
					 | 
				
			||||||
        const fullPicker = new Lazy(() => LanguagePicker.dropdownFor(allLanguages, label))
 | 
					 | 
				
			||||||
        super(fullPicker, normalPicker, Locale.showLinkToWeblate)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static dropdownFor(languages: string[], label: string | BaseUIElement): BaseUIElement {
 | 
					    private static dropdownFor(languages: string[], label: string | BaseUIElement): BaseUIElement {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -248,31 +248,29 @@ export default class FeatureInfoBox extends ScrollableFullScreen {
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        editElements.push(
 | 
					        editElements.push(
 | 
				
			||||||
            new VariableUiElement(
 | 
					            Toggle.If(state.featureSwitchIsDebugging,
 | 
				
			||||||
                state.featureSwitchIsDebugging.map((isDebugging) => {
 | 
					                () => {
 | 
				
			||||||
                    if (isDebugging) {
 | 
					                    const config_all_tags: TagRenderingConfig = new TagRenderingConfig(
 | 
				
			||||||
                        const config_all_tags: TagRenderingConfig = new TagRenderingConfig(
 | 
					                        { render: "{all_tags()}" },
 | 
				
			||||||
                            { render: "{all_tags()}" },
 | 
					                        ""
 | 
				
			||||||
                            ""
 | 
					                    )
 | 
				
			||||||
                        )
 | 
					                    const config_download: TagRenderingConfig = new TagRenderingConfig(
 | 
				
			||||||
                        const config_download: TagRenderingConfig = new TagRenderingConfig(
 | 
					                        { render: "{export_as_geojson()}" },
 | 
				
			||||||
                            { render: "{export_as_geojson()}" },
 | 
					                        ""
 | 
				
			||||||
                            ""
 | 
					                    )
 | 
				
			||||||
                        )
 | 
					                    const config_id: TagRenderingConfig = new TagRenderingConfig(
 | 
				
			||||||
                        const config_id: TagRenderingConfig = new TagRenderingConfig(
 | 
					                        { render: "{open_in_iD()}" },
 | 
				
			||||||
                            { render: "{open_in_iD()}" },
 | 
					                        ""
 | 
				
			||||||
                            ""
 | 
					                    )
 | 
				
			||||||
                        )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        return new Combine([
 | 
					                    return new Combine([
 | 
				
			||||||
                            new TagRenderingAnswer(tags, config_all_tags, state),
 | 
					                        new TagRenderingAnswer(tags, config_all_tags, state),
 | 
				
			||||||
                            new TagRenderingAnswer(tags, config_download, state),
 | 
					                        new TagRenderingAnswer(tags, config_download, state),
 | 
				
			||||||
                            new TagRenderingAnswer(tags, config_id, state),
 | 
					                        new TagRenderingAnswer(tags, config_id, state),
 | 
				
			||||||
                            "This is layer " + layerConfig.id,
 | 
					                        "This is layer " + layerConfig.id,
 | 
				
			||||||
                        ])
 | 
					                    ])
 | 
				
			||||||
                    }
 | 
					                }
 | 
				
			||||||
                })
 | 
					                )
 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return new Combine(editElements).SetClass("flex flex-col")
 | 
					        return new Combine(editElements).SetClass("flex flex-col")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,38 @@ export default class TagApplyButton implements AutoAction {
 | 
				
			||||||
    public readonly example =
 | 
					    public readonly example =
 | 
				
			||||||
        "`{tag_apply(survey_date=$_now:date, Surveyed today!)}`, `{tag_apply(addr:street=$addr:street, Apply the address, apply_icon.svg, _closest_osm_id)"
 | 
					        "`{tag_apply(survey_date=$_now:date, Surveyed today!)}`, `{tag_apply(addr:street=$addr:street, Apply the address, apply_icon.svg, _closest_osm_id)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Parses a tag specification
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * TagApplyButton.parseTagSpec("key=value;key0=value0") // => [["key","value"],["key0","value0"]]
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * // Should handle escaped ";"
 | 
				
			||||||
 | 
					     * TagApplyButton.parseTagSpec("key=value;key0=value0\\;value1") // => [["key","value"],["key0","value0;value1"]]
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private static parseTagSpec(spec: string): [string, string][]{
 | 
				
			||||||
 | 
					        const tgsSpec : [string, string][] = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while(spec.length > 0){
 | 
				
			||||||
 | 
					            const [part] = spec.match(/((\\;)|[^;])*/)
 | 
				
			||||||
 | 
					            spec = spec.substring(part.length + 1) // +1 to remove the pending ';' as well
 | 
				
			||||||
 | 
					            const kv = part.split("=").map((s) => s.trim().replace("\\;",";"))
 | 
				
			||||||
 | 
					            if (kv.length == 2) {
 | 
				
			||||||
 | 
					                tgsSpec.push(<[string, string]> kv)
 | 
				
			||||||
 | 
					            }else if (kv.length < 2) {
 | 
				
			||||||
 | 
					                throw "Invalid key spec: no '=' found in " + spec
 | 
				
			||||||
 | 
					            }else{
 | 
				
			||||||
 | 
					                throw "Invalid key spec: multiple '=' found in " + spec
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (const spec of tgsSpec) {
 | 
				
			||||||
 | 
					            if (spec[0].endsWith(":")) {
 | 
				
			||||||
 | 
					                throw "The key for a tag specification for import or apply ends with ':'. The theme author probably wrote key:=otherkey instead of key=$otherkey"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return tgsSpec
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static generateTagsToApply(spec: string, tagSource: Store<any>): Store<Tag[]> {
 | 
					    public static generateTagsToApply(spec: string, tagSource: Store<any>): Store<Tag[]> {
 | 
				
			||||||
        // Check whether we need to look up a single value
 | 
					        // Check whether we need to look up a single value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,19 +83,7 @@ export default class TagApplyButton implements AutoAction {
 | 
				
			||||||
            spec = tagSource.data[spec.replace("$", "")]
 | 
					            spec = tagSource.data[spec.replace("$", "")]
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const tgsSpec = spec.split(";").map((spec) => {
 | 
					       const tgsSpec = TagApplyButton.parseTagSpec(spec)
 | 
				
			||||||
            const kv = spec.split("=").map((s) => s.trim())
 | 
					 | 
				
			||||||
            if (kv.length != 2) {
 | 
					 | 
				
			||||||
                throw "Invalid key spec: multiple '=' found in " + spec
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return kv
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (const spec of tgsSpec) {
 | 
					 | 
				
			||||||
            if (spec[0].endsWith(":")) {
 | 
					 | 
				
			||||||
                throw "A tag specification for import or apply ends with ':'. The theme author probably wrote key:=otherkey instead of key=$otherkey"
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return tagSource.map((tags) => {
 | 
					        return tagSource.map((tags) => {
 | 
				
			||||||
            const newTags: Tag[] = []
 | 
					            const newTags: Tag[] = []
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,7 @@ export default class Translations {
 | 
				
			||||||
     * translation.textFor("nl") // => "Nederlands"
 | 
					     * translation.textFor("nl") // => "Nederlands"
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    static T(t: string | any, context = undefined): TypedTranslation<object> {
 | 
					    static T(t: string | undefined | null | Translation | TypedTranslation<object>, context = undefined): TypedTranslation<object> {
 | 
				
			||||||
        if (t === undefined || t === null) {
 | 
					        if (t === undefined || t === null) {
 | 
				
			||||||
            return undefined
 | 
					            return undefined
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -51,7 +51,7 @@ export default class Translations {
 | 
				
			||||||
        if (typeof t === "string") {
 | 
					        if (typeof t === "string") {
 | 
				
			||||||
            return new TypedTranslation<object>({ "*": t }, context)
 | 
					            return new TypedTranslation<object>({ "*": t }, context)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (t.render !== undefined) {
 | 
					        if (t["render"] !== undefined) {
 | 
				
			||||||
            const msg =
 | 
					            const msg =
 | 
				
			||||||
                "Creating a translation, but this object contains a 'render'-field. Use the translation directly"
 | 
					                "Creating a translation, but this object contains a 'render'-field. Use the translation directly"
 | 
				
			||||||
            console.error(msg, t)
 | 
					            console.error(msg, t)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "id": "filters",
 | 
					  "id": "filters",
 | 
				
			||||||
  "description": "This layer acts as library for common filters",
 | 
					  "description": "This layer acts as library for common filters",
 | 
				
			||||||
  "mapRendering": [],
 | 
					  "mapRendering": null,
 | 
				
			||||||
  "source": {
 | 
					  "source": {
 | 
				
			||||||
    "osmTags": "id~*"
 | 
					    "osmTags": "id~*"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					@ -94,4 +94,4 @@
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
[
 | 
					[
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "path": "hotel.svg",
 | 
					    "path": "hotel.svg",
 | 
				
			||||||
    "license": "",
 | 
					    "license": "CC0",
 | 
				
			||||||
    "authors": [
 | 
					    "authors": [
 | 
				
			||||||
      "Andy Allan",
 | 
					      "Andy Allan",
 | 
				
			||||||
      "Michael Glanznig",
 | 
					      "Michael Glanznig",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,6 +58,7 @@
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "tagRenderings": [
 | 
					  "tagRenderings": [
 | 
				
			||||||
 | 
					    "images",
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      "id": "kerb-type",
 | 
					      "id": "kerb-type",
 | 
				
			||||||
      "question": {
 | 
					      "question": {
 | 
				
			||||||
| 
						 | 
					@ -373,4 +374,4 @@
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -234,4 +234,4 @@
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -173,4 +173,4 @@
 | 
				
			||||||
      "width": "1"
 | 
					      "width": "1"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -121,7 +121,7 @@
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "filter": [
 | 
					  "filter": [
 | 
				
			||||||
      "open_now"
 | 
					    "open_now"
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "mapRendering": [
 | 
					  "mapRendering": [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					@ -145,4 +145,4 @@
 | 
				
			||||||
      "width": "1"
 | 
					      "width": "1"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1189,4 +1189,4 @@
 | 
				
			||||||
    "enableRelocation": false,
 | 
					    "enableRelocation": false,
 | 
				
			||||||
    "enableImproveAccuracy": true
 | 
					    "enableImproveAccuracy": true
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -187,4 +187,4 @@
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										49
									
								
								assets/themes/width/icon.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								assets/themes/width/icon.svg
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,49 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
				
			||||||
 | 
					<svg
 | 
				
			||||||
 | 
					   width="500"
 | 
				
			||||||
 | 
					   height="500"
 | 
				
			||||||
 | 
					   version="1.1"
 | 
				
			||||||
 | 
					   id="svg20"
 | 
				
			||||||
 | 
					   sodipodi:docname="icon.svg"
 | 
				
			||||||
 | 
					   inkscape:version="1.2.1 (0f2f062aeb, 2022-09-21, custom)"
 | 
				
			||||||
 | 
					   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
				
			||||||
 | 
					   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
				
			||||||
 | 
					   xmlns="http://www.w3.org/2000/svg"
 | 
				
			||||||
 | 
					   xmlns:svg="http://www.w3.org/2000/svg">
 | 
				
			||||||
 | 
					  <defs
 | 
				
			||||||
 | 
					     id="defs24" />
 | 
				
			||||||
 | 
					  <sodipodi:namedview
 | 
				
			||||||
 | 
					     id="namedview22"
 | 
				
			||||||
 | 
					     pagecolor="#505050"
 | 
				
			||||||
 | 
					     bordercolor="#eeeeee"
 | 
				
			||||||
 | 
					     borderopacity="1"
 | 
				
			||||||
 | 
					     inkscape:showpageshadow="0"
 | 
				
			||||||
 | 
					     inkscape:pageopacity="0"
 | 
				
			||||||
 | 
					     inkscape:pagecheckerboard="0"
 | 
				
			||||||
 | 
					     inkscape:deskcolor="#505050"
 | 
				
			||||||
 | 
					     showgrid="false"
 | 
				
			||||||
 | 
					     showguides="true"
 | 
				
			||||||
 | 
					     inkscape:zoom="0.6971062"
 | 
				
			||||||
 | 
					     inkscape:cx="755.98238"
 | 
				
			||||||
 | 
					     inkscape:cy="65.269826"
 | 
				
			||||||
 | 
					     inkscape:window-width="1920"
 | 
				
			||||||
 | 
					     inkscape:window-height="995"
 | 
				
			||||||
 | 
					     inkscape:window-x="0"
 | 
				
			||||||
 | 
					     inkscape:window-y="0"
 | 
				
			||||||
 | 
					     inkscape:window-maximized="1"
 | 
				
			||||||
 | 
					     inkscape:current-layer="svg20">
 | 
				
			||||||
 | 
					    <sodipodi:guide
 | 
				
			||||||
 | 
					       position="4.4436256,249.99444"
 | 
				
			||||||
 | 
					       orientation="0,-1"
 | 
				
			||||||
 | 
					       id="guide132"
 | 
				
			||||||
 | 
					       inkscape:locked="false" />
 | 
				
			||||||
 | 
					  </sodipodi:namedview>
 | 
				
			||||||
 | 
					  <path
 | 
				
			||||||
 | 
					     d="M 34.421203,251.09539 H 466.71474 m -356.64217,-86.4587 -86.458705,86.4587 86.458705,86.45871 m 280.9908,-172.91741 86.45871,86.4587 -86.45871,86.45871"
 | 
				
			||||||
 | 
					     stroke="#000000"
 | 
				
			||||||
 | 
					     stroke-width="43.2294"
 | 
				
			||||||
 | 
					     stroke-linejoin="round"
 | 
				
			||||||
 | 
					     stroke-linecap="round"
 | 
				
			||||||
 | 
					     fill="none"
 | 
				
			||||||
 | 
					     id="path18" />
 | 
				
			||||||
 | 
					</svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 1.5 KiB  | 
							
								
								
									
										8
									
								
								assets/themes/width/license_info.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								assets/themes/width/license_info.json
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					[
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "path": "icon.svg",
 | 
				
			||||||
 | 
					    "license": "CC0; trivial",
 | 
				
			||||||
 | 
					    "authors": [],
 | 
				
			||||||
 | 
					    "sources": []
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
							
								
								
									
										271
									
								
								assets/themes/width/width.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								assets/themes/width/width.json
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,271 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "id": "width",
 | 
				
			||||||
 | 
					  "description": {
 | 
				
			||||||
 | 
					    "nl": "<h3>De straat is opgebruikt</h3> <p>Er is steeds meer druk op de openbare ruimte. Voetgangers, fietsers, steps, auto's, bussen, bestelwagens, buggies, cargobikes, ... willen allemaal hun deel van de openbare ruimte en de straat.</p> <p>In deze studie nemen we Brugge onder de loep en kijken we hoe breed elke straat is én hoe breed elke straat zou moeten zijn voor een veilig én vlot verkeer.</p> <h3>Legende</h3> <span style='background: red'>   </span> Straat te smal voor veilig verkeer<br/> <span style='background: #0f0'>   </span> Straat is breed genoeg veilig verkeer<br/> <span style='background: orange'>   </span> Straat zonder voetpad, te smal als ook voetgangers plaats krijgen<br/> <span style='background: lightgrey'>   </span> Autoluw, autoloos of enkel plaatselijk verkeer<br/> <br/> <br/> Een gestippelde lijn is een straat waar ook voor fietsers éénrichtingsverkeer geldt.<br/> Klik op een straat om meer informatie te zien."
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "title": {
 | 
				
			||||||
 | 
					    "nl": "Straatbreedtes"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "mustHaveLanguage": [
 | 
				
			||||||
 | 
					    "nl"
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "hideFromOverview": true,
 | 
				
			||||||
 | 
					  "enableUserBadge": false,
 | 
				
			||||||
 | 
					  "enableShareScreen": false,
 | 
				
			||||||
 | 
					  "enableLayers": false,
 | 
				
			||||||
 | 
					  "enableMoreQuests": false,
 | 
				
			||||||
 | 
					  "enableSearch": false,
 | 
				
			||||||
 | 
					  "enableBackgroundLayerSelection": false,
 | 
				
			||||||
 | 
					  "icon": "./assets/themes/width/icon.svg",
 | 
				
			||||||
 | 
					  "startLat": 51.20875,
 | 
				
			||||||
 | 
					  "startLon": 3.22435,
 | 
				
			||||||
 | 
					  "startZoom": 14,
 | 
				
			||||||
 | 
					  "widenFactor": 0.05,
 | 
				
			||||||
 | 
					  "clustering": false,
 | 
				
			||||||
 | 
					  "lockLocation": [
 | 
				
			||||||
 | 
					    [
 | 
				
			||||||
 | 
					      3.2006263732910156,
 | 
				
			||||||
 | 
					      51.22699040520305
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    [
 | 
				
			||||||
 | 
					      3.2529830932617188,
 | 
				
			||||||
 | 
					      51.190748429411705
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "defaultBackgroundId": "Stadia.AlidadeSmoothDark",
 | 
				
			||||||
 | 
					  "layers": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "street_with_width",
 | 
				
			||||||
 | 
					      "description": "A layer showing street with corresponding widths + an analysis of what this width is used for",
 | 
				
			||||||
 | 
					      "name": {
 | 
				
			||||||
 | 
					        "nl": "Straten met een breedte"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "calculatedTags": [
 | 
				
			||||||
 | 
					        "_car_width:=2 /* The width that a single car needs */",
 | 
				
			||||||
 | 
					        "_cyclistWidth:=1.5 /* The width a single cyclist needs to be safely overtaken */",
 | 
				
			||||||
 | 
					        "_pedestrianWidth:=0.75 /* The width a pedestrian needs if sidewalks are missing */",
 | 
				
			||||||
 | 
					        "_has_left_parking=(feat.properties['parking:lane:left'] ?? feat.properties['parking:lane:both']) === 'parallel'",
 | 
				
			||||||
 | 
					        "_has_right_parking=(feat.properties['parking:lane:right'] ?? feat.properties['parking:lane:both']) === 'parallel'",
 | 
				
			||||||
 | 
					        "_has_other_parking= ['parking:lane:left','parking:lane:right','parking:lane:both'].some(key => ['perpendicular','diagonal'].indexOf(feat.properties[key]) >= 0)",
 | 
				
			||||||
 | 
					        "_parallel_parking_count=feat.get('_has_right_parking') + feat.get('_has_left_parking') /* in javascript logic: true + true == 2*/",
 | 
				
			||||||
 | 
					        "_width:needed:parking=feat.get('_parallel_parking_count') * feat.get('_car_width')",
 | 
				
			||||||
 | 
					        "_has_sidewalk_left=['left','both'].indexOf(feat.properties['sidewalk']) >= 0",
 | 
				
			||||||
 | 
					        "_has_sidewalk_right=['right','both'].indexOf(feat.properties['sidewalk']) >= 0",
 | 
				
			||||||
 | 
					        "_pedestrian_flows_in_carriageway= 2 - feat.get('_has_sidewalk_left') - feat.get('_has_sidewalk_right')",
 | 
				
			||||||
 | 
					        "_width:needed:pedestrians=feat.get('_pedestrianWidth') * feat.get('_pedestrian_flows_in_carriageway')",
 | 
				
			||||||
 | 
					        "_oneway_car=(feat.properties['oneway:motor_vehicle'] ?? feat.properties['oneway']) == 'yes'",
 | 
				
			||||||
 | 
					        "_width:needed:cars=feat.get('_car_width') * (2 - feat.get('_oneway_car'))",
 | 
				
			||||||
 | 
					        "_cycling_allowed=feat.properties.bicycle != 'use_sidepath' && feat.properties.bicycle!='no'",
 | 
				
			||||||
 | 
					        "_oneway_bicycle=((feat.properties['oneway:bicycle'] ?? feat.properties['oneway']) == 'yes') && feat.properties['cycleway'] != 'opposite'",
 | 
				
			||||||
 | 
					        "_width:needed:cyclists=feat.get('_cycling_allowed') ? (feat.get('_cyclistWidth') * (2 - feat.get('_oneway_bicycle'))) : 0",
 | 
				
			||||||
 | 
					        "_width:needed:total:=feat.get('_width:needed:cars') + feat.get('_width:needed:parking') +  feat.get('_width:needed:cyclists') +  feat.get('_width:needed:pedestrians')",
 | 
				
			||||||
 | 
					        "_width:difference:=feat.get('_width:needed:total') - feat.get('width:carriageway')",
 | 
				
			||||||
 | 
					        "_width:difference:no_pedestrians:=feat.get('_width:difference') - feat.get('_width:needed:pedestrians')"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "minzoom": 12,
 | 
				
			||||||
 | 
					      "source": {
 | 
				
			||||||
 | 
					        "osmTags": "width:carriageway~*"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "title": {
 | 
				
			||||||
 | 
					        "render": {
 | 
				
			||||||
 | 
					          "nl": "{name}"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "mappings": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "if": "name=",
 | 
				
			||||||
 | 
					            "then": {
 | 
				
			||||||
 | 
					              "nl": "Naamloos segment"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "tagRenderings": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "id": "carriageway_width",
 | 
				
			||||||
 | 
					          "render": "Deze straat is <b>{width:carriageway}m</b> breed",
 | 
				
			||||||
 | 
					          "question": "Hoe breed is deze straat?",
 | 
				
			||||||
 | 
					          "freeform": {
 | 
				
			||||||
 | 
					            "key": "width:carriageway",
 | 
				
			||||||
 | 
					            "type": "distance",
 | 
				
			||||||
 | 
					            "helperArgs": [
 | 
				
			||||||
 | 
					              21,
 | 
				
			||||||
 | 
					              "map"
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "id": "too_little_width",
 | 
				
			||||||
 | 
					          "render": "Deze straat heeft <span class='alert'>{_width:difference}m</span> te weinig. De ruimte die nodig zou zijn is:",
 | 
				
			||||||
 | 
					          "mappings": [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "if": {
 | 
				
			||||||
 | 
					                "or": [
 | 
				
			||||||
 | 
					                  "_width:difference~-.*",
 | 
				
			||||||
 | 
					                  "_width:difference=0"
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              "then": "Deze straat is breed genoeg:"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "id": "needed_for_cars",
 | 
				
			||||||
 | 
					          "render": "<b>{_width:needed:cars}m</b> voor het autoverkeer",
 | 
				
			||||||
 | 
					          "mappings": [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "if": "oneway=yes",
 | 
				
			||||||
 | 
					              "then": "<b>{_width:needed:cars}m</b> voor het éénrichtings-autoverkeer"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "if": "oneway=no",
 | 
				
			||||||
 | 
					              "then": "<b>{_width:needed:cars}m</b> voor het tweerichtings-autoverkeer"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "id": "needed_for_parking",
 | 
				
			||||||
 | 
					          "render": "<b>{_width:needed:parking}m</b> voor het geparkeerde wagens",
 | 
				
			||||||
 | 
					          "condition": "_width:needed:parking!=0"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "id": "needed_for_cyclists",
 | 
				
			||||||
 | 
					          "render": "<b>{_width:needed:cyclists}m</b> voor fietsers",
 | 
				
			||||||
 | 
					          "mappings": [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "if": "bicycle=use_sidepath",
 | 
				
			||||||
 | 
					              "then": "Fietsers hebben hier een vrijliggend fietspad en worden dus niet meegerekend"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "if": "oneway:bicycle=yes",
 | 
				
			||||||
 | 
					              "then": "<b>{_width:needed:cyclists}m</b> voor fietsers die met de rijrichting mee moeten"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "id": "needed_for_pedestrians",
 | 
				
			||||||
 | 
					          "render": "<b>{_width:needed:pedestrians}m</b> voor voetgangers",
 | 
				
			||||||
 | 
					          "condition": "_width:needed:pedestrians!=0",
 | 
				
			||||||
 | 
					          "mappings": [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "if": {
 | 
				
			||||||
 | 
					                "or": [
 | 
				
			||||||
 | 
					                  "sidewalk=none",
 | 
				
			||||||
 | 
					                  "sidewalk=no"
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              "then": "<b>{_width:needed:pedestrians}m</b> voor voetgangers: er zijn hier geen voetpaden"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "if": {
 | 
				
			||||||
 | 
					                "or": [
 | 
				
			||||||
 | 
					                  "sidewalk=left",
 | 
				
			||||||
 | 
					                  "sidewalk=right"
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              "then": "<b>{_width:needed:pedestrians}m</b> voor voetgangers: er is slechts aan één kant een voetpad"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "id": "total_width_needed",
 | 
				
			||||||
 | 
					          "render": "<span style='border: 1px solid black; border-radius: 0.5em; padding: 0.25em;'><b>{_width:needed:total}m</b> nodig in het totaal</span>"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "id": "has_sidewalks",
 | 
				
			||||||
 | 
					          "condition": "id=disabled",
 | 
				
			||||||
 | 
					          "question": {
 | 
				
			||||||
 | 
					            "nl": "Heeft deze straat voetpaden?"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "mappings": [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "if": "sidewalk=both",
 | 
				
			||||||
 | 
					              "then": {
 | 
				
			||||||
 | 
					                "nl": "Voetpad aan beide zijden"
 | 
				
			||||||
 | 
					              }   
 | 
				
			||||||
 | 
					            },{
 | 
				
			||||||
 | 
					              "if": "sidewalk=none",
 | 
				
			||||||
 | 
					              "then": {
 | 
				
			||||||
 | 
					                "nl": "Heeft géén voetpaden"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            },{
 | 
				
			||||||
 | 
					              "if": "sidewalk=left",
 | 
				
			||||||
 | 
					              "then": {
 | 
				
			||||||
 | 
					                "nl": "Voetpad aan de linkerkant"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "if": "sidewalk=right",
 | 
				
			||||||
 | 
					              "then": {
 | 
				
			||||||
 | 
					                "nl": "Voetpad aan de rechterzijde"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "mapRendering": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "location": [
 | 
				
			||||||
 | 
					            "point"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "icon": "./assets/themes/width/icon.svg",
 | 
				
			||||||
 | 
					          "iconSize": "40,40,center"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "width": "4",
 | 
				
			||||||
 | 
					          "color": {
 | 
				
			||||||
 | 
					            "render": "#00f",
 | 
				
			||||||
 | 
					            "mappings": [
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "if": {
 | 
				
			||||||
 | 
					                  "or": [
 | 
				
			||||||
 | 
					                    "access=destination",
 | 
				
			||||||
 | 
					                    "highway=pedestrian",
 | 
				
			||||||
 | 
					                    "motor_vehicle=no",
 | 
				
			||||||
 | 
					                    "motor_vehicle=destination"
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "then": "lightgrey"
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "if": {
 | 
				
			||||||
 | 
					                  "and": [
 | 
				
			||||||
 | 
					                    "_width:difference!~-.*",
 | 
				
			||||||
 | 
					                    "_width:difference:no_pedestrians~-.*"
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "then": "orange"
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "if": "_width:difference~-.*",
 | 
				
			||||||
 | 
					                "then": "#0f0"
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "if": "_width:difference!~-.*",
 | 
				
			||||||
 | 
					                "then": "#f00"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "dashArray": {
 | 
				
			||||||
 | 
					            "render": "",
 | 
				
			||||||
 | 
					            "mappings": [
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "if": {
 | 
				
			||||||
 | 
					                  "and": [
 | 
				
			||||||
 | 
					                    "oneway=yes",
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      "or": [
 | 
				
			||||||
 | 
					                        "oneway:bicycle=yes",
 | 
				
			||||||
 | 
					                        "oneway:bicycle="
 | 
				
			||||||
 | 
					                      ]
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "then": "5 6"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -261,7 +261,9 @@ function main(args: string[]) {
 | 
				
			||||||
        mkdirSync("./assets/generated")
 | 
					        mkdirSync("./assets/generated")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let contents = ScriptUtils.readDirRecSync("./assets").filter(
 | 
					    let contents = ScriptUtils.readDirRecSync("./assets")
 | 
				
			||||||
 | 
					        .filter(p => !p.startsWith("./assets/templates/"))
 | 
				
			||||||
 | 
					        .filter(
 | 
				
			||||||
        (entry) => entry.indexOf("./assets/generated") != 0
 | 
					        (entry) => entry.indexOf("./assets/generated") != 0
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    let licensePaths = contents.filter((entry) => entry.indexOf("license_info.json") >= 0)
 | 
					    let licensePaths = contents.filter((entry) => entry.indexOf("license_info.json") >= 0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue