Merge develop

This commit is contained in:
Pieter Vander Vennet 2021-11-12 01:45:31 +01:00
commit 1843927d00
495 changed files with 95272 additions and 55870 deletions

1
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1 @@
liberapay: pietervdvn

65
.github/workflows/codeql-analysis.yml vendored Normal file
View file

@ -0,0 +1,65 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View file

@ -37,6 +37,13 @@ jobs:
git clone --depth 1 --single-branch --branch master "https://x-access-token:$DEPLOY_KEY_PIETERVDVN@github.com/pietervdvn/pietervdvn.github.io.git"
echo "Destination repo is cloned"
- name: Sync repo
env:
DEPLOY_KEY_PIETERVDVN: ${{ secrets.DEPLOY_KEY_PIETERVDVN }}
run: |
cd pietervdvn.github.io
git pull
- name: "Copying files"
run: |
echo "Deploying"

View file

@ -1,14 +1,33 @@
import * as known_layers from "../assets/generated/known_layers_and_themes.json"
import {Utils} from "../Utils";
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
import {TagRenderingConfigJson} from "../Models/ThemeConfig/Json/TagRenderingConfigJson";
import SharedTagRenderings from "./SharedTagRenderings";
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
import WithContextLoader from "../Models/ThemeConfig/WithContextLoader";
export default class AllKnownLayers {
public static inited = (_ => {
WithContextLoader.getKnownTagRenderings = (id => AllKnownLayers.getTagRendering(id))
return true
})()
// Must be below the list...
public static sharedLayers: Map<string, LayerConfig> = AllKnownLayers.getSharedLayers();
public static sharedLayersJson: Map<string, any> = AllKnownLayers.getSharedLayersJson();
public static added_by_default: string[] = ["gps_location", "home_location", "gps_track"]
public static no_include: string[] = [ "conflation", "left_right_style"]
/**
* Layer IDs of layers which have special properties through built-in hooks
*/
public static priviliged_layers: string[] = [...AllKnownLayers.added_by_default, "type_node",...AllKnownLayers.no_include]
private static getSharedLayers(): Map<string, LayerConfig> {
const sharedLayers = new Map<string, LayerConfig>();
for (const layer of known_layers.layers) {
@ -16,7 +35,6 @@ export default class AllKnownLayers {
// @ts-ignore
const parsed = new LayerConfig(layer, "shared_layers")
sharedLayers.set(layer.id, parsed);
sharedLayers[layer.id] = parsed;
} catch (e) {
if (!Utils.runningFromConsole) {
console.error("CRITICAL: Could not parse a layer configuration!", layer.id, " due to", e)
@ -48,7 +66,7 @@ export default class AllKnownLayers {
return sharedLayers;
}
private static getSharedLayersJson(): Map<string, any> {
private static getSharedLayersJson(): Map<string, LayerConfigJson> {
const sharedLayers = new Map<string, any>();
for (const layer of known_layers.layers) {
sharedLayers.set(layer.id, layer);
@ -57,5 +75,41 @@ export default class AllKnownLayers {
return sharedLayers;
}
/**
* Gets the appropriate tagRenderingJSON
* Allows to steal them from other layers.
* This will add the tags of the layer to the configuration though!
* @param renderingId
*/
static getTagRendering(renderingId: string): TagRenderingConfigJson {
if(renderingId.indexOf(".") < 0){
return SharedTagRenderings.SharedTagRenderingJson.get(renderingId)
}
const [layerId, id] = renderingId.split(".")
const layer = AllKnownLayers.getSharedLayersJson().get(layerId)
if(layer === undefined){
if(Utils.runningFromConsole){
// Probably generating the layer overview
return <TagRenderingConfigJson> {
id: "dummy"
}
}
throw "Builtin layer "+layerId+" not found"
}
const renderings = layer?.tagRenderings ?? []
for (const rendering of renderings) {
if(rendering["id"] === id){
const found = <TagRenderingConfigJson> JSON.parse(JSON.stringify(rendering))
if(found.condition === undefined){
found.condition = layer.source.osmTags
}else{
found.condition = {and: [found.condition, layer.source.osmTags]}
}
return found
}
}
throw `The rendering with id ${id} was not found in the builtin layer ${layerId}. Try one of ${Utils.NoNull(renderings.map(r => r["id"])).join(", ")}`
}
}

View file

@ -2,6 +2,10 @@ import AllKnownLayers from "./AllKnownLayers";
import * as known_themes from "../assets/generated/known_layers_and_themes.json"
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
import BaseUIElement from "../UI/BaseUIElement";
import Combine from "../UI/Base/Combine";
import Title from "../UI/Base/Title";
import List from "../UI/Base/List";
export class AllKnownLayouts {
@ -9,16 +13,16 @@ export class AllKnownLayouts {
public static allKnownLayouts: Map<string, LayoutConfig> = AllKnownLayouts.AllLayouts();
public static layoutsList: LayoutConfig[] = AllKnownLayouts.GenerateOrderedList(AllKnownLayouts.allKnownLayouts);
public static AllPublicLayers(){
const allLayers : LayerConfig[] = []
public static AllPublicLayers() {
const allLayers: LayerConfig[] = []
const seendIds = new Set<string>()
const publicLayouts = AllKnownLayouts.layoutsList.filter(l => !l.hideFromOverview)
for (const layout of publicLayouts) {
if(layout.hideFromOverview){
if (layout.hideFromOverview) {
continue
}
for (const layer of layout.layers) {
if(seendIds.has(layer.id)){
if (seendIds.has(layer.id)) {
continue
}
seendIds.add(layer.id)
@ -28,7 +32,51 @@ export class AllKnownLayouts {
}
return allLayers
}
public static GenLayerOverviewText(): BaseUIElement {
for (const id of AllKnownLayers.priviliged_layers) {
if (!AllKnownLayers.sharedLayers.has(id)) {
throw "Priviliged layer definition not found: " + id
}
}
const allLayers: LayerConfig[] = Array.from(AllKnownLayers.sharedLayers.values())
const themesPerLayer = new Map<string, string[]>()
for (const layout of Array.from(AllKnownLayouts.allKnownLayouts.values())) {
if(layout.hideFromOverview){
continue
}
for (const layer of layout.layers) {
if (!themesPerLayer.has(layer.id)) {
themesPerLayer.set(layer.id, [])
}
themesPerLayer.get(layer.id).push(layout.id)
}
}
let popularLayerCutoff = 2;
const popupalLayers = allLayers.filter((layer) => themesPerLayer.get(layer.id)?.length >= 2)
.filter(layer => AllKnownLayers.priviliged_layers.indexOf(layer.id) < 0)
return new Combine([
new Title("Special and other useful layers", 1),
"MapComplete has a few data layers available in the theme which have special properties through builtin-hooks. Furthermore, there are some normal layers (which are built from normal Theme-config files) but are so general that they get a mention here.",
new Title("Priviliged layers", 1),
new List(AllKnownLayers.priviliged_layers.map(id => "[" + id + "](#" + id + ")")),
...AllKnownLayers.priviliged_layers
.map(id => AllKnownLayers.sharedLayers.get(id))
.map((l) => l.GenerateDocumentation(themesPerLayer.get(l.id), AllKnownLayers.added_by_default.indexOf(l.id) >= 0, AllKnownLayers.no_include.indexOf(l.id) < 0)),
new Title("Frequently reused layers", 1),
"The following layers are used by at least "+popularLayerCutoff+" mapcomplete themes and might be interesting for your custom theme too",
new List(popupalLayers.map(layer => "[" + layer.id + "](#" + layer.id + ")")),
...popupalLayers.map((layer) => layer.GenerateDocumentation(themesPerLayer.get(layer.id)))
])
}
private static GenerateOrderedList(allKnownLayouts: Map<string, LayoutConfig>): LayoutConfig[] {
const keys = ["personal", "cyclofix", "hailhydrant", "bookcases", "toilets", "aed"]
const list = []

View file

@ -15,7 +15,7 @@ export default class SharedTagRenderings {
const d = new Map<string, TagRenderingConfig>()
for (const key of Array.from(configJsons.keys())) {
try {
d.set(key, new TagRenderingConfig(configJsons.get(key), undefined, `SharedTagRenderings.${key}`))
d.set(key, new TagRenderingConfig(configJsons.get(key), `SharedTagRenderings.${key}`))
} catch (e) {
if (!Utils.runningFromConsole) {
console.error("BUG: could not parse", key, " from questions.json or icons.json - this error happened during the build step of the SharedTagRenderings", e)
@ -37,8 +37,11 @@ export default class SharedTagRenderings {
for (const key in icons) {
dict.set(key, <TagRenderingConfigJson>icons[key])
}
dict.forEach((value, key) => value.id = key)
return dict;
}
}

236
Docs/BuiltinLayers.md Normal file
View file

@ -0,0 +1,236 @@
Special and other useful layers
=================================
MapComplete has a few data layers available in the theme which have special properties through builtin-hooks. Furthermore, there are some normal layers (which are built from normal Theme-config files) but are so general that they get a mention here.
Priviliged layers
===================
- [gps_location](#gps_location)
- [home_location](#home_location)
- [gps_track](#gps_track)
- [type_node](#type_node)
- [conflation](#conflation)
- [left_right_style](#left_right_style)
### gps_location
Meta layer showing the current location of the user. Add this to your theme and override the icon to change the appearance of the current location. The object will always have `id=gps` and will have _all_ the properties included in the [`Coordinates`-object](https://developer.mozilla.org/en-US/docs/Web/API/GeolocationCoordinates) returned by the browser.
[Go to the source code](../assets/layers/gps_location/gps_location.json)
- **This layer is included automatically in every theme. This layer might contain no points**
- Not clickable by default. If you import this layer in your theme, override `title` to make this clickable
- Not visible in the layer selection by default. If you want to make this layer toggable, override `name`
### home_location
Meta layer showing the home location of the user. The home location can be set in the [profile settings](https://www.openstreetmap.org/profile/edit) of OpenStreetMap.
[Go to the source code](../assets/layers/home_location/home_location.json)
- **This layer is included automatically in every theme. This layer might contain no points**
- Not clickable by default. If you import this layer in your theme, override `title` to make this clickable
- Not visible in the layer selection by default. If you want to make this layer toggable, override `name`
### gps_track
Meta layer showing the previou locations of the user. Add this to your theme and override the icon to change the appearance of the current location.
[Go to the source code](../assets/layers/gps_track/gps_track.json)
- **This layer is included automatically in every theme. This layer might contain no points**
- Not visible in the layer selection by default. If you want to make this layer toggable, override `name`
### type_node
This is a priviliged meta_layer which exports _every_ point in OSM. This only works if zoomed below the point that the full tile is loaded (and not loaded via Overpass). Note that this point will also contain a property `parent_ways` which contains all the ways this node is part of as a list. This is mainly used for extremely specialized themes, which do advanced conflations. Expert use only.
[Go to the source code](../assets/layers/type_node/type_node.json)
- Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings`
### conflation
If the import-button is set to conflate two ways, a preview is shown. This layer defines how this preview is rendered. This layer cannot be included in a theme.
[Go to the source code](../assets/layers/conflation/conflation.json)
- This layer can **not** be included in a theme. It is solely used by [special renderings](SpecialRenderings.md) showing a minimap with custom data.
### left_right_style
Special meta-style which will show one single line, either on the left or on the right depending on the id. This is used in the small popups with left_right roads. Cannot be included in a theme
[Go to the source code](../assets/layers/left_right_style/left_right_style.json)
- This layer can **not** be included in a theme. It is solely used by [special renderings](SpecialRenderings.md) showing a minimap with custom data.
Frequently reused layers
==========================
The following layers are used by at least 2 mapcomplete themes and might be interesting for your custom theme too
- [bicycle_library](#bicycle_library)
- [drinking_water](#drinking_water)
- [food](#food)
- [map](#map)
- [all_streets](#all_streets)
### bicycle_library
A facility where bicycles can be lent for longer period of times
[Go to the source code](../assets/layers/bicycle_library/bicycle_library.json)
#### Themes using this layer
- [bicyclelib](https://mapcomplete.osm.be/bicyclelib)
- [cyclofix](https://mapcomplete.osm.be/cyclofix)
### drinking_water
[Go to the source code](../assets/layers/drinking_water/drinking_water.json)
#### Themes using this layer
- [cyclofix](https://mapcomplete.osm.be/cyclofix)
- [drinking_water](https://mapcomplete.osm.be/drinking_water)
- [nature](https://mapcomplete.osm.be/nature)
### food
[Go to the source code](../assets/layers/food/food.json)
#### Themes using this layer
- [food](https://mapcomplete.osm.be/food)
- [fritures](https://mapcomplete.osm.be/fritures)
### map
A map, meant for tourists which is permanently installed in the public space
[Go to the source code](../assets/layers/map/map.json)
#### Themes using this layer
- [maps](https://mapcomplete.osm.be/maps)
- [nature](https://mapcomplete.osm.be/nature)
### all_streets
[Go to the source code](../assets/layers/all_streets/all_streets.json)
- Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings`
#### Themes using this layer
- [cyclestreets](https://mapcomplete.osm.be/cyclestreets)
- [street_lighting](https://mapcomplete.osm.be/street_lighting)
This document is autogenerated from AllKnownLayers.ts

View file

@ -1,4 +1,5 @@
Metatags
==========
@ -11,6 +12,7 @@ The are calculated automatically on every feature when the data arrives in the w
**Hint:** when using metatags, add the [query parameter](URL_Parameters.md) `debug=true` to the URL. This will include a box in the popup for features which shows all the properties of the object
Metatags calculated by MapComplete
------------------------------------
@ -19,6 +21,7 @@ The are calculated automatically on every feature when the data arrives in the w
The following values are always calculated, by default, by MapComplete and are available automatically on all elements in every theme
### _lat, _lon
@ -28,6 +31,7 @@ The latitude and longitude of the point (or centerpoint in the case of a way/are
### _layer
@ -37,6 +41,7 @@ The layer-id to which this feature belongs. Note that this might be return any a
### _surface, _surface:ha
@ -46,6 +51,7 @@ The surface area of the feature, in square meters and in hectare. Not set on poi
This is a lazy metatag and is only calculated when needed
### _length, _length:km
@ -55,6 +61,7 @@ The total length of a feature in meters (and in kilometers, rounded to one decim
### Theme-defined keys
@ -64,6 +71,7 @@ If 'units' is defined in the layoutConfig, then this metatagger will rewrite the
### _country
@ -73,6 +81,7 @@ The country code of the property (with latlon2country)
### _isOpen, _isOpen:description
@ -82,6 +91,7 @@ If 'opening_hours' is present, it will add the current state of the feature (bei
This is a lazy metatag and is only calculated when needed
### _direction:numerical, _direction:leftright
@ -91,6 +101,7 @@ _direction:numerical is a normalized, numerical direction based on 'camera:direc
### _now:date, _now:datetime, _loaded:date, _loaded:_datetime
@ -100,7 +111,8 @@ Adds the time that the data got loaded - pretty much the time of downloading fro
### _last_edit:contributor, _last_edit:contributor:uid, _last_edit:changeset, _last_edit:timestamp, _version_number
### _last_edit:contributor, _last_edit:contributor:uid, _last_edit:changeset, _last_edit:timestamp, _version_number, _backend
@ -109,6 +121,17 @@ Information about the last edit of this object.
### sidewalk:left, sidewalk:right, generic_key:left:property, generic_key:right:property
Rewrites tags from 'generic_key:both:property' as 'generic_key:left:property' and 'generic_key:right:property' (and similar for sidewalk tagging). Note that this rewritten tags _will be reuploaded on a change_. To prevent to much unrelated retagging, this is only enabled if the layer has at least some lineRenderings with offset defined
Calculating tags with Javascript
----------------------------------
@ -157,12 +180,14 @@ The above code will be executed for every feature in the layer. The feature is a
Some advanced functions are available on **feat** as well:
- distanceTo
- overlapWith
- closest
- closestn
- memberships
- [distanceTo](#distanceTo)
- [overlapWith](#overlapWith)
- [closest](#closest)
- [closestn](#closestn)
- [memberships](#memberships)
- [get](#get)
### distanceTo
Calculates the distance between the feature and a specified point in kilometer. The input should either be a pair of coordinates, a geojson feature or the ID of an object
@ -170,20 +195,26 @@ Some advanced functions are available on **feat** as well:
0. feature OR featureID OR longitude
1. undefined OR latitude
### overlapWith
Gives a list of features from the specified layer which this feature (partly) overlaps with. If the current feature is a point, all features that embed the point are given. The returned value is `{ feat: GeoJSONFeature, overlap: number}[]` where `overlap` is the overlapping surface are (in m²) for areas, the overlapping length (in meter) if the current feature is a line or `undefined` if the current feature is a point.
Gives a list of features from the specified layer which this feature (partly) overlaps with. A point which is embedded in the feature is detected as well.If the current feature is a point, all features that this point is embeded in are given.
The returned value is `{ feat: GeoJSONFeature, overlap: number}[]` where `overlap` is the overlapping surface are (in m²) for areas, the overlapping length (in meter) if the current feature is a line or `undefined` if the current feature is a point.
The resulting list is sorted in descending order by overlap. The feature with the most overlap will thus be the first in the list
For example to get all objects which overlap or embed from a layer, use `_contained_climbing_routes_properties=feat.overlapWith('climbing_route')`
0. ...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)
### closest
Given either a list of geojson features or a single layer name, gives the single object which is nearest to the feature. In the case of ways/polygons, only the centerpoint is considered. Returns a single geojson feature or undefined if nothing is found (or not yet laoded)
0. list of features or a layer name or '*' to get all features
### closestn
Given either a list of geojson features or a single layer name, gives the n closest objects which are nearest to the feature (excluding the feature itself). In the case of ways/polygons, only the centerpoint is considered. Returns a list of `{feat: geojson, distance:number}` the empty list if nothing is found (or not yet loaded)
@ -195,6 +226,7 @@ If a 'unique tag key' is given, the tag with this key will only appear once (e.g
2. unique tag key (optional)
3. maxDistanceInMeters (optional)
### memberships
Gives a list of `{role: string, relation: Relation}`-objects, containing all the relations that this feature is part of.
@ -202,4 +234,13 @@ If a 'unique tag key' is given, the tag with this key will only appear once (e.g
For example: `_part_of_walking_routes=feat.memberships().map(r => r.relation.tags.name).join(';')`
Generated from SimpleMetaTagger, ExtraFunction
### get
Gets the property of the feature, parses it (as JSON) and returns it. Might return 'undefined' if not defined, null, ...
0. key
This document is autogenerated from SimpleMetaTagger, ExtraFunction

42
Docs/ContributorRights.md Normal file
View file

@ -0,0 +1,42 @@
Rights of contributors
======================
If a contributor is quite active within MapComplete, this contributor might be granted access to the main repository.
If you have access to the repository, you can make a fork of an already existing branch and push this new branch to
github. This means that this branch will be _automatically built_ and be **deployed**
to `https://pietervdvn.github.io/mc/<branchname>`. You can see the deploy process
on [Github Actions](https://github.com/pietervdvn/MapComplete/actions). Don't worry about pushing too much. These
deploys are free and totally automatic. They might fail if something is wrong, but this will hinder no-one.
Additionaly, some other maintainer might step in and merge the latest develop with your branch, making later pull
requests easier.
Don't worry about bugs
----------------------
As a non-admin contributor, you can _not_ make changes to the `master` nor to the `develop` branch. This is because, as
soon as master is changed, this is built and deployed on `mapcomplete.osm.be`, which a lot of people use. An error there
will cause a lot of grieve.
A push on `develop` is automatically deployed to [pietervdvn.github.io/mc/develop] and is used by quite some people to.
People using this version should know that this is a testing ground for new features and might contain a bug every now
and then.
In other words, to get your theme deployed on the main instances, you'll still have to create a pull request. The
maintainers will then doublecheck and pull it in.
If you have a local repository
------------------------------
If you have made a fork earlier and have received contributor rights, you need to tell your local git repository that
pushing to the main repository is possible.
To do this:
1. type `git remote add upstream git@github.com:pietervdvn/MapComplete`
2. Run `git push upstream` to push your latest changes to the main repo (and not your fork). Running `git push` will
push to your fork.
Alternatively, if you don't have any unmerged changes, you can remove your local copy and clone `pietervdvn/MapComplete`
again to start fresh.

View file

@ -28,14 +28,15 @@ To develop and build MapComplete, you
0. Make a fork and clone the repository.
0. Install the nodejs version specified in [.tool-versions](./.tool-versions)
- On linux: install npm first `sudo apt install npm`, then install `n` using npm: ` npm install -g n`, which can then install node with `n install <node-version>`
- You can [use asdf to manage your runtime versions](https://asdf-vm.com/).
- On linux: install npm first `sudo apt install npm`, then install `n` using npm: ` npm install -g n`, which can
then install node with `n install <node-version>`
- You can [use asdf to manage your runtime versions](https://asdf-vm.com/).
0. Install `npm`. Linux: `sudo apt install npm` (or your favourite package manager), Windows: install
nodeJS: https://nodejs.org/en/download/
0. On iOS, install `wget` (`brew install wget`)
0. Run `npm run init` which …
- runs `npm install`
- generates some additional dependencies and files
- runs `npm install`
- generates some additional dependencies and files
0. Run `npm run start` to host a local testversion at http://localhost:1234/index.html
0. By default, a landing page with available themes is served. In order to load a single theme, use `layout=themename`
or `userlayout=true#<layout configuration>` as [Query parameter](URL_Parameters.md). Note that the shorter URLs (
@ -106,7 +107,8 @@ Try removing `node_modules`, `package-lock.json` and `.cache`
Misc setup
----------
The json-git-merger is used to quickly merge translation files, [documentation here](https://github.com/jonatanpedersen/git-json-merge#single-project--directory)
~~The json-git-merger is used to quickly merge translation files, [documentation here](https://github.com/jonatanpedersen/git-json-merge#single-project--directory).~~
This merge driver is broken and would sometimes drop new questions or duplicate them... Not a good idea!
Overview of package.json-scripts
--------------------------------

View file

@ -105,11 +105,68 @@ Every field is documented in the source code itself - you can find them here:
- [The `TagRendering`](https://github.com/pietervdvn/MapComplete/blob/master/Models/ThemeConfig/Json/TagRenderingConfigJson.ts)
- At last, the exact semantics of tags is documented [here](Tags_format.md)
A JSON-schema file is available in Docs/Schemas - use LayoutConfig.schema.json to validate a theme file.
### MetaTags
There are few tags available that are calculated for convenience - e.g. the country an object is located
at. [An overview of all these metatags is available here](Docs/CalculatedTags.md)
### TagRendering groups
A tagRendering can have a `group`-attribute, which acts as a tag.
All tagRenderings with the same group name will be rendered together, in the same order as they were defined.
For example, if the defined tagrenderings have groups `A A B A A B B B`, the group order is `A B` and first all tagrenderings from group A will be rendered (thus numbers 0, 1, 3 and 4) followed by the question box for this group.
Then, all the tagRenderings for group B will be shown, thus number 2, 5, 6 and 7, again followed by their questionbox.
Additionally, every tagrendering will receive a the groupname as class in the HTML, which can be used to hook up custom CSS.
If no group tag is given, the group is `` (empty string)
### Deciding the questions position
By default, the questions are shown just beneath their group.
To override this behaviour, one can add a tagrendering with id `questions` to move the questions up.
To add a title to the questions, one can add a `render` and a condition.
To change the behaviour of the questionbox to show _all_ questions at once, one can use a helperArgs in the freeform field with option `showAllQuestions`.
For example, to show the questions on top, use:
```
"tagRenderings": [
{ "id": "questions" }
{ ... some tagrendering ... }
{ ... more tagrendering ...}
]
```
To show _all_ the questions of a group at once in the middle of the tagrenderings, with a header, use:
```
"tagRenderings": [
{
"id": "questions" ,
"group": "groupname",
"render": {
"en": "<h3>Technical questions</h3>The following questions are very technical!<br />{questions}
},
"freeform": {
"key": "questions",
"helperArgs": {
"showAllQuestions": true
}
}
}
{ ... some tagrendering ... }
{ ... more tagrendering ...}
]
```
Some hints
------------
@ -173,16 +230,7 @@ Instead, make one layer for one kind of object and change the icon based on attr
Using layers as filters - this doesn't work!
_All_ data is downloaded in one go and cached locally first. The layer selection (bottom left of the live app) then
selects _anything_ that matches the criteria. This match is then passed of to the rendering layer, which selects the
layer independently. This means that a feature can show up, even if it's layer is unselected!
For example, in the [cyclofix-theme](https://mapcomplete.osm.org/cyclofix), there is the layer with _bike-wash_ for do
it yourself bikecleaning - points marked with `service:bicycle:cleaning`. However, a bicycle repair shop can offer this
service too!
If all the layers are deselected except the bike wash layer, a shop having this tag will still match and will still show
up as shop.
Use the `filter`-functionality instead
### Not reading the .JSON-specs

View file

@ -1,145 +1,181 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.43.0 (0)
-->
<!-- Title: G Pages: 1 -->
<svg width="664pt" height="566pt"
viewBox="0.00 0.00 664.25 566.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 562)">
<title>G</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-562 660.25,-562 660.25,4 -4,4"/>
<!-- init -->
<g id="node1" class="node">
<title>init</title>
<polygon fill="none" stroke="black" points="242.25,-558 188.25,-558 188.25,-522 242.25,-522 242.25,-558"/>
<text text-anchor="middle" x="215.25" y="-536.3" font-family="Times,serif" font-size="14.00">init</text>
</g>
<!-- denied -->
<g id="node2" class="node">
<title>denied</title>
<ellipse fill="none" stroke="black" cx="42.25" cy="-279" rx="42.49" ry="18"/>
<text text-anchor="middle" x="42.25" y="-275.3" font-family="Times,serif" font-size="14.00">denied</text>
</g>
<!-- init&#45;&gt;denied -->
<g id="edge1" class="edge">
<title>init&#45;&gt;denied</title>
<path fill="none" stroke="black" d="M188.23,-531.67C143.21,-517.82 54.16,-483.1 17.25,-417 -2.35,-381.91 14.04,-334.64 27.95,-305.79"/>
<polygon fill="black" stroke="black" points="31.12,-307.26 32.51,-296.76 24.88,-304.1 31.12,-307.26"/>
<text text-anchor="middle" x="132.25" y="-405.8" font-family="Times,serif" font-size="14.00">geolocation permanently denied</text>
</g>
<!-- getting_location -->
<g id="node3" class="node">
<title>getting_location</title>
<ellipse fill="none" stroke="black" cx="366.25" cy="-279" rx="85.29" ry="18"/>
<text text-anchor="middle" x="366.25" y="-275.3" font-family="Times,serif" font-size="14.00">getting_location</text>
</g>
<!-- init&#45;&gt;getting_location -->
<g id="edge2" class="edge">
<title>init&#45;&gt;getting_location</title>
<path fill="none" stroke="black" d="M242.41,-538.69C294.16,-537.46 403.84,-531.59 427.25,-504 481.59,-439.95 469.34,-387.69 427.25,-315 424.07,-309.52 419.68,-304.83 414.7,-300.82"/>
<polygon fill="black" stroke="black" points="416.68,-297.93 406.47,-295.09 412.67,-303.68 416.68,-297.93"/>
<text text-anchor="middle" x="559.75" y="-405.8" font-family="Times,serif" font-size="14.00">previously granted flag set</text>
</g>
<!-- idle -->
<g id="node4" class="node">
<title>idle</title>
<ellipse fill="none" stroke="black" cx="255.25" cy="-453" rx="27.9" ry="18"/>
<text text-anchor="middle" x="255.25" y="-449.3" font-family="Times,serif" font-size="14.00">idle</text>
</g>
<!-- init&#45;&gt;idle -->
<g id="edge3" class="edge">
<title>init&#45;&gt;idle</title>
<path fill="none" stroke="black" d="M212.27,-521.58C211.37,-511.6 211.62,-499.1 216.25,-489 218.98,-483.03 223.28,-477.64 228.03,-472.99"/>
<polygon fill="black" stroke="black" points="230.48,-475.49 235.73,-466.29 225.89,-470.21 230.48,-475.49"/>
<text text-anchor="middle" x="321.75" y="-492.8" font-family="Times,serif" font-size="14.00">previously granted flag unset</text>
</g>
<!-- location_found -->
<g id="node6" class="node">
<title>location_found</title>
<ellipse fill="none" stroke="black" cx="366.25" cy="-192" rx="77.99" ry="18"/>
<text text-anchor="middle" x="366.25" y="-188.3" font-family="Times,serif" font-size="14.00">location_found</text>
</g>
<!-- getting_location&#45;&gt;location_found -->
<g id="edge8" class="edge">
<title>getting_location&#45;&gt;location_found</title>
<path fill="none" stroke="black" d="M366.25,-260.8C366.25,-249.16 366.25,-233.55 366.25,-220.24"/>
<polygon fill="black" stroke="black" points="369.75,-220.18 366.25,-210.18 362.75,-220.18 369.75,-220.18"/>
<text text-anchor="middle" x="417.25" y="-231.8" font-family="Times,serif" font-size="14.00">location found</text>
</g>
<!-- request_permission -->
<g id="node5" class="node">
<title>request_permission</title>
<ellipse fill="none" stroke="black" cx="264.25" cy="-366" rx="102.08" ry="18"/>
<text text-anchor="middle" x="264.25" y="-362.3" font-family="Times,serif" font-size="14.00">request_permission</text>
</g>
<!-- idle&#45;&gt;request_permission -->
<g id="edge4" class="edge">
<title>idle&#45;&gt;request_permission</title>
<path fill="none" stroke="black" d="M282.79,-448.82C302.7,-444.93 328.29,-436.26 341.25,-417 349.95,-404.06 340.76,-393.72 326.08,-385.86"/>
<polygon fill="black" stroke="black" points="327.44,-382.63 316.9,-381.53 324.45,-388.96 327.44,-382.63"/>
<text text-anchor="middle" x="371.75" y="-405.8" font-family="Times,serif" font-size="14.00">on click</text>
</g>
<!-- request_permission&#45;&gt;denied -->
<g id="edge7" class="edge">
<title>request_permission&#45;&gt;denied</title>
<path fill="none" stroke="black" d="M202.76,-351.6C180.78,-345.99 156.06,-338.72 134.25,-330 113.26,-321.61 90.96,-309.57 73.57,-299.42"/>
<polygon fill="black" stroke="black" points="75.34,-296.4 64.96,-294.3 71.77,-302.42 75.34,-296.4"/>
<text text-anchor="middle" x="206.25" y="-318.8" font-family="Times,serif" font-size="14.00">permanently denied</text>
</g>
<!-- request_permission&#45;&gt;getting_location -->
<g id="edge5" class="edge">
<title>request_permission&#45;&gt;getting_location</title>
<path fill="none" stroke="black" d="M271.38,-348C276.49,-337.43 284.24,-324.16 294.25,-315 300.73,-309.07 308.39,-303.93 316.27,-299.56"/>
<polygon fill="black" stroke="black" points="317.92,-302.64 325.2,-294.94 314.71,-296.43 317.92,-302.64"/>
<text text-anchor="middle" x="360.75" y="-318.8" font-family="Times,serif" font-size="14.00">granted (sets flag)</text>
</g>
<!-- request_permission&#45;&gt;idle -->
<g id="edge6" class="edge">
<title>request_permission&#45;&gt;idle</title>
<path fill="none" stroke="black" d="M257.1,-384.15C255.12,-389.74 253.24,-396.04 252.25,-402 251.02,-409.35 250.95,-417.37 251.4,-424.8"/>
<polygon fill="black" stroke="black" points="247.92,-425.14 252.32,-434.78 254.89,-424.5 247.92,-425.14"/>
<text text-anchor="middle" x="294.75" y="-405.8" font-family="Times,serif" font-size="14.00">not granted</text>
</g>
<!-- open_lock -->
<g id="node7" class="node">
<title>open_lock</title>
<ellipse fill="none" stroke="black" cx="333.25" cy="-105" rx="55.79" ry="18"/>
<text text-anchor="middle" x="333.25" y="-101.3" font-family="Times,serif" font-size="14.00">open_lock</text>
</g>
<!-- location_found&#45;&gt;open_lock -->
<g id="edge9" class="edge">
<title>location_found&#45;&gt;open_lock</title>
<path fill="none" stroke="black" d="M359.57,-173.8C354.98,-161.97 348.79,-146.03 343.56,-132.58"/>
<polygon fill="black" stroke="black" points="346.68,-130.94 339.8,-122.89 340.16,-133.47 346.68,-130.94"/>
<text text-anchor="middle" x="448.25" y="-144.8" font-family="Times,serif" font-size="14.00">on click (zooms to location)</text>
</g>
<!-- open_lock&#45;&gt;location_found -->
<g id="edge10" class="edge">
<title>open_lock&#45;&gt;location_found</title>
<path fill="none" stroke="black" d="M295.44,-118.33C275.01,-127.12 256.04,-140.15 267.25,-156 273.92,-165.44 283.37,-172.35 293.8,-177.41"/>
<polygon fill="black" stroke="black" points="292.6,-180.7 303.17,-181.39 295.34,-174.26 292.6,-180.7"/>
<text text-anchor="middle" x="305.25" y="-144.8" font-family="Times,serif" font-size="14.00">after 3 sec</text>
</g>
<!-- closed_lock -->
<g id="node8" class="node">
<title>closed_lock</title>
<ellipse fill="none" stroke="black" cx="454.25" cy="-18" rx="63.09" ry="18"/>
<text text-anchor="middle" x="454.25" y="-14.3" font-family="Times,serif" font-size="14.00">closed_lock</text>
</g>
<!-- open_lock&#45;&gt;closed_lock -->
<g id="edge11" class="edge">
<title>open_lock&#45;&gt;closed_lock</title>
<path fill="none" stroke="black" d="M328.89,-87.05C327.23,-76.5 327.17,-63.24 334.25,-54 346.04,-38.59 364.24,-29.68 382.92,-24.6"/>
<polygon fill="black" stroke="black" points="383.78,-28 392.71,-22.28 382.17,-21.18 383.78,-28"/>
<text text-anchor="middle" x="447.75" y="-57.8" font-family="Times,serif" font-size="14.00">on click (locks zoom to location)</text>
</g>
<!-- closed_lock&#45;&gt;location_found -->
<g id="edge12" class="edge">
<title>closed_lock&#45;&gt;location_found</title>
<path fill="none" stroke="black" d="M513.08,-24.74C531.5,-29.64 549.95,-38.41 561.25,-54 588.04,-90.95 580.67,-122.9 549.25,-156 535.31,-170.68 491.24,-179.37 449.85,-184.42"/>
<polygon fill="black" stroke="black" points="449.22,-180.97 439.68,-185.6 450.02,-187.93 449.22,-180.97"/>
<text text-anchor="middle" x="604.75" y="-101.3" font-family="Times,serif" font-size="14.00">on click</text>
</g>
</g>
viewBox="0.00 0.00 664.25 566.00" xmlns="http://www.w3.org/2000/svg">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 562)">
<title>G</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-562 660.25,-562 660.25,4 -4,4"/>
<!-- init -->
<g id="node1" class="node">
<title>init</title>
<polygon fill="none" stroke="black" points="242.25,-558 188.25,-558 188.25,-522 242.25,-522 242.25,-558"/>
<text text-anchor="middle" x="215.25" y="-536.3" font-family="Times,serif" font-size="14.00">init</text>
</g>
<!-- denied -->
<g id="node2" class="node">
<title>denied</title>
<ellipse fill="none" stroke="black" cx="42.25" cy="-279" rx="42.49" ry="18"/>
<text text-anchor="middle" x="42.25" y="-275.3" font-family="Times,serif" font-size="14.00">denied</text>
</g>
<!-- init&#45;&gt;denied -->
<g id="edge1" class="edge">
<title>init&#45;&gt;denied</title>
<path fill="none" stroke="black"
d="M188.23,-531.67C143.21,-517.82 54.16,-483.1 17.25,-417 -2.35,-381.91 14.04,-334.64 27.95,-305.79"/>
<polygon fill="black" stroke="black" points="31.12,-307.26 32.51,-296.76 24.88,-304.1 31.12,-307.26"/>
<text text-anchor="middle" x="132.25" y="-405.8" font-family="Times,serif" font-size="14.00">geolocation
permanently denied
</text>
</g>
<!-- getting_location -->
<g id="node3" class="node">
<title>getting_location</title>
<ellipse fill="none" stroke="black" cx="366.25" cy="-279" rx="85.29" ry="18"/>
<text text-anchor="middle" x="366.25" y="-275.3" font-family="Times,serif" font-size="14.00">
getting_location
</text>
</g>
<!-- init&#45;&gt;getting_location -->
<g id="edge2" class="edge">
<title>init&#45;&gt;getting_location</title>
<path fill="none" stroke="black"
d="M242.41,-538.69C294.16,-537.46 403.84,-531.59 427.25,-504 481.59,-439.95 469.34,-387.69 427.25,-315 424.07,-309.52 419.68,-304.83 414.7,-300.82"/>
<polygon fill="black" stroke="black" points="416.68,-297.93 406.47,-295.09 412.67,-303.68 416.68,-297.93"/>
<text text-anchor="middle" x="559.75" y="-405.8" font-family="Times,serif" font-size="14.00">previously
granted flag set
</text>
</g>
<!-- idle -->
<g id="node4" class="node">
<title>idle</title>
<ellipse fill="none" stroke="black" cx="255.25" cy="-453" rx="27.9" ry="18"/>
<text text-anchor="middle" x="255.25" y="-449.3" font-family="Times,serif" font-size="14.00">idle</text>
</g>
<!-- init&#45;&gt;idle -->
<g id="edge3" class="edge">
<title>init&#45;&gt;idle</title>
<path fill="none" stroke="black"
d="M212.27,-521.58C211.37,-511.6 211.62,-499.1 216.25,-489 218.98,-483.03 223.28,-477.64 228.03,-472.99"/>
<polygon fill="black" stroke="black" points="230.48,-475.49 235.73,-466.29 225.89,-470.21 230.48,-475.49"/>
<text text-anchor="middle" x="321.75" y="-492.8" font-family="Times,serif" font-size="14.00">previously
granted flag unset
</text>
</g>
<!-- location_found -->
<g id="node6" class="node">
<title>location_found</title>
<ellipse fill="none" stroke="black" cx="366.25" cy="-192" rx="77.99" ry="18"/>
<text text-anchor="middle" x="366.25" y="-188.3" font-family="Times,serif" font-size="14.00">
location_found
</text>
</g>
<!-- getting_location&#45;&gt;location_found -->
<g id="edge8" class="edge">
<title>getting_location&#45;&gt;location_found</title>
<path fill="none" stroke="black" d="M366.25,-260.8C366.25,-249.16 366.25,-233.55 366.25,-220.24"/>
<polygon fill="black" stroke="black" points="369.75,-220.18 366.25,-210.18 362.75,-220.18 369.75,-220.18"/>
<text text-anchor="middle" x="417.25" y="-231.8" font-family="Times,serif" font-size="14.00">location
found
</text>
</g>
<!-- request_permission -->
<g id="node5" class="node">
<title>request_permission</title>
<ellipse fill="none" stroke="black" cx="264.25" cy="-366" rx="102.08" ry="18"/>
<text text-anchor="middle" x="264.25" y="-362.3" font-family="Times,serif" font-size="14.00">
request_permission
</text>
</g>
<!-- idle&#45;&gt;request_permission -->
<g id="edge4" class="edge">
<title>idle&#45;&gt;request_permission</title>
<path fill="none" stroke="black"
d="M282.79,-448.82C302.7,-444.93 328.29,-436.26 341.25,-417 349.95,-404.06 340.76,-393.72 326.08,-385.86"/>
<polygon fill="black" stroke="black" points="327.44,-382.63 316.9,-381.53 324.45,-388.96 327.44,-382.63"/>
<text text-anchor="middle" x="371.75" y="-405.8" font-family="Times,serif" font-size="14.00">on click</text>
</g>
<!-- request_permission&#45;&gt;denied -->
<g id="edge7" class="edge">
<title>request_permission&#45;&gt;denied</title>
<path fill="none" stroke="black"
d="M202.76,-351.6C180.78,-345.99 156.06,-338.72 134.25,-330 113.26,-321.61 90.96,-309.57 73.57,-299.42"/>
<polygon fill="black" stroke="black" points="75.34,-296.4 64.96,-294.3 71.77,-302.42 75.34,-296.4"/>
<text text-anchor="middle" x="206.25" y="-318.8" font-family="Times,serif" font-size="14.00">permanently
denied
</text>
</g>
<!-- request_permission&#45;&gt;getting_location -->
<g id="edge5" class="edge">
<title>request_permission&#45;&gt;getting_location</title>
<path fill="none" stroke="black"
d="M271.38,-348C276.49,-337.43 284.24,-324.16 294.25,-315 300.73,-309.07 308.39,-303.93 316.27,-299.56"/>
<polygon fill="black" stroke="black" points="317.92,-302.64 325.2,-294.94 314.71,-296.43 317.92,-302.64"/>
<text text-anchor="middle" x="360.75" y="-318.8" font-family="Times,serif" font-size="14.00">granted (sets
flag)
</text>
</g>
<!-- request_permission&#45;&gt;idle -->
<g id="edge6" class="edge">
<title>request_permission&#45;&gt;idle</title>
<path fill="none" stroke="black"
d="M257.1,-384.15C255.12,-389.74 253.24,-396.04 252.25,-402 251.02,-409.35 250.95,-417.37 251.4,-424.8"/>
<polygon fill="black" stroke="black" points="247.92,-425.14 252.32,-434.78 254.89,-424.5 247.92,-425.14"/>
<text text-anchor="middle" x="294.75" y="-405.8" font-family="Times,serif" font-size="14.00">not granted
</text>
</g>
<!-- open_lock -->
<g id="node7" class="node">
<title>open_lock</title>
<ellipse fill="none" stroke="black" cx="333.25" cy="-105" rx="55.79" ry="18"/>
<text text-anchor="middle" x="333.25" y="-101.3" font-family="Times,serif" font-size="14.00">open_lock
</text>
</g>
<!-- location_found&#45;&gt;open_lock -->
<g id="edge9" class="edge">
<title>location_found&#45;&gt;open_lock</title>
<path fill="none" stroke="black" d="M359.57,-173.8C354.98,-161.97 348.79,-146.03 343.56,-132.58"/>
<polygon fill="black" stroke="black" points="346.68,-130.94 339.8,-122.89 340.16,-133.47 346.68,-130.94"/>
<text text-anchor="middle" x="448.25" y="-144.8" font-family="Times,serif" font-size="14.00">on click (zooms
to location)
</text>
</g>
<!-- open_lock&#45;&gt;location_found -->
<g id="edge10" class="edge">
<title>open_lock&#45;&gt;location_found</title>
<path fill="none" stroke="black"
d="M295.44,-118.33C275.01,-127.12 256.04,-140.15 267.25,-156 273.92,-165.44 283.37,-172.35 293.8,-177.41"/>
<polygon fill="black" stroke="black" points="292.6,-180.7 303.17,-181.39 295.34,-174.26 292.6,-180.7"/>
<text text-anchor="middle" x="305.25" y="-144.8" font-family="Times,serif" font-size="14.00">after 3 sec
</text>
</g>
<!-- closed_lock -->
<g id="node8" class="node">
<title>closed_lock</title>
<ellipse fill="none" stroke="black" cx="454.25" cy="-18" rx="63.09" ry="18"/>
<text text-anchor="middle" x="454.25" y="-14.3" font-family="Times,serif" font-size="14.00">closed_lock
</text>
</g>
<!-- open_lock&#45;&gt;closed_lock -->
<g id="edge11" class="edge">
<title>open_lock&#45;&gt;closed_lock</title>
<path fill="none" stroke="black"
d="M328.89,-87.05C327.23,-76.5 327.17,-63.24 334.25,-54 346.04,-38.59 364.24,-29.68 382.92,-24.6"/>
<polygon fill="black" stroke="black" points="383.78,-28 392.71,-22.28 382.17,-21.18 383.78,-28"/>
<text text-anchor="middle" x="447.75" y="-57.8" font-family="Times,serif" font-size="14.00">on click (locks
zoom to location)
</text>
</g>
<!-- closed_lock&#45;&gt;location_found -->
<g id="edge12" class="edge">
<title>closed_lock&#45;&gt;location_found</title>
<path fill="none" stroke="black"
d="M513.08,-24.74C531.5,-29.64 549.95,-38.41 561.25,-54 588.04,-90.95 580.67,-122.9 549.25,-156 535.31,-170.68 491.24,-179.37 449.85,-184.42"/>
<polygon fill="black" stroke="black" points="449.22,-180.97 439.68,-185.6 450.02,-187.93 449.22,-180.97"/>
<text text-anchor="middle" x="604.75" y="-101.3" font-family="Times,serif" font-size="14.00">on click</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

View file

@ -6,13 +6,15 @@ Some highlights of new releases.
0.10
----
The 0.10 version contains a lot of refactorings on various core of the application, namely in the rendering stack, the fetching of data and uploading.
The 0.10 version contains a lot of refactorings on various core of the application, namely in the rendering stack, the
fetching of data and uploading.
Some highlights are:
1. The addition of fallback overpass servers
2. Fetching data from OSM directly (especially useful in the personal theme)
3. Splitting all the features per tile (with a maximum amount of features per tile, splitting further if needed), making everything a ton faster
3. Splitting all the features per tile (with a maximum amount of features per tile, splitting further if needed), making
everything a ton faster
4. If a tile has too much features, the featuers are not shown. Instead, a rectangle with the feature amount is shown.
Furthermore, it contains a few new themes and theme updates:
@ -31,9 +33,8 @@ Other various small improvements:
0.8 and 0.9
-----------
Addition of filters per layer
Addition of a download-as-pdf for select themes
Addition of a download-as-geojson and download-as-csv for select themes
Addition of filters per layer Addition of a download-as-pdf for select themes Addition of a download-as-geojson and
download-as-csv for select themes
...

View file

@ -0,0 +1,39 @@
{
"$ref": "#/definitions/AndOrTagConfigJson",
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
},
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false
}

View file

@ -0,0 +1,37 @@
export default {
"$ref": "#/definitions/AndOrTagConfigJson",
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
}
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}

View file

@ -0,0 +1,93 @@
{
"type": "object",
"properties": {
"extraDeleteReasons": {
"description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from",
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {
"description": "The text that will be shown to the user - translatable"
},
"changesetMessage": {
"description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english",
"type": "string"
}
},
"required": [
"changesetMessage",
"explanation"
]
}
},
"nonDeleteMappings": {
"description": "In some cases, a (starting) contributor might wish to delete a feature even though deletion is not appropriate.\n(The most relevant case are small paths running over private property. These should be marked as 'private' instead of deleted, as the community might trace the path again from aerial imagery, gettting us back to the original situation).\n\nBy adding a 'nonDeleteMapping', an option can be added into the list which will retag the feature.\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"$ref": "#/definitions/AndOrTagConfigJson"
},
"then": {}
},
"required": [
"if",
"then"
]
}
},
"softDeletionTags": {
"description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"neededChangesets": {
"description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.",
"type": "number"
}
},
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
},
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false
}

View file

@ -0,0 +1,91 @@
export default {
"type": "object",
"properties": {
"extraDeleteReasons": {
"description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from",
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {
"description": "The text that will be shown to the user - translatable"
},
"changesetMessage": {
"description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english",
"type": "string"
}
},
"required": [
"changesetMessage",
"explanation"
]
}
},
"nonDeleteMappings": {
"description": "In some cases, a (starting) contributor might wish to delete a feature even though deletion is not appropriate.\n(The most relevant case are small paths running over private property. These should be marked as 'private' instead of deleted, as the community might trace the path again from aerial imagery, gettting us back to the original situation).\n\nBy adding a 'nonDeleteMapping', an option can be added into the list which will retag the feature.\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"$ref": "#/definitions/AndOrTagConfigJson"
},
"then": {}
},
"required": [
"if",
"then"
]
}
},
"softDeletionTags": {
"description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"neededChangesets": {
"description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.",
"type": "number"
}
},
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
}
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}

View file

@ -0,0 +1,72 @@
{
"type": "object",
"properties": {
"id": {
"description": "An id/name for this filter, used to set the URL parameters",
"type": "string"
},
"options": {
"description": "The options for a filter\nIf there are multiple options these will be a list of radio buttons\nIf there is only one option this will be a checkbox\nFiltering is done based on the given osmTags that are compared to the objects in that layer.",
"type": "array",
"items": {
"type": "object",
"properties": {
"question": {},
"osmTags": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"question"
]
}
}
},
"required": [
"id",
"options"
],
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
},
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false
}

View file

@ -0,0 +1,70 @@
export default {
"type": "object",
"properties": {
"id": {
"description": "An id/name for this filter, used to set the URL parameters",
"type": "string"
},
"options": {
"description": "The options for a filter\nIf there are multiple options these will be a list of radio buttons\nIf there is only one option this will be a checkbox\nFiltering is done based on the given osmTags that are compared to the objects in that layer.",
"type": "array",
"items": {
"type": "object",
"properties": {
"question": {},
"osmTags": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"question"
]
}
}
},
"required": [
"id",
"options"
],
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
}
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}

View file

@ -0,0 +1,900 @@
{
"description": "Configuration for a single layer",
"type": "object",
"properties": {
"id": {
"description": "The id of this layer.\nThis should be a simple, lowercase, human readable string that is used to identify the layer.",
"type": "string"
},
"name": {
"description": "The name of this layer\nUsed in the layer control panel and the 'Personal theme'.\n\nIf not given, will be hidden (and thus not toggable) in the layer control"
},
"description": {
"description": "A description for this layer.\nShown in the layer selections and in the personel theme"
},
"source": {
"description": "This determines where the data for the layer is fetched.\nThere are some options:\n\n# Query OSM directly\nsource: {osmTags: \"key=value\"}\n will fetch all objects with given tags from OSM.\n Currently, this will create a query to overpass and fetch the data - in the future this might fetch from the OSM API\n\n# Query OSM Via the overpass API with a custom script\nsource: {overpassScript: \"<custom overpass tags>\"} when you want to do special things. _This should be really rare_.\n This means that the data will be pulled from overpass with this script, and will ignore the osmTags for the query\n However, for the rest of the pipeline, the OsmTags will _still_ be used. This is important to enable layers etc...\n\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}\nSome API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this\n\nNote that both geojson-options might set a flag 'isOsmCache' indicating that the data originally comes from OSM too\n\n\nNOTE: the previous format was 'overpassTags: AndOrTagConfigJson | string', which is interpreted as a shorthand for source: {osmTags: \"key=value\"}\n While still supported, this is considered deprecated",
"anyOf": [
{
"allOf": [
{
"type": "object",
"properties": {
"osmTags": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"overpassScript": {
"type": "string"
}
},
"required": [
"osmTags"
]
},
{
"type": "object",
"properties": {
"maxCacheAge": {
"description": "The maximum amount of seconds that a tile is allowed to linger in the cache",
"type": "number"
}
}
}
]
},
{
"allOf": [
{
"type": "object",
"properties": {
"osmTags": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"geoJson": {
"type": "string"
},
"geoJsonZoomLevel": {
"type": "number"
},
"isOsmCache": {
"type": "boolean"
},
"mercatorCrs": {
"type": "boolean"
}
},
"required": [
"geoJson",
"osmTags"
]
},
{
"type": "object",
"properties": {
"maxCacheAge": {
"description": "The maximum amount of seconds that a tile is allowed to linger in the cache",
"type": "number"
}
}
}
]
}
]
},
"calculatedTags": {
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]",
"type": "array",
"items": {
"type": "string"
}
},
"doNotDownload": {
"description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration",
"type": "boolean"
},
"isShown": {
"description": "This tag rendering should either be 'yes' or 'no'. If 'no' is returned, then the feature will be hidden from view.\nThis is useful to hide certain features from view.\n\nImportant: hiding features does not work dynamically, but is only calculated when the data is first renders.\nThis implies that it is not possible to hide a feature after a tagging change\n\nThe default value is 'yes'",
"$ref": "#/definitions/TagRenderingConfigJson"
},
"minzoom": {
"description": "The minimum needed zoomlevel required before loading of the data start\nDefault: 0",
"type": "number"
},
"minzoomVisible": {
"description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible",
"type": "number"
},
"title": {
"description": "The title shown in a popup for elements of this layer.",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"titleIcons": {
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons",
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"mapRendering": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/default_3"
},
{
"$ref": "#/definitions/default_4"
}
]
}
},
"passAllFeatures": {
"description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directionss on cameras",
"type": "boolean"
},
"presets": {
"description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all",
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {
"description": "The title - shown on the 'add-new'-button."
},
"tags": {
"description": "The tags to add. It determines the icon too",
"type": "array",
"items": {
"type": "string"
}
},
"description": {
"description": "The _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)"
},
"preciseInput": {
"description": "If set, the user will prompted to confirm the location before actually adding the data.\nThis will be with a 'drag crosshair'-method.\n\nIf 'preferredBackgroundCategory' is set, the element will attempt to pick a background layer of that category.",
"anyOf": [
{
"type": "object",
"properties": {
"preferredBackground": {
"description": "The type of background picture",
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "string"
}
]
},
"snapToLayer": {
"description": "If specified, these layers will be shown to and the new point will be snapped towards it",
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "string"
}
]
},
"maxSnapDistance": {
"description": "If specified, a new point will only be snapped if it is within this range.\nDistance in meter\n\nDefault: 10",
"type": "number"
}
},
"required": [
"preferredBackground"
]
},
{
"enum": [
true
],
"type": "boolean"
}
]
}
},
"required": [
"tags",
"title"
]
}
},
"tagRenderings": {
"description": "All the tag renderings.\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together",
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
},
"override": {}
},
"required": [
"builtin",
"override"
]
},
{
"type": "object",
"properties": {
"rewrite": {
"type": "array",
"items": {
"type": "object",
"properties": {
"sourceString": {
"type": "string"
},
"into": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"into",
"sourceString"
]
}
},
"renderings": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
},
"override": {}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
]
}
}
},
"required": [
"renderings",
"rewrite"
]
},
{
"type": "string"
}
]
}
},
"filter": {
"description": "All the extra questions for filtering",
"type": "array",
"items": {
"$ref": "#/definitions/default"
}
},
"deletion": {
"description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n The delete dialog\n =================\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted from OSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n#### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.",
"anyOf": [
{
"$ref": "#/definitions/DeleteConfigJson"
},
{
"type": "boolean"
}
]
},
"allowMove": {
"description": "Indicates if a point can be moved and configures the modalities.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\nOff by default. Can be enabled by setting this flag or by configuring.",
"anyOf": [
{
"$ref": "#/definitions/default_2"
},
{
"type": "boolean"
}
]
},
"allowSplit": {
"description": "IF set, a 'split this road' button is shown",
"type": "boolean"
},
"units": {
"description": "In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...)\n\nSometimes, multiple denominations are possible (e.g. km/h vs mile/h; megawatt vs kilowatt vs gigawatt for power generators, ...)\n\nThis brings in some troubles, as there are multiple ways to write it (no denomitation, 'm' vs 'meter' 'metre', ...)\n\nNot only do we want to write consistent data to OSM, we also want to present this consistently to the user.\nThis is handled by defining units.\n\n# Rendering\n\nTo render a value with long (human) denomination, use {canonical(key)}\n\n# Usage\n\nFirst of all, you define which keys have units applied, for example:\n\n```\nunits: [\n appliesTo: [\"maxspeed\", \"maxspeed:hgv\", \"maxspeed:bus\"]\n applicableUnits: [\n ...\n ]\n]\n```\n\nApplicableUnits defines which is the canonical extension, how it is presented to the user, ...:\n\n```\napplicableUnits: [\n{\n canonicalDenomination: \"km/h\",\n alternativeDenomination: [\"km/u\", \"kmh\", \"kph\"]\n default: true,\n human: {\n en: \"kilometer/hour\",\n nl: \"kilometer/uur\"\n },\n humanShort: {\n en: \"km/h\",\n nl: \"km/u\"\n }\n},\n{\n canoncialDenomination: \"mph\",\n ... similar for miles an hour ...\n}\n]\n```\n\n\nIf this is defined, then every key which the denominations apply to (`maxspeed`, `maxspeed:hgv` and `maxspeed:bus`) will be rewritten at the metatagging stage:\nevery value will be parsed and the canonical extension will be added add presented to the other parts of the code.\n\nAlso, if a freeform text field is used, an extra dropdown with applicable denominations will be given",
"type": "array",
"items": {
"$ref": "#/definitions/default_1"
}
}
},
"required": [
"id",
"mapRendering",
"source"
],
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
},
"additionalProperties": false
},
"ApplicableUnitJson": {
"type": "object",
"properties": {
"canonicalDenomination": {
"description": "The canonical value which will be added to the text.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'",
"type": "string"
},
"canonicalDenominationSingular": {
"description": "The canonical denomination in the case that the unit is precisely '1'",
"type": "string"
},
"alternativeDenomination": {
"description": "A list of alternative values which can occur in the OSM database - used for parsing.",
"type": "array",
"items": {
"type": "string"
}
},
"human": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}"
},
"humanSingular": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"x²\n}"
},
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"default": {
"description": "The default interpretation - only one can be set.\nIf none is set, the first unit will be considered the default interpretation of a value without a unit",
"type": "boolean"
}
},
"required": [
"canonicalDenomination"
],
"additionalProperties": false
},
"TagRenderingConfigJson": {
"description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.",
"type": "object",
"properties": {
"id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise",
"type": "string"
},
"group": {
"description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.",
"type": "string"
},
"render": {
"description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`"
},
"question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only"
},
"condition": {
"description": "Only show this question if the object also matches the following tags.\n\nThis is useful to ask a follow-up question. E.g. if there is a diaper table, then ask a follow-up question on diaper tables...",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"freeform": {
"description": "Allow freeform text input from the user",
"type": "object",
"properties": {
"key": {
"description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown",
"type": "string"
},
"type": {
"description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values",
"type": "string"
},
"helperArgs": {
"description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'",
"type": "array",
"items": {}
},
"addExtraTags": {
"description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'",
"type": "array",
"items": {
"type": "string"
}
},
"inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.",
"type": "boolean"
},
"default": {
"description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)",
"type": "string"
}
},
"required": [
"key"
]
},
"multiAnswer": {
"description": "If true, use checkboxes instead of radio buttons when asking the question",
"type": "boolean"
},
"mappings": {
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option"
},
"hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n \n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": [
"string",
"boolean"
]
}
]
},
"ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"if",
"then"
]
}
}
},
"additionalProperties": false
},
"default_3": {
"description": "The PointRenderingConfig gives all details onto how to render a single point of a feature.\n\nThis can be used if:\n\n- The feature is a point\n- To render something at the centroid of an area, or at the start, end or projected centroid of a way",
"type": "object",
"properties": {
"location": {
"description": "All the locations that this point should be rendered at.\nUsing `location: [\"point\", \"centroid\"] will always render centerpoint",
"type": "array",
"items": {
"enum": [
"centroid",
"end",
"point",
"start"
],
"type": "string"
}
},
"icon": {
"description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;<path to my icon.svg>`",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"iconBadges": {
"description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"if",
"then"
]
}
},
"iconSize": {
"description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"rotation": {
"description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"label": {
"description": "A HTML-fragment that is shown below the icon, for example:\n<div style=\"background: white; display: block\">{name}</div>\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"location"
],
"additionalProperties": false
},
"default_4": {
"description": "The LineRenderingConfig gives all details onto how to render a single line of a feature.\n\nThis can be used if:\n\n- The feature is a line\n- The feature is an area",
"type": "object",
"properties": {
"color": {
"description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"width": {
"description": "The stroke-width for way-elements",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"dashArray": {
"description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"lineCap": {
"description": "The form at the end of a line",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"fill": {
"description": "Wehter or not to fill polygons",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"enum": [
"no",
"yes"
],
"type": "string"
}
]
},
"fillColor": {
"description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"offset": {
"description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "number"
}
]
}
},
"additionalProperties": false
},
"default": {
"type": "object",
"properties": {
"id": {
"description": "An id/name for this filter, used to set the URL parameters",
"type": "string"
},
"options": {
"description": "The options for a filter\nIf there are multiple options these will be a list of radio buttons\nIf there is only one option this will be a checkbox\nFiltering is done based on the given osmTags that are compared to the objects in that layer.",
"type": "array",
"items": {
"type": "object",
"properties": {
"question": {},
"osmTags": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"question"
]
}
}
},
"required": [
"id",
"options"
],
"additionalProperties": false
},
"DeleteConfigJson": {
"type": "object",
"properties": {
"extraDeleteReasons": {
"description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from",
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {
"description": "The text that will be shown to the user - translatable"
},
"changesetMessage": {
"description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english",
"type": "string"
}
},
"required": [
"changesetMessage",
"explanation"
]
}
},
"nonDeleteMappings": {
"description": "In some cases, a (starting) contributor might wish to delete a feature even though deletion is not appropriate.\n(The most relevant case are small paths running over private property. These should be marked as 'private' instead of deleted, as the community might trace the path again from aerial imagery, gettting us back to the original situation).\n\nBy adding a 'nonDeleteMapping', an option can be added into the list which will retag the feature.\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"$ref": "#/definitions/AndOrTagConfigJson"
},
"then": {}
},
"required": [
"if",
"then"
]
}
},
"softDeletionTags": {
"description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"neededChangesets": {
"description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.",
"type": "number"
}
},
"additionalProperties": false
},
"default_2": {
"type": "object",
"properties": {
"enableImproveAccuracy": {
"description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason",
"type": "boolean"
},
"enableRelocation": {
"description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason",
"type": "boolean"
}
},
"additionalProperties": false
},
"default_1": {
"type": "object",
"properties": {
"appliesToKey": {
"description": "Every key from this list will be normalized",
"type": "array",
"items": {
"type": "string"
}
},
"eraseInvalidValues": {
"description": "If set, invalid values will be erased in the MC application (but not in OSM of course!)\nBe careful with setting this",
"type": "boolean"
},
"applicableUnits": {
"description": "The possible denominations",
"type": "array",
"items": {
"$ref": "#/definitions/ApplicableUnitJson"
}
}
},
"required": [
"applicableUnits",
"appliesToKey"
],
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false
}

View file

@ -0,0 +1,890 @@
export default {
"description": "Configuration for a single layer",
"type": "object",
"properties": {
"id": {
"description": "The id of this layer.\nThis should be a simple, lowercase, human readable string that is used to identify the layer.",
"type": "string"
},
"name": {
"description": "The name of this layer\nUsed in the layer control panel and the 'Personal theme'.\n\nIf not given, will be hidden (and thus not toggable) in the layer control"
},
"description": {
"description": "A description for this layer.\nShown in the layer selections and in the personel theme"
},
"source": {
"description": "This determines where the data for the layer is fetched.\nThere are some options:\n\n# Query OSM directly\nsource: {osmTags: \"key=value\"}\n will fetch all objects with given tags from OSM.\n Currently, this will create a query to overpass and fetch the data - in the future this might fetch from the OSM API\n\n# Query OSM Via the overpass API with a custom script\nsource: {overpassScript: \"<custom overpass tags>\"} when you want to do special things. _This should be really rare_.\n This means that the data will be pulled from overpass with this script, and will ignore the osmTags for the query\n However, for the rest of the pipeline, the OsmTags will _still_ be used. This is important to enable layers etc...\n\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}\nSome API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this\n\nNote that both geojson-options might set a flag 'isOsmCache' indicating that the data originally comes from OSM too\n\n\nNOTE: the previous format was 'overpassTags: AndOrTagConfigJson | string', which is interpreted as a shorthand for source: {osmTags: \"key=value\"}\n While still supported, this is considered deprecated",
"anyOf": [
{
"allOf": [
{
"type": "object",
"properties": {
"osmTags": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"overpassScript": {
"type": "string"
}
},
"required": [
"osmTags"
]
},
{
"type": "object",
"properties": {
"maxCacheAge": {
"description": "The maximum amount of seconds that a tile is allowed to linger in the cache",
"type": "number"
}
}
}
]
},
{
"allOf": [
{
"type": "object",
"properties": {
"osmTags": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"geoJson": {
"type": "string"
},
"geoJsonZoomLevel": {
"type": "number"
},
"isOsmCache": {
"type": "boolean"
},
"mercatorCrs": {
"type": "boolean"
}
},
"required": [
"geoJson",
"osmTags"
]
},
{
"type": "object",
"properties": {
"maxCacheAge": {
"description": "The maximum amount of seconds that a tile is allowed to linger in the cache",
"type": "number"
}
}
}
]
}
]
},
"calculatedTags": {
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]",
"type": "array",
"items": {
"type": "string"
}
},
"doNotDownload": {
"description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration",
"type": "boolean"
},
"isShown": {
"description": "This tag rendering should either be 'yes' or 'no'. If 'no' is returned, then the feature will be hidden from view.\nThis is useful to hide certain features from view.\n\nImportant: hiding features does not work dynamically, but is only calculated when the data is first renders.\nThis implies that it is not possible to hide a feature after a tagging change\n\nThe default value is 'yes'",
"$ref": "#/definitions/TagRenderingConfigJson"
},
"minzoom": {
"description": "The minimum needed zoomlevel required before loading of the data start\nDefault: 0",
"type": "number"
},
"minzoomVisible": {
"description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible",
"type": "number"
},
"title": {
"description": "The title shown in a popup for elements of this layer.",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"titleIcons": {
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons",
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"mapRendering": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/default_3"
},
{
"$ref": "#/definitions/default_4"
}
]
}
},
"passAllFeatures": {
"description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directionss on cameras",
"type": "boolean"
},
"presets": {
"description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all",
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {
"description": "The title - shown on the 'add-new'-button."
},
"tags": {
"description": "The tags to add. It determines the icon too",
"type": "array",
"items": {
"type": "string"
}
},
"description": {
"description": "The _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)"
},
"preciseInput": {
"description": "If set, the user will prompted to confirm the location before actually adding the data.\nThis will be with a 'drag crosshair'-method.\n\nIf 'preferredBackgroundCategory' is set, the element will attempt to pick a background layer of that category.",
"anyOf": [
{
"type": "object",
"properties": {
"preferredBackground": {
"description": "The type of background picture",
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "string"
}
]
},
"snapToLayer": {
"description": "If specified, these layers will be shown to and the new point will be snapped towards it",
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "string"
}
]
},
"maxSnapDistance": {
"description": "If specified, a new point will only be snapped if it is within this range.\nDistance in meter\n\nDefault: 10",
"type": "number"
}
},
"required": [
"preferredBackground"
]
},
{
"enum": [
true
],
"type": "boolean"
}
]
}
},
"required": [
"tags",
"title"
]
}
},
"tagRenderings": {
"description": "All the tag renderings.\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together",
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
},
"override": {}
},
"required": [
"builtin",
"override"
]
},
{
"type": "object",
"properties": {
"rewrite": {
"type": "array",
"items": {
"type": "object",
"properties": {
"sourceString": {
"type": "string"
},
"into": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"into",
"sourceString"
]
}
},
"renderings": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
},
"override": {}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
]
}
}
},
"required": [
"renderings",
"rewrite"
]
},
{
"type": "string"
}
]
}
},
"filter": {
"description": "All the extra questions for filtering",
"type": "array",
"items": {
"$ref": "#/definitions/default"
}
},
"deletion": {
"description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n The delete dialog\n =================\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted from OSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n#### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.",
"anyOf": [
{
"$ref": "#/definitions/DeleteConfigJson"
},
{
"type": "boolean"
}
]
},
"allowMove": {
"description": "Indicates if a point can be moved and configures the modalities.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\nOff by default. Can be enabled by setting this flag or by configuring.",
"anyOf": [
{
"$ref": "#/definitions/default_2"
},
{
"type": "boolean"
}
]
},
"allowSplit": {
"description": "IF set, a 'split this road' button is shown",
"type": "boolean"
},
"units": {
"description": "In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...)\n\nSometimes, multiple denominations are possible (e.g. km/h vs mile/h; megawatt vs kilowatt vs gigawatt for power generators, ...)\n\nThis brings in some troubles, as there are multiple ways to write it (no denomitation, 'm' vs 'meter' 'metre', ...)\n\nNot only do we want to write consistent data to OSM, we also want to present this consistently to the user.\nThis is handled by defining units.\n\n# Rendering\n\nTo render a value with long (human) denomination, use {canonical(key)}\n\n# Usage\n\nFirst of all, you define which keys have units applied, for example:\n\n```\nunits: [\n appliesTo: [\"maxspeed\", \"maxspeed:hgv\", \"maxspeed:bus\"]\n applicableUnits: [\n ...\n ]\n]\n```\n\nApplicableUnits defines which is the canonical extension, how it is presented to the user, ...:\n\n```\napplicableUnits: [\n{\n canonicalDenomination: \"km/h\",\n alternativeDenomination: [\"km/u\", \"kmh\", \"kph\"]\n default: true,\n human: {\n en: \"kilometer/hour\",\n nl: \"kilometer/uur\"\n },\n humanShort: {\n en: \"km/h\",\n nl: \"km/u\"\n }\n},\n{\n canoncialDenomination: \"mph\",\n ... similar for miles an hour ...\n}\n]\n```\n\n\nIf this is defined, then every key which the denominations apply to (`maxspeed`, `maxspeed:hgv` and `maxspeed:bus`) will be rewritten at the metatagging stage:\nevery value will be parsed and the canonical extension will be added add presented to the other parts of the code.\n\nAlso, if a freeform text field is used, an extra dropdown with applicable denominations will be given",
"type": "array",
"items": {
"$ref": "#/definitions/default_1"
}
}
},
"required": [
"id",
"mapRendering",
"source"
],
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
}
},
"ApplicableUnitJson": {
"type": "object",
"properties": {
"canonicalDenomination": {
"description": "The canonical value which will be added to the text.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'",
"type": "string"
},
"canonicalDenominationSingular": {
"description": "The canonical denomination in the case that the unit is precisely '1'",
"type": "string"
},
"alternativeDenomination": {
"description": "A list of alternative values which can occur in the OSM database - used for parsing.",
"type": "array",
"items": {
"type": "string"
}
},
"human": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}"
},
"humanSingular": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"x²\n}"
},
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"default": {
"description": "The default interpretation - only one can be set.\nIf none is set, the first unit will be considered the default interpretation of a value without a unit",
"type": "boolean"
}
},
"required": [
"canonicalDenomination"
]
},
"TagRenderingConfigJson": {
"description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.",
"type": "object",
"properties": {
"id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise",
"type": "string"
},
"group": {
"description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.",
"type": "string"
},
"render": {
"description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`"
},
"question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only"
},
"condition": {
"description": "Only show this question if the object also matches the following tags.\n\nThis is useful to ask a follow-up question. E.g. if there is a diaper table, then ask a follow-up question on diaper tables...",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"freeform": {
"description": "Allow freeform text input from the user",
"type": "object",
"properties": {
"key": {
"description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown",
"type": "string"
},
"type": {
"description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values",
"type": "string"
},
"helperArgs": {
"description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'",
"type": "array",
"items": {}
},
"addExtraTags": {
"description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'",
"type": "array",
"items": {
"type": "string"
}
},
"inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.",
"type": "boolean"
},
"default": {
"description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)",
"type": "string"
}
},
"required": [
"key"
]
},
"multiAnswer": {
"description": "If true, use checkboxes instead of radio buttons when asking the question",
"type": "boolean"
},
"mappings": {
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option"
},
"hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n \n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": [
"string",
"boolean"
]
}
]
},
"ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"if",
"then"
]
}
}
}
},
"default_3": {
"description": "The PointRenderingConfig gives all details onto how to render a single point of a feature.\n\nThis can be used if:\n\n- The feature is a point\n- To render something at the centroid of an area, or at the start, end or projected centroid of a way",
"type": "object",
"properties": {
"location": {
"description": "All the locations that this point should be rendered at.\nUsing `location: [\"point\", \"centroid\"] will always render centerpoint",
"type": "array",
"items": {
"enum": [
"centroid",
"end",
"point",
"start"
],
"type": "string"
}
},
"icon": {
"description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;<path to my icon.svg>`",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"iconBadges": {
"description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"if",
"then"
]
}
},
"iconSize": {
"description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"rotation": {
"description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"label": {
"description": "A HTML-fragment that is shown below the icon, for example:\n<div style=\"background: white; display: block\">{name}</div>\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"location"
]
},
"default_4": {
"description": "The LineRenderingConfig gives all details onto how to render a single line of a feature.\n\nThis can be used if:\n\n- The feature is a line\n- The feature is an area",
"type": "object",
"properties": {
"color": {
"description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"width": {
"description": "The stroke-width for way-elements",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"dashArray": {
"description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"lineCap": {
"description": "The form at the end of a line",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"fill": {
"description": "Wehter or not to fill polygons",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"enum": [
"no",
"yes"
],
"type": "string"
}
]
},
"fillColor": {
"description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"offset": {
"description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "number"
}
]
}
}
},
"default": {
"type": "object",
"properties": {
"id": {
"description": "An id/name for this filter, used to set the URL parameters",
"type": "string"
},
"options": {
"description": "The options for a filter\nIf there are multiple options these will be a list of radio buttons\nIf there is only one option this will be a checkbox\nFiltering is done based on the given osmTags that are compared to the objects in that layer.",
"type": "array",
"items": {
"type": "object",
"properties": {
"question": {},
"osmTags": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"question"
]
}
}
},
"required": [
"id",
"options"
]
},
"DeleteConfigJson": {
"type": "object",
"properties": {
"extraDeleteReasons": {
"description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from",
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {
"description": "The text that will be shown to the user - translatable"
},
"changesetMessage": {
"description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english",
"type": "string"
}
},
"required": [
"changesetMessage",
"explanation"
]
}
},
"nonDeleteMappings": {
"description": "In some cases, a (starting) contributor might wish to delete a feature even though deletion is not appropriate.\n(The most relevant case are small paths running over private property. These should be marked as 'private' instead of deleted, as the community might trace the path again from aerial imagery, gettting us back to the original situation).\n\nBy adding a 'nonDeleteMapping', an option can be added into the list which will retag the feature.\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"$ref": "#/definitions/AndOrTagConfigJson"
},
"then": {}
},
"required": [
"if",
"then"
]
}
},
"softDeletionTags": {
"description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"neededChangesets": {
"description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.",
"type": "number"
}
}
},
"default_2": {
"type": "object",
"properties": {
"enableImproveAccuracy": {
"description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason",
"type": "boolean"
},
"enableRelocation": {
"description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason",
"type": "boolean"
}
}
},
"default_1": {
"type": "object",
"properties": {
"appliesToKey": {
"description": "Every key from this list will be normalized",
"type": "array",
"items": {
"type": "string"
}
},
"eraseInvalidValues": {
"description": "If set, invalid values will be erased in the MC application (but not in OSM of course!)\nBe careful with setting this",
"type": "boolean"
},
"applicableUnits": {
"description": "The possible denominations",
"type": "array",
"items": {
"$ref": "#/definitions/ApplicableUnitJson"
}
}
},
"required": [
"applicableUnits",
"appliesToKey"
]
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,293 @@
{
"description": "The LineRenderingConfig gives all details onto how to render a single line of a feature.\n\nThis can be used if:\n\n- The feature is a line\n- The feature is an area",
"type": "object",
"properties": {
"color": {
"description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"width": {
"description": "The stroke-width for way-elements",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"dashArray": {
"description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"lineCap": {
"description": "The form at the end of a line",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"fill": {
"description": "Wehter or not to fill polygons",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"enum": [
"no",
"yes"
],
"type": "string"
}
]
},
"fillColor": {
"description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"offset": {
"description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "number"
}
]
}
},
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
},
"additionalProperties": false
},
"ApplicableUnitJson": {
"type": "object",
"properties": {
"canonicalDenomination": {
"description": "The canonical value which will be added to the text.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'",
"type": "string"
},
"canonicalDenominationSingular": {
"description": "The canonical denomination in the case that the unit is precisely '1'",
"type": "string"
},
"alternativeDenomination": {
"description": "A list of alternative values which can occur in the OSM database - used for parsing.",
"type": "array",
"items": {
"type": "string"
}
},
"human": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}"
},
"humanSingular": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"x²\n}"
},
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"default": {
"description": "The default interpretation - only one can be set.\nIf none is set, the first unit will be considered the default interpretation of a value without a unit",
"type": "boolean"
}
},
"required": [
"canonicalDenomination"
],
"additionalProperties": false
},
"TagRenderingConfigJson": {
"description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.",
"type": "object",
"properties": {
"id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise",
"type": "string"
},
"group": {
"description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.",
"type": "string"
},
"render": {
"description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`"
},
"question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only"
},
"condition": {
"description": "Only show this question if the object also matches the following tags.\n\nThis is useful to ask a follow-up question. E.g. if there is a diaper table, then ask a follow-up question on diaper tables...",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"freeform": {
"description": "Allow freeform text input from the user",
"type": "object",
"properties": {
"key": {
"description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown",
"type": "string"
},
"type": {
"description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values",
"type": "string"
},
"helperArgs": {
"description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'",
"type": "array",
"items": {}
},
"addExtraTags": {
"description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'",
"type": "array",
"items": {
"type": "string"
}
},
"inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.",
"type": "boolean"
},
"default": {
"description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)",
"type": "string"
}
},
"required": [
"key"
]
},
"multiAnswer": {
"description": "If true, use checkboxes instead of radio buttons when asking the question",
"type": "boolean"
},
"mappings": {
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option"
},
"hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n \n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": [
"string",
"boolean"
]
}
]
},
"ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"if",
"then"
]
}
}
},
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false
}

View file

@ -0,0 +1,289 @@
export default {
"description": "The LineRenderingConfig gives all details onto how to render a single line of a feature.\n\nThis can be used if:\n\n- The feature is a line\n- The feature is an area",
"type": "object",
"properties": {
"color": {
"description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"width": {
"description": "The stroke-width for way-elements",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"dashArray": {
"description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"lineCap": {
"description": "The form at the end of a line",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"fill": {
"description": "Wehter or not to fill polygons",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"enum": [
"no",
"yes"
],
"type": "string"
}
]
},
"fillColor": {
"description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"offset": {
"description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "number"
}
]
}
},
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
}
},
"ApplicableUnitJson": {
"type": "object",
"properties": {
"canonicalDenomination": {
"description": "The canonical value which will be added to the text.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'",
"type": "string"
},
"canonicalDenominationSingular": {
"description": "The canonical denomination in the case that the unit is precisely '1'",
"type": "string"
},
"alternativeDenomination": {
"description": "A list of alternative values which can occur in the OSM database - used for parsing.",
"type": "array",
"items": {
"type": "string"
}
},
"human": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}"
},
"humanSingular": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"x²\n}"
},
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"default": {
"description": "The default interpretation - only one can be set.\nIf none is set, the first unit will be considered the default interpretation of a value without a unit",
"type": "boolean"
}
},
"required": [
"canonicalDenomination"
]
},
"TagRenderingConfigJson": {
"description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.",
"type": "object",
"properties": {
"id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise",
"type": "string"
},
"group": {
"description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.",
"type": "string"
},
"render": {
"description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`"
},
"question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only"
},
"condition": {
"description": "Only show this question if the object also matches the following tags.\n\nThis is useful to ask a follow-up question. E.g. if there is a diaper table, then ask a follow-up question on diaper tables...",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"freeform": {
"description": "Allow freeform text input from the user",
"type": "object",
"properties": {
"key": {
"description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown",
"type": "string"
},
"type": {
"description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values",
"type": "string"
},
"helperArgs": {
"description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'",
"type": "array",
"items": {}
},
"addExtraTags": {
"description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'",
"type": "array",
"items": {
"type": "string"
}
},
"inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.",
"type": "boolean"
},
"default": {
"description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)",
"type": "string"
}
},
"required": [
"key"
]
},
"multiAnswer": {
"description": "If true, use checkboxes instead of radio buttons when asking the question",
"type": "boolean"
},
"mappings": {
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option"
},
"hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n \n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": [
"string",
"boolean"
]
}
]
},
"ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"if",
"then"
]
}
}
}
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}

View file

@ -0,0 +1,87 @@
{
"type": "object",
"properties": {
"enableImproveAccuracy": {
"description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason",
"type": "boolean"
},
"enableRelocation": {
"description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason",
"type": "boolean"
}
},
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
},
"additionalProperties": false
},
"ApplicableUnitJson": {
"type": "object",
"properties": {
"canonicalDenomination": {
"description": "The canonical value which will be added to the text.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'",
"type": "string"
},
"canonicalDenominationSingular": {
"description": "The canonical denomination in the case that the unit is precisely '1'",
"type": "string"
},
"alternativeDenomination": {
"description": "A list of alternative values which can occur in the OSM database - used for parsing.",
"type": "array",
"items": {
"type": "string"
}
},
"human": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}"
},
"humanSingular": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"x²\n}"
},
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"default": {
"description": "The default interpretation - only one can be set.\nIf none is set, the first unit will be considered the default interpretation of a value without a unit",
"type": "boolean"
}
},
"required": [
"canonicalDenomination"
],
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false
}

View file

@ -0,0 +1,84 @@
export default {
"type": "object",
"properties": {
"enableImproveAccuracy": {
"description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason",
"type": "boolean"
},
"enableRelocation": {
"description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason",
"type": "boolean"
}
},
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
}
},
"ApplicableUnitJson": {
"type": "object",
"properties": {
"canonicalDenomination": {
"description": "The canonical value which will be added to the text.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'",
"type": "string"
},
"canonicalDenominationSingular": {
"description": "The canonical denomination in the case that the unit is precisely '1'",
"type": "string"
},
"alternativeDenomination": {
"description": "A list of alternative values which can occur in the OSM database - used for parsing.",
"type": "array",
"items": {
"type": "string"
}
},
"human": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}"
},
"humanSingular": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"x²\n}"
},
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"default": {
"description": "The default interpretation - only one can be set.\nIf none is set, the first unit will be considered the default interpretation of a value without a unit",
"type": "boolean"
}
},
"required": [
"canonicalDenomination"
]
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}

View file

@ -0,0 +1,305 @@
{
"description": "The PointRenderingConfig gives all details onto how to render a single point of a feature.\n\nThis can be used if:\n\n- The feature is a point\n- To render something at the centroid of an area, or at the start, end or projected centroid of a way",
"type": "object",
"properties": {
"location": {
"description": "All the locations that this point should be rendered at.\nUsing `location: [\"point\", \"centroid\"] will always render centerpoint",
"type": "array",
"items": {
"enum": [
"centroid",
"end",
"point",
"start"
],
"type": "string"
}
},
"icon": {
"description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;<path to my icon.svg>`",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"iconBadges": {
"description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"if",
"then"
]
}
},
"iconSize": {
"description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"rotation": {
"description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"label": {
"description": "A HTML-fragment that is shown below the icon, for example:\n<div style=\"background: white; display: block\">{name}</div>\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"location"
],
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
},
"additionalProperties": false
},
"ApplicableUnitJson": {
"type": "object",
"properties": {
"canonicalDenomination": {
"description": "The canonical value which will be added to the text.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'",
"type": "string"
},
"canonicalDenominationSingular": {
"description": "The canonical denomination in the case that the unit is precisely '1'",
"type": "string"
},
"alternativeDenomination": {
"description": "A list of alternative values which can occur in the OSM database - used for parsing.",
"type": "array",
"items": {
"type": "string"
}
},
"human": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}"
},
"humanSingular": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"x²\n}"
},
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"default": {
"description": "The default interpretation - only one can be set.\nIf none is set, the first unit will be considered the default interpretation of a value without a unit",
"type": "boolean"
}
},
"required": [
"canonicalDenomination"
],
"additionalProperties": false
},
"TagRenderingConfigJson": {
"description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.",
"type": "object",
"properties": {
"id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise",
"type": "string"
},
"group": {
"description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.",
"type": "string"
},
"render": {
"description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`"
},
"question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only"
},
"condition": {
"description": "Only show this question if the object also matches the following tags.\n\nThis is useful to ask a follow-up question. E.g. if there is a diaper table, then ask a follow-up question on diaper tables...",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"freeform": {
"description": "Allow freeform text input from the user",
"type": "object",
"properties": {
"key": {
"description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown",
"type": "string"
},
"type": {
"description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values",
"type": "string"
},
"helperArgs": {
"description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'",
"type": "array",
"items": {}
},
"addExtraTags": {
"description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'",
"type": "array",
"items": {
"type": "string"
}
},
"inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.",
"type": "boolean"
},
"default": {
"description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)",
"type": "string"
}
},
"required": [
"key"
]
},
"multiAnswer": {
"description": "If true, use checkboxes instead of radio buttons when asking the question",
"type": "boolean"
},
"mappings": {
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option"
},
"hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n \n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": [
"string",
"boolean"
]
}
]
},
"ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"if",
"then"
]
}
}
},
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false
}

View file

@ -0,0 +1,301 @@
export default {
"description": "The PointRenderingConfig gives all details onto how to render a single point of a feature.\n\nThis can be used if:\n\n- The feature is a point\n- To render something at the centroid of an area, or at the start, end or projected centroid of a way",
"type": "object",
"properties": {
"location": {
"description": "All the locations that this point should be rendered at.\nUsing `location: [\"point\", \"centroid\"] will always render centerpoint",
"type": "array",
"items": {
"enum": [
"centroid",
"end",
"point",
"start"
],
"type": "string"
}
},
"icon": {
"description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;<path to my icon.svg>`",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"iconBadges": {
"description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"if",
"then"
]
}
},
"iconSize": {
"description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"rotation": {
"description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"label": {
"description": "A HTML-fragment that is shown below the icon, for example:\n<div style=\"background: white; display: block\">{name}</div>\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"location"
],
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
}
},
"ApplicableUnitJson": {
"type": "object",
"properties": {
"canonicalDenomination": {
"description": "The canonical value which will be added to the text.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'",
"type": "string"
},
"canonicalDenominationSingular": {
"description": "The canonical denomination in the case that the unit is precisely '1'",
"type": "string"
},
"alternativeDenomination": {
"description": "A list of alternative values which can occur in the OSM database - used for parsing.",
"type": "array",
"items": {
"type": "string"
}
},
"human": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}"
},
"humanSingular": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"x²\n}"
},
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"default": {
"description": "The default interpretation - only one can be set.\nIf none is set, the first unit will be considered the default interpretation of a value without a unit",
"type": "boolean"
}
},
"required": [
"canonicalDenomination"
]
},
"TagRenderingConfigJson": {
"description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.",
"type": "object",
"properties": {
"id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise",
"type": "string"
},
"group": {
"description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.",
"type": "string"
},
"render": {
"description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`"
},
"question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only"
},
"condition": {
"description": "Only show this question if the object also matches the following tags.\n\nThis is useful to ask a follow-up question. E.g. if there is a diaper table, then ask a follow-up question on diaper tables...",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"freeform": {
"description": "Allow freeform text input from the user",
"type": "object",
"properties": {
"key": {
"description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown",
"type": "string"
},
"type": {
"description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values",
"type": "string"
},
"helperArgs": {
"description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'",
"type": "array",
"items": {}
},
"addExtraTags": {
"description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'",
"type": "array",
"items": {
"type": "string"
}
},
"inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.",
"type": "boolean"
},
"default": {
"description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)",
"type": "string"
}
},
"required": [
"key"
]
},
"multiAnswer": {
"description": "If true, use checkboxes instead of radio buttons when asking the question",
"type": "boolean"
},
"mappings": {
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option"
},
"hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n \n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": [
"string",
"boolean"
]
}
]
},
"ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"if",
"then"
]
}
}
}
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}

View file

@ -0,0 +1,167 @@
{
"description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.",
"type": "object",
"properties": {
"id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise",
"type": "string"
},
"group": {
"description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.",
"type": "string"
},
"render": {
"description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`"
},
"question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only"
},
"condition": {
"description": "Only show this question if the object also matches the following tags.\n\nThis is useful to ask a follow-up question. E.g. if there is a diaper table, then ask a follow-up question on diaper tables...",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"freeform": {
"description": "Allow freeform text input from the user",
"type": "object",
"properties": {
"key": {
"description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown",
"type": "string"
},
"type": {
"description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values",
"type": "string"
},
"helperArgs": {
"description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'",
"type": "array",
"items": {}
},
"addExtraTags": {
"description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'",
"type": "array",
"items": {
"type": "string"
}
},
"inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.",
"type": "boolean"
},
"default": {
"description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)",
"type": "string"
}
},
"required": [
"key"
]
},
"multiAnswer": {
"description": "If true, use checkboxes instead of radio buttons when asking the question",
"type": "boolean"
},
"mappings": {
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option"
},
"hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n \n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": [
"string",
"boolean"
]
}
]
},
"ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"if",
"then"
]
}
}
},
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
},
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false
}

View file

@ -0,0 +1,165 @@
export default {
"description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.",
"type": "object",
"properties": {
"id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise",
"type": "string"
},
"group": {
"description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.",
"type": "string"
},
"render": {
"description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`"
},
"question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only"
},
"condition": {
"description": "Only show this question if the object also matches the following tags.\n\nThis is useful to ask a follow-up question. E.g. if there is a diaper table, then ask a follow-up question on diaper tables...",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"freeform": {
"description": "Allow freeform text input from the user",
"type": "object",
"properties": {
"key": {
"description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown",
"type": "string"
},
"type": {
"description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values",
"type": "string"
},
"helperArgs": {
"description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'",
"type": "array",
"items": {}
},
"addExtraTags": {
"description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'",
"type": "array",
"items": {
"type": "string"
}
},
"inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.",
"type": "boolean"
},
"default": {
"description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)",
"type": "string"
}
},
"required": [
"key"
]
},
"multiAnswer": {
"description": "If true, use checkboxes instead of radio buttons when asking the question",
"type": "boolean"
},
"mappings": {
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option"
},
"hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n \n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": [
"string",
"boolean"
]
}
]
},
"ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"if",
"then"
]
}
}
},
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
}
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}

View file

@ -0,0 +1,569 @@
{
"description": "Configuration for a tilesource config",
"type": "object",
"properties": {
"id": {
"description": "Id of this overlay, used in the URL-parameters to set the state",
"type": "string"
},
"source": {
"description": "The path, where {x}, {y} and {z} will be substituted",
"type": "string"
},
"isOverlay": {
"description": "Wether or not this is an overlay. Default: true",
"type": "boolean"
},
"name": {
"description": "How this will be shown in the selection menu.\nMake undefined if this may not be toggled"
},
"minZoom": {
"description": "Only visible at this or a higher zoom level",
"type": "number"
},
"maxZoom": {
"description": "Only visible at this or a lower zoom level",
"type": "number"
},
"defaultState": {
"description": "The default state, set to false to hide by default",
"type": "boolean"
}
},
"required": [
"defaultState",
"id",
"source"
],
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
},
"additionalProperties": false
},
"ApplicableUnitJson": {
"type": "object",
"properties": {
"canonicalDenomination": {
"description": "The canonical value which will be added to the text.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'",
"type": "string"
},
"canonicalDenominationSingular": {
"description": "The canonical denomination in the case that the unit is precisely '1'",
"type": "string"
},
"alternativeDenomination": {
"description": "A list of alternative values which can occur in the OSM database - used for parsing.",
"type": "array",
"items": {
"type": "string"
}
},
"human": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}"
},
"humanSingular": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"x²\n}"
},
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"default": {
"description": "The default interpretation - only one can be set.\nIf none is set, the first unit will be considered the default interpretation of a value without a unit",
"type": "boolean"
}
},
"required": [
"canonicalDenomination"
],
"additionalProperties": false
},
"TagRenderingConfigJson": {
"description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.",
"type": "object",
"properties": {
"id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise",
"type": "string"
},
"group": {
"description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.",
"type": "string"
},
"render": {
"description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`"
},
"question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only"
},
"condition": {
"description": "Only show this question if the object also matches the following tags.\n\nThis is useful to ask a follow-up question. E.g. if there is a diaper table, then ask a follow-up question on diaper tables...",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"freeform": {
"description": "Allow freeform text input from the user",
"type": "object",
"properties": {
"key": {
"description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown",
"type": "string"
},
"type": {
"description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values",
"type": "string"
},
"helperArgs": {
"description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'",
"type": "array",
"items": {}
},
"addExtraTags": {
"description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'",
"type": "array",
"items": {
"type": "string"
}
},
"inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.",
"type": "boolean"
},
"default": {
"description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)",
"type": "string"
}
},
"required": [
"key"
]
},
"multiAnswer": {
"description": "If true, use checkboxes instead of radio buttons when asking the question",
"type": "boolean"
},
"mappings": {
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option"
},
"hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n \n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": [
"string",
"boolean"
]
}
]
},
"ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"if",
"then"
]
}
}
},
"additionalProperties": false
},
"default_3": {
"description": "The PointRenderingConfig gives all details onto how to render a single point of a feature.\n\nThis can be used if:\n\n- The feature is a point\n- To render something at the centroid of an area, or at the start, end or projected centroid of a way",
"type": "object",
"properties": {
"location": {
"description": "All the locations that this point should be rendered at.\nUsing `location: [\"point\", \"centroid\"] will always render centerpoint",
"type": "array",
"items": {
"enum": [
"centroid",
"end",
"point",
"start"
],
"type": "string"
}
},
"icon": {
"description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;<path to my icon.svg>`",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"iconBadges": {
"description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"if",
"then"
]
}
},
"iconSize": {
"description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"rotation": {
"description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"label": {
"description": "A HTML-fragment that is shown below the icon, for example:\n<div style=\"background: white; display: block\">{name}</div>\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"location"
],
"additionalProperties": false
},
"default_4": {
"description": "The LineRenderingConfig gives all details onto how to render a single line of a feature.\n\nThis can be used if:\n\n- The feature is a line\n- The feature is an area",
"type": "object",
"properties": {
"color": {
"description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"width": {
"description": "The stroke-width for way-elements",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"dashArray": {
"description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"lineCap": {
"description": "The form at the end of a line",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"fill": {
"description": "Wehter or not to fill polygons",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"enum": [
"no",
"yes"
],
"type": "string"
}
]
},
"fillColor": {
"description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"offset": {
"description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "number"
}
]
}
},
"additionalProperties": false
},
"default": {
"type": "object",
"properties": {
"id": {
"description": "An id/name for this filter, used to set the URL parameters",
"type": "string"
},
"options": {
"description": "The options for a filter\nIf there are multiple options these will be a list of radio buttons\nIf there is only one option this will be a checkbox\nFiltering is done based on the given osmTags that are compared to the objects in that layer.",
"type": "array",
"items": {
"type": "object",
"properties": {
"question": {},
"osmTags": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"question"
]
}
}
},
"required": [
"id",
"options"
],
"additionalProperties": false
},
"DeleteConfigJson": {
"type": "object",
"properties": {
"extraDeleteReasons": {
"description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from",
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {
"description": "The text that will be shown to the user - translatable"
},
"changesetMessage": {
"description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english",
"type": "string"
}
},
"required": [
"changesetMessage",
"explanation"
]
}
},
"nonDeleteMappings": {
"description": "In some cases, a (starting) contributor might wish to delete a feature even though deletion is not appropriate.\n(The most relevant case are small paths running over private property. These should be marked as 'private' instead of deleted, as the community might trace the path again from aerial imagery, gettting us back to the original situation).\n\nBy adding a 'nonDeleteMapping', an option can be added into the list which will retag the feature.\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"$ref": "#/definitions/AndOrTagConfigJson"
},
"then": {}
},
"required": [
"if",
"then"
]
}
},
"softDeletionTags": {
"description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"neededChangesets": {
"description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.",
"type": "number"
}
},
"additionalProperties": false
},
"default_2": {
"type": "object",
"properties": {
"enableImproveAccuracy": {
"description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason",
"type": "boolean"
},
"enableRelocation": {
"description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason",
"type": "boolean"
}
},
"additionalProperties": false
},
"default_1": {
"type": "object",
"properties": {
"appliesToKey": {
"description": "Every key from this list will be normalized",
"type": "array",
"items": {
"type": "string"
}
},
"eraseInvalidValues": {
"description": "If set, invalid values will be erased in the MC application (but not in OSM of course!)\nBe careful with setting this",
"type": "boolean"
},
"applicableUnits": {
"description": "The possible denominations",
"type": "array",
"items": {
"$ref": "#/definitions/ApplicableUnitJson"
}
}
},
"required": [
"applicableUnits",
"appliesToKey"
],
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false
}

View file

@ -0,0 +1,559 @@
export default {
"description": "Configuration for a tilesource config",
"type": "object",
"properties": {
"id": {
"description": "Id of this overlay, used in the URL-parameters to set the state",
"type": "string"
},
"source": {
"description": "The path, where {x}, {y} and {z} will be substituted",
"type": "string"
},
"isOverlay": {
"description": "Wether or not this is an overlay. Default: true",
"type": "boolean"
},
"name": {
"description": "How this will be shown in the selection menu.\nMake undefined if this may not be toggled"
},
"minZoom": {
"description": "Only visible at this or a higher zoom level",
"type": "number"
},
"maxZoom": {
"description": "Only visible at this or a lower zoom level",
"type": "number"
},
"defaultState": {
"description": "The default state, set to false to hide by default",
"type": "boolean"
}
},
"required": [
"defaultState",
"id",
"source"
],
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
}
},
"ApplicableUnitJson": {
"type": "object",
"properties": {
"canonicalDenomination": {
"description": "The canonical value which will be added to the text.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'",
"type": "string"
},
"canonicalDenominationSingular": {
"description": "The canonical denomination in the case that the unit is precisely '1'",
"type": "string"
},
"alternativeDenomination": {
"description": "A list of alternative values which can occur in the OSM database - used for parsing.",
"type": "array",
"items": {
"type": "string"
}
},
"human": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}"
},
"humanSingular": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"x²\n}"
},
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"default": {
"description": "The default interpretation - only one can be set.\nIf none is set, the first unit will be considered the default interpretation of a value without a unit",
"type": "boolean"
}
},
"required": [
"canonicalDenomination"
]
},
"TagRenderingConfigJson": {
"description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.",
"type": "object",
"properties": {
"id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise",
"type": "string"
},
"group": {
"description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.",
"type": "string"
},
"render": {
"description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`"
},
"question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only"
},
"condition": {
"description": "Only show this question if the object also matches the following tags.\n\nThis is useful to ask a follow-up question. E.g. if there is a diaper table, then ask a follow-up question on diaper tables...",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"freeform": {
"description": "Allow freeform text input from the user",
"type": "object",
"properties": {
"key": {
"description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown",
"type": "string"
},
"type": {
"description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values",
"type": "string"
},
"helperArgs": {
"description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'",
"type": "array",
"items": {}
},
"addExtraTags": {
"description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'",
"type": "array",
"items": {
"type": "string"
}
},
"inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.",
"type": "boolean"
},
"default": {
"description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)",
"type": "string"
}
},
"required": [
"key"
]
},
"multiAnswer": {
"description": "If true, use checkboxes instead of radio buttons when asking the question",
"type": "boolean"
},
"mappings": {
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option"
},
"hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n \n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": [
"string",
"boolean"
]
}
]
},
"ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"if",
"then"
]
}
}
}
},
"default_3": {
"description": "The PointRenderingConfig gives all details onto how to render a single point of a feature.\n\nThis can be used if:\n\n- The feature is a point\n- To render something at the centroid of an area, or at the start, end or projected centroid of a way",
"type": "object",
"properties": {
"location": {
"description": "All the locations that this point should be rendered at.\nUsing `location: [\"point\", \"centroid\"] will always render centerpoint",
"type": "array",
"items": {
"enum": [
"centroid",
"end",
"point",
"start"
],
"type": "string"
}
},
"icon": {
"description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;<path to my icon.svg>`",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"iconBadges": {
"description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"then": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"if",
"then"
]
}
},
"iconSize": {
"description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"rotation": {
"description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"label": {
"description": "A HTML-fragment that is shown below the icon, for example:\n<div style=\"background: white; display: block\">{name}</div>\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"location"
]
},
"default_4": {
"description": "The LineRenderingConfig gives all details onto how to render a single line of a feature.\n\nThis can be used if:\n\n- The feature is a line\n- The feature is an area",
"type": "object",
"properties": {
"color": {
"description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"width": {
"description": "The stroke-width for way-elements",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"dashArray": {
"description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"lineCap": {
"description": "The form at the end of a line",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"fill": {
"description": "Wehter or not to fill polygons",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"enum": [
"no",
"yes"
],
"type": "string"
}
]
},
"fillColor": {
"description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "string"
}
]
},
"offset": {
"description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details",
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "number"
}
]
}
}
},
"default": {
"type": "object",
"properties": {
"id": {
"description": "An id/name for this filter, used to set the URL parameters",
"type": "string"
},
"options": {
"description": "The options for a filter\nIf there are multiple options these will be a list of radio buttons\nIf there is only one option this will be a checkbox\nFiltering is done based on the given osmTags that are compared to the objects in that layer.",
"type": "array",
"items": {
"type": "object",
"properties": {
"question": {},
"osmTags": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"required": [
"question"
]
}
}
},
"required": [
"id",
"options"
]
},
"DeleteConfigJson": {
"type": "object",
"properties": {
"extraDeleteReasons": {
"description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from",
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {
"description": "The text that will be shown to the user - translatable"
},
"changesetMessage": {
"description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english",
"type": "string"
}
},
"required": [
"changesetMessage",
"explanation"
]
}
},
"nonDeleteMappings": {
"description": "In some cases, a (starting) contributor might wish to delete a feature even though deletion is not appropriate.\n(The most relevant case are small paths running over private property. These should be marked as 'private' instead of deleted, as the community might trace the path again from aerial imagery, gettting us back to the original situation).\n\nBy adding a 'nonDeleteMapping', an option can be added into the list which will retag the feature.\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!",
"type": "array",
"items": {
"type": "object",
"properties": {
"if": {
"$ref": "#/definitions/AndOrTagConfigJson"
},
"then": {}
},
"required": [
"if",
"then"
]
}
},
"softDeletionTags": {
"description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```",
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
},
"neededChangesets": {
"description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.",
"type": "number"
}
}
},
"default_2": {
"type": "object",
"properties": {
"enableImproveAccuracy": {
"description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason",
"type": "boolean"
},
"enableRelocation": {
"description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason",
"type": "boolean"
}
}
},
"default_1": {
"type": "object",
"properties": {
"appliesToKey": {
"description": "Every key from this list will be normalized",
"type": "array",
"items": {
"type": "string"
}
},
"eraseInvalidValues": {
"description": "If set, invalid values will be erased in the MC application (but not in OSM of course!)\nBe careful with setting this",
"type": "boolean"
},
"applicableUnits": {
"description": "The possible denominations",
"type": "array",
"items": {
"$ref": "#/definitions/ApplicableUnitJson"
}
}
},
"required": [
"applicableUnits",
"appliesToKey"
]
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}

View file

@ -0,0 +1,101 @@
{
"type": "object",
"properties": {
"appliesToKey": {
"description": "Every key from this list will be normalized",
"type": "array",
"items": {
"type": "string"
}
},
"eraseInvalidValues": {
"description": "If set, invalid values will be erased in the MC application (but not in OSM of course!)\nBe careful with setting this",
"type": "boolean"
},
"applicableUnits": {
"description": "The possible denominations",
"type": "array",
"items": {
"$ref": "#/definitions/ApplicableUnitJson"
}
}
},
"required": [
"applicableUnits",
"appliesToKey"
],
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
},
"additionalProperties": false
},
"ApplicableUnitJson": {
"type": "object",
"properties": {
"canonicalDenomination": {
"description": "The canonical value which will be added to the text.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'",
"type": "string"
},
"canonicalDenominationSingular": {
"description": "The canonical denomination in the case that the unit is precisely '1'",
"type": "string"
},
"alternativeDenomination": {
"description": "A list of alternative values which can occur in the OSM database - used for parsing.",
"type": "array",
"items": {
"type": "string"
}
},
"human": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}"
},
"humanSingular": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"x²\n}"
},
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"default": {
"description": "The default interpretation - only one can be set.\nIf none is set, the first unit will be considered the default interpretation of a value without a unit",
"type": "boolean"
}
},
"required": [
"canonicalDenomination"
],
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false
}

View file

@ -0,0 +1,98 @@
export default {
"type": "object",
"properties": {
"appliesToKey": {
"description": "Every key from this list will be normalized",
"type": "array",
"items": {
"type": "string"
}
},
"eraseInvalidValues": {
"description": "If set, invalid values will be erased in the MC application (but not in OSM of course!)\nBe careful with setting this",
"type": "boolean"
},
"applicableUnits": {
"description": "The possible denominations",
"type": "array",
"items": {
"$ref": "#/definitions/ApplicableUnitJson"
}
}
},
"required": [
"applicableUnits",
"appliesToKey"
],
"definitions": {
"AndOrTagConfigJson": {
"type": "object",
"properties": {
"and": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
},
"or": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AndOrTagConfigJson"
},
{
"type": "string"
}
]
}
}
}
},
"ApplicableUnitJson": {
"type": "object",
"properties": {
"canonicalDenomination": {
"description": "The canonical value which will be added to the text.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'",
"type": "string"
},
"canonicalDenominationSingular": {
"description": "The canonical denomination in the case that the unit is precisely '1'",
"type": "string"
},
"alternativeDenomination": {
"description": "A list of alternative values which can occur in the OSM database - used for parsing.",
"type": "array",
"items": {
"type": "string"
}
},
"human": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}"
},
"humanSingular": {
"description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"x²\n}"
},
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"default": {
"description": "The default interpretation - only one can be set.\nIf none is set, the first unit will be considered the default interpretation of a value without a unit",
"type": "boolean"
}
},
"required": [
"canonicalDenomination"
]
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}

View file

@ -1,4 +1,9 @@
# Available types for text fields
Available types for text fields
=================================
The listed types here trigger a special input element. Use them in `tagrendering.freeform.type` of your tagrendering to activate them
@ -8,7 +13,7 @@ A basic string
## text
A string, but allows input of longer strings more comfortably (a text area)
A string, but allows input of longer strings more comfortably and supports newlines (a text area)
## date
@ -24,7 +29,46 @@ A geographical length in meters (rounded at two points). Will give an extra mini
## wikidata
A wikidata identifier, e.g. Q42. Input helper arguments: [ key: the value of this tag will initialize search (default: name), options: { removePrefixes: string[], removePostfixes: string[] } these prefixes and postfixes will be removed from the initial search value]
A wikidata identifier, e.g. Q42.
### Helper arguments
name | doc
------ | -----
key | the value of this tag will initialize search (default: name)
options | A JSON-object of type `{ removePrefixes: string[], removePostfixes: string[] }`.
subarg | doc
-------- | -----
removePrefixes | remove these snippets of text from the start of the passed string to search
removePostfixes | remove these snippets of text from the end of the passed string to search
### Example usage
The following is the 'freeform'-part of a layer config which will trigger a search for the wikidata item corresponding with the name of the selected feature. It will also remove '-street', '-square', ... if found at the end of the name
```
"freeform": {
"key": "name:etymology:wikidata",
"type": "wikidata",
"helperArgs": [
"name",
{
"removePostfixes": [
"street",
"boulevard",
"path",
"square",
"plaza",
]
}
]
}
```
## int
@ -60,8 +104,45 @@ A phone number
## opening_hours
Has extra elements to easily input when a POI is opened
Has extra elements to easily input when a POI is opened.
### Helper arguments
name | doc
------ | -----
options | A JSON-object of type `{ prefix: string, postfix: string }`.
subarg | doc
-------- | -----
prefix | Piece of text that will always be added to the front of the generated opening hours. If the OSM-data does not start with this, it will fail to parse
postfix | Piece of text that will always be added to the end of the generated opening hours
### Example usage
To add a conditional (based on time) access restriction:
```
"freeform": {
"key": "access:conditional",
"type": "opening_hours",
"helperArgs": [
{
"prefix":"no @ (",
"postfix":")"
}
]
}
```
*Don't forget to pass the prefix and postfix in the rendering as well*: `{opening_hours_table(opening_hours,yes @ &LPARENS, &RPARENS )`
## color
Shows a color picker Generated from ValidatedTextField.ts
Shows a color picker
This document is autogenerated from ValidatedTextField.ts

View file

@ -1,24 +1,59 @@
### Special tag renderings
In a tagrendering, some special values are substituted by an advanced UI-element. This allows advanced features and visualizations to be reused by custom themes or even to query third-party API's. General usage is `{func_name()}`, `{func_name(arg, someotherarg)}` or `{func_name(args):cssStyle}`. Note that you _do not_fcs need to use quotes around your arguments, the comma is enough to separate them. This also implies you cannot use a comma in your args
In a tagrendering, some special values are substituted by an advanced UI-element. This allows advanced features and visualizations to be reused by custom themes or even to query third-party API's.
General usage is `{func_name()}`, `{func_name(arg, someotherarg)}` or `{func_name(args):cssStyle}`. Note that you _do not_ need to use quotes around your arguments, the comma is enough to separate them. This also implies you cannot use a comma in your args
- [all_tags](#all_tags)
- [image_carousel](#image_carousel)
- [image_upload](#image_upload)
- [wikipedia](#wikipedia)
- [minimap](#minimap)
- [sided_minimap](#sided_minimap)
- [reviews](#reviews)
- [opening_hours_table](#opening_hours_table)
- [live](#live)
- [histogram](#histogram)
- [share_link](#share_link)
- [canonical](#canonical)
- [import_button](#import_button)
- [multi_apply](#multi_apply)
- [tag_apply](#tag_apply)
### all_tags
Prints all key-value pairs of the object - used for debugging
#### Example usage
`{all_tags()}`
`{all_tags()}`
### image_carousel
Creates an image carousel for the given sources. An attempt will be made to guess what source is used. Supported: Wikidata identifiers, Wikipedia pages, Wikimedia categories, IMGUR (with attribution, direct links)
name | default | description
------ | --------- | -------------
image key/prefix (multiple values allowed if comma-seperated) | image | The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc...
image key/prefix (multiple values allowed if comma-seperated) | image,mapillary,image,wikidata,wikimedia_commons,image,image | The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc...
#### Example usage
`{image_carousel(image)}`
`{image_carousel(image,mapillary,image,wikidata,wikimedia_commons,image,image)}`
### image_upload
Creates a button where a user can upload an image to IMGUR
@ -28,9 +63,13 @@ name | default | description
image-key | image | Image tag to add the URL to (or image-tag:0, image-tag:1 when multiple images are added)
label | Add image | The text to show on the button
#### Example usage
`{image_upload(image,Add image)}`
`{image_upload(image,Add image)}`
### wikipedia
A box showing the corresponding wikipedia article - based on the wikidata tag
@ -39,21 +78,44 @@ name | default | description
------ | --------- | -------------
keyToShowWikipediaFor | wikidata | Use the wikidata entry from this key to show the wikipedia article for
#### Example usage
`{wikipedia()}` is a basic example, `{wikipedia(name:etymology:wikidata)}` to show the wikipedia page of whom the feature was named after. Also remember that these can be styled, e.g. `{wikipedia():max-height: 10rem}` to limit the height
`{wikipedia()}` is a basic example, `{wikipedia(name:etymology:wikidata)}` to show the wikipedia page of whom the feature was named after. Also remember that these can be styled, e.g. `{wikipedia():max-height: 10rem}` to limit the height
### minimap
A small map showing the selected feature. Note that no styling is applied, wrap this in a div
A small map showing the selected feature.
name | default | description
------ | --------- | -------------
zoomlevel | 18 | The (maximum) zoomlevel: the target zoomlevel after fitting the entire feature. The minimap will fit the entire feature, then zoom out to this zoom level. The higher, the more zoomed in with 1 being the entire world and 19 being really close
idKey | id | (Matches all resting arguments) This argument should be the key of a property of the feature. The corresponding value is interpreted as either the id or the a list of ID's. The features with these ID's will be shown on this minimap.
#### Example usage
`{minimap()}`, `{minimap(17, id, _list_of_embedded_feature_ids_calculated_by_calculated_tag):height:10rem; border: 2px solid black}`
`{minimap()}`, `{minimap(17, id, _list_of_embedded_feature_ids_calculated_by_calculated_tag):height:10rem; border: 2px solid black}`
### sided_minimap
A small map showing _only one side_ the selected feature. *This features requires to have linerenderings with offset* as only linerenderings with a postive or negative offset will be shown. Note: in most cases, this map will be automatically introduced
name | default | description
------ | --------- | -------------
side | _undefined_ | The side to show, either `left` or `right`
#### Example usage
`{sided_minimap(left)}`
### reviews
Adds an overview of the mangrove-reviews of this object. Mangrove.Reviews needs - in order to identify the reviewed object - a coordinate and a name. By default, the name of the object is given, but this can be overwritten
@ -61,11 +123,15 @@ idKey | id | (Matches all resting arguments) This argument should be the key of
name | default | description
------ | --------- | -------------
subjectKey | name | The key to use to determine the subject. If specified, the subject will be <b>tags[subjectKey]</b>
fallback | undefined | The identifier to use, if <i>tags[subjectKey]</i> as specified above is not available. This is effectively a fallback value
fallback | _undefined_ | The identifier to use, if <i>tags[subjectKey]</i> as specified above is not available. This is effectively a fallback value
#### Example usage
`{reviews()}` for a vanilla review, `{reviews(name, play_forest)}` to review a play forest. If a name is known, the name will be used as identifier, otherwise 'play_forest' is used
`{reviews()}` for a vanilla review, `{reviews(name, play_forest)}` to review a play forest. If a name is known, the name will be used as identifier, otherwise 'play_forest' is used
### opening_hours_table
Creates an opening-hours table. Usage: {opening_hours_table(opening_hours)} to create a table of the tag 'opening_hours'.
@ -73,63 +139,87 @@ fallback | undefined | The identifier to use, if <i>tags[subjectKey]</i> as spec
name | default | description
------ | --------- | -------------
key | opening_hours | The tagkey from which the table is constructed.
prefix | _empty string_ | Remove this string from the start of the value before parsing. __Note: use `&LPARENs` to indicate `(` if needed__
postfix | _empty string_ | Remove this string from the end of the value before parsing. __Note: use `&RPARENs` to indicate `)` if needed__
#### Example usage
`{opening_hours_table(opening_hours)}`
A normal opening hours table can be invoked with `{opening_hours_table()}`. A table for e.g. conditional access with opening hours can be `{opening_hours_table(access:conditional, no @ &LPARENS, &RPARENS)}`
### live
Downloads a JSON from the given URL, e.g. '{live(example.org/data.json, shorthand:x.y.z, other:a.b.c, shorthand)}' will download the given file, will create an object {shorthand: json[x][y][z], other: json[a][b][c] out of it and will return 'other' or 'json[a][b][c]. This is made to use in combination with tags, e.g. {live({url}, {url:format}, needed_value)}
name | default | description
------ | --------- | -------------
Url | undefined | The URL to load
Shorthands | undefined | A list of shorthands, of the format 'shorthandname:path.path.path'. separated by ;
path | undefined | The path (or shorthand) that should be returned
Url | _undefined_ | The URL to load
Shorthands | _undefined_ | A list of shorthands, of the format 'shorthandname:path.path.path'. separated by ;
path | _undefined_ | The path (or shorthand) that should be returned
#### Example usage
{live({url},{url:format},hour)} {live(https://data.mobility.brussels/bike/api/counts/?request=live&featureID=CB2105,hour:data.hour_cnt;day:data.day_cnt;year:data.year_cnt,hour)}
{live({url},{url:format},hour)} {live(https://data.mobility.brussels/bike/api/counts/?request=live&featureID=CB2105,hour:data.hour_cnt;day:data.day_cnt;year:data.year_cnt,hour)}
### histogram
Create a histogram for a list of given values, read from the properties.
name | default | description
------ | --------- | -------------
key | undefined | The key to be read and to generate a histogram from
title | | The text to put above the given values column
countHeader | | The text to put above the counts
colors* | undefined | (Matches all resting arguments - optional) Matches a regex onto a color value, e.g. `3[a-zA-Z+-]*:#33cc33`
key | _undefined_ | The key to be read and to generate a histogram from
title | _empty string_ | The text to put above the given values column
countHeader | _empty string_ | The text to put above the counts
colors* | _undefined_ | (Matches all resting arguments - optional) Matches a regex onto a color value, e.g. `3[a-zA-Z+-]*:#33cc33`
#### Example usage
`{histogram('some_key')}` with properties being `{some_key: ['a','b','a','c']} to create a histogram
`{histogram('some_key')}` with properties being `{some_key: ['a','b','a','c']} to create a histogram
### share_link
Creates a link that (attempts to) open the native 'share'-screen
name | default | description
------ | --------- | -------------
url | undefined | The url to share (default: current URL)
url | _undefined_ | The url to share (default: current URL)
#### Example usage
{share_link()} to share the current page, {share_link(<some_url>)} to share the given url
{share_link()} to share the current page, {share_link(<some_url>)} to share the given url
### canonical
Converts a short, canonical value into the long, translated text
name | default | description
------ | --------- | -------------
key | undefined | The key of the tag to give the canonical text for
key | _undefined_ | The key of the tag to give the canonical text for
#### Example usage
{canonical(length)} will give 42 metre (in french)
{canonical(length)} will give 42 metre (in french)
### import_button
This button will copy the data from an external dataset into OpenStreetMap. It is only functional in official themes but can be tested in unofficial themes.
#### Importing a dataset into OpenStreetMap: requirements
If you want to import a dataset, make sure that:
1. The dataset to import has a suitable license
@ -138,36 +228,104 @@ If you want to import a dataset, make sure that:
There are also some technicalities in your theme to keep in mind:
1. The new point will be added and will flow through the program as any other new point as if it came from OSM.
1. The new feature will be added and will flow through the program as any other new point as if it came from OSM.
This means that there should be a layer which will match the new tags and which will display it.
2. The original point from your geojson layer will gain the tag '_imported=yes'.
2. The original feature from your geojson layer will gain the tag '_imported=yes'.
This should be used to change the appearance or even to hide it (eg by changing the icon size to zero)
3. There should be a way for the theme to detect previously imported points, even after reloading.
A reference number to the original dataset is an excellen way to do this
A reference number to the original dataset is an excellent way to do this
4. When importing ways, the theme creator is also responsible of avoiding overlapping ways.
#### Disabled in unofficial themes
The import button can be tested in an unofficial theme by adding `test=true` or `backend=osm-test` as [URL-paramter](URL_Parameters.md).
The import button will show up then. If in testmode, you can read the changeset-XML directly in the web console.
In the case that MapComplete is pointed to the testing grounds, the edit will be made on https://master.apis.dev.openstreetmap.org
#### Specifying which tags to copy or add
The argument `tags` of the import button takes a `;`-seperated list of tags to add.
These can either be a tag to add, such as `amenity=fast_food` or can use a substitution, e.g. `addr:housenumber=$number`.
This new point will then have the tags `amenity=fast_food` and `addr:housenumber` with the value that was saved in `number` in the original feature.
If a value to substitute is undefined, empty string will be used instead.
This supports multiple values, e.g. `ref=$source:geometry:type/$source:geometry:ref`
Remark that the syntax is slightly different then expected; it uses '$' to note a value to copy, followed by a name (matched with `[a-zA-Z0-9_:]*`). Sadly, delimiting with `{}` as these already mark the boundaries of the special rendering...
Note that these values can be prepare with javascript in the theme by using a [calculatedTag](calculatedTags.md#calculating-tags-with-javascript)
name | default | description
------ | --------- | -------------
tags | undefined | Tags to copy-specification. This contains one or more pairs (seperated by a `;`), e.g. `amenity=fast_food; addr:housenumber=$number`. This new point will then have the tags `amenity=fast_food` and `addr:housenumber` with the value that was saved in `number` in the original feature. (Hint: prepare these values, e.g. with calculatedTags)
targetLayer | _undefined_ | The id of the layer where this point should end up. This is not very strict, it will simply result in checking that this layer is shown preventing possible duplicate elements
tags | _undefined_ | The tags to add onto the new object - see specification above
text | Import this data into OpenStreetMap | The text to show on the button
icon | ./assets/svg/addSmall.svg | A nice icon to show in the button
minzoom | 18 | How far the contributor must zoom in before being able to import the point
Snap onto layer(s)/replace geometry with this other way | _undefined_ | - If the value corresponding with this key starts with 'way/' and the feature is a LineString or Polygon, the original OSM-way geometry will be changed to match the new geometry
- If a way of the given layer(s) is closeby, will snap the new point onto this way (similar as preset might snap). To show multiple layers to snap onto, use a `;`-seperated list
snap max distance | 5 | The maximum distance that this point will move to snap onto a layer (in meters)
#### Example usage
`{import_button(,Import this data into OpenStreetMap,./assets/svg/addSmall.svg,18)}`
`{import_button(,,Import this data into OpenStreetMap,./assets/svg/addSmall.svg,18,,5)}`
### multi_apply
A button to apply the tagging of this object onto a list of other features. This is an advanced feature for which you'll need calculatedTags
name | default | description
------ | --------- | -------------
feature_ids | undefined | A JSOn-serialized list of IDs of features to apply the tagging on
keys | undefined | One key (or multiple keys, seperated by ';') of the attribute that should be copied onto the other features.
text | undefined | The text to show on the button
autoapply | undefined | A boolean indicating wether this tagging should be applied automatically if the relevant tags on this object are changed. A visual element indicating the multi_apply is still shown
overwrite | undefined | If set to 'true', the tags on the other objects will always be overwritten. The default behaviour will be to only change the tags on other objects if they are either undefined or had the same value before the change
feature_ids | _undefined_ | A JSOn-serialized list of IDs of features to apply the tagging on
keys | _undefined_ | One key (or multiple keys, seperated by ';') of the attribute that should be copied onto the other features.
text | _undefined_ | The text to show on the button
autoapply | _undefined_ | A boolean indicating wether this tagging should be applied automatically if the relevant tags on this object are changed. A visual element indicating the multi_apply is still shown
overwrite | _undefined_ | If set to 'true', the tags on the other objects will always be overwritten. The default behaviour will be to only change the tags on other objects if they are either undefined or had the same value before the change
#### Example usage
{multi_apply(_features_with_the_same_name_within_100m, name:etymology:wikidata;name:etymology, Apply etymology information on all nearby objects with the same name)} Generated from UI/SpecialVisualisations.ts
{multi_apply(_features_with_the_same_name_within_100m, name:etymology:wikidata;name:etymology, Apply etymology information on all nearby objects with the same name)}
### tag_apply
Shows a big button; clicking this button will apply certain tags onto the feature.
The first argument takes a specification of which tags to add.
These can either be a tag to add, such as `amenity=fast_food` or can use a substitution, e.g. `addr:housenumber=$number`.
This new point will then have the tags `amenity=fast_food` and `addr:housenumber` with the value that was saved in `number` in the original feature.
If a value to substitute is undefined, empty string will be used instead.
This supports multiple values, e.g. `ref=$source:geometry:type/$source:geometry:ref`
Remark that the syntax is slightly different then expected; it uses '$' to note a value to copy, followed by a name (matched with `[a-zA-Z0-9_:]*`). Sadly, delimiting with `{}` as these already mark the boundaries of the special rendering...
Note that these values can be prepare with javascript in the theme by using a [calculatedTag](calculatedTags.md#calculating-tags-with-javascript)
name | default | description
------ | --------- | -------------
tags_to_apply | _undefined_ | A specification of the tags to apply
message | _undefined_ | The text to show to the contributor
image | _undefined_ | An image to show to the contributor on the button
id_of_object_to_apply_this_one | _undefined_ | If specified, applies the the tags onto _another_ object. The id will be read from properties[id_of_object_to_apply_this_one] of the selected object. The tags are still calculated based on the tags of the _selected_ element
#### Example usage
`{tag_apply(survey_date:=$_now:date, Surveyed today!)}`
This document is autogenerated from UI/SpecialVisualisations.ts

View file

@ -112,7 +112,7 @@
},
{
"key": "wheelchair",
"description": "Layer 'Defibrillators' shows wheelchair=designated with a fixed text, namely 'This place is specially adapated for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open AED Map')",
"description": "Layer 'Defibrillators' shows wheelchair=designated with a fixed text, namely 'This place is specially adapted for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open AED Map')",
"value": "designated"
},
{

View file

@ -103,7 +103,7 @@
},
{
"key": "wheelchair",
"description": "Layer 'Cafés and pubs' shows wheelchair=designated with a fixed text, namely 'This place is specially adapated for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
"description": "Layer 'Cafés and pubs' shows wheelchair=designated with a fixed text, namely 'This place is specially adapted for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
"value": "designated"
},
{
@ -121,6 +121,26 @@
"description": "Layer 'Cafés and pubs' shows wheelchair=no with a fixed text, namely 'This place is not reachable with a wheelchair' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
"value": "no"
},
{
"key": "service:electricity",
"description": "Layer 'Cafés and pubs' shows service:electricity=yes with a fixed text, namely 'There are plenty of domestic sockets available to customers seated indoors, where they can charge their electronics' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
"value": "yes"
},
{
"key": "service:electricity",
"description": "Layer 'Cafés and pubs' shows service:electricity=limited with a fixed text, namely 'There are a few domestic sockets available to customers seated indoors, where they can charge their electronics' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
"value": "limited"
},
{
"key": "service:electricity",
"description": "Layer 'Cafés and pubs' shows service:electricity=ask with a fixed text, namely 'There are no sockets available indoors to customers, but charging might be possible if the staff is asked' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
"value": "ask"
},
{
"key": "service:electricity",
"description": "Layer 'Cafés and pubs' shows service:electricity=no with a fixed text, namely 'There are a no domestic sockets available to customers seated indoors' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
"value": "no"
},
{
"key": "dog",
"description": "Layer 'Cafés and pubs' shows dog=yes with a fixed text, namely 'Dogs are allowed' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",

View file

@ -48,7 +48,7 @@
},
{
"key": "bicycle",
"description": "Layer 'Charging stations' shows bicycle=yes with a fixed text, namely '<b>bicycles</b> can be charged here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"description": "Layer 'Charging stations' shows bicycle=yes with a fixed text, namely '<b>Bcycles</b> can be charged here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
@ -92,7 +92,7 @@
},
{
"key": "access",
"description": "Layer 'Charging stations' shows access=customers with a fixed text, namely 'Only customers of the place this station belongs to can use this charging station<br/><span class='subtle'>E.g. a charging station operated by hotel which is only usable by their guests</span> ' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"description": "Layer 'Charging stations' shows access=customers with a fixed text, namely 'Only customers of the place this station belongs to can use this charging station<br/><span class='subtle'>E.g. a charging station operated by hotel which is only usable by their guests</span>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "customers"
},
{
@ -252,677 +252,66 @@
"key": "socket:schuko",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:schuko' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:schuko:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:schuko:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:schuko:voltage",
"description": "Layer 'Charging stations' shows socket:socket:schuko:voltage=230 V with a fixed text, namely '<div style='display: inline-block'><b><b>Schuko wall plug</b> without ground pin (CEE7/4 type F)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/CEE7_4F.svg'/></div> outputs 230 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "230 V"
},
{
"key": "socket:schuko:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:schuko:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:schuko:current",
"description": "Layer 'Charging stations' shows socket:socket:schuko:current=16 A with a fixed text, namely '<div style='display: inline-block'><b><b>Schuko wall plug</b> without ground pin (CEE7/4 type F)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/CEE7_4F.svg'/></div> outputs at most 16 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "16 A"
},
{
"key": "socket:schuko:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:schuko:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:schuko:output",
"description": "Layer 'Charging stations' shows socket:socket:schuko:output=3.6 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Schuko wall plug</b> without ground pin (CEE7/4 type F)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/CEE7_4F.svg'/></div> outputs at most 3.6 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "3.6 kw"
},
{
"key": "socket:typee",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:typee' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:typee:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:typee:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:typee:voltage",
"description": "Layer 'Charging stations' shows socket:socket:typee:voltage=230 V with a fixed text, namely '<div style='display: inline-block'><b><b>European wall plug</b> with ground pin (CEE7/4 type E)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/TypeE.svg'/></div> outputs 230 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "230 V"
},
{
"key": "socket:typee:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:typee:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:typee:current",
"description": "Layer 'Charging stations' shows socket:socket:typee:current=16 A with a fixed text, namely '<div style='display: inline-block'><b><b>European wall plug</b> with ground pin (CEE7/4 type E)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/TypeE.svg'/></div> outputs at most 16 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "16 A"
},
{
"key": "socket:typee:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:typee:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:typee:output",
"description": "Layer 'Charging stations' shows socket:socket:typee:output=3 kw with a fixed text, namely '<div style='display: inline-block'><b><b>European wall plug</b> with ground pin (CEE7/4 type E)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/TypeE.svg'/></div> outputs at most 3 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "3 kw"
},
{
"key": "socket:socket:typee:output",
"description": "Layer 'Charging stations' shows socket:socket:typee:output=22 kw with a fixed text, namely '<div style='display: inline-block'><b><b>European wall plug</b> with ground pin (CEE7/4 type E)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/TypeE.svg'/></div> outputs at most 22 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "22 kw"
},
{
"key": "socket:chademo",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:chademo' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:chademo:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:chademo:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:chademo:voltage",
"description": "Layer 'Charging stations' shows socket:socket:chademo:voltage=500 V with a fixed text, namely '<div style='display: inline-block'><b><b>Chademo</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Chademo_type4.svg'/></div> outputs 500 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "500 V"
},
{
"key": "socket:chademo:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:chademo:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:chademo:current",
"description": "Layer 'Charging stations' shows socket:socket:chademo:current=120 A with a fixed text, namely '<div style='display: inline-block'><b><b>Chademo</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Chademo_type4.svg'/></div> outputs at most 120 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "120 A"
},
{
"key": "socket:chademo:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:chademo:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:chademo:output",
"description": "Layer 'Charging stations' shows socket:socket:chademo:output=50 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Chademo</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Chademo_type4.svg'/></div> outputs at most 50 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "50 kw"
},
{
"key": "socket:type1_cable",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type1_cable' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:type1_cable:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type1_cable:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type1_cable:voltage",
"description": "Layer 'Charging stations' shows socket:socket:type1_cable:voltage=200 V with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 with cable</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div> outputs 200 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "200 V"
},
{
"key": "socket:socket:type1_cable:voltage",
"description": "Layer 'Charging stations' shows socket:socket:type1_cable:voltage=240 V with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 with cable</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div> outputs 240 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "240 V"
},
{
"key": "socket:type1_cable:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type1_cable:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type1_cable:current",
"description": "Layer 'Charging stations' shows socket:socket:type1_cable:current=32 A with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 with cable</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div> outputs at most 32 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "32 A"
},
{
"key": "socket:type1_cable:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type1_cable:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type1_cable:output",
"description": "Layer 'Charging stations' shows socket:socket:type1_cable:output=3.7 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 with cable</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div> outputs at most 3.7 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "3.7 kw"
},
{
"key": "socket:socket:type1_cable:output",
"description": "Layer 'Charging stations' shows socket:socket:type1_cable:output=7 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 with cable</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div> outputs at most 7 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "7 kw"
},
{
"key": "socket:type1",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type1' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:type1:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type1:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type1:voltage",
"description": "Layer 'Charging stations' shows socket:socket:type1:voltage=200 V with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 <i>without</i> cable</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div> outputs 200 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "200 V"
},
{
"key": "socket:socket:type1:voltage",
"description": "Layer 'Charging stations' shows socket:socket:type1:voltage=240 V with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 <i>without</i> cable</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div> outputs 240 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "240 V"
},
{
"key": "socket:type1:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type1:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type1:current",
"description": "Layer 'Charging stations' shows socket:socket:type1:current=32 A with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 <i>without</i> cable</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div> outputs at most 32 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "32 A"
},
{
"key": "socket:type1:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type1:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type1:output",
"description": "Layer 'Charging stations' shows socket:socket:type1:output=3.7 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 <i>without</i> cable</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div> outputs at most 3.7 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "3.7 kw"
},
{
"key": "socket:socket:type1:output",
"description": "Layer 'Charging stations' shows socket:socket:type1:output=6.6 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 <i>without</i> cable</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div> outputs at most 6.6 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "6.6 kw"
},
{
"key": "socket:socket:type1:output",
"description": "Layer 'Charging stations' shows socket:socket:type1:output=7 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 <i>without</i> cable</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div> outputs at most 7 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "7 kw"
},
{
"key": "socket:socket:type1:output",
"description": "Layer 'Charging stations' shows socket:socket:type1:output=7.2 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 <i>without</i> cable</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div> outputs at most 7.2 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "7.2 kw"
},
{
"key": "socket:type1_combo",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type1_combo' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:type1_combo:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type1_combo:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type1_combo:voltage",
"description": "Layer 'Charging stations' shows socket:socket:type1_combo:voltage=400 V with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 CCS</b> (aka Type 1 Combo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1-ccs.svg'/></div> outputs 400 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "400 V"
},
{
"key": "socket:socket:type1_combo:voltage",
"description": "Layer 'Charging stations' shows socket:socket:type1_combo:voltage=1000 V with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 CCS</b> (aka Type 1 Combo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1-ccs.svg'/></div> outputs 1000 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "1000 V"
},
{
"key": "socket:type1_combo:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type1_combo:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type1_combo:current",
"description": "Layer 'Charging stations' shows socket:socket:type1_combo:current=50 A with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 CCS</b> (aka Type 1 Combo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1-ccs.svg'/></div> outputs at most 50 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "50 A"
},
{
"key": "socket:socket:type1_combo:current",
"description": "Layer 'Charging stations' shows socket:socket:type1_combo:current=125 A with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 CCS</b> (aka Type 1 Combo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1-ccs.svg'/></div> outputs at most 125 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "125 A"
},
{
"key": "socket:type1_combo:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type1_combo:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type1_combo:output",
"description": "Layer 'Charging stations' shows socket:socket:type1_combo:output=50 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 CCS</b> (aka Type 1 Combo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1-ccs.svg'/></div> outputs at most 50 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "50 kw"
},
{
"key": "socket:socket:type1_combo:output",
"description": "Layer 'Charging stations' shows socket:socket:type1_combo:output=62.5 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 CCS</b> (aka Type 1 Combo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1-ccs.svg'/></div> outputs at most 62.5 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "62.5 kw"
},
{
"key": "socket:socket:type1_combo:output",
"description": "Layer 'Charging stations' shows socket:socket:type1_combo:output=150 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 CCS</b> (aka Type 1 Combo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1-ccs.svg'/></div> outputs at most 150 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "150 kw"
},
{
"key": "socket:socket:type1_combo:output",
"description": "Layer 'Charging stations' shows socket:socket:type1_combo:output=350 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 1 CCS</b> (aka Type 1 Combo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1-ccs.svg'/></div> outputs at most 350 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "350 kw"
},
{
"key": "socket:tesla_supercharger",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_supercharger' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:tesla_supercharger:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_supercharger:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:tesla_supercharger:voltage",
"description": "Layer 'Charging stations' shows socket:socket:tesla_supercharger:voltage=480 V with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> outputs 480 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "480 V"
},
{
"key": "socket:tesla_supercharger:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_supercharger:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:tesla_supercharger:current",
"description": "Layer 'Charging stations' shows socket:socket:tesla_supercharger:current=125 A with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> outputs at most 125 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "125 A"
},
{
"key": "socket:socket:tesla_supercharger:current",
"description": "Layer 'Charging stations' shows socket:socket:tesla_supercharger:current=350 A with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> outputs at most 350 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "350 A"
},
{
"key": "socket:tesla_supercharger:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_supercharger:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:tesla_supercharger:output",
"description": "Layer 'Charging stations' shows socket:socket:tesla_supercharger:output=120 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> outputs at most 120 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "120 kw"
},
{
"key": "socket:socket:tesla_supercharger:output",
"description": "Layer 'Charging stations' shows socket:socket:tesla_supercharger:output=150 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> outputs at most 150 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "150 kw"
},
{
"key": "socket:socket:tesla_supercharger:output",
"description": "Layer 'Charging stations' shows socket:socket:tesla_supercharger:output=250 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> outputs at most 250 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "250 kw"
},
{
"key": "socket:type2",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type2' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:type2:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type2:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type2:voltage",
"description": "Layer 'Charging stations' shows socket:socket:type2:voltage=230 V with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_socket.svg'/></div> outputs 230 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "230 V"
},
{
"key": "socket:socket:type2:voltage",
"description": "Layer 'Charging stations' shows socket:socket:type2:voltage=400 V with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_socket.svg'/></div> outputs 400 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "400 V"
},
{
"key": "socket:type2:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type2:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type2:current",
"description": "Layer 'Charging stations' shows socket:socket:type2:current=16 A with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_socket.svg'/></div> outputs at most 16 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "16 A"
},
{
"key": "socket:socket:type2:current",
"description": "Layer 'Charging stations' shows socket:socket:type2:current=32 A with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_socket.svg'/></div> outputs at most 32 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "32 A"
},
{
"key": "socket:type2:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type2:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type2:output",
"description": "Layer 'Charging stations' shows socket:socket:type2:output=11 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_socket.svg'/></div> outputs at most 11 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "11 kw"
},
{
"key": "socket:socket:type2:output",
"description": "Layer 'Charging stations' shows socket:socket:type2:output=22 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_socket.svg'/></div> outputs at most 22 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "22 kw"
},
{
"key": "socket:type2_combo",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type2_combo' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:type2_combo:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type2_combo:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type2_combo:voltage",
"description": "Layer 'Charging stations' shows socket:socket:type2_combo:voltage=500 V with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2 CCS</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div> outputs 500 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "500 V"
},
{
"key": "socket:socket:type2_combo:voltage",
"description": "Layer 'Charging stations' shows socket:socket:type2_combo:voltage=920 V with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2 CCS</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div> outputs 920 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "920 V"
},
{
"key": "socket:type2_combo:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type2_combo:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type2_combo:current",
"description": "Layer 'Charging stations' shows socket:socket:type2_combo:current=125 A with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2 CCS</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div> outputs at most 125 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "125 A"
},
{
"key": "socket:socket:type2_combo:current",
"description": "Layer 'Charging stations' shows socket:socket:type2_combo:current=350 A with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2 CCS</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div> outputs at most 350 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "350 A"
},
{
"key": "socket:type2_combo:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type2_combo:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type2_combo:output",
"description": "Layer 'Charging stations' shows socket:socket:type2_combo:output=50 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2 CCS</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div> outputs at most 50 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "50 kw"
},
{
"key": "socket:type2_cable",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type2_cable' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:type2_cable:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type2_cable:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type2_cable:voltage",
"description": "Layer 'Charging stations' shows socket:socket:type2_cable:voltage=230 V with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2 with cable</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div> outputs 230 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "230 V"
},
{
"key": "socket:socket:type2_cable:voltage",
"description": "Layer 'Charging stations' shows socket:socket:type2_cable:voltage=400 V with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2 with cable</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div> outputs 400 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "400 V"
},
{
"key": "socket:type2_cable:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type2_cable:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type2_cable:current",
"description": "Layer 'Charging stations' shows socket:socket:type2_cable:current=16 A with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2 with cable</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div> outputs at most 16 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "16 A"
},
{
"key": "socket:socket:type2_cable:current",
"description": "Layer 'Charging stations' shows socket:socket:type2_cable:current=32 A with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2 with cable</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div> outputs at most 32 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "32 A"
},
{
"key": "socket:type2_cable:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:type2_cable:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:type2_cable:output",
"description": "Layer 'Charging stations' shows socket:socket:type2_cable:output=11 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2 with cable</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div> outputs at most 11 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "11 kw"
},
{
"key": "socket:socket:type2_cable:output",
"description": "Layer 'Charging stations' shows socket:socket:type2_cable:output=22 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Type 2 with cable</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div> outputs at most 22 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "22 kw"
},
{
"key": "socket:tesla_supercharger_ccs",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_supercharger_ccs' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:tesla_supercharger_ccs:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_supercharger_ccs:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:tesla_supercharger_ccs:voltage",
"description": "Layer 'Charging stations' shows socket:socket:tesla_supercharger_ccs:voltage=500 V with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger CCS</b> (a branded type2_css)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div> outputs 500 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "500 V"
},
{
"key": "socket:socket:tesla_supercharger_ccs:voltage",
"description": "Layer 'Charging stations' shows socket:socket:tesla_supercharger_ccs:voltage=920 V with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger CCS</b> (a branded type2_css)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div> outputs 920 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "920 V"
},
{
"key": "socket:tesla_supercharger_ccs:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_supercharger_ccs:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:tesla_supercharger_ccs:current",
"description": "Layer 'Charging stations' shows socket:socket:tesla_supercharger_ccs:current=125 A with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger CCS</b> (a branded type2_css)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div> outputs at most 125 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "125 A"
},
{
"key": "socket:socket:tesla_supercharger_ccs:current",
"description": "Layer 'Charging stations' shows socket:socket:tesla_supercharger_ccs:current=350 A with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger CCS</b> (a branded type2_css)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div> outputs at most 350 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "350 A"
},
{
"key": "socket:tesla_supercharger_ccs:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_supercharger_ccs:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:tesla_supercharger_ccs:output",
"description": "Layer 'Charging stations' shows socket:socket:tesla_supercharger_ccs:output=50 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger CCS</b> (a branded type2_css)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div> outputs at most 50 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "50 kw"
},
{
"key": "socket:tesla_destination",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_destination' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:tesla_destination:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_destination:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:tesla_destination:voltage",
"description": "Layer 'Charging stations' shows socket:socket:tesla_destination:voltage=480 V with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger (destination)</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> outputs 480 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "480 V"
},
{
"key": "socket:tesla_destination:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_destination:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:tesla_destination:current",
"description": "Layer 'Charging stations' shows socket:socket:tesla_destination:current=125 A with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger (destination)</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> outputs at most 125 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "125 A"
},
{
"key": "socket:socket:tesla_destination:current",
"description": "Layer 'Charging stations' shows socket:socket:tesla_destination:current=350 A with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger (destination)</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> outputs at most 350 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "350 A"
},
{
"key": "socket:tesla_destination:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_destination:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:tesla_destination:output",
"description": "Layer 'Charging stations' shows socket:socket:tesla_destination:output=120 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger (destination)</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> outputs at most 120 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "120 kw"
},
{
"key": "socket:socket:tesla_destination:output",
"description": "Layer 'Charging stations' shows socket:socket:tesla_destination:output=150 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger (destination)</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> outputs at most 150 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "150 kw"
},
{
"key": "socket:socket:tesla_destination:output",
"description": "Layer 'Charging stations' shows socket:socket:tesla_destination:output=250 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla Supercharger (destination)</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> outputs at most 250 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "250 kw"
},
{
"key": "socket:tesla_destination",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_destination' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:tesla_destination:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_destination:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:tesla_destination:voltage",
"description": "Layer 'Charging stations' shows socket:socket:tesla_destination:voltage=230 V with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla supercharger (destination</b> (A Type 2 with cable branded as tesla)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div> outputs 230 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "230 V"
},
{
"key": "socket:socket:tesla_destination:voltage",
"description": "Layer 'Charging stations' shows socket:socket:tesla_destination:voltage=400 V with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla supercharger (destination</b> (A Type 2 with cable branded as tesla)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div> outputs 400 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "400 V"
},
{
"key": "socket:tesla_destination:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_destination:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:tesla_destination:current",
"description": "Layer 'Charging stations' shows socket:socket:tesla_destination:current=16 A with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla supercharger (destination</b> (A Type 2 with cable branded as tesla)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div> outputs at most 16 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "16 A"
},
{
"key": "socket:socket:tesla_destination:current",
"description": "Layer 'Charging stations' shows socket:socket:tesla_destination:current=32 A with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla supercharger (destination</b> (A Type 2 with cable branded as tesla)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div> outputs at most 32 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "32 A"
},
{
"key": "socket:tesla_destination:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:tesla_destination:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:tesla_destination:output",
"description": "Layer 'Charging stations' shows socket:socket:tesla_destination:output=11 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla supercharger (destination</b> (A Type 2 with cable branded as tesla)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div> outputs at most 11 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "11 kw"
},
{
"key": "socket:socket:tesla_destination:output",
"description": "Layer 'Charging stations' shows socket:socket:tesla_destination:output=22 kw with a fixed text, namely '<div style='display: inline-block'><b><b>Tesla supercharger (destination</b> (A Type 2 with cable branded as tesla)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div> outputs at most 22 kw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "22 kw"
},
{
"key": "socket:USB-A",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:USB-A' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:USB-A:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:USB-A:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:USB-A:voltage",
"description": "Layer 'Charging stations' shows socket:socket:USB-A:voltage=5 V with a fixed text, namely '<div style='display: inline-block'><b><b>USB</b> to charge phones and small electronics</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/usb_port.svg'/></div> outputs 5 volt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "5 V"
},
{
"key": "socket:USB-A:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:USB-A:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:USB-A:current",
"description": "Layer 'Charging stations' shows socket:socket:USB-A:current=1 A with a fixed text, namely '<div style='display: inline-block'><b><b>USB</b> to charge phones and small electronics</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/usb_port.svg'/></div> outputs at most 1 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "1 A"
},
{
"key": "socket:socket:USB-A:current",
"description": "Layer 'Charging stations' shows socket:socket:USB-A:current=2 A with a fixed text, namely '<div style='display: inline-block'><b><b>USB</b> to charge phones and small electronics</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/usb_port.svg'/></div> outputs at most 2 A' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "2 A"
},
{
"key": "socket:USB-A:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:USB-A:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:socket:USB-A:output",
"description": "Layer 'Charging stations' shows socket:socket:USB-A:output=5w with a fixed text, namely '<div style='display: inline-block'><b><b>USB</b> to charge phones and small electronics</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/usb_port.svg'/></div> outputs at most 5w' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "5w"
},
{
"key": "socket:socket:USB-A:output",
"description": "Layer 'Charging stations' shows socket:socket:USB-A:output=10w with a fixed text, namely '<div style='display: inline-block'><b><b>USB</b> to charge phones and small electronics</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/usb_port.svg'/></div> outputs at most 10w' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "10w"
},
{
"key": "socket:bosch_3pin",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:bosch_3pin' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:bosch_3pin:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:bosch_3pin:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:bosch_3pin:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:bosch_3pin:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:bosch_3pin:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:bosch_3pin:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:bosch_5pin",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:bosch_5pin' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:bosch_5pin:voltage",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:bosch_5pin:voltage' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:bosch_5pin:current",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:bosch_5pin:current' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "socket:bosch_5pin:output",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'socket:bosch_5pin:output' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "authentication:membership_card",
"description": "Layer 'Charging stations' shows authentication:membership_card=yes with a fixed text, namely 'Authentication by a membership card' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:app",
"description": "Layer 'Charging stations' shows authentication:app=yes with a fixed text, namely 'Authentication by an app' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:phone_call",
"description": "Layer 'Charging stations' shows authentication:phone_call=yes with a fixed text, namely 'Authentication via phone call is available' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:short_message",
"description": "Layer 'Charging stations' shows authentication:short_message=yes with a fixed text, namely 'Authentication via phone call is available' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:nfc",
"description": "Layer 'Charging stations' shows authentication:nfc=yes with a fixed text, namely 'Authentication via NFC is available' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:money_card",
"description": "Layer 'Charging stations' shows authentication:money_card=yes with a fixed text, namely 'Authentication via Money Card is available' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:debit_card",
"description": "Layer 'Charging stations' shows authentication:debit_card=yes with a fixed text, namely 'Authentication via debit card is available' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:none",
"description": "Layer 'Charging stations' shows authentication:none=yes with a fixed text, namely 'No authentication is needed' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:phone_call:number",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'authentication:phone_call:number' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "opening_hours",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'opening_hours' (in the MapComplete.osm.be theme 'Charging stations')"
@ -932,20 +321,75 @@
"description": "Layer 'Charging stations' shows opening_hours=24/7 with a fixed text, namely '24/7 opened (including holidays)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "24/7"
},
{
"key": "charge",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'charge' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "fee",
"description": "Layer 'Charging stations' shows fee=no&charge= with a fixed text, namely 'Free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"description": "Layer 'Charging stations' shows fee=no with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'Charging stations')",
"value": "no"
},
{
"key": "charge",
"description": "Layer 'Charging stations' shows fee=no&charge= with a fixed text, namely 'Free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key charge.",
"key": "fee",
"description": "Layer 'Charging stations' shows fee=no&fee:conditional=&charge=&authentication:none=yes with a fixed text, namely 'Free to use (without authenticating)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "no"
},
{
"key": "fee:conditional",
"description": "Layer 'Charging stations' shows fee=no&fee:conditional=&charge=&authentication:none=yes with a fixed text, namely 'Free to use (without authenticating)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key fee:conditional.",
"value": ""
},
{
"key": "charge",
"description": "Layer 'Charging stations' shows fee=no&fee:conditional=&charge=&authentication:none=yes with a fixed text, namely 'Free to use (without authenticating)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key charge.",
"value": ""
},
{
"key": "authentication:none",
"description": "Layer 'Charging stations' shows fee=no&fee:conditional=&charge=&authentication:none=yes with a fixed text, namely 'Free to use (without authenticating)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "fee",
"description": "Layer 'Charging stations' shows fee=no&fee:conditional=&charge=&authentication:none=no with a fixed text, namely 'Free to use, but one has to authenticate' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "no"
},
{
"key": "fee:conditional",
"description": "Layer 'Charging stations' shows fee=no&fee:conditional=&charge=&authentication:none=no with a fixed text, namely 'Free to use, but one has to authenticate' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key fee:conditional.",
"value": ""
},
{
"key": "charge",
"description": "Layer 'Charging stations' shows fee=no&fee:conditional=&charge=&authentication:none=no with a fixed text, namely 'Free to use, but one has to authenticate' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key charge.",
"value": ""
},
{
"key": "authentication:none",
"description": "Layer 'Charging stations' shows fee=no&fee:conditional=&charge=&authentication:none=no with a fixed text, namely 'Free to use, but one has to authenticate' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "no"
},
{
"key": "fee",
"description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/... who operates the charging station' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "fee:conditional",
"description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/... who operates the charging station' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "no @ customers"
},
{
"key": "fee",
"description": "Layer 'Charging stations' shows fee=yes&fee:conditional= with a fixed text, namely 'Paid use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "fee:conditional",
"description": "Layer 'Charging stations' shows fee=yes&fee:conditional= with a fixed text, namely 'Paid use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key fee:conditional.",
"value": ""
},
{
"key": "charge",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'charge' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "payment:cash",
"description": "Layer 'Charging stations' shows payment:cash=yes with a fixed text, namely 'Cash is accepted here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
@ -966,6 +410,50 @@
"description": "Layer 'Charging stations' shows payment:membership_card=yes with a fixed text, namely 'Payment is done using a membership card' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:membership_card",
"description": "Layer 'Charging stations' shows authentication:membership_card=yes with a fixed text, namely 'Authentication by a membership card' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:app",
"description": "Layer 'Charging stations' shows authentication:app=yes with a fixed text, namely 'Authentication by an app' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:phone_call",
"description": "Layer 'Charging stations' shows authentication:phone_call=yes with a fixed text, namely 'Authentication via phone call is available' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:short_message",
"description": "Layer 'Charging stations' shows authentication:short_message=yes with a fixed text, namely 'Authentication via SMS is available' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:nfc",
"description": "Layer 'Charging stations' shows authentication:nfc=yes with a fixed text, namely 'Authentication via NFC is available' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:money_card",
"description": "Layer 'Charging stations' shows authentication:money_card=yes with a fixed text, namely 'Authentication via Money Card is available' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:debit_card",
"description": "Layer 'Charging stations' shows authentication:debit_card=yes with a fixed text, namely 'Authentication via debit card is available' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:none",
"description": "Layer 'Charging stations' shows authentication:none=yes with a fixed text, namely 'Charging here is (also) possible without authentication' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "yes"
},
{
"key": "authentication:phone_call:number",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'authentication:phone_call:number' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "maxstay",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'maxstay' (in the MapComplete.osm.be theme 'Charging stations')"
@ -1053,51 +541,131 @@
"key": "ref",
"description": "Layer 'Charging stations' shows and asks freeform values for key 'ref' (in the MapComplete.osm.be theme 'Charging stations')"
},
{
"key": "operational_status",
"description": "Layer 'Charging stations' shows operational_status=broken with a fixed text, namely 'This charging station is broken' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "broken"
},
{
"key": "planned:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=charging_station&amenity= with a fixed text, namely 'A charging station is planned here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "charging_station"
},
{
"key": "amenity",
"description": "Layer 'Charging stations' shows planned:amenity=charging_station&amenity= with a fixed text, namely 'A charging station is planned here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key amenity.",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=&operational_status=broken&amenity=charging_station with a fixed text, namely 'This charging station works' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key planned:amenity.",
"value": ""
},
{
"key": "construction:amenity",
"description": "Layer 'Charging stations' shows construction:amenity=charging_station&amenity= with a fixed text, namely 'A charging station is constructed here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "charging_station"
},
{
"key": "amenity",
"description": "Layer 'Charging stations' shows construction:amenity=charging_station&amenity= with a fixed text, namely 'A charging station is constructed here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key amenity.",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=&operational_status=broken&amenity=charging_station with a fixed text, namely 'This charging station works' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key construction:amenity.",
"value": ""
},
{
"key": "disused:amenity",
"description": "Layer 'Charging stations' shows disused:amenity=charging_station&amenity= with a fixed text, namely 'This charging station has beed permanently disabled and is not in use anymore but is still visible' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "charging_station"
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=&operational_status=broken&amenity=charging_station with a fixed text, namely 'This charging station works' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key disused:amenity.",
"value": ""
},
{
"key": "operational_status",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=&operational_status=broken&amenity=charging_station with a fixed text, namely 'This charging station works' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "broken"
},
{
"key": "amenity",
"description": "Layer 'Charging stations' shows disused:amenity=charging_station&amenity= with a fixed text, namely 'This charging station has beed permanently disabled and is not in use anymore but is still visible' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key amenity.",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=&operational_status=broken&amenity=charging_station with a fixed text, namely 'This charging station works' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "charging_station"
},
{
"key": "planned:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=charging_station&construction:amenity=&disused:amenity=&operational_status=&amenity= with a fixed text, namely 'This charging station is broken' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "charging_station"
},
{
"key": "construction:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=charging_station&construction:amenity=&disused:amenity=&operational_status=&amenity= with a fixed text, namely 'This charging station is broken' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key construction:amenity.",
"value": ""
},
{
"key": "disused:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=charging_station&construction:amenity=&disused:amenity=&operational_status=&amenity= with a fixed text, namely 'This charging station is broken' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key disused:amenity.",
"value": ""
},
{
"key": "operational_status",
"description": "Layer 'Charging stations' shows planned:amenity=charging_station&construction:amenity=&disused:amenity=&operational_status=&amenity= with a fixed text, namely 'This charging station is broken' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key operational_status.",
"value": ""
},
{
"key": "amenity",
"description": "Layer 'Charging stations' shows amenity=charging_station&operational_status= with a fixed text, namely 'This charging station works' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"description": "Layer 'Charging stations' shows planned:amenity=charging_station&construction:amenity=&disused:amenity=&operational_status=&amenity= with a fixed text, namely 'This charging station is broken' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key amenity.",
"value": ""
},
{
"key": "planned:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=charging_station&disused:amenity=&operational_status=&amenity= with a fixed text, namely 'A charging station is planned here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key planned:amenity.",
"value": ""
},
{
"key": "construction:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=charging_station&disused:amenity=&operational_status=&amenity= with a fixed text, namely 'A charging station is planned here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "charging_station"
},
{
"key": "disused:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=charging_station&disused:amenity=&operational_status=&amenity= with a fixed text, namely 'A charging station is planned here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key disused:amenity.",
"value": ""
},
{
"key": "operational_status",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=charging_station&disused:amenity=&operational_status=&amenity= with a fixed text, namely 'A charging station is planned here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key operational_status.",
"value": ""
},
{
"key": "amenity",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=charging_station&disused:amenity=&operational_status=&amenity= with a fixed text, namely 'A charging station is planned here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key amenity.",
"value": ""
},
{
"key": "planned:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=charging_station&operational_status=&amenity= with a fixed text, namely 'A charging station is constructed here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key planned:amenity.",
"value": ""
},
{
"key": "construction:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=charging_station&operational_status=&amenity= with a fixed text, namely 'A charging station is constructed here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key construction:amenity.",
"value": ""
},
{
"key": "disused:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=charging_station&operational_status=&amenity= with a fixed text, namely 'A charging station is constructed here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "charging_station"
},
{
"key": "operational_status",
"description": "Layer 'Charging stations' shows amenity=charging_station&operational_status= with a fixed text, namely 'This charging station works' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key operational_status.",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=charging_station&operational_status=&amenity= with a fixed text, namely 'A charging station is constructed here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key operational_status.",
"value": ""
},
{
"key": "amenity",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=charging_station&operational_status=&amenity= with a fixed text, namely 'A charging station is constructed here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key amenity.",
"value": ""
},
{
"key": "planned:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=&operational_status=&amenity=charging_station with a fixed text, namely 'This charging station has beed permanently disabled and is not in use anymore but is still visible' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key planned:amenity.",
"value": ""
},
{
"key": "construction:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=&operational_status=&amenity=charging_station with a fixed text, namely 'This charging station has beed permanently disabled and is not in use anymore but is still visible' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key construction:amenity.",
"value": ""
},
{
"key": "disused:amenity",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=&operational_status=&amenity=charging_station with a fixed text, namely 'This charging station has beed permanently disabled and is not in use anymore but is still visible' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key disused:amenity.",
"value": ""
},
{
"key": "operational_status",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=&operational_status=&amenity=charging_station with a fixed text, namely 'This charging station has beed permanently disabled and is not in use anymore but is still visible' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations') Picking this answer will delete the key operational_status.",
"value": ""
},
{
"key": "amenity",
"description": "Layer 'Charging stations' shows planned:amenity=&construction:amenity=&disused:amenity=&operational_status=&amenity=charging_station with a fixed text, namely 'This charging station has beed permanently disabled and is not in use anymore but is still visible' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",
"value": "charging_station"
},
{
"key": "parking:fee",
"description": "Layer 'Charging stations' shows parking:fee=no with a fixed text, namely 'No additional parking cost while charging' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Charging stations')",

View file

@ -194,6 +194,26 @@
"key": "wikipedia",
"description": "The layer 'Climbing gyms allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "name",
"description": "Layer 'Climbing gyms' shows and asks freeform values for key 'name' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "website",
"description": "Layer 'Climbing gyms' shows and asks freeform values for key 'website' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "phone",
"description": "Layer 'Climbing gyms' shows and asks freeform values for key 'phone' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "email",
"description": "Layer 'Climbing gyms' shows and asks freeform values for key 'email' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "opening_hours",
"description": "Layer 'Climbing gyms' shows and asks freeform values for key 'opening_hours' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "url",
"description": "Layer 'Climbing gyms' shows and asks freeform values for key 'url' (in the MapComplete.osm.be theme 'Open Climbing Map')"
@ -314,26 +334,6 @@
"key": "climbing:speed",
"description": "Layer 'Climbing gyms' shows climbing:speed~^..*$ with a fixed text, namely 'There are {climbing:speed} speed climbing walls' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "name",
"description": "Layer 'Climbing gyms' shows and asks freeform values for key 'name' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "website",
"description": "Layer 'Climbing gyms' shows and asks freeform values for key 'website' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "phone",
"description": "Layer 'Climbing gyms' shows and asks freeform values for key 'phone' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "email",
"description": "Layer 'Climbing gyms' shows and asks freeform values for key 'email' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "opening_hours",
"description": "Layer 'Climbing gyms' shows and asks freeform values for key 'opening_hours' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "climbing",
"description": "The MapComplete theme Open Climbing Map has a layer Climbing routes showing features with this tag",
@ -355,6 +355,46 @@
"key": "wikipedia",
"description": "The layer 'Climbing routes allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "name",
"description": "Layer 'Climbing routes' shows and asks freeform values for key 'name' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "noname",
"description": "Layer 'Climbing routes' shows noname=yes&name= with a fixed text, namely 'This climbing route doesn't have a name' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "yes"
},
{
"key": "name",
"description": "Layer 'Climbing routes' shows noname=yes&name= with a fixed text, namely 'This climbing route doesn't have a name' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map') Picking this answer will delete the key name.",
"value": ""
},
{
"key": "climbing:length",
"description": "Layer 'Climbing routes' shows and asks freeform values for key 'climbing:length' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "climbing:grade:french",
"description": "Layer 'Climbing routes' shows and asks freeform values for key 'climbing:grade:french' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "climbing:bolts",
"description": "Layer 'Climbing routes' shows and asks freeform values for key 'climbing:bolts' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "climbing:bolted",
"description": "Layer 'Climbing routes' shows climbing:bolted=no with a fixed text, namely 'This route is not bolted' (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "no"
},
{
"key": "climbing:bolted",
"description": "Layer 'Climbing routes' shows climbing:bolted=no&climbing:bolts= with a fixed text, namely 'This route is not bolted' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "no&climbing:bolts="
},
{
"key": "description",
"description": "Layer 'Climbing routes' shows and asks freeform values for key 'description' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "url",
"description": "Layer 'Climbing routes' shows and asks freeform values for key 'url' (in the MapComplete.osm.be theme 'Open Climbing Map')"
@ -475,46 +515,6 @@
"key": "climbing:speed",
"description": "Layer 'Climbing routes' shows climbing:speed~^..*$ with a fixed text, namely 'There are {climbing:speed} speed climbing walls' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "name",
"description": "Layer 'Climbing routes' shows and asks freeform values for key 'name' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "noname",
"description": "Layer 'Climbing routes' shows noname=yes&name= with a fixed text, namely 'This climbing route doesn't have a name' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "yes"
},
{
"key": "name",
"description": "Layer 'Climbing routes' shows noname=yes&name= with a fixed text, namely 'This climbing route doesn't have a name' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map') Picking this answer will delete the key name.",
"value": ""
},
{
"key": "climbing:length",
"description": "Layer 'Climbing routes' shows and asks freeform values for key 'climbing:length' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "climbing:grade:french",
"description": "Layer 'Climbing routes' shows and asks freeform values for key 'climbing:grade:french' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "climbing:bolts",
"description": "Layer 'Climbing routes' shows and asks freeform values for key 'climbing:bolts' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "climbing:bolted",
"description": "Layer 'Climbing routes' shows climbing:bolted=no with a fixed text, namely 'This route is not bolted' (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "no"
},
{
"key": "climbing:bolted",
"description": "Layer 'Climbing routes' shows climbing:bolted=no&climbing:bolts= with a fixed text, namely 'This route is not bolted' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "no&climbing:bolts="
},
{
"key": "description",
"description": "Layer 'Climbing routes' shows and asks freeform values for key 'description' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "sport",
"description": "The MapComplete theme Open Climbing Map has a layer Climbing opportunities showing features with this tag",
@ -536,6 +536,44 @@
"key": "wikipedia",
"description": "The layer 'Climbing opportunities allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "name",
"description": "Layer 'Climbing opportunities' shows and asks freeform values for key 'name' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "noname",
"description": "Layer 'Climbing opportunities' shows noname=yes&name= with a fixed text, namely 'This climbing opportunity doesn't have a name' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "yes"
},
{
"key": "name",
"description": "Layer 'Climbing opportunities' shows noname=yes&name= with a fixed text, namely 'This climbing opportunity doesn't have a name' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map') Picking this answer will delete the key name.",
"value": ""
},
{
"key": "climbing",
"description": "Layer 'Climbing opportunities' shows climbing=boulder with a fixed text, namely 'A climbing boulder - a single rock or cliff with one or a few climbing routes which can be climbed safely without rope' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "boulder"
},
{
"key": "climbing",
"description": "Layer 'Climbing opportunities' shows climbing=crag with a fixed text, namely 'A climbing crag - a single rock or cliff with at least a few climbing routes' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "crag"
},
{
"key": "climbing",
"description": "Layer 'Climbing opportunities' shows climbing=area with a fixed text, namely 'A climbing area with one or more climbing crags and/or boulders' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "area"
},
{
"key": "rock",
"description": "Layer 'Climbing opportunities' shows and asks freeform values for key 'rock' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "rock",
"description": "Layer 'Climbing opportunities' shows rock=limestone with a fixed text, namely 'Limestone' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "limestone"
},
{
"key": "url",
"description": "Layer 'Climbing opportunities' shows and asks freeform values for key 'url' (in the MapComplete.osm.be theme 'Open Climbing Map')"
@ -656,44 +694,6 @@
"key": "climbing:speed",
"description": "Layer 'Climbing opportunities' shows climbing:speed~^..*$ with a fixed text, namely 'There are {climbing:speed} speed climbing walls' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "name",
"description": "Layer 'Climbing opportunities' shows and asks freeform values for key 'name' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "noname",
"description": "Layer 'Climbing opportunities' shows noname=yes&name= with a fixed text, namely 'This climbing opportunity doesn't have a name' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "yes"
},
{
"key": "name",
"description": "Layer 'Climbing opportunities' shows noname=yes&name= with a fixed text, namely 'This climbing opportunity doesn't have a name' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map') Picking this answer will delete the key name.",
"value": ""
},
{
"key": "climbing",
"description": "Layer 'Climbing opportunities' shows climbing=boulder with a fixed text, namely 'A climbing boulder - a single rock or cliff with one or a few climbing routes which can be climbed safely without rope' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "boulder"
},
{
"key": "climbing",
"description": "Layer 'Climbing opportunities' shows climbing=crag with a fixed text, namely 'A climbing crag - a single rock or cliff with at least a few climbing routes' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "crag"
},
{
"key": "climbing",
"description": "Layer 'Climbing opportunities' shows climbing=area with a fixed text, namely 'A climbing area with one or more climbing crags and/or boulders' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "area"
},
{
"key": "rock",
"description": "Layer 'Climbing opportunities' shows and asks freeform values for key 'rock' (in the MapComplete.osm.be theme 'Open Climbing Map')"
},
{
"key": "rock",
"description": "Layer 'Climbing opportunities' shows rock=limestone with a fixed text, namely 'Limestone' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Climbing Map')",
"value": "limestone"
},
{
"key": "leisure",
"description": "The MapComplete theme Open Climbing Map has a layer Climbing opportunities? showing features with this tag",

View file

@ -600,7 +600,7 @@
},
{
"key": "cycle_barrier:type",
"description": "Layer 'Barriers' shows cycle_barrier:type=double with a fixed text, namely 'Double, two barriers behind each other <img src='./assets/themes/cycle_infra/Cycle_barrier_double.png' style='width:8em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"description": "Layer 'Barriers' shows cycle_barrier:type=double with a fixed text, namely 'Double, two barriers behind each other <img src='./assets/themes/cycle_infra/Cycle_barrier_double.svg' style='width:8em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "double"
},
{

View file

@ -116,25 +116,6 @@
"key": "opening_hours",
"description": "Layer 'Bike cafe' shows and asks freeform values for key 'opening_hours' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Bike cafe' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bike cafe' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bike cafe' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bike cafe' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "yes"
},
{
"key": "shop",
"description": "The MapComplete theme Cyclofix - an open map for cyclists has a layer Bike repair/shop showing features with this tag",
@ -417,25 +398,6 @@
"key": "description",
"description": "Layer 'Bicycle library' shows and asks freeform values for key 'description' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Bicycle library' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bicycle library' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bicycle library' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bicycle library' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "yes"
},
{
"key": "amenity",
"description": "The MapComplete theme Cyclofix - an open map for cyclists has a layer Bike stations (repair, pump or both) showing features with this tag",
@ -616,25 +578,6 @@
"description": "Layer 'Bike stations (repair, pump or both)' shows level=1 with a fixed text, namely 'Located on the first floor' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "1"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Bike stations (repair, pump or both)' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bike stations (repair, pump or both)' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bike stations (repair, pump or both)' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bike stations (repair, pump or both)' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "yes"
},
{
"key": "amenity",
"description": "The MapComplete theme Cyclofix - an open map for cyclists has a layer Bicycle tube vending machine showing features with this tag",
@ -751,25 +694,6 @@
"description": "Layer 'Bicycle tube vending machine' shows vending:bicycle_lock=yes with a fixed text, namely 'Bicycle locks are sold here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "yes"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Bicycle tube vending machine' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bicycle tube vending machine' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bicycle tube vending machine' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bicycle tube vending machine' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "yes"
},
{
"key": "amenity",
"description": "The MapComplete theme Cyclofix - an open map for cyclists has a layer Drinking water showing features with this tag",
@ -820,25 +744,6 @@
"description": "Layer 'Drinking water' shows bottle=no with a fixed text, namely 'Water bottles may not fit' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Drinking water' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Drinking water' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Drinking water' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Drinking water' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "yes"
},
{
"key": "theme",
"description": "The MapComplete theme Cyclofix - an open map for cyclists has a layer Bike related object showing features with this tag",
@ -920,25 +825,6 @@
"key": "opening_hours",
"description": "Layer 'Bike related object' shows and asks freeform values for key 'opening_hours' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Bike related object' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bike related object' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bike related object' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bike related object' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "yes"
},
{
"key": "service:bicycle:cleaning",
"description": "The MapComplete theme Cyclofix - an open map for cyclists has a layer Bike cleaning service showing features with this tag",
@ -1080,13 +966,13 @@
},
{
"key": "location",
"description": "Layer 'Bike parking' shows location=underground with a fixed text, namely 'Underground parking' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "underground"
"description": "Layer 'Bike parking' shows location=surface with a fixed text, namely 'Surface level parking' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "surface"
},
{
"key": "location",
"description": "Layer 'Bike parking' shows location=surface with a fixed text, namely 'Surface level parking' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "surface"
"description": "Layer 'Bike parking' shows location=rooftop with a fixed text, namely 'Rooftop parking' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "rooftop"
},
{
"key": "location",
@ -1149,25 +1035,6 @@
{
"key": "capacity:cargo_bike",
"description": "Layer 'Bike parking' shows and asks freeform values for key 'capacity:cargo_bike' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Bike parking' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bike parking' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bike parking' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Bike parking' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
"value": "yes"
}
]
}

View file

@ -59,25 +59,6 @@
"key": "bottle",
"description": "Layer 'Drinking water' shows bottle=no with a fixed text, namely 'Water bottles may not fit' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Drinking Water')",
"value": "no"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Drinking water' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'Drinking Water')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Drinking water' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Drinking Water')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Drinking water' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'Drinking Water')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Drinking water' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Drinking Water')",
"value": "yes"
}
]
}

View file

@ -0,0 +1,206 @@
{
"data_format": 1,
"project": {
"name": "MapComplete Open Etymology Map",
"description": "What is the origin of a toponym?",
"project_url": "https://mapcomplete.osm.be/etymology",
"doc_url": "https://github.com/pietervdvn/MapComplete/tree/master/assets/themes/",
"icon_url": "https://mapcomplete.osm.be/assets/layers/etymology/logo.svg",
"contact_name": "Pieter Vander Vennet, ",
"contact_email": "pietervdvn@posteo.net"
},
"tags": [
{
"key": "name:etymology:wikidata",
"description": "The MapComplete theme Open Etymology Map has a layer Has etymolgy showing features with this tag"
},
{
"key": "name:etymology",
"description": "The MapComplete theme Open Etymology Map has a layer Has etymolgy showing features with this tag"
},
{
"key": "image",
"description": "The layer 'Has etymolgy shows images based on the keys image, image:0, image:1,... and wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "mapillary",
"description": "The layer 'Has etymolgy shows images based on the keys image, image:0, image:1,... and wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikidata",
"description": "The layer 'Has etymolgy shows images based on the keys image, image:0, image:1,... and wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikipedia",
"description": "The layer 'Has etymolgy shows images based on the keys image, image:0, image:1,... and wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "name:etymology:wikidata",
"description": "Layer 'Has etymolgy' shows and asks freeform values for key 'name:etymology:wikidata' (in the MapComplete.osm.be theme 'Open Etymology Map')"
},
{
"key": "name:etymology",
"description": "Layer 'Has etymolgy' shows and asks freeform values for key 'name:etymology' (in the MapComplete.osm.be theme 'Open Etymology Map')"
},
{
"key": "name:etymology",
"description": "Layer 'Has etymolgy' shows name:etymology=unknown with a fixed text, namely 'The origin of this name is unknown in all literature' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Etymology Map')",
"value": "unknown"
},
{
"key": "image",
"description": "The layer 'Has etymolgy allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "mapillary",
"description": "The layer 'Has etymolgy allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikidata",
"description": "The layer 'Has etymolgy allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikipedia",
"description": "The layer 'Has etymolgy allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikidata",
"description": "Layer 'Has etymolgy' shows and asks freeform values for key 'wikidata' (in the MapComplete.osm.be theme 'Open Etymology Map')"
},
{
"key": "wikidata",
"description": "Layer 'Has etymolgy' shows wikidata= with a fixed text, namely 'No Wikipedia page has been linked yet' (in the MapComplete.osm.be theme 'Open Etymology Map') Picking this answer will delete the key wikidata.",
"value": ""
},
{
"key": "name",
"description": "The MapComplete theme Open Etymology Map has a layer Streets without etymology information showing features with this tag"
},
{
"key": "highway",
"description": "The MapComplete theme Open Etymology Map has a layer Streets without etymology information showing features with this tag"
},
{
"key": "image",
"description": "The layer 'Streets without etymology information shows images based on the keys image, image:0, image:1,... and wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "mapillary",
"description": "The layer 'Streets without etymology information shows images based on the keys image, image:0, image:1,... and wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikidata",
"description": "The layer 'Streets without etymology information shows images based on the keys image, image:0, image:1,... and wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikipedia",
"description": "The layer 'Streets without etymology information shows images based on the keys image, image:0, image:1,... and wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "name:etymology:wikidata",
"description": "Layer 'Streets without etymology information' shows and asks freeform values for key 'name:etymology:wikidata' (in the MapComplete.osm.be theme 'Open Etymology Map')"
},
{
"key": "name:etymology",
"description": "Layer 'Streets without etymology information' shows and asks freeform values for key 'name:etymology' (in the MapComplete.osm.be theme 'Open Etymology Map')"
},
{
"key": "name:etymology",
"description": "Layer 'Streets without etymology information' shows name:etymology=unknown with a fixed text, namely 'The origin of this name is unknown in all literature' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Etymology Map')",
"value": "unknown"
},
{
"key": "image",
"description": "The layer 'Streets without etymology information allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "mapillary",
"description": "The layer 'Streets without etymology information allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikidata",
"description": "The layer 'Streets without etymology information allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikipedia",
"description": "The layer 'Streets without etymology information allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikidata",
"description": "Layer 'Streets without etymology information' shows and asks freeform values for key 'wikidata' (in the MapComplete.osm.be theme 'Open Etymology Map')"
},
{
"key": "wikidata",
"description": "Layer 'Streets without etymology information' shows wikidata= with a fixed text, namely 'No Wikipedia page has been linked yet' (in the MapComplete.osm.be theme 'Open Etymology Map') Picking this answer will delete the key wikidata.",
"value": ""
},
{
"key": "name",
"description": "The MapComplete theme Open Etymology Map has a layer Parks and forests without etymology information showing features with this tag"
},
{
"key": "leisure",
"description": "The MapComplete theme Open Etymology Map has a layer Parks and forests without etymology information showing features with this tag",
"value": "park"
},
{
"key": "landuse",
"description": "The MapComplete theme Open Etymology Map has a layer Parks and forests without etymology information showing features with this tag",
"value": "forest"
},
{
"key": "image",
"description": "The layer 'Parks and forests without etymology information shows images based on the keys image, image:0, image:1,... and wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "mapillary",
"description": "The layer 'Parks and forests without etymology information shows images based on the keys image, image:0, image:1,... and wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikidata",
"description": "The layer 'Parks and forests without etymology information shows images based on the keys image, image:0, image:1,... and wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikipedia",
"description": "The layer 'Parks and forests without etymology information shows images based on the keys image, image:0, image:1,... and wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "name:etymology:wikidata",
"description": "Layer 'Parks and forests without etymology information' shows and asks freeform values for key 'name:etymology:wikidata' (in the MapComplete.osm.be theme 'Open Etymology Map')"
},
{
"key": "name:etymology",
"description": "Layer 'Parks and forests without etymology information' shows and asks freeform values for key 'name:etymology' (in the MapComplete.osm.be theme 'Open Etymology Map')"
},
{
"key": "name:etymology",
"description": "Layer 'Parks and forests without etymology information' shows name:etymology=unknown with a fixed text, namely 'The origin of this name is unknown in all literature' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Etymology Map')",
"value": "unknown"
},
{
"key": "image",
"description": "The layer 'Parks and forests without etymology information allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "mapillary",
"description": "The layer 'Parks and forests without etymology information allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikidata",
"description": "The layer 'Parks and forests without etymology information allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikipedia",
"description": "The layer 'Parks and forests without etymology information allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "wikidata",
"description": "Layer 'Parks and forests without etymology information' shows and asks freeform values for key 'wikidata' (in the MapComplete.osm.be theme 'Open Etymology Map')"
},
{
"key": "wikidata",
"description": "Layer 'Parks and forests without etymology information' shows wikidata= with a fixed text, namely 'No Wikipedia page has been linked yet' (in the MapComplete.osm.be theme 'Open Etymology Map') Picking this answer will delete the key wikidata.",
"value": ""
}
]
}

View file

@ -78,7 +78,7 @@
},
{
"key": "wheelchair",
"description": "Layer 'Restaurants and fast food' shows wheelchair=designated with a fixed text, namely 'This place is specially adapated for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Restaurants and fast food')",
"description": "Layer 'Restaurants and fast food' shows wheelchair=designated with a fixed text, namely 'This place is specially adapted for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Restaurants and fast food')",
"value": "designated"
},
{
@ -305,6 +305,26 @@
"description": "Layer 'Restaurants and fast food' shows reusable_packaging:accept=only with a fixed text, namely 'You <b>must</b> bring your own container to order here.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Restaurants and fast food')",
"value": "only"
},
{
"key": "service:electricity",
"description": "Layer 'Restaurants and fast food' shows service:electricity=yes with a fixed text, namely 'There are plenty of domestic sockets available to customers seated indoors, where they can charge their electronics' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Restaurants and fast food')",
"value": "yes"
},
{
"key": "service:electricity",
"description": "Layer 'Restaurants and fast food' shows service:electricity=limited with a fixed text, namely 'There are a few domestic sockets available to customers seated indoors, where they can charge their electronics' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Restaurants and fast food')",
"value": "limited"
},
{
"key": "service:electricity",
"description": "Layer 'Restaurants and fast food' shows service:electricity=ask with a fixed text, namely 'There are no sockets available indoors to customers, but charging might be possible if the staff is asked' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Restaurants and fast food')",
"value": "ask"
},
{
"key": "service:electricity",
"description": "Layer 'Restaurants and fast food' shows service:electricity=no with a fixed text, namely 'There are a no domestic sockets available to customers seated indoors' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Restaurants and fast food')",
"value": "no"
},
{
"key": "dog",
"description": "Layer 'Restaurants and fast food' shows dog=yes with a fixed text, namely 'Dogs are allowed' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Restaurants and fast food')",

View file

@ -83,7 +83,7 @@
},
{
"key": "wheelchair",
"description": "Layer 'Fries shop' shows wheelchair=designated with a fixed text, namely 'This place is specially adapated for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"description": "Layer 'Fries shop' shows wheelchair=designated with a fixed text, namely 'This place is specially adapted for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"value": "designated"
},
{
@ -310,6 +310,26 @@
"description": "Layer 'Fries shop' shows reusable_packaging:accept=only with a fixed text, namely 'You <b>must</b> bring your own container to order here.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"value": "only"
},
{
"key": "service:electricity",
"description": "Layer 'Fries shop' shows service:electricity=yes with a fixed text, namely 'There are plenty of domestic sockets available to customers seated indoors, where they can charge their electronics' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"value": "yes"
},
{
"key": "service:electricity",
"description": "Layer 'Fries shop' shows service:electricity=limited with a fixed text, namely 'There are a few domestic sockets available to customers seated indoors, where they can charge their electronics' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"value": "limited"
},
{
"key": "service:electricity",
"description": "Layer 'Fries shop' shows service:electricity=ask with a fixed text, namely 'There are no sockets available indoors to customers, but charging might be possible if the staff is asked' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"value": "ask"
},
{
"key": "service:electricity",
"description": "Layer 'Fries shop' shows service:electricity=no with a fixed text, namely 'There are a no domestic sockets available to customers seated indoors' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"value": "no"
},
{
"key": "dog",
"description": "Layer 'Fries shop' shows dog=yes with a fixed text, namely 'Dogs are allowed' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
@ -398,7 +418,7 @@
},
{
"key": "wheelchair",
"description": "Layer 'Restaurants and fast food' shows wheelchair=designated with a fixed text, namely 'This place is specially adapated for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"description": "Layer 'Restaurants and fast food' shows wheelchair=designated with a fixed text, namely 'This place is specially adapted for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"value": "designated"
},
{
@ -625,6 +645,26 @@
"description": "Layer 'Restaurants and fast food' shows reusable_packaging:accept=only with a fixed text, namely 'You <b>must</b> bring your own container to order here.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"value": "only"
},
{
"key": "service:electricity",
"description": "Layer 'Restaurants and fast food' shows service:electricity=yes with a fixed text, namely 'There are plenty of domestic sockets available to customers seated indoors, where they can charge their electronics' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"value": "yes"
},
{
"key": "service:electricity",
"description": "Layer 'Restaurants and fast food' shows service:electricity=limited with a fixed text, namely 'There are a few domestic sockets available to customers seated indoors, where they can charge their electronics' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"value": "limited"
},
{
"key": "service:electricity",
"description": "Layer 'Restaurants and fast food' shows service:electricity=ask with a fixed text, namely 'There are no sockets available indoors to customers, but charging might be possible if the staff is asked' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"value": "ask"
},
{
"key": "service:electricity",
"description": "Layer 'Restaurants and fast food' shows service:electricity=no with a fixed text, namely 'There are a no domestic sockets available to customers seated indoors' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",
"value": "no"
},
{
"key": "dog",
"description": "Layer 'Restaurants and fast food' shows dog=yes with a fixed text, namely 'Dogs are allowed' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Friturenkaart')",

View file

@ -52,7 +52,7 @@
},
{
"key": "wheelchair",
"description": "Layer 'Hackerspace' shows wheelchair=designated with a fixed text, namely 'This place is specially adapated for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Hackerspaces')",
"description": "Layer 'Hackerspace' shows wheelchair=designated with a fixed text, namely 'This place is specially adapted for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Hackerspaces')",
"value": "designated"
},
{

View file

@ -74,25 +74,6 @@
"key": "map_source:attribution",
"description": "Layer 'Maps' shows map_source:attribution=no with a fixed text, namely 'There is no attribution at all' (in the MapComplete.osm.be theme 'A map of maps')",
"value": "no"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Maps' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'A map of maps')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Maps' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'A map of maps')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Maps' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'A map of maps')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Maps' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'A map of maps')",
"value": "yes"
}
]
}

View file

@ -60,25 +60,6 @@
"description": "Layer 'Drinking water' shows bottle=no with a fixed text, namely 'Water bottles may not fit' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "no"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Drinking water' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'De Natuur in')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Drinking water' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Drinking water' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Drinking water' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "yes"
},
{
"key": "leisure",
"description": "The MapComplete theme De Natuur in has a layer Vogelkijkhutten showing features with this tag",
@ -189,25 +170,6 @@
"description": "Layer 'Vogelkijkhutten' shows operator=Agentschap Natuur en Bos with a fixed text, namely 'Beheer door het Agentschap Natuur en Bos ' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "Agentschap Natuur en Bos"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Vogelkijkhutten' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'De Natuur in')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Vogelkijkhutten' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Vogelkijkhutten' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Vogelkijkhutten' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "yes"
},
{
"key": "tourism",
"description": "The MapComplete theme De Natuur in has a layer Maps showing features with this tag",
@ -273,25 +235,6 @@
"description": "Layer 'Maps' shows map_source:attribution=no with a fixed text, namely 'There is no attribution at all' (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "no"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Maps' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'De Natuur in')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Maps' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Maps' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Maps' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "yes"
},
{
"key": "information",
"description": "The MapComplete theme De Natuur in has a layer Information boards showing features with this tag",
@ -313,25 +256,6 @@
"key": "wikipedia",
"description": "The layer 'Information boards allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Information boards' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'De Natuur in')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Information boards' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Information boards' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Information boards' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "yes"
},
{
"key": "leisure",
"description": "The MapComplete theme De Natuur in has a layer Natuurgebied showing features with this tag",
@ -505,25 +429,6 @@
"key": "wikidata",
"description": "Layer 'Natuurgebied' shows wikidata= with a fixed text, namely 'No Wikipedia page has been linked yet' (in the MapComplete.osm.be theme 'De Natuur in') Picking this answer will delete the key wikidata.",
"value": ""
},
{
"key": "service:bicycle:cleaning:charge",
"description": "Layer 'Natuurgebied' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'De Natuur in')"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Natuurgebied' shows service:bicycle:cleaning:fee=no&service:bicycle:cleaning:charge= with a fixed text, namely 'The cleaning service is free to use' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "no&service:bicycle:cleaning:charge="
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Natuurgebied' shows service:bicycle:cleaning:fee=no& with a fixed text, namely 'Free to use' (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "no&"
},
{
"key": "service:bicycle:cleaning:fee",
"description": "Layer 'Natuurgebied' shows service:bicycle:cleaning:fee=yes with a fixed text, namely 'The cleaning service has a fee' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'De Natuur in')",
"value": "yes"
}
]
}

View file

@ -76,19 +76,9 @@
"description": "Layer 'Observation towers' shows payment:cards=yes with a fixed text, namely 'Payment cards are accepted here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Observation towers')",
"value": "yes"
},
{
"key": "payment:app",
"description": "Layer 'Observation towers' shows payment:app=yes with a fixed text, namely 'Payment is done using a dedicated app' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Observation towers')",
"value": "yes"
},
{
"key": "payment:membership_card",
"description": "Layer 'Observation towers' shows payment:membership_card=yes with a fixed text, namely 'Payment is done using a membership card' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Observation towers')",
"value": "yes"
},
{
"key": "wheelchair",
"description": "Layer 'Observation towers' shows wheelchair=designated with a fixed text, namely 'This place is specially adapated for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Observation towers')",
"description": "Layer 'Observation towers' shows wheelchair=designated with a fixed text, namely 'This place is specially adapted for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Observation towers')",
"value": "designated"
},
{

View file

@ -0,0 +1,225 @@
{
"data_format": 1,
"project": {
"name": "MapComplete Street Lighting",
"description": "On this map you can find everything about street lighting",
"project_url": "https://mapcomplete.osm.be/street_lighting",
"doc_url": "https://github.com/pietervdvn/MapComplete/tree/master/assets/themes/",
"icon_url": "https://mapcomplete.osm.be/assets/layers/street_lamps/street_lamp.svg",
"contact_name": "Pieter Vander Vennet, Robin van der Linde",
"contact_email": "pietervdvn@posteo.net"
},
"tags": [
{
"key": "highway",
"description": "The MapComplete theme Street Lighting has a layer Street Lamps showing features with this tag",
"value": "street_lamp"
},
{
"key": "ref",
"description": "Layer 'Street Lamps' shows and asks freeform values for key 'ref' (in the MapComplete.osm.be theme 'Street Lighting')"
},
{
"key": "support",
"description": "Layer 'Street Lamps' shows support=catenary with a fixed text, namely 'This lamp is suspended using cables' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "catenary"
},
{
"key": "support",
"description": "Layer 'Street Lamps' shows support=ceiling with a fixed text, namely 'This lamp is mounted on a ceiling' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "ceiling"
},
{
"key": "support",
"description": "Layer 'Street Lamps' shows support=ground with a fixed text, namely 'This lamp is mounted in the ground' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "ground"
},
{
"key": "support",
"description": "Layer 'Street Lamps' shows support=pedestal with a fixed text, namely 'This lamp is mounted on a short pole (mostly < 1.5m)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "pedestal"
},
{
"key": "support",
"description": "Layer 'Street Lamps' shows support=pole with a fixed text, namely 'This lamp is mounted on a pole' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "pole"
},
{
"key": "support",
"description": "Layer 'Street Lamps' shows support=wall with a fixed text, namely 'This lamp is mounted directly to the wall' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "wall"
},
{
"key": "support",
"description": "Layer 'Street Lamps' shows support=wall_mount with a fixed text, namely 'This lamp is mounted to the wall using a metal bar' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "wall_mount"
},
{
"key": "lamp_mount",
"description": "Layer 'Street Lamps' shows lamp_mount=straight_mast with a fixed text, namely 'This lamp sits atop of a straight mast' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "straight_mast"
},
{
"key": "lamp_mount",
"description": "Layer 'Street Lamps' shows lamp_mount=bent_mast with a fixed text, namely 'This lamp sits at the end of a bent mast' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "bent_mast"
},
{
"key": "light:method",
"description": "Layer 'Street Lamps' shows light:method=electric with a fixed text, namely 'This lamp is lit electrically' (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "electric"
},
{
"key": "light:method",
"description": "Layer 'Street Lamps' shows light:method=LED with a fixed text, namely 'This lamp uses LEDs' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "LED"
},
{
"key": "light:method",
"description": "Layer 'Street Lamps' shows light:method=incandescent with a fixed text, namely 'This lamp uses incandescent lighting' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "incandescent"
},
{
"key": "light:method",
"description": "Layer 'Street Lamps' shows light:method=halogen with a fixed text, namely 'This lamp uses halogen lighting' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "halogen"
},
{
"key": "light:method",
"description": "Layer 'Street Lamps' shows light:method=discharge with a fixed text, namely 'This lamp uses discharge lamps (unknown type)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "discharge"
},
{
"key": "light:method",
"description": "Layer 'Street Lamps' shows light:method=mercury with a fixed text, namely 'This lamp uses a mercury-vapour lamp (lightly blueish)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "mercury"
},
{
"key": "light:method",
"description": "Layer 'Street Lamps' shows light:method=metal-halide with a fixed text, namely 'This lamp uses metal-halide lamps (bright white)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "metal-halide"
},
{
"key": "light:method",
"description": "Layer 'Street Lamps' shows light:method=fluorescent with a fixed text, namely 'This lamp uses fluorescent lighting' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "fluorescent"
},
{
"key": "light:method",
"description": "Layer 'Street Lamps' shows light:method=sodium with a fixed text, namely 'This lamp uses sodium lamps (unknown type)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "sodium"
},
{
"key": "light:method",
"description": "Layer 'Street Lamps' shows light:method=low_pressure_sodium with a fixed text, namely 'This lamp uses low pressure sodium lamps (monochrome orange)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "low_pressure_sodium"
},
{
"key": "light:method",
"description": "Layer 'Street Lamps' shows light:method=high_pressure_sodium with a fixed text, namely 'This lamp uses high pressure sodium lamps (orange with white)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "high_pressure_sodium"
},
{
"key": "light:method",
"description": "Layer 'Street Lamps' shows light:method=gas with a fixed text, namely 'This lamp is lit using gas' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "gas"
},
{
"key": "light:colour",
"description": "Layer 'Street Lamps' shows and asks freeform values for key 'light:colour' (in the MapComplete.osm.be theme 'Street Lighting')"
},
{
"key": "light:colour",
"description": "Layer 'Street Lamps' shows light:colour=white with a fixed text, namely 'This lamp emits white light' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "white"
},
{
"key": "light:colour",
"description": "Layer 'Street Lamps' shows light:colour=green with a fixed text, namely 'This lamp emits green light' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "green"
},
{
"key": "light:colour",
"description": "Layer 'Street Lamps' shows light:colour=orange with a fixed text, namely 'This lamp emits orange light' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "orange"
},
{
"key": "light:count",
"description": "Layer 'Street Lamps' shows and asks freeform values for key 'light:count' (in the MapComplete.osm.be theme 'Street Lighting')"
},
{
"key": "light:count",
"description": "Layer 'Street Lamps' shows light:count=1 with a fixed text, namely 'This lamp has 1 fixture' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "1"
},
{
"key": "light:count",
"description": "Layer 'Street Lamps' shows light:count=2 with a fixed text, namely 'This lamp has 2 fixtures' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "2"
},
{
"key": "light:lit",
"description": "Layer 'Street Lamps' shows light:lit=dusk-dawn with a fixed text, namely 'This lamp is lit at night' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "dusk-dawn"
},
{
"key": "light:lit",
"description": "Layer 'Street Lamps' shows light:lit=24/7 with a fixed text, namely 'This lamp is lit 24/7' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "24/7"
},
{
"key": "light:lit",
"description": "Layer 'Street Lamps' shows light:lit=motion with a fixed text, namely 'This lamp is lit based on motion' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "motion"
},
{
"key": "light:lit",
"description": "Layer 'Street Lamps' shows light:lit=demand with a fixed text, namely 'This lamp is lit based on demand (e.g. with a pushbutton)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "demand"
},
{
"key": "light:direction",
"description": "Layer 'Street Lamps' shows and asks freeform values for key 'light:direction' (in the MapComplete.osm.be theme 'Street Lighting')"
},
{
"key": "lit",
"description": "Layer 'Lit streets' shows lit=yes with a fixed text, namely 'This street is lit' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "yes"
},
{
"key": "lit",
"description": "Layer 'Lit streets' shows lit=no with a fixed text, namely 'This street is not lit' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "no"
},
{
"key": "lit",
"description": "Layer 'Lit streets' shows lit=sunset-sunrise with a fixed text, namely 'This street is lit at night' (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "sunset-sunrise"
},
{
"key": "lit",
"description": "Layer 'Lit streets' shows lit=24/7 with a fixed text, namely 'This street is lit 24/7' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "24/7"
},
{
"key": "lit",
"description": "Layer 'All streets' shows lit=yes with a fixed text, namely 'This street is lit' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "yes"
},
{
"key": "lit",
"description": "Layer 'All streets' shows lit=no with a fixed text, namely 'This street is not lit' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "no"
},
{
"key": "lit",
"description": "Layer 'All streets' shows lit=sunset-sunrise with a fixed text, namely 'This street is lit at night' (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "sunset-sunrise"
},
{
"key": "lit",
"description": "Layer 'All streets' shows lit=24/7 with a fixed text, namely 'This street is lit 24/7' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Street Lighting')",
"value": "24/7"
}
]
}

View file

@ -74,6 +74,25 @@
"key": "charge",
"description": "Layer 'Toilets' shows and asks freeform values for key 'charge' (in the MapComplete.osm.be theme 'Open Toilet Map')"
},
{
"key": "payment:cash",
"description": "Layer 'Toilets' shows payment:cash=yes with a fixed text, namely 'Cash is accepted here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Toilet Map')",
"value": "yes"
},
{
"key": "payment:cards",
"description": "Layer 'Toilets' shows payment:cards=yes with a fixed text, namely 'Payment cards are accepted here' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Toilet Map')",
"value": "yes"
},
{
"key": "opening_hours",
"description": "Layer 'Toilets' shows and asks freeform values for key 'opening_hours' (in the MapComplete.osm.be theme 'Open Toilet Map')"
},
{
"key": "opening_hours",
"description": "Layer 'Toilets' shows opening_hours=24/7 with a fixed text, namely 'Opened 24/7' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Toilet Map')",
"value": "24/7"
},
{
"key": "wheelchair",
"description": "Layer 'Toilets' shows wheelchair=yes with a fixed text, namely 'There is a dedicated toilet for wheelchair users' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Toilet Map')",
@ -150,7 +169,7 @@
},
{
"key": "toilets:paper_supplied",
"description": "Layer 'Toilets' shows toilets:paper_supplied=yes with a fixed text, namely 'Toilet paper is equipped with toilet paper' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Toilet Map')",
"description": "Layer 'Toilets' shows toilets:paper_supplied=yes with a fixed text, namely 'This toilet is equipped with toilet paper' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Toilet Map')",
"value": "yes"
},
{

View file

@ -44,6 +44,31 @@
"key": "waste",
"description": "Layer 'Waste Basket' shows waste=sharps with a fixed text, namely 'A waste basket for needles and other sharp objects' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Waste Basket')",
"value": "sharps"
},
{
"key": "vending",
"description": "Layer 'Waste Basket' shows vending=dog_excrement_bag&not:vending= with a fixed text, namely 'This waste basket has a dispenser for (dog) excrement bags' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Waste Basket')",
"value": "dog_excrement_bag"
},
{
"key": "not:vending",
"description": "Layer 'Waste Basket' shows vending=dog_excrement_bag&not:vending= with a fixed text, namely 'This waste basket has a dispenser for (dog) excrement bags' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Waste Basket') Picking this answer will delete the key not:vending.",
"value": ""
},
{
"key": "not:vending",
"description": "Layer 'Waste Basket' shows not:vending=dog_excrement_bag&vending= with a fixed text, namely 'This waste basket <b>does not</b> have a dispenser for (dog) excrement bags' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Waste Basket')",
"value": "dog_excrement_bag"
},
{
"key": "vending",
"description": "Layer 'Waste Basket' shows not:vending=dog_excrement_bag&vending= with a fixed text, namely 'This waste basket <b>does not</b> have a dispenser for (dog) excrement bags' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Waste Basket') Picking this answer will delete the key vending.",
"value": ""
},
{
"key": "vending",
"description": "Layer 'Waste Basket' shows vending= with a fixed text, namely 'This waste basket <b>does not</b> have a dispenser for (dog) excrement bags' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Waste Basket') Picking this answer will delete the key vending.",
"value": ""
}
]
}

View file

@ -1,7 +1,7 @@
from datetime import datetime
from matplotlib import pyplot
import json
import sys
from datetime import datetime
from matplotlib import pyplot
def pyplot_init():
@ -9,54 +9,55 @@ def pyplot_init():
pyplot.figure(figsize=(14, 8), dpi=200)
pyplot.xticks(rotation='vertical')
pyplot.grid()
def genKeys(data, type):
keys = map(lambda kv: kv["key"], data)
if type == "date":
keys = map(lambda key : datetime.strptime(key, "%Y-%m-%dT%H:%M:%S.000Z"), keys)
keys = map(lambda key: datetime.strptime(key, "%Y-%m-%dT%H:%M:%S.000Z"), keys)
return list(keys)
def createPie(options):
data = options["plot"]["count"]
keys = genKeys(data, options["interpetKeysAs"])
values = list(map(lambda kv: kv["value"], data))
total = sum(map(lambda kv : kv["value"], data))
total = sum(map(lambda kv: kv["value"], data))
first_pct = data[0]["value"] / total
pyplot_init()
pyplot.pie(values, labels=keys, startangle=(90 - 360 * first_pct / 2))
def createBar(options):
data = options["plot"]["count"]
keys = genKeys(data, options["interpetKeysAs"])
values = list(map(lambda kv: kv["value"], data))
pyplot.bar(keys, values, label=options["name"])
pyplot.legend()
pyplot_init()
title = sys.argv[1]
pyplot.title = title
names = []
while(True):
while (True):
line = sys.stdin.readline()
if line == "" or line == "\n":
if(len(names) > 1):
pyplot.legend(loc="upper left", ncol=3)
pyplot.savefig(title+".png", dpi=400, facecolor='w', edgecolor='w',
if (len(names) > 1):
pyplot.legend(loc="upper left", ncol=3)
pyplot.savefig(title + ".png", dpi=400, facecolor='w', edgecolor='w',
bbox_inches='tight')
break
options = json.loads(line)
print("Creating "+options["plot"]["type"]+" '"+options["name"]+"'")
print("Creating " + options["plot"]["type"] + " '" + options["name"] + "'")
names.append(options["name"])
if(options["plot"]["type"] == "pie"):
if (options["plot"]["type"] == "pie"):
createPie(options)
elif(options["plot"]["type"] == "bar"):
elif (options["plot"]["type"] == "bar"):
createBar(options)
else:
print("Unkown type: "+options.type)
print("Unkown type: " + options.type)

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 KiB

After

Width:  |  Height:  |  Size: 273 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 231 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 507 KiB

After

Width:  |  Height:  |  Size: 518 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 KiB

After

Width:  |  Height:  |  Size: 546 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 689 KiB

After

Width:  |  Height:  |  Size: 707 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 737 KiB

After

Width:  |  Height:  |  Size: 731 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 439 KiB

After

Width:  |  Height:  |  Size: 445 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 469 KiB

After

Width:  |  Height:  |  Size: 468 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 KiB

After

Width:  |  Height:  |  Size: 481 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 KiB

After

Width:  |  Height:  |  Size: 533 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Before After
Before After

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -20,41 +20,6 @@ the URL-parameters are stated in the part between the `?` and the `#`. There are
Finally, the URL-hash is the part after the `#`. It is `node/1234` in this case.
download-control-toggle
-------------------------
Whether or not the download panel is shown The default value is _false_
filter-toggle
---------------
Whether or not the filter view is shown The default value is _false_
tab
-----
The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >50 changesets) The default value is _0_
z
---
The initial/current zoom level The default value is _0_
lat
-----
The initial/current latitude The default value is _0_
lon
-----
The initial/current longitude of the app The default value is _0_
fs-userbadge
--------------
@ -62,40 +27,47 @@ Finally, the URL-hash is the part after the `#`. It is `node/1234` in this case.
Disables/Enables the user information pill (userbadge) at the top left. Disabling this disables logging in and thus disables editing all together, effectively putting MapComplete into read-only mode. The default value is _true_
fs-search
-----------
Disables/Enables the search bar The default value is _true_
fs-background
---------------
Disables/Enables the background layer control The default value is _true_
fs-filter
-----------
Disables/Enables the filter The default value is _true_
fs-add-new
------------
Disables/Enables the 'add new feature'-popup. (A theme without presets might not have it in the first place) The default value is _true_
fs-welcome-message
--------------------
Disables/enables the help menu or welcome message The default value is _true_
fs-iframe
-----------
Disables/Enables the iframe-popup The default value is _false_
fs-iframe-popout
------------------
Disables/Enables the iframe-popout button. If in iframe mode and the welcome message is hidden, a popout button to the full mapcomplete instance is shown instead (unless disabled with this switch) The default value is _true_
fs-more-quests
@ -104,53 +76,41 @@ Finally, the URL-hash is the part after the `#`. It is `node/1234` in this case.
Disables/Enables the 'More Quests'-tab in the welcome message The default value is _true_
fs-share-screen
-----------------
Disables/Enables the 'Share-screen'-tab in the welcome message The default value is _true_
fs-geolocation
----------------
Disables/Enables the geolocation button The default value is _true_
fs-all-questions
------------------
Always show all questions The default value is _false_
fs-export
-----------
Enable the export as GeoJSON and CSV button The default value is _false_
fs-pdf
--------
Enable the PDF download button The default value is _false_
test
------
If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org The default value is _false_
debug
-------
If true, shows some extra debugging help such as all the available tags on every object The default value is _false_
fake-user
-----------
If true, 'dryrun' mode is activated and a fake user account is loaded The default value is _false_
backend
---------
@ -158,22 +118,54 @@ Finally, the URL-hash is the part after the `#`. It is `node/1234` in this case.
The OSM backend to use - can be used to redirect mapcomplete to the testing backend when using 'osm-test' The default value is _osm_
test
------
If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org The default value is _false_
debug
-------
If true, shows some extra debugging help such as all the available tags on every object The default value is _false_
fake-user
-----------
If true, 'dryrun' mode is activated and a fake user account is loaded The default value is _false_
overpassUrl
-------------
Point mapcomplete to a different overpass-instance. Example: https://overpass-api.de/api/interpreter The default value is _https://overpass-api.de/api/interpreter,https://overpass.kumi.systems/api/interpreter,https://overpass.openstreetmap.ru/cgi/interpreter_
overpassTimeout
-----------------
Set a different timeout (in seconds) for queries in overpass The default value is _30_
custom-css
------------
If specified, the custom css from the given link will be loaded additionaly The default value is __
overpassMaxZoom
-----------------
point to switch between OSM-api and overpass The default value is _17_
osmApiTileSize
----------------
Tilesize when the OSM-API is used to fetch data within a BBOX The default value is _18_
background
@ -182,7 +174,10 @@ Finally, the URL-hash is the part after the `#`. It is `node/1234` in this case.
The id of the background layer to start with The default value is _osm_
layer-<layer-id>
------------------
Wether or not the layer with id <layer-id> is shown The default value is _true_ Generated from QueryParameters
Wether or not the layer with id <layer-id> is shown The default value is _true_
This document is autogenerated from QueryParameters

View file

@ -5,8 +5,10 @@ import Loc from "../../Models/Loc";
export interface AvailableBaseLayersObj {
readonly osmCarto: BaseLayer;
layerOverview: BaseLayer[];
AvailableLayersAt(location: UIEventSource<Loc>): UIEventSource<BaseLayer[]>
SelectBestLayerAccordingTo(location: UIEventSource<Loc>, preferedCategory: UIEventSource<string | string[]>): UIEventSource<BaseLayer> ;
AvailableLayersAt(location: UIEventSource<Loc>): UIEventSource<BaseLayer[]>
SelectBestLayerAccordingTo(location: UIEventSource<Loc>, preferedCategory: UIEventSource<string | string[]>): UIEventSource<BaseLayer>;
}
@ -15,13 +17,13 @@ export interface AvailableBaseLayersObj {
* Changes the basemap
*/
export default class AvailableBaseLayers {
public static layerOverview: BaseLayer[];
public static osmCarto: BaseLayer;
private static implementation: AvailableBaseLayersObj
static AvailableLayersAt(location: UIEventSource<Loc>): UIEventSource<BaseLayer[]> {
return AvailableBaseLayers.implementation?.AvailableLayersAt(location) ?? new UIEventSource<BaseLayer[]>([]);
}
@ -31,7 +33,7 @@ export default class AvailableBaseLayers {
}
public static implement(backend: AvailableBaseLayersObj){
public static implement(backend: AvailableBaseLayersObj) {
AvailableBaseLayers.layerOverview = backend.layerOverview
AvailableBaseLayers.osmCarto = backend.osmCarto
AvailableBaseLayers.implementation = backend

View file

@ -3,13 +3,13 @@ import {UIEventSource} from "../UIEventSource";
import Loc from "../../Models/Loc";
import {GeoOperations} from "../GeoOperations";
import * as editorlayerindex from "../../assets/editor-layer-index.json";
import * as L from "leaflet";
import {TileLayer} from "leaflet";
import * as X from "leaflet-providers";
import * as L from "leaflet";
import {Utils} from "../../Utils";
import {AvailableBaseLayersObj} from "./AvailableBaseLayers";
export default class AvailableBaseLayersImplementation implements AvailableBaseLayersObj{
export default class AvailableBaseLayersImplementation implements AvailableBaseLayersObj {
public readonly osmCarto: BaseLayer =
{
@ -28,102 +28,6 @@ export default class AvailableBaseLayersImplementation implements AvailableBaseL
public layerOverview = AvailableBaseLayersImplementation.LoadRasterIndex().concat(AvailableBaseLayersImplementation.LoadProviderIndex());
public AvailableLayersAt(location: UIEventSource<Loc>): UIEventSource<BaseLayer[]> {
const source = location.map(
(currentLocation) => {
if (currentLocation === undefined) {
return this.layerOverview;
}
const currentLayers = source?.data; // A bit unorthodox - I know
const newLayers = this.CalculateAvailableLayersAt(currentLocation?.lon, currentLocation?.lat);
if (currentLayers === undefined) {
return newLayers;
}
if (newLayers.length !== currentLayers.length) {
return newLayers;
}
for (let i = 0; i < newLayers.length; i++) {
if (newLayers[i].name !== currentLayers[i].name) {
return newLayers;
}
}
return currentLayers;
});
return source;
}
public SelectBestLayerAccordingTo(location: UIEventSource<Loc>, preferedCategory: UIEventSource<string | string[]>): UIEventSource<BaseLayer> {
return this.AvailableLayersAt(location).map(available => {
// First float all 'best layers' to the top
available.sort((a, b) => {
if (a.isBest && b.isBest) {
return 0;
}
if (!a.isBest) {
return 1
}
return -1;
}
)
if (preferedCategory.data === undefined) {
return available[0]
}
let prefered: string []
if (typeof preferedCategory.data === "string") {
prefered = [preferedCategory.data]
} else {
prefered = preferedCategory.data;
}
prefered.reverse();
for (const category of prefered) {
//Then sort all 'photo'-layers to the top. Stability of the sorting will force a 'best' photo layer on top
available.sort((a, b) => {
if (a.category === category && b.category === category) {
return 0;
}
if (a.category !== category) {
return 1
}
return -1;
}
)
}
return available[0]
})
}
private CalculateAvailableLayersAt(lon: number, lat: number): BaseLayer[] {
const availableLayers = [this.osmCarto]
const globalLayers = [];
for (const layerOverviewItem of this.layerOverview) {
const layer = layerOverviewItem;
if (layer.feature?.geometry === undefined || layer.feature?.geometry === null) {
globalLayers.push(layer);
continue;
}
if (lon === undefined || lat === undefined) {
continue;
}
if (GeoOperations.inside([lon, lat], layer.feature)) {
availableLayers.push(layer);
}
}
return availableLayers.concat(globalLayers);
}
private static LoadRasterIndex(): BaseLayer[] {
const layers: BaseLayer[] = []
// @ts-ignore
@ -289,4 +193,100 @@ export default class AvailableBaseLayersImplementation implements AvailableBaseL
subdomains: domains
});
}
public AvailableLayersAt(location: UIEventSource<Loc>): UIEventSource<BaseLayer[]> {
const source = location.map(
(currentLocation) => {
if (currentLocation === undefined) {
return this.layerOverview;
}
const currentLayers = source?.data; // A bit unorthodox - I know
const newLayers = this.CalculateAvailableLayersAt(currentLocation?.lon, currentLocation?.lat);
if (currentLayers === undefined) {
return newLayers;
}
if (newLayers.length !== currentLayers.length) {
return newLayers;
}
for (let i = 0; i < newLayers.length; i++) {
if (newLayers[i].name !== currentLayers[i].name) {
return newLayers;
}
}
return currentLayers;
});
return source;
}
public SelectBestLayerAccordingTo(location: UIEventSource<Loc>, preferedCategory: UIEventSource<string | string[]>): UIEventSource<BaseLayer> {
return this.AvailableLayersAt(location).map(available => {
// First float all 'best layers' to the top
available.sort((a, b) => {
if (a.isBest && b.isBest) {
return 0;
}
if (!a.isBest) {
return 1
}
return -1;
}
)
if (preferedCategory.data === undefined) {
return available[0]
}
let prefered: string []
if (typeof preferedCategory.data === "string") {
prefered = [preferedCategory.data]
} else {
prefered = preferedCategory.data;
}
prefered.reverse();
for (const category of prefered) {
//Then sort all 'photo'-layers to the top. Stability of the sorting will force a 'best' photo layer on top
available.sort((a, b) => {
if (a.category === category && b.category === category) {
return 0;
}
if (a.category !== category) {
return 1
}
return -1;
}
)
}
return available[0]
})
}
private CalculateAvailableLayersAt(lon: number, lat: number): BaseLayer[] {
const availableLayers = [this.osmCarto]
const globalLayers = [];
for (const layerOverviewItem of this.layerOverview) {
const layer = layerOverviewItem;
if (layer.feature?.geometry === undefined || layer.feature?.geometry === null) {
globalLayers.push(layer);
continue;
}
if (lon === undefined || lat === undefined) {
continue;
}
if (GeoOperations.inside([lon, lat], layer.feature)) {
availableLayers.push(layer);
}
}
return availableLayers.concat(globalLayers);
}
}

View file

@ -13,11 +13,11 @@ export default class BackgroundLayerResetter {
location: UIEventSource<Loc>,
availableLayers: UIEventSource<BaseLayer[]>,
defaultLayerId: string = undefined) {
if(Utils.runningFromConsole){
if (Utils.runningFromConsole) {
return
}
defaultLayerId = defaultLayerId ?? AvailableBaseLayers.osmCarto.id;
// Change the baselayer back to OSM if we go out of the current range of the layer

View file

@ -1,13 +1,27 @@
import * as L from "leaflet";
import {UIEventSource} from "../UIEventSource";
import Svg from "../../Svg";
import Img from "../../UI/Base/Img";
import {LocalStorageSource} from "../Web/LocalStorageSource";
import {VariableUiElement} from "../../UI/Base/VariableUIElement";
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
import {QueryParameters} from "../Web/QueryParameters";
import FeatureSource from "../FeatureSource/FeatureSource";
export interface GeoLocationPointProperties {
id: "gps",
"user:location": "yes",
"date": string,
"latitude": number
"longitude":number,
"speed": number,
"accuracy": number
"heading": number
"altitude":number
}
export default class GeoLocationHandler extends VariableUiElement {
private readonly currentLocation: FeatureSource
/**
* Wether or not the geolocation is active, aka the user requested the current location
* @private
@ -25,20 +39,12 @@ export default class GeoLocationHandler extends VariableUiElement {
* @private
*/
private readonly _permission: UIEventSource<string>;
/***
* The marker on the map, in order to update it
* @private
*/
private _marker: L.Marker;
/**
* Literally: _currentGPSLocation.data != undefined
* @private
*/
private readonly _hasLocation: UIEventSource<boolean>;
private readonly _currentGPSLocation: UIEventSource<{
latlng: any;
accuracy: number;
}>;
private readonly _currentGPSLocation: UIEventSource<Coordinates>;
/**
* Kept in order to update the marker
* @private
@ -63,10 +69,15 @@ export default class GeoLocationHandler extends VariableUiElement {
private readonly _layoutToUse: LayoutConfig;
constructor(
currentGPSLocation: UIEventSource<{ latlng: any; accuracy: number }>,
leafletMap: UIEventSource<L.Map>,
layoutToUse: LayoutConfig
state: {
currentUserLocation: FeatureSource,
leafletMap: UIEventSource<any>,
layoutToUse: LayoutConfig,
featureSwitchGeolocation: UIEventSource<boolean>
}
) {
const currentGPSLocation = new UIEventSource<Coordinates>(undefined, "GPS-coordinate")
const leafletMap = state.leafletMap
const hasLocation = currentGPSLocation.map(
(location) => location !== undefined
);
@ -127,7 +138,7 @@ export default class GeoLocationHandler extends VariableUiElement {
this._previousLocationGrant = previousLocationGrant;
this._currentGPSLocation = currentGPSLocation;
this._leafletMap = leafletMap;
this._layoutToUse = layoutToUse;
this._layoutToUse = state.layoutToUse;
this._hasLocation = hasLocation;
const self = this;
@ -172,7 +183,7 @@ export default class GeoLocationHandler extends VariableUiElement {
const latLonGiven = QueryParameters.wasInitialized("lat") && QueryParameters.wasInitialized("lon")
this.init(false, !latLonGiven);
this.init(false, !latLonGiven && state.featureSwitchGeolocation.data);
isLocked.addCallbackAndRunD(isLocked => {
if (isLocked) {
@ -182,9 +193,29 @@ export default class GeoLocationHandler extends VariableUiElement {
}
})
this.currentLocation = state.currentUserLocation
this._currentGPSLocation.addCallback((location) => {
self._previousLocationGrant.setData("granted");
const feature = {
"type": "Feature",
properties: <GeoLocationPointProperties>{
id: "gps",
"user:location": "yes",
"date": new Date().toISOString(),
"latitude": location.latitude,
"longitude": location.longitude,
"speed": location.speed,
"accuracy": location.accuracy,
"heading": location.heading,
"altitude": location.altitude
},
geometry: {
type: "Point",
coordinates: [location.longitude, location.latitude],
}
}
self.currentLocation.features.setData([{feature, freshness: new Date()}])
const timeSinceRequest =
(new Date().getTime() - (self._lastUserRequest?.getTime() ?? 0)) / 1000;
@ -194,36 +225,11 @@ export default class GeoLocationHandler extends VariableUiElement {
self.MoveToCurrentLoction();
}
let color = "#1111cc";
try {
color = getComputedStyle(document.body).getPropertyValue(
"--catch-detail-color"
);
} catch (e) {
console.error(e);
}
const icon = L.icon({
iconUrl: Img.AsData(Svg.location.replace(/#000000/g, color).replace(/#000/g, color)),
iconSize: [40, 40], // size of the icon
iconAnchor: [20, 20], // point of the icon which will correspond to marker's location
});
const map = self._leafletMap.data;
if(map === undefined){
return;
}
const newMarker = L.marker(location.latlng, {icon: icon});
newMarker.addTo(map);
if (self._marker !== undefined) {
map.removeLayer(self._marker);
}
self._marker = newMarker;
});
}
private init(askPermission: boolean, forceZoom: boolean) {
private init(askPermission: boolean, zoomToLocation: boolean) {
const self = this;
if (self._isActive.data) {
@ -237,7 +243,7 @@ export default class GeoLocationHandler extends VariableUiElement {
?.then(function (status) {
console.log("Geolocation permission is ", status.state);
if (status.state === "granted") {
self.StartGeolocating(forceZoom);
self.StartGeolocating(zoomToLocation);
}
self._permission.setData(status.state);
status.onchange = function () {
@ -249,10 +255,10 @@ export default class GeoLocationHandler extends VariableUiElement {
}
if (askPermission) {
self.StartGeolocating(forceZoom);
self.StartGeolocating(zoomToLocation);
} else if (this._previousLocationGrant.data === "granted") {
this._previousLocationGrant.setData("");
self.StartGeolocating(forceZoom);
self.StartGeolocating(zoomToLocation);
}
}
@ -261,8 +267,8 @@ export default class GeoLocationHandler extends VariableUiElement {
this._lastUserRequest = undefined;
if (
this._currentGPSLocation.data.latlng[0] === 0 &&
this._currentGPSLocation.data.latlng[1] === 0
this._currentGPSLocation.data.latitude === 0 &&
this._currentGPSLocation.data.longitude === 0
) {
console.debug("Not moving to GPS-location: it is null island");
return;
@ -275,20 +281,22 @@ export default class GeoLocationHandler extends VariableUiElement {
if (b !== true) {
// B is an array with our locklocation
inRange =
b[0][0] <= location.latlng[0] &&
location.latlng[0] <= b[1][0] &&
b[0][1] <= location.latlng[1] &&
location.latlng[1] <= b[1][1];
b[0][0] <= location.latitude &&
location.latitude <= b[1][0] &&
b[0][1] <= location.longitude &&
location.longitude <= b[1][1];
}
}
if (!inRange) {
console.log(
"Not zooming to GPS location: out of bounds",
b,
location.latlng
location
);
} else {
this._leafletMap.data.setView(location.latlng, targetZoom);
const currentZoom = this._leafletMap.data.getZoom()
this._leafletMap.data.setView([location.latitude, location.longitude], Math.max(targetZoom ?? 0, currentZoom));
}
}
@ -312,10 +320,7 @@ export default class GeoLocationHandler extends VariableUiElement {
navigator.geolocation.watchPosition(
function (position) {
self._currentGPSLocation.setData({
latlng: [position.coords.latitude, position.coords.longitude],
accuracy: position.coords.accuracy,
});
self._currentGPSLocation.setData(position.coords);
},
function () {
console.warn("Could not get location with navigator.geolocation");

View file

@ -113,8 +113,7 @@ export default class OverpassFeatureSource implements FeatureSource {
let data: any = undefined
let date: Date = undefined
let lastUsed = 0;
const layersToDownload = []
for (const layer of this.state.layoutToUse.layers) {
@ -137,7 +136,7 @@ export default class OverpassFeatureSource implements FeatureSource {
const self = this;
const overpassUrls = self.state.overpassUrl.data
let bounds : BBox
let bounds: BBox
do {
try {
@ -180,9 +179,9 @@ export default class OverpassFeatureSource implements FeatureSource {
}
} while (data === undefined && this._isActive.data);
try {
if(data === undefined){
if (data === undefined) {
return undefined
}
data.features.forEach(feature => SimpleMetaTagger.objectMetaInfo.applyMetaTagsOnFeature(feature, date, undefined));

View file

@ -31,10 +31,10 @@ export default class PendingChangesUploader {
}
});
if(Utils.runningFromConsole){
if (Utils.runningFromConsole) {
return;
}
document.addEventListener('mouseout', e => {
// @ts-ignore
if (!e.toElement && !e.relatedTarget) {

View file

@ -6,6 +6,8 @@ import {ElementStorage} from "../ElementStorage";
import {Changes} from "../Osm/Changes";
import {OsmObject} from "../Osm/OsmObject";
import {OsmConnection} from "../Osm/OsmConnection";
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
import SimpleMetaTagger from "../SimpleMetaTagger";
export default class SelectedElementTagsUpdater {
@ -14,13 +16,14 @@ export default class SelectedElementTagsUpdater {
"changeset",
"user",
"uid",
"id"] )
"id"])
constructor(state: {
selectedElement: UIEventSource<any>,
allElements: ElementStorage,
changes: Changes,
osmConnection: OsmConnection
osmConnection: OsmConnection,
layoutToUse: LayoutConfig
}) {
@ -37,7 +40,8 @@ export default class SelectedElementTagsUpdater {
selectedElement: UIEventSource<any>,
allElements: ElementStorage,
changes: Changes,
osmConnection: OsmConnection
osmConnection: OsmConnection,
layoutToUse: LayoutConfig
}) {
@ -70,11 +74,18 @@ export default class SelectedElementTagsUpdater {
selectedElement: UIEventSource<any>,
allElements: ElementStorage,
changes: Changes,
osmConnection: OsmConnection
osmConnection: OsmConnection,
layoutToUse: LayoutConfig
}, latestTags: any, id: string
) {
try {
const leftRightSensitive = state.layoutToUse.isLeftRightSensitive()
if (leftRightSensitive) {
SimpleMetaTagger.removeBothTagging(latestTags)
}
const pendingChanges = state.changes.pendingChanges.data
.filter(change => change.type + "/" + change.id === id)
.filter(change => change.tags !== undefined);
@ -92,6 +103,7 @@ export default class SelectedElementTagsUpdater {
}
}
// With the changes applied, we merge them onto the upstream object
let somethingChanged = false;
const currentTagsSource = state.allElements.getEventSourceById(id);
@ -115,7 +127,7 @@ export default class SelectedElementTagsUpdater {
if (currentKey.startsWith("_")) {
continue
}
if(this.metatags.has(currentKey)){
if (this.metatags.has(currentKey)) {
continue
}
if (currentKey in latestTags) {

View file

@ -10,7 +10,7 @@ import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
* Makes sure the hash shows the selected element and vice-versa.
*/
export default class SelectedFeatureHandler {
private static readonly _no_trigger_on = new Set(["welcome", "copyright", "layers", "new", "filter","", undefined])
private static readonly _no_trigger_on = new Set(["welcome", "copyright", "layers", "new", "filters", "", undefined])
private readonly hash: UIEventSource<string>;
private readonly state: {
selectedElement: UIEventSource<any>,
@ -88,7 +88,7 @@ export default class SelectedFeatureHandler {
if (!(hash.startsWith("node") || hash.startsWith("way") || hash.startsWith("relation"))) {
return;
}
OsmObject.DownloadObjectAsync(hash).then(obj => {
@ -114,6 +114,7 @@ export default class SelectedFeatureHandler {
// Hash has been cleared - we clear the selected element
state.selectedElement.setData(undefined);
} else {
// we search the element to select
const feature = state.allElements.ContainingFeatures.get(h)
if (feature === undefined) {

View file

@ -80,6 +80,5 @@ export default class StrayClickHandler {
}
}

View file

@ -8,7 +8,7 @@ import {ElementStorage} from "../ElementStorage";
import {Utils} from "../../Utils";
export default class TitleHandler {
constructor(state : {
constructor(state: {
selectedElement: UIEventSource<any>,
layoutToUse: LayoutConfig,
allElements: ElementStorage
@ -28,7 +28,7 @@ export default class TitleHandler {
continue;
}
if (layer.source.osmTags.matchesProperties(tags)) {
const tagsSource = state.allElements.getEventSourceById(tags.id)
const tagsSource = state.allElements.getEventSourceById(tags.id) ?? new UIEventSource<any>(tags)
const title = new TagRenderingAnswer(tagsSource, layer.title)
return new Combine([defaultTitle, " | ", title]).ConstructElement()?.innerText ?? defaultTitle;
}
@ -39,7 +39,7 @@ export default class TitleHandler {
currentTitle.addCallbackAndRunD(title => {
if(Utils.runningFromConsole){
if (Utils.runningFromConsole) {
return
}
document.title = title

View file

@ -4,11 +4,11 @@ import {GeoOperations} from "./GeoOperations";
export class BBox {
static global: BBox = new BBox([[-180, -90], [180, 90]]);
readonly maxLat: number;
readonly maxLon: number;
readonly minLat: number;
readonly minLon: number;
static global: BBox = new BBox([[-180, -90], [180, 90]]);
constructor(coordinates) {
this.maxLat = -90;
@ -45,6 +45,17 @@ export class BBox {
return feature.bbox;
}
static fromTile(z: number, x: number, y: number): BBox {
return new BBox(Tiles.tile_bounds_lon_lat(z, x, y))
}
static fromTileIndex(i: number): BBox {
if (i === 0) {
return BBox.global
}
return BBox.fromTile(...Tiles.tile_from_index(i))
}
/**
* Constructs a tilerange which fully contains this bbox (thus might be a bit larger)
* @param zoomlevel
@ -83,24 +94,6 @@ export class BBox {
return true;
}
private check() {
if (isNaN(this.maxLon) || isNaN(this.maxLat) || isNaN(this.minLon) || isNaN(this.minLat)) {
console.log(this);
throw "BBOX has NAN";
}
}
static fromTile(z: number, x: number, y: number): BBox {
return new BBox(Tiles.tile_bounds_lon_lat(z, x, y))
}
static fromTileIndex(i: number): BBox {
if (i === 0) {
return BBox.global
}
return BBox.fromTile(...Tiles.tile_from_index(i))
}
getEast() {
return this.maxLon
}
@ -117,6 +110,11 @@ export class BBox {
return this.minLat
}
contains(lonLat: [number, number]) {
return this.minLat <= lonLat[1] && lonLat[1] <= this.maxLat
&& this.minLon <= lonLat[0] && lonLat[0] <= this.maxLon
}
pad(factor: number, maxIncrease = 2): BBox {
const latDiff = Math.min(maxIncrease / 2, Math.abs(this.maxLat - this.minLat) * factor)
@ -174,4 +172,11 @@ export class BBox {
}
private check() {
if (isNaN(this.maxLon) || isNaN(this.maxLat) || isNaN(this.minLon) || isNaN(this.minLat)) {
console.log(this);
throw "BBOX has NAN";
}
}
}

View file

@ -8,6 +8,7 @@ export default class ContributorCount {
public readonly Contributors: UIEventSource<Map<string, number>> = new UIEventSource<Map<string, number>>(new Map<string, number>());
private readonly state: { featurePipeline: FeaturePipeline, currentBounds: UIEventSource<BBox>, locationControl: UIEventSource<Loc> };
private lastUpdate: Date = undefined;
constructor(state: { featurePipeline: FeaturePipeline, currentBounds: UIEventSource<BBox>, locationControl: UIEventSource<Loc> }) {
this.state = state;
@ -16,15 +17,13 @@ export default class ContributorCount {
self.update(bbox)
})
state.featurePipeline.runningQuery.addCallbackAndRun(
_ => self.update(state.currentBounds.data)
_ => self.update(state.currentBounds.data)
)
}
private lastUpdate: Date = undefined;
private update(bbox: BBox) {
if(bbox === undefined){
if (bbox === undefined) {
return;
}
const now = new Date();

View file

@ -10,6 +10,7 @@ import {UIEventSource} from "./UIEventSource";
import {LocalStorageSource} from "./Web/LocalStorageSource";
import LZString from "lz-string";
import * as personal from "../assets/themes/personal/personal.json";
import LegacyJsonConvert from "../Models/ThemeConfig/LegacyJsonConvert";
export default class DetermineLayout {
@ -60,42 +61,10 @@ export default class DetermineLayout {
layer.minzoom = Math.max(16, layer.minzoom)
}
}
return [layoutToUse, undefined]
}
private static async LoadRemoteTheme(link: string): Promise<LayoutConfig | null> {
console.log("Downloading map theme from ", link);
new FixedUiElement(`Downloading the theme from the <a href="${link}">link</a>...`)
.AttachTo("centermessage");
try {
const parsed = await Utils.downloadJson(link)
console.log("Got ", parsed)
try {
parsed.id = link;
return new LayoutConfig(parsed, false).patchImages(link, JSON.stringify(parsed));
} catch (e) {
console.error(e)
DetermineLayout.ShowErrorOnCustomTheme(
`<a href="${link}">${link}</a> is invalid:`,
new FixedUiElement(e)
)
return null;
}
} catch (e) {
console.erorr(e)
DetermineLayout.ShowErrorOnCustomTheme(
`<a href="${link}">${link}</a> is invalid - probably not found or invalid JSON:`,
new FixedUiElement(e)
)
return null;
}
}
public static LoadLayoutFromHash(
userLayoutParam: UIEventSource<string>
): [LayoutConfig, string] | null {
@ -136,6 +105,7 @@ export default class DetermineLayout {
}
}
LegacyJsonConvert.fixThemeConfig(json)
const layoutToUse = new LayoutConfig(json, false);
userLayoutParam.setData(layoutToUse.id);
return [layoutToUse, btoa(Utils.MinifyJSON(JSON.stringify(json)))];
@ -163,4 +133,37 @@ export default class DetermineLayout {
.AttachTo("centermessage");
}
private static async LoadRemoteTheme(link: string): Promise<LayoutConfig | null> {
console.log("Downloading map theme from ", link);
new FixedUiElement(`Downloading the theme from the <a href="${link}">link</a>...`)
.AttachTo("centermessage");
try {
const parsed = await Utils.downloadJson(link)
console.log("Got ", parsed)
LegacyJsonConvert.fixThemeConfig(parsed)
try {
parsed.id = link;
return new LayoutConfig(parsed, false).patchImages(link, JSON.stringify(parsed));
} catch (e) {
console.error(e)
DetermineLayout.ShowErrorOnCustomTheme(
`<a href="${link}">${link}</a> is invalid:`,
new FixedUiElement(e)
)
return null;
}
} catch (e) {
console.error(e)
DetermineLayout.ShowErrorOnCustomTheme(
`<a href="${link}">${link}</a> is invalid - probably not found or invalid JSON:`,
new FixedUiElement(e)
)
return null;
}
}
}

View file

@ -39,10 +39,10 @@ export class ElementStorage {
}
getEventSourceById(elementId): UIEventSource<any> {
if(elementId === undefined){
if (elementId === undefined) {
return undefined;
}
return this._elements.get(elementId);
return this._elements.get(elementId);
}
has(id) {

View file

@ -54,16 +54,17 @@ export class ExtraFunction {
private static readonly OverlapFunc = new ExtraFunction(
{
name: "overlapWith",
doc: "Gives a list of features from the specified layer which this feature (partly) overlaps with. " +
"If the current feature is a point, all features that embed the point are given. " +
doc: "Gives a list of features from the specified layer which this feature (partly) overlaps with. A point which is embedded in the feature is detected as well." +
"If the current feature is a point, all features that this point is embeded in are given.\n\n" +
"The returned value is `{ feat: GeoJSONFeature, overlap: number}[]` where `overlap` is the overlapping surface are (in m²) for areas, the overlapping length (in meter) if the current feature is a line or `undefined` if the current feature is a point.\n" +
"The resulting list is sorted in descending order by overlap. The feature with the most overlap will thus be the first in the list\n" +
"\n" +
"For example to get all objects which overlap or embed from a layer, use `_contained_climbing_routes_properties=feat.overlapWith('climbing_route')`",
args: ["...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)"]
},
(params, feat) => {
return (...layerIds: string[]) => {
const result = []
const result: { feat: any, overlap: number }[] = []
const bbox = BBox.get(feat)
@ -79,6 +80,9 @@ export class ExtraFunction {
result.push(...GeoOperations.calculateOverlap(feat, otherLayer));
}
}
result.sort((a, b) => b.overlap - a.overlap)
return result;
}
}
@ -163,12 +167,41 @@ export class ExtraFunction {
}
)
private static readonly GetParsed = new ExtraFunction(
{
name: "get",
doc: "Gets the property of the feature, parses it (as JSON) and returns it. Might return 'undefined' if not defined, null, ...",
args: ["key"]
},
(params, feat) => {
return key => {
const value = feat.properties[key]
if (value === undefined) {
return undefined;
}
try {
const parsed = JSON.parse(value)
if (parsed === null) {
return undefined;
}
return parsed;
} catch (e) {
console.warn("Could not parse property " + key + " due to: " + e + ", the value is " + value)
return undefined;
}
}
}
)
private static readonly allFuncs: ExtraFunction[] = [
ExtraFunction.DistanceToFunc,
ExtraFunction.OverlapFunc,
ExtraFunction.ClosestObjectFunc,
ExtraFunction.ClosestNObjectFunc,
ExtraFunction.Memberships
ExtraFunction.Memberships,
ExtraFunction.GetParsed
];
private readonly _name: string;
private readonly _args: string[];
@ -200,7 +233,7 @@ export class ExtraFunction {
return new Combine([
ExtraFunction.intro,
new List(ExtraFunction.allFuncs.map(func => func._name)),
new List(ExtraFunction.allFuncs.map(func => `[${func._name}](#${func._name})`)),
...elems
]);
}
@ -222,7 +255,6 @@ export class ExtraFunction {
const maxFeatures = options?.maxFeatures ?? 1
const maxDistance = options?.maxDistance ?? 500
const uniqueTag: string | undefined = options?.uniqueTag
console.log("Requested closestN")
if (typeof features === "string") {
const name = features
const bbox = GeoOperations.bbox(GeoOperations.buffer(GeoOperations.bbox(feature), maxDistance))
@ -238,7 +270,7 @@ export class ExtraFunction {
let closestFeatures: { feat: any, distance: number }[] = [];
for (const featureList of features) {
for (const otherFeature of featureList) {
if (otherFeature === feature || otherFeature.id === feature.id) {
if (otherFeature === feature || otherFeature.properties.id === feature.properties.id) {
continue; // We ignore self
}
const distance = GeoOperations.distanceBetween(
@ -249,6 +281,11 @@ export class ExtraFunction {
console.error("Could not calculate the distance between", feature, "and", otherFeature)
throw "Undefined distance!"
}
if (distance === 0) {
console.trace("Got a suspiciously zero distance between", otherFeature, "and self-feature", feature)
}
if (distance > maxDistance) {
continue
}

View file

@ -39,7 +39,7 @@ export default class SaveTileToLocalStorageActor {
}
}
public static poison(layers: string[], lon: number, lat: number) {
public static poison(layers: string[], lon: number, lat: number) {
for (let z = 0; z < 25; z++) {
const {x, y} = Tiles.embedded_tile(lat, lon, z)

View file

@ -12,7 +12,6 @@ import OverpassFeatureSource from "../Actors/OverpassFeatureSource";
import {Changes} from "../Osm/Changes";
import GeoJsonSource from "./Sources/GeoJsonSource";
import Loc from "../../Models/Loc";
import WayHandlingApplyingFeatureSource from "./Sources/WayHandlingApplyingFeatureSource";
import RegisteringAllFromFeatureSourceActor from "./Actors/RegisteringAllFromFeatureSourceActor";
import TiledFromLocalStorageSource from "./TiledFeatureSource/TiledFromLocalStorageSource";
import SaveTileToLocalStorageActor from "./Actors/SaveTileToLocalStorageActor";
@ -26,6 +25,8 @@ import OsmFeatureSource from "./TiledFeatureSource/OsmFeatureSource";
import {OsmConnection} from "../Osm/OsmConnection";
import {Tiles} from "../../Models/TileRange";
import TileFreshnessCalculator from "./TileFreshnessCalculator";
import {ElementStorage} from "../ElementStorage";
import FullNodeDatabaseSource from "./TiledFeatureSource/FullNodeDatabaseSource";
/**
@ -74,6 +75,9 @@ export default class FeaturePipeline {
constructor(
handleFeatureSource: (source: FeatureSourceForLayer & Tiled) => void,
state: {
readonly historicalUserLocations: FeatureSourceForLayer & Tiled;
readonly homeLocation: FeatureSourceForLayer & Tiled;
readonly currentUserLocation: FeatureSourceForLayer & Tiled;
readonly filteredLayers: UIEventSource<FilteredLayer[]>,
readonly locationControl: UIEventSource<Loc>,
readonly selectedElement: UIEventSource<any>,
@ -85,7 +89,8 @@ export default class FeaturePipeline {
readonly overpassMaxZoom: UIEventSource<number>;
readonly osmConnection: OsmConnection
readonly currentBounds: UIEventSource<BBox>,
readonly osmApiTileSize: UIEventSource<number>
readonly osmApiTileSize: UIEventSource<number>,
readonly allElements: ElementStorage
}) {
this.state = state;
@ -123,13 +128,11 @@ export default class FeaturePipeline {
const perLayerHierarchy = new Map<string, TileHierarchyMerger>()
this.perLayerHierarchy = perLayerHierarchy
const patchedHandleFeatureSource = function (src: FeatureSourceForLayer & IndexedFeatureSource & Tiled) {
function patchedHandleFeatureSource (src: FeatureSourceForLayer & IndexedFeatureSource & Tiled) {
// This will already contain the merged features for this tile. In other words, this will only be triggered once for every tile
const srcFiltered =
new FilteringFeatureSource(state, src.tileIndex,
new WayHandlingApplyingFeatureSource(
new ChangeGeometryApplicator(src, state.changes)
)
new ChangeGeometryApplicator(src, state.changes)
)
handleFeatureSource(srcFiltered)
@ -137,6 +140,14 @@ export default class FeaturePipeline {
// We do not mark as visited here, this is the responsability of the code near the actual loader (e.g. overpassLoader and OSMApiFeatureLoader)
};
function handlePriviligedFeatureSource(src: FeatureSourceForLayer & Tiled){
// Passthrough to passed function, except that it registers as well
handleFeatureSource(src)
src.features.addCallbackAndRunD(fs => {
fs.forEach(ff => state.allElements.addOrGetElement(ff.feature))
})
}
for (const filteredLayer of state.filteredLayers.data) {
const id = filteredLayer.layerDef.id
@ -147,6 +158,26 @@ export default class FeaturePipeline {
this.freshnesses.set(id, new TileFreshnessCalculator())
if (id === "type_node") {
// Handles by the 'FullNodeDatabaseSource'
continue;
}
if (id === "gps_location") {
handlePriviligedFeatureSource(state.currentUserLocation)
continue
}
if (id === "gps_track") {
handlePriviligedFeatureSource(state.historicalUserLocations)
continue
}
if (id === "home_location") {
handlePriviligedFeatureSource(state.homeLocation)
continue
}
if (source.geojsonSource === undefined) {
// This is an OSM layer
// We load the cached values and register them
@ -222,6 +253,18 @@ export default class FeaturePipeline {
})
})
if (state.layoutToUse.trackAllNodes) {
const fullNodeDb = new FullNodeDatabaseSource(
state.filteredLayers.data.filter(l => l.layerDef.id === "type_node")[0],
tile => {
new RegisteringAllFromFeatureSourceActor(tile)
perLayerHierarchy.get(tile.layer.layerDef.id).registerTile(tile)
tile.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(tile))
})
osmFeatureSource.rawDataHandlers.push((osmJson, tileId) => fullNodeDb.handleOsmJson(osmJson, tileId))
}
const updater = this.initOverpassUpdater(state, useOsmApi)
this.overpassUpdater = updater;
@ -266,7 +309,7 @@ export default class FeaturePipeline {
// Whenever fresh data comes in, we need to update the metatagging
self.newDataLoadedSignal.stabilized(1000).addCallback(_ => {
self.newDataLoadedSignal.stabilized(250).addCallback(src => {
self.updateAllMetaTagging()
})
@ -282,6 +325,34 @@ export default class FeaturePipeline {
}
public GetAllFeaturesWithin(bbox: BBox): any[][] {
const self = this
const tiles = []
Array.from(this.perLayerHierarchy.keys())
.forEach(key => tiles.push(...self.GetFeaturesWithin(key, bbox)))
return tiles;
}
public GetFeaturesWithin(layerId: string, bbox: BBox): any[][] {
if (layerId === "*") {
return this.GetAllFeaturesWithin(bbox)
}
const requestedHierarchy = this.perLayerHierarchy.get(layerId)
if (requestedHierarchy === undefined) {
console.warn("Layer ", layerId, "is not defined. Try one of ", Array.from(this.perLayerHierarchy.keys()))
return undefined;
}
return TileHierarchyTools.getTiles(requestedHierarchy, bbox)
.filter(featureSource => featureSource.features?.data !== undefined)
.map(featureSource => featureSource.features.data.map(fs => fs.feature))
}
public GetTilesPerLayerWithin(bbox: BBox, handleTile: (tile: FeatureSourceForLayer & Tiled) => void) {
Array.from(this.perLayerHierarchy.values()).forEach(hierarchy => {
TileHierarchyTools.getTiles(hierarchy, bbox).forEach(handleTile)
})
}
private freshnessForVisibleLayers(z: number, x: number, y: number): Date {
let oldestDate = undefined;
for (const flayer of this.state.filteredLayers.data) {
@ -391,7 +462,7 @@ export default class FeaturePipeline {
window.setTimeout(
() => {
const layerDef = src.layer.layerDef;
MetaTagging.addMetatags(
const somethingChanged = MetaTagging.addMetatags(
src.features.data,
{
memberships: this.relationTracker,
@ -412,40 +483,13 @@ export default class FeaturePipeline {
private updateAllMetaTagging() {
const self = this;
console.debug("Updating the meta tagging of all tiles as new data got loaded")
this.perLayerHierarchy.forEach(hierarchy => {
hierarchy.loadedTiles.forEach(src => {
self.applyMetaTags(src)
hierarchy.loadedTiles.forEach(tile => {
self.applyMetaTags(tile)
})
})
}
public GetAllFeaturesWithin(bbox: BBox): any[][] {
const self = this
const tiles = []
Array.from(this.perLayerHierarchy.keys())
.forEach(key => tiles.push(...self.GetFeaturesWithin(key, bbox)))
return tiles;
}
public GetFeaturesWithin(layerId: string, bbox: BBox): any[][] {
if (layerId === "*") {
return this.GetAllFeaturesWithin(bbox)
}
const requestedHierarchy = this.perLayerHierarchy.get(layerId)
if (requestedHierarchy === undefined) {
console.warn("Layer ", layerId, "is not defined. Try one of ", Array.from(this.perLayerHierarchy.keys()))
return undefined;
}
return TileHierarchyTools.getTiles(requestedHierarchy, bbox)
.filter(featureSource => featureSource.features?.data !== undefined)
.map(featureSource => featureSource.features.data.map(fs => fs.feature))
}
public GetTilesPerLayerWithin(bbox: BBox, handleTile: (tile: FeatureSourceForLayer & Tiled) => void) {
Array.from(this.perLayerHierarchy.values()).forEach(hierarchy => {
TileHierarchyTools.getTiles(hierarchy, bbox).forEach(handleTile)
})
}
}

View file

@ -1,5 +1,4 @@
import {UIEventSource} from "../UIEventSource";
import {Utils} from "../../Utils";
import FilteredLayer from "../../Models/FilteredLayer";
import {BBox} from "../BBox";
@ -19,7 +18,7 @@ export interface Tiled {
/**
* A feature source which only contains features for the defined layer
*/
export interface FeatureSourceForLayer extends FeatureSource{
export interface FeatureSourceForLayer extends FeatureSource {
readonly layer: FilteredLayer
}

View file

@ -14,15 +14,15 @@ export default class PerLayerFeatureSourceSplitter {
constructor(layers: UIEventSource<FilteredLayer[]>,
handleLayerData: (source: FeatureSourceForLayer & Tiled) => void,
upstream: FeatureSource,
options?:{
tileIndex?: number,
handleLeftovers?: (featuresWithoutLayer: any[]) => void
options?: {
tileIndex?: number,
handleLeftovers?: (featuresWithoutLayer: any[]) => void
}) {
const knownLayers = new Map<string, FeatureSourceForLayer & Tiled>()
function update() {
const features = upstream.features.data;
const features = upstream.features?.data;
if (features === undefined) {
return;
}
@ -35,6 +35,7 @@ export default class PerLayerFeatureSourceSplitter {
const featuresPerLayer = new Map<string, { feature, freshness } []>();
const noLayerFound = []
function addTo(layer: FilteredLayer, feature: { feature, freshness }) {
const id = layer.layerDef.id
const list = featuresPerLayer.get(id)
@ -80,9 +81,9 @@ export default class PerLayerFeatureSourceSplitter {
featureSource.features.setData(features)
}
}
// AT last, the leftovers are handled
if(options?.handleLeftovers !== undefined && noLayerFound.length > 0){
if (options?.handleLeftovers !== undefined && noLayerFound.length > 0) {
options.handleLeftovers(noLayerFound)
}
}

View file

@ -11,9 +11,9 @@ import {ChangeDescription, ChangeDescriptionTools} from "../../Osm/Actions/Chang
export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]);
public readonly name: string;
public readonly layer: FilteredLayer
private readonly source: IndexedFeatureSource;
private readonly changes: Changes;
public readonly layer: FilteredLayer
constructor(source: (IndexedFeatureSource & FeatureSourceForLayer), changes: Changes) {
this.source = source;
@ -22,10 +22,10 @@ export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
this.name = "ChangesApplied(" + source.name + ")"
this.features = new UIEventSource<{ feature: any; freshness: Date }[]>(undefined)
const self = this;
source.features.addCallbackAndRunD(_ => self.update())
changes.allChanges.addCallbackAndRunD(_ => self.update())
}
@ -52,9 +52,9 @@ export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
const changesPerId = new Map<string, ChangeDescription[]>()
for (const ch of changesToApply) {
const key = ch.type + "/" + ch.id
if(changesPerId.has(key)){
if (changesPerId.has(key)) {
changesPerId.get(key).push(ch)
}else{
} else {
changesPerId.set(key, [ch])
}
}
@ -66,7 +66,7 @@ export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
newFeatures.push(feature)
continue;
}
// Allright! We have a feature to rewrite!
const copy = {
...feature

View file

@ -5,7 +5,6 @@
import {UIEventSource} from "../../UIEventSource";
import FeatureSource, {FeatureSourceForLayer, IndexedFeatureSource, Tiled} from "../FeatureSource";
import FilteredLayer from "../../../Models/FilteredLayer";
import {Utils} from "../../../Utils";
import {Tiles} from "../../../Models/TileRange";
import {BBox} from "../../BBox";
@ -14,17 +13,17 @@ export default class FeatureSourceMerger implements FeatureSourceForLayer, Tiled
public features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]);
public readonly name;
public readonly layer: FilteredLayer
private readonly _sources: UIEventSource<FeatureSource[]>;
public readonly tileIndex: number;
public readonly bbox: BBox;
public readonly containedIds: UIEventSource<Set<string>> = new UIEventSource<Set<string>>(new Set())
private readonly _sources: UIEventSource<FeatureSource[]>;
constructor(layer: FilteredLayer, tileIndex: number, bbox: BBox, sources: UIEventSource<FeatureSource[]>) {
this.tileIndex = tileIndex;
this.bbox = bbox;
this._sources = sources;
this.layer = layer;
this.name = "FeatureSourceMerger("+layer.layerDef.id+", "+Tiles.tile_from_index(tileIndex).join(",")+")"
this.name = "FeatureSourceMerger(" + layer.layerDef.id + ", " + Tiles.tile_from_index(tileIndex).join(",") + ")"
const self = this;
const handledSources = new Set<FeatureSource>();

View file

@ -1,9 +1,10 @@
import {UIEventSource} from "../../UIEventSource";
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig";
import FilteredLayer from "../../../Models/FilteredLayer";
import {FeatureSourceForLayer, Tiled} from "../FeatureSource";
import Hash from "../../Web/Hash";
import {BBox} from "../../BBox";
import {ElementStorage} from "../../ElementStorage";
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig";
export default class FilteringFeatureSource implements FeatureSourceForLayer, Tiled {
public features: UIEventSource<{ feature: any; freshness: Date }[]> =
@ -12,79 +13,106 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
public readonly layer: FilteredLayer;
public readonly tileIndex: number
public readonly bbox: BBox
private readonly upstream: FeatureSourceForLayer;
private readonly state: {
locationControl: UIEventSource<{ zoom: number }>; selectedElement: UIEventSource<any>,
allElements: ElementStorage
};
private readonly _alreadyRegistered = new Set<UIEventSource<any>>();
private readonly _is_dirty = new UIEventSource(false)
constructor(
state: {
locationControl: UIEventSource<{ zoom: number }>,
selectedElement: UIEventSource<any>,
allElements: ElementStorage
},
tileIndex,
upstream: FeatureSourceForLayer
) {
const self = this;
this.name = "FilteringFeatureSource(" + upstream.name + ")"
this.tileIndex = tileIndex
this.bbox = BBox.fromTileIndex(tileIndex)
this.upstream = upstream
this.state = state
this.layer = upstream.layer;
const layer = upstream.layer;
function update() {
const features: { feature: any; freshness: Date }[] = upstream.features.data;
const newFeatures = features.filter((f) => {
if (
state.selectedElement.data?.id === f.feature.id ||
f.feature.id === Hash.hash.data) {
// This is the selected object - it gets a free pass even if zoom is not sufficient or it is filtered away
return true;
}
const isShown = layer.layerDef.isShown;
const tags = f.feature.properties;
if (isShown.IsKnown(tags)) {
const result = layer.layerDef.isShown.GetRenderValue(
f.feature.properties
).txt;
if (result !== "yes") {
return false;
}
}
const tagsFilter = layer.appliedFilters.data;
for (const filter of tagsFilter ?? []) {
const neededTags = filter.filter.options[filter.selected].osmTags
if (!neededTags.matchesProperties(f.feature.properties)) {
// Hidden by the filter on the layer itself - we want to hide it no matter wat
return false;
}
}
return true;
});
self.features.setData(newFeatures);
}
const self = this;
upstream.features.addCallback(() => {
update();
self.update();
});
layer.appliedFilters.addCallback(_ => {
update()
self.update()
})
update();
this._is_dirty.stabilized(250).addCallbackAndRunD(dirty => {
if (dirty) {
self.update()
}
})
this.update();
}
private static showLayer(
layer: {
isDisplayed: UIEventSource<boolean>;
layerDef: LayerConfig;
}) {
return layer.isDisplayed.data;
public update() {
const self = this;
const layer = this.upstream.layer;
const features: { feature: any; freshness: Date }[] = this.upstream.features.data;
const newFeatures = features.filter((f) => {
self.registerCallback(f.feature, layer.layerDef)
if (
this.state.selectedElement.data?.id === f.feature.id ||
f.feature.id === Hash.hash.data) {
// This is the selected object - it gets a free pass even if zoom is not sufficient or it is filtered away
return true;
}
const isShown = layer.layerDef.isShown;
const tags = f.feature.properties;
if (isShown.IsKnown(tags)) {
const result = layer.layerDef.isShown.GetRenderValue(
f.feature.properties
).txt;
if (result !== "yes") {
return false;
}
}
const tagsFilter = layer.appliedFilters.data;
for (const filter of tagsFilter ?? []) {
const neededTags = filter.filter.options[filter.selected].osmTags
if (!neededTags.matchesProperties(f.feature.properties)) {
// Hidden by the filter on the layer itself - we want to hide it no matter wat
return false;
}
}
return true;
});
this.features.setData(newFeatures);
this._is_dirty.setData(false)
}
private registerCallback(feature: any, layer: LayerConfig) {
const src = this.state.allElements.addOrGetElement(feature)
if (this._alreadyRegistered.has(src)) {
return
}
this._alreadyRegistered.add(src)
if (layer.isShown !== undefined) {
const self = this;
src.map(tags => layer.isShown?.GetRenderValue(tags, "yes").txt).addCallbackAndRunD(isShown => {
self._is_dirty.setData(true)
})
}
}
}

View file

@ -15,12 +15,10 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>;
public readonly name;
public readonly isOsmCache: boolean
private readonly seenids: Set<string> = new Set<string>()
public readonly layer: FilteredLayer;
public readonly tileIndex
public readonly bbox;
private readonly seenids: Set<string> = new Set<string>()
/**
* Only used if the actual source is a tiled geojson.
* A big feature might be contained in multiple tiles.
@ -32,7 +30,7 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
public constructor(flayer: FilteredLayer,
zxy?: [number, number, number],
options?: {
featureIdBlacklist?: UIEventSource<Set<string>>
featureIdBlacklist?: UIEventSource<Set<string>>
}) {
if (flayer.layerDef.source.geojsonZoomLevel !== undefined && zxy === undefined) {
@ -45,18 +43,18 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
if (zxy !== undefined) {
const [z, x, y] = zxy;
let tile_bbox = BBox.fromTile(z, x, y)
let bounds : { minLat: number, maxLat: number, minLon: number, maxLon: number } = tile_bbox
if(this.layer.layerDef.source.mercatorCrs){
let bounds: { minLat: number, maxLat: number, minLon: number, maxLon: number } = tile_bbox
if (this.layer.layerDef.source.mercatorCrs) {
bounds = tile_bbox.toMercator()
}
url = url
.replace('{z}', "" + z)
.replace('{x}', "" + x)
.replace('{y}', "" + y)
.replace('{y_min}',""+bounds.minLat)
.replace('{y_max}',""+bounds.maxLat)
.replace('{x_min}',""+bounds.minLon)
.replace('{x_max}',""+bounds.maxLon)
.replace('{y_min}', "" + bounds.minLat)
.replace('{y_max}', "" + bounds.maxLat)
.replace('{x_min}', "" + bounds.minLon)
.replace('{x_max}', "" + bounds.maxLon)
this.tileIndex = Tiles.tile_index(z, x, y)
this.bbox = BBox.fromTile(z, x, y)
@ -78,11 +76,11 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
const self = this;
Utils.downloadJson(url)
.then(json => {
if(json.features === undefined || json.features === null){
if (json.features === undefined || json.features === null) {
return;
}
if(self.layer.layerDef.source.mercatorCrs){
if (self.layer.layerDef.source.mercatorCrs) {
json = GeoOperations.GeoJsonToWGS84(json)
}
@ -109,8 +107,8 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
continue;
}
self.seenids.add(props.id)
if(self.featureIdBlacklist?.data?.has(props.id)){
if (self.featureIdBlacklist?.data?.has(props.id)) {
continue;
}
@ -122,7 +120,7 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
newFeatures.push({feature: feature, freshness: freshness})
}
if ( newFeatures.length == 0) {
if (newFeatures.length == 0) {
return;
}

View file

@ -7,7 +7,7 @@ import State from "../../../State";
export class NewGeometryFromChangesFeatureSource implements FeatureSource {
// This class name truly puts the 'Java' into 'Javascript'
/**
* A feature source containing exclusively new elements
*/
@ -31,7 +31,6 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
// Already handled
!seenChanges.has(ch)))
.addCallbackAndRunD(changes => {
if (changes.length === 0) {
return;
}
@ -54,10 +53,10 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
for (const kv of change.tags) {
tags[kv.k] = kv.v
}
tags["id"] = change.type+"/"+change.id
tags["id"] = change.type + "/" + change.id
tags["_backend"] = State.state.osmConnection._oauth_config.url
switch (change.type) {
case "node":
const n = new OsmNode(change.id)
@ -71,7 +70,7 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
const w = new OsmWay(change.id)
w.tags = tags
w.nodes = change.changes["nodes"]
w.coordinates = change.changes["coordinates"].map(coor => coor.reverse())
w.coordinates = change.changes["coordinates"].map(coor => [coor[1], coor[0]])
add(w.asGeoJson())
break;
case "relation":
@ -86,7 +85,7 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
}
}
self.features.ping()
})
}

View file

@ -6,19 +6,19 @@ import FeatureSource, {Tiled} from "../FeatureSource";
import {UIEventSource} from "../../UIEventSource";
import {BBox} from "../../BBox";
export default class RememberingSource implements FeatureSource , Tiled{
export default class RememberingSource implements FeatureSource, Tiled {
public readonly features: UIEventSource<{ feature: any, freshness: Date }[]>;
public readonly name;
public readonly tileIndex : number
public readonly bbox : BBox
public readonly tileIndex: number
public readonly bbox: BBox
constructor(source: FeatureSource & Tiled) {
const self = this;
this.name = "RememberingSource of " + source.name;
this.tileIndex= source.tileIndex
this.tileIndex = source.tileIndex
this.bbox = source.bbox;
const empty = [];
this.features = source.features.map(features => {
const oldFeatures = self.features?.data ?? empty;

View file

@ -0,0 +1,118 @@
/**
* This feature source helps the ShowDataLayer class: it introduces the necessary extra features and indiciates with what renderConfig it should be rendered.
*/
import {UIEventSource} from "../../UIEventSource";
import {GeoOperations} from "../../GeoOperations";
import FeatureSource from "../FeatureSource";
import PointRenderingConfig from "../../../Models/ThemeConfig/PointRenderingConfig";
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig";
export default class RenderingMultiPlexerFeatureSource {
public readonly features: UIEventSource<(any & { pointRenderingIndex: number | undefined, lineRenderingIndex: number | undefined })[]>;
constructor(upstream: FeatureSource, layer: LayerConfig) {
this.features = upstream.features.map(
features => {
if (features === undefined) {
return;
}
const pointRenderObjects: { rendering: PointRenderingConfig, index: number }[] = layer.mapRendering.map((r, i) => ({
rendering: r,
index: i
}))
const pointRenderings = pointRenderObjects.filter(r => r.rendering.location.has("point"))
const centroidRenderings = pointRenderObjects.filter(r => r.rendering.location.has("centroid"))
const startRenderings = pointRenderObjects.filter(r => r.rendering.location.has("start"))
const endRenderings = pointRenderObjects.filter(r => r.rendering.location.has("end"))
const lineRenderObjects = layer.lineRendering
const withIndex: (any & { pointRenderingIndex: number | undefined, lineRenderingIndex: number | undefined, multiLineStringIndex: number | undefined })[] = [];
function addAsPoint(feat, rendering, coordinate) {
const patched = {
...feat,
pointRenderingIndex: rendering.index
}
patched.geometry = {
type: "Point",
coordinates: coordinate
}
withIndex.push(patched)
}
for (const f of features) {
const feat = f.feature;
if (feat.geometry.type === "Point") {
for (const rendering of pointRenderings) {
withIndex.push({
...feat,
pointRenderingIndex: rendering.index
})
}
} else {
// This is a a line: add the centroids
for (const rendering of centroidRenderings) {
addAsPoint(feat, rendering, GeoOperations.centerpointCoordinates(feat))
}
if (feat.geometry.type === "LineString") {
// Add start- and endpoints
const coordinates = feat.geometry.coordinates
for (const rendering of startRenderings) {
addAsPoint(feat, rendering, coordinates[0])
}
for (const rendering of endRenderings) {
const coordinate = coordinates[coordinates.length - 1]
addAsPoint(feat, rendering, coordinate)
}
}
if (feat.geometry.type === "MultiLineString") {
// Multilinestrings get a special treatment: we split them into their subparts before rendering
const lineList: [number, number][][] = feat.geometry.coordinates
for (let i1 = 0; i1 < lineList.length; i1++) {
const coordinates = lineList[i1];
for (let i = 0; i < lineRenderObjects.length; i++) {
const orig = {
...feat,
lineRenderingIndex: i,
multiLineStringIndex: i1
}
orig.geometry.coordinates = coordinates
orig.geometry.type = "LineString"
withIndex.push(orig)
}
}
}else{
// AT last, add it 'as is' to what we should render
for (let i = 0; i < lineRenderObjects.length; i++) {
withIndex.push({
...feat,
lineRenderingIndex: i
})
}
}
}
}
return withIndex;
}
);
}
}

Some files were not shown because too many files have changed in this diff Show more