- You are not afraid of editing a JSON file. If you don't know what a JSON file is, [read this intro](https://www.w3schools.com/whatis/whatis_json.asp)
A **theme** (or _layout_) is a single map showing one or more layers.
The layers should work together in such a way that they serve a certain **audience**.
You should be able to state in a few sentences whom would be the user of such a map, e.g.
- a cyclist searching for bike repair
- a thirsty person who needs water
- someone who wants to know what their street is named after
- ...
Some layers will be useful for many themes (e.g. _drinking water_, _toilets_, _shops_, ...). Due to this, MapComplete supports to reuse already existing official layers into a theme.
To include an already existing layer, simply type the layer id, e.g.:
```json
{
"id": "my-theme",
"title": "My theme for xyz",
"...": "...",
"layers": [
{
"id": "my super-awesome new layer"
},
"bench",
"shops",
"drinking_water",
"toilet"
]
}
```
Note that it is good practice to use an existing layer and to tweak it:
```json
{
"id": "my super awesome theme",
"...": "...",
"layers": [
{
"builtin": [
"toilet",
"bench"
],
"override": {
"#": "Override is a section which copies all the keys here and 'pastes' them into the existing layers. For example, the 'minzoom' defined here will redifine the minzoom of 'toilet' and 'bench'",
"minzoom": 17,
"#0": "Appending to lists is supported to, e.g. to add an extra question",
"tagRenderings+": [
{
"id": "new-question",
"question": "What is <someproperty>?",
"render": "{property}",
"...": "..."
}
],
"#1": "Note that paths will be followed: the below block will add/change the icon of the layer, without changing the other properties of the first tag rendering. (Assumption: the first mapRendering is the icon rendering)",
"mapRendering": [
{
"icon": {
"render": "new-icon.svg"
}
}
]
}
}
]
}
```
### What is a good layer?
A good layer is layer which shows **all** objects of a certain type, e.g. **all** shops, **all** restaurants, ...
It asks some relevant questions, with the most important and easiests questions first.
#### Don't: use a layer to filter
**Do not define a layer which filters on an attribute**, such as <del>all restaurants with a vegetarian diet</del>, <del>all shops which accept bitcoin</del>.
Instead, use the filter functionality instead. This can be used from the layer to hide some objects based on their properties.
When the contributor wants to add a new point, they'll be notified that some features might be hidden and only be allowed to add a new point when the points are shown.
![](./FilterFunctionality.gif)
```json
{
"id": "my awesome layer",
"tagRenderings": "... some relevant attributes and questions ...",
"mapRenderings": "... display on the map ... ",
"filter": [
{
"id": "vegetarian",
"options": [
{
"question": {
"en": "Has a vegetarian menu"
},
"osmTags": {
"or": [
"diet:vegetarian=yes",
"diet:vegetarian=only",
"diet:vegan=yes",
"diet:vegan=only"
]
}
}
]
}
]
}
```
If you want to show only features of a certain type, there is a workaround.
For example, the [fritures map](https://mapcomplete.org/fritures.html?z=1&welcome-control-toggle=true) will show french fries shop, aka every `amenity~fast_food|restaurant` with `cuisine=friture`.
However, quite a few fritures are already mapped as fastfood but have their `cuisine`-tag missing (or misspelled).
There is a workaround for this: show **all** food related items at zoomlevel 19 (or higher), and only show the fritures when zoomed out.
In order to achieve this:
1. The layer 'food' is defined in a separate file and reused
2. The layer food is imported in the theme 'fritures'. With 'override', some properties are changed, namely:
- The `osmTags` are overwritten: `cuisine=friture` is now required
- The presets are overwritten and _disabled_
- The _id_ and _name_ of the layer are changed
3. The layer `food` is imported _a second time_, but now the minzoom is set to `19`. This will show _all_ restaurants.
In case of a friture which is already added as fastfood, they'll see the fastfood popup instead of adding a new item:
![](./FilteredByDepth.gif)
```json
{
"layers": [
{
"builtin": "food",
"override": {
"id": "friture",
"name": {
"en": "Fries shop"
},
"=presets": [],
"source": {
"=osmTags": {
"and": [
"cuisine=friture",
{
"or": [
"amenity=fast_food",
"amenity=restaurant"
]
}
]
}
}
}
},
{
"builtin": "food",
"override": {
"minzoom": 19,
"filter": null,
"name": null
}
}
]
}
```
### What is a good question and tagrendering?
A tagrendering maps an attribute onto a piece of human readable text.
These should be **full sentences**, e.g. `"render": "The maximum speed of this road is {maxspeed} km/h"`
In some cases, there might be some predifined special values as mappings, such as `"mappings": [{"if": "maxspeed=30", "then": "The maxspeed is 30km/h"}]`
The question then follows logically: `{"question": "What is the maximum allowed speed for this road, in km/h?"}`
At last, you'll also want to say that the user can type an answer too and that it has to be a number: `"freeform":{"key": "maxspeed","type":"pnat"}`.
The entire tagRendering will thus be:
```json
{
"question": "What is the maximum allowed speed for this road, in km/h?",
"render": "The maximum speed of this road is {maxspeed} km/h",
"freeform":{"key": "maxspeed","type":"pnat"},
"mappings": [{"if": "maxspeed=30", "then": "The maxspeed is 30km/h"}]
2) Make sure your theme has good tagging - i.e. a wiki page must exist for the used tags
3) Make sure there are somewhat decent icons. Note that there is _no_ styleguide at the moment though. Icons must be included and have license info in the corresponding `license_info.json`-files. (Run `npm run query:licenses` to build those)