Merge remote-tracking branch 'origin/develop' into project/cycle-infra

This commit is contained in:
pgm-chardelv1 2021-07-27 15:16:55 +02:00
commit ccf1e636ee
35 changed files with 16664 additions and 274 deletions

View file

@ -6,12 +6,13 @@ import {And} from "../../Logic/Tags/And";
import {Tag} from "../../Logic/Tags/Tag";
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
import SubstitutingTag from "../../Logic/Tags/SubstitutingTag";
import ComparingTag from "../../Logic/Tags/ComparingTag";
export class FromJSON {
public static SimpleTag(json: string, context?: string): Tag {
const tag = Utils.SplitFirst(json, "=");
if(tag.length !== 2){
if (tag.length !== 2) {
throw `Invalid tag: no (or too much) '=' found (in ${context ?? "unkown context"})`
}
return new Tag(tag[0], tag[1]);
@ -26,6 +27,15 @@ export class FromJSON {
}
}
private static comparators
: [string, (a: number, b: number) => boolean][]
= [
["<=", (a, b) => a <= b],
[">=", (a, b) => a >= b],
["<", (a, b) => a < b],
[">", (a, b) => a > b],
]
private static TagUnsafe(json: AndOrTagConfigJson | string, context: string = ""): TagsFilter {
if (json === undefined) {
@ -33,6 +43,27 @@ export class FromJSON {
}
if (typeof (json) == "string") {
const tag = json as string;
for (const [operator, comparator] of FromJSON.comparators) {
if (tag.indexOf(operator) >= 0) {
const split = Utils.SplitFirst(tag, operator);
const val = Number(split[1].trim())
if (isNaN(val)) {
throw `Error: not a valid value for a comparison: ${split[1]}, make sure it is a number and nothing more (at ${context})`
}
const f = (value: string | undefined) => {
const b = Number(value?.replace(/[^\d.]/g,''))
if (isNaN(b)) {
return false;
}
return comparator(b, val)
}
return new ComparingTag(split[0], f, operator + val)
}
}
if (tag.indexOf("!~") >= 0) {
const split = Utils.SplitFirst(tag, "!~");
if (split[1] === "*") {
@ -54,11 +85,11 @@ export class FromJSON {
new RegExp("^" + split[1] + "$")
);
}
if(tag.indexOf(":=") >= 0){
if (tag.indexOf(":=") >= 0) {
const split = Utils.SplitFirst(tag, ":=");
return new SubstitutingTag(split[0], split[1]);
}
if (tag.indexOf("!=") >= 0) {
const split = Utils.SplitFirst(tag, "!=");
if (split[1] === "*") {

View file

@ -95,7 +95,7 @@ export default class LayoutConfig {
}
);
this.defaultBackgroundId = json.defaultBackgroundId;
this.layers = LayoutConfig.ExtractLayers(json, this.units, official);
this.layers = LayoutConfig.ExtractLayers(json, this.units, official, context);
// ALl the layers are constructed, let them share tags in now!
const roaming: { r, source: LayerConfig }[] = []
@ -160,12 +160,12 @@ export default class LayoutConfig {
}
private static ExtractLayers(json: LayoutConfigJson, units: Unit[], official: boolean): LayerConfig[] {
private static ExtractLayers(json: LayoutConfigJson, units: Unit[], official: boolean, context: string): LayerConfig[] {
const result: LayerConfig[] = []
json.layers.forEach((layer, i) => {
if (typeof layer === "string") {
if (AllKnownLayers.sharedLayersJson[layer] !== undefined) {
if (AllKnownLayers.sharedLayersJson.get(layer) !== undefined) {
if (json.overrideAll !== undefined) {
let lyr = JSON.parse(JSON.stringify(AllKnownLayers.sharedLayersJson[layer]));
const newLayer = new LayerConfig(Utils.Merge(json.overrideAll, lyr), units, `${json.id}+overrideAll.layers[${i}]`, official)
@ -176,7 +176,8 @@ export default class LayoutConfig {
return
}
} else {
throw "Unknown fixed layer " + layer;
console.log("Layer ", layer," not kown, try one of", Array.from(AllKnownLayers.sharedLayers.keys()).join(", "))
throw `Unknown builtin layer ${layer} at ${context}.layers[${i}]`;
}
}
@ -195,9 +196,9 @@ export default class LayoutConfig {
names = [names]
}
names.forEach(name => {
const shared = AllKnownLayers.sharedLayersJson[name];
const shared = AllKnownLayers.sharedLayersJson.get(name);
if (shared === undefined) {
throw "Unknown fixed layer " + name;
throw `Unknown shared/builtin layer ${name} at ${context}.layers[${i}]. Available layers are ${Array.from(AllKnownLayers.sharedLayersJson.keys()).join(", ")}`;
}
// @ts-ignore
let newLayer: LayerConfigJson = Utils.Merge(layer.override, JSON.parse(JSON.stringify(shared))); // We make a deep copy of the shared layer, in order to protect it from changes

View file

@ -141,6 +141,7 @@ Some advanced functions are available on **feat** as well:
- overlapWith
- closest
- memberships
- score
### distanceTo
@ -168,4 +169,12 @@ Some advanced functions are available on **feat** as well:
For example: `_part_of_walking_routes=feat.memberships().map(r => r.relation.tags.name).join(';')`
### score
Given the path of an aspected routing json file, will calculate the score. This score is wrapped in a UIEventSource, so for further calculations, use `.map(score => ...)`
For example: `_comfort_score=feat.score('https://raw.githubusercontent.com/pietervdvn/AspectedRouting/master/Examples/bicycle/aspects/bicycle.comfort.json')`
0. path
Generated from SimpleMetaTagger, ExtraFunction

View file

@ -0,0 +1,111 @@
{
"data_format": 1,
"project": {
"name": "MapComplete Open Artwork Map",
"description": "Welcome to Open Artwork Map, a map of statues, busts, grafittis and other artwork all over the world",
"project_url": "https://mapcomplete.osm.be/artwork",
"doc_url": "https://github.com/pietervdvn/MapComplete/tree/master/assets/themes/",
"icon_url": "https://mapcomplete.osm.be/assets/themes/artwork/artwork.svg",
"contact_name": "Pieter Vander Vennet, MapComplete",
"contact_email": "pietervdvn@posteo.net"
},
"tags": [
{
"key": "tourism",
"description": "The MapComplete theme Open Artwork Map has a layer Artworks showing features with this tag",
"value": "artwork"
},
{
"key": "image",
"description": "The layer 'Artworks 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 'Artworks 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 'Artworks 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 'Artworks 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": "artwork_type",
"description": "Layer 'Artworks' shows and asks freeform values for key 'artwork_type' (in the MapComplete.osm.be theme 'Open Artwork Map')"
},
{
"key": "artwork_type",
"description": "Layer 'Artworks' shows artwork_type=architecture with a fixed text, namely 'Architecture' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Artwork Map')",
"value": "architecture"
},
{
"key": "artwork_type",
"description": "Layer 'Artworks' shows artwork_type=mural with a fixed text, namely 'Mural' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Artwork Map')",
"value": "mural"
},
{
"key": "artwork_type",
"description": "Layer 'Artworks' shows artwork_type=painting with a fixed text, namely 'Painting' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Artwork Map')",
"value": "painting"
},
{
"key": "artwork_type",
"description": "Layer 'Artworks' shows artwork_type=sculpture with a fixed text, namely 'Sculpture' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Artwork Map')",
"value": "sculpture"
},
{
"key": "artwork_type",
"description": "Layer 'Artworks' shows artwork_type=statue with a fixed text, namely 'Statue' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Artwork Map')",
"value": "statue"
},
{
"key": "artwork_type",
"description": "Layer 'Artworks' shows artwork_type=bust with a fixed text, namely 'Bust' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Artwork Map')",
"value": "bust"
},
{
"key": "artwork_type",
"description": "Layer 'Artworks' shows artwork_type=stone with a fixed text, namely 'Stone' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Artwork Map')",
"value": "stone"
},
{
"key": "artwork_type",
"description": "Layer 'Artworks' shows artwork_type=installation with a fixed text, namely 'Installation' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Artwork Map')",
"value": "installation"
},
{
"key": "artwork_type",
"description": "Layer 'Artworks' shows artwork_type=graffiti with a fixed text, namely 'Graffiti' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Artwork Map')",
"value": "graffiti"
},
{
"key": "artwork_type",
"description": "Layer 'Artworks' shows artwork_type=relief with a fixed text, namely 'Relief' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Artwork Map')",
"value": "relief"
},
{
"key": "artwork_type",
"description": "Layer 'Artworks' shows artwork_type=azulejo with a fixed text, namely 'Azulejo (Spanish decorative tilework)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Artwork Map')",
"value": "azulejo"
},
{
"key": "artwork_type",
"description": "Layer 'Artworks' shows artwork_type=tilework with a fixed text, namely 'Tilework' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Open Artwork Map')",
"value": "tilework"
},
{
"key": "artist_name",
"description": "Layer 'Artworks' shows and asks freeform values for key 'artist_name' (in the MapComplete.osm.be theme 'Open Artwork Map')"
},
{
"key": "website",
"description": "Layer 'Artworks' shows and asks freeform values for key 'website' (in the MapComplete.osm.be theme 'Open Artwork Map')"
},
{
"key": "wikidata",
"description": "Layer 'Artworks' shows and asks freeform values for key 'wikidata' (in the MapComplete.osm.be theme 'Open Artwork Map')"
}
]
}

View file

@ -5,7 +5,7 @@
"description": "A bicycle library is a place where bicycles can be lent, often for a small yearly fee",
"project_url": "https://mapcomplete.osm.be/bicyclelib",
"doc_url": "https://github.com/pietervdvn/MapComplete/tree/master/assets/themes/",
"icon_url": "https://mapcomplete.osm.be/assets/themes/bicycle_library/logo.svg",
"icon_url": "https://mapcomplete.osm.be/assets/themes/bicyclelib/logo.svg",
"contact_name": "Pieter Vander Vennet, MapComplete",
"contact_email": "pietervdvn@posteo.net"
},

View file

@ -5,7 +5,7 @@
"description": "Find sites to spend the night with your camper",
"project_url": "https://mapcomplete.osm.be/campersite",
"doc_url": "https://github.com/pietervdvn/MapComplete/tree/master/assets/themes/",
"icon_url": "https://mapcomplete.osm.be/assets/themes/campersites/caravan.svg",
"icon_url": "https://mapcomplete.osm.be/assets/themes/campersite/caravan.svg",
"contact_name": "Pieter Vander Vennet, joost schouppe",
"contact_email": "pietervdvn@posteo.net"
},

View file

@ -0,0 +1,707 @@
{
"data_format": 1,
"project": {
"name": "MapComplete Bicycle infrastructure",
"description": "A map where you can view and edit things related to the bicycle infrastructure.",
"project_url": "https://mapcomplete.osm.be/cycle_infra",
"doc_url": "https://github.com/pietervdvn/MapComplete/tree/master/assets/themes/",
"icon_url": "https://mapcomplete.osm.be/assets/themes/cycle_infra/cycle-infra.svg",
"contact_name": "Pieter Vander Vennet, ",
"contact_email": "pietervdvn@posteo.net"
},
"tags": [
{
"key": "highway",
"description": "The MapComplete theme Bicycle infrastructure has a layer Cycleways showing features with this tag",
"value": "cycleway"
},
{
"key": "cycleway",
"description": "The MapComplete theme Bicycle infrastructure has a layer Cycleways showing features with this tag",
"value": "lane"
},
{
"key": "cycleway",
"description": "The MapComplete theme Bicycle infrastructure has a layer Cycleways showing features with this tag",
"value": "shared_lane"
},
{
"key": "cycleway",
"description": "The MapComplete theme Bicycle infrastructure has a layer Cycleways showing features with this tag",
"value": "track"
},
{
"key": "cyclestreet",
"description": "The MapComplete theme Bicycle infrastructure has a layer Cycleways showing features with this tag",
"value": "yes"
},
{
"key": "highway",
"description": "The MapComplete theme Bicycle infrastructure has a layer Cycleways showing features with this tag",
"value": "path"
},
{
"key": "bicycle",
"description": "The MapComplete theme Bicycle infrastructure has a layer Cycleways showing features with this tag",
"value": "designated"
},
{
"key": "cycleway",
"description": "Layer 'Cycleways' shows cycleway=shared_lane with a fixed text, namely 'There is a shared lane' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "shared_lane"
},
{
"key": "cycleway",
"description": "Layer 'Cycleways' shows cycleway=lane with a fixed text, namely 'There is a lane next to the road (seperated with paint)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "lane"
},
{
"key": "cycleway",
"description": "Layer 'Cycleways' shows cycleway=track with a fixed text, namely 'There is a track, but no cycleway drawn seperately from this road on the map.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "track"
},
{
"key": "cycleway",
"description": "Layer 'Cycleways' shows cycleway=seperate with a fixed text, namely 'There is a seperately drawn cycleway' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "seperate"
},
{
"key": "cycleway",
"description": "Layer 'Cycleways' shows cycleway=no with a fixed text, namely 'There is no cycleway' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "no"
},
{
"key": "cycleway",
"description": "Layer 'Cycleways' shows cycleway=no with a fixed text, namely 'There is no cycleway' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "no"
},
{
"key": "lit",
"description": "Layer 'Cycleways' 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 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "lit",
"description": "Layer 'Cycleways' shows lit=no with a fixed text, namely 'This road is not lit' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "no"
},
{
"key": "lit",
"description": "Layer 'Cycleways' shows lit=sunset-sunrise with a fixed text, namely 'This road is lit at night' (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "sunset-sunrise"
},
{
"key": "lit",
"description": "Layer 'Cycleways' shows lit=24/7 with a fixed text, namely 'This road is lit 24/7' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "24/7"
},
{
"key": "cyclestreet",
"description": "Layer 'Cycleways' shows cyclestreet=yes with a fixed text, namely 'This is a cyclestreet, and a 30km/h zone.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "cyclestreet",
"description": "Layer 'Cycleways' shows cyclestreet=yes with a fixed text, namely 'This is a cyclestreet' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "cyclestreet",
"description": "Layer 'Cycleways' shows cyclestreet= with a fixed text, namely 'This is not a cyclestreet.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure') Picking this answer will delete the key cyclestreet.",
"value": ""
},
{
"key": "maxspeed",
"description": "Layer 'Cycleways' shows and asks freeform values for key 'maxspeed' (in the MapComplete.osm.be theme 'Bicycle infrastructure')"
},
{
"key": "maxspeed",
"description": "Layer 'Cycleways' shows maxspeed=20 with a fixed text, namely 'The maximum speed is 20 km/h' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "20"
},
{
"key": "maxspeed",
"description": "Layer 'Cycleways' shows maxspeed=30 with a fixed text, namely 'The maximum speed is 30 km/h' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "30"
},
{
"key": "maxspeed",
"description": "Layer 'Cycleways' shows maxspeed=50 with a fixed text, namely 'The maximum speed is 50 km/h' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "50"
},
{
"key": "maxspeed",
"description": "Layer 'Cycleways' shows maxspeed=70 with a fixed text, namely 'The maximum speed is 70 km/h' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "70"
},
{
"key": "maxspeed",
"description": "Layer 'Cycleways' shows maxspeed=90 with a fixed text, namely 'The maximum speed is 90 km/h' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "90"
},
{
"key": "cycleway:surface",
"description": "Layer 'Cycleways' shows and asks freeform values for key 'cycleway:surface' (in the MapComplete.osm.be theme 'Bicycle infrastructure')"
},
{
"key": "cycleway:surface",
"description": "Layer 'Cycleways' shows cycleway:surface=wood with a fixed text, namely 'This cycleway is made of wood' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "wood"
},
{
"key": "cycleway:surface",
"description": "Layer 'Cycleways' shows cycleway:surface=concrete with a fixed text, namely 'This cycleway is made of concrete' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "concrete"
},
{
"key": "cycleway:surface",
"description": "Layer 'Cycleways' shows cycleway:surface=cobblestone with a fixed text, namely 'This cycleway is made of cobblestone' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "cobblestone"
},
{
"key": "cycleway:surface",
"description": "Layer 'Cycleways' shows cycleway:surface=asphalt with a fixed text, namely 'This cycleway is made of asphalt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "asphalt"
},
{
"key": "cycleway:surface",
"description": "Layer 'Cycleways' shows cycleway:surface=paved with a fixed text, namely 'This cycleway is paved' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "paved"
},
{
"key": "cycleway:smoothness",
"description": "Layer 'Cycleways' shows cycleway:smoothness=excellent with a fixed text, namely 'Usable for thin rollers: rollerblade, skateboard' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "excellent"
},
{
"key": "cycleway:smoothness",
"description": "Layer 'Cycleways' shows cycleway:smoothness=good with a fixed text, namely 'Usable for thin wheels: racing bike' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "good"
},
{
"key": "cycleway:smoothness",
"description": "Layer 'Cycleways' shows cycleway:smoothness=intermediate with a fixed text, namely 'Usable for normal wheels: city bike, wheelchair, scooter' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "intermediate"
},
{
"key": "cycleway:smoothness",
"description": "Layer 'Cycleways' shows cycleway:smoothness=bad with a fixed text, namely 'Usable for robust wheels: trekking bike, car, rickshaw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "bad"
},
{
"key": "cycleway:smoothness",
"description": "Layer 'Cycleways' shows cycleway:smoothness=very_bad with a fixed text, namely 'Usable for vehicles with high clearance: light duty off-road vehicle' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "very_bad"
},
{
"key": "cycleway:smoothness",
"description": "Layer 'Cycleways' shows cycleway:smoothness=horrible with a fixed text, namely 'Usable for off-road vehicles: heavy duty off-road vehicle' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "horrible"
},
{
"key": "cycleway:smoothness",
"description": "Layer 'Cycleways' shows cycleway:smoothness=very_horrible with a fixed text, namely 'Usable for specialized off-road vehicles: tractor, ATV' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "very_horrible"
},
{
"key": "cycleway:smoothness",
"description": "Layer 'Cycleways' shows cycleway:smoothness=impassable with a fixed text, namely 'Impassable / No wheeled vehicle' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "impassable"
},
{
"key": "surface",
"description": "Layer 'Cycleways' shows and asks freeform values for key 'surface' (in the MapComplete.osm.be theme 'Bicycle infrastructure')"
},
{
"key": "surface",
"description": "Layer 'Cycleways' shows surface=wood with a fixed text, namely 'This street is made of wood' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "wood"
},
{
"key": "surface",
"description": "Layer 'Cycleways' shows surface=concrete with a fixed text, namely 'This street is made of concrete' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "concrete"
},
{
"key": "surface",
"description": "Layer 'Cycleways' shows surface=cobblestone with a fixed text, namely 'This street is made of cobblestone' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "cobblestone"
},
{
"key": "surface",
"description": "Layer 'Cycleways' shows surface=asphalt with a fixed text, namely 'This street is made of asphalt' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "asphalt"
},
{
"key": "surface",
"description": "Layer 'Cycleways' shows surface=paved with a fixed text, namely 'This street is paved' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "paved"
},
{
"key": "smoothness",
"description": "Layer 'Cycleways' shows smoothness=excellent with a fixed text, namely 'Usable for thin rollers: rollerblade, skateboard' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "excellent"
},
{
"key": "smoothness",
"description": "Layer 'Cycleways' shows smoothness=good with a fixed text, namely 'Usable for thin wheels: racing bike' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "good"
},
{
"key": "smoothness",
"description": "Layer 'Cycleways' shows smoothness=intermediate with a fixed text, namely 'Usable for normal wheels: city bike, wheelchair, scooter' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "intermediate"
},
{
"key": "smoothness",
"description": "Layer 'Cycleways' shows smoothness=bad with a fixed text, namely 'Usable for robust wheels: trekking bike, car, rickshaw' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "bad"
},
{
"key": "smoothness",
"description": "Layer 'Cycleways' shows smoothness=very_bad with a fixed text, namely 'Usable for vehicles with high clearance: light duty off-road vehicle' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "very_bad"
},
{
"key": "smoothness",
"description": "Layer 'Cycleways' shows smoothness=horrible with a fixed text, namely 'Usable for off-road vehicles: heavy duty off-road vehicle' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "horrible"
},
{
"key": "smoothness",
"description": "Layer 'Cycleways' shows smoothness=very_horrible with a fixed text, namely 'Usable for specialized off-road vehicles: tractor, ATV' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "very_horrible"
},
{
"key": "smoothness",
"description": "Layer 'Cycleways' shows smoothness=impassable with a fixed text, namely 'Impassable / No wheeled vehicle' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "impassable"
},
{
"key": "width:carriageway",
"description": "Layer 'Cycleways' shows and asks freeform values for key 'width:carriageway' (in the MapComplete.osm.be theme 'Bicycle infrastructure')"
},
{
"key": "cycleway:traffic_sign",
"description": "Layer 'Cycleways' shows cycleway:traffic_sign=BE:D7 with a fixed text, namely 'Compulsory cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7"
},
{
"key": "cycleway:traffic_sign",
"description": "Layer 'Cycleways' shows cycleway:traffic_sign~^BE:D7;.*$ with a fixed text, namely 'Compulsory cycleway (with supplementary sign)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'> ' (in the MapComplete.osm.be theme 'Bicycle infrastructure')"
},
{
"key": "cycleway:traffic_sign",
"description": "Layer 'Cycleways' shows cycleway:traffic_sign=BE:D9 with a fixed text, namely 'Segregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D9"
},
{
"key": "cycleway:traffic_sign",
"description": "Layer 'Cycleways' shows cycleway:traffic_sign=BE:D10 with a fixed text, namely 'Unsegregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D10"
},
{
"key": "cycleway:traffic_sign",
"description": "Layer 'Cycleways' shows cycleway:traffic_sign=none with a fixed text, namely 'No traffic sign present' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "none"
},
{
"key": "traffic_sign",
"description": "Layer 'Cycleways' shows traffic_sign=BE:D7 with a fixed text, namely 'Compulsory cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7"
},
{
"key": "traffic_sign",
"description": "Layer 'Cycleways' shows traffic_sign~^BE:D7;.*$ with a fixed text, namely 'Compulsory cycleway (with supplementary sign)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'> ' (in the MapComplete.osm.be theme 'Bicycle infrastructure')"
},
{
"key": "traffic_sign",
"description": "Layer 'Cycleways' shows traffic_sign=BE:D9 with a fixed text, namely 'Segregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D9"
},
{
"key": "traffic_sign",
"description": "Layer 'Cycleways' shows traffic_sign=BE:D10 with a fixed text, namely 'Unsegregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D10"
},
{
"key": "traffic_sign",
"description": "Layer 'Cycleways' shows traffic_sign=none with a fixed text, namely 'No traffic sign present' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "none"
},
{
"key": "cycleway:traffic_sign",
"description": "Layer 'Cycleways' shows cycleway:traffic_sign=BE:D7;BE:M6 with a fixed text, namely '<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7;BE:M6"
},
{
"key": "cycleway:traffic_sign",
"description": "Layer 'Cycleways' shows cycleway:traffic_sign=BE:D7;BE:M13 with a fixed text, namely '<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7;BE:M13"
},
{
"key": "cycleway:traffic_sign",
"description": "Layer 'Cycleways' shows cycleway:traffic_sign=BE:D7;BE:M14 with a fixed text, namely '<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7;BE:M14"
},
{
"key": "cycleway:traffic_sign",
"description": "Layer 'Cycleways' shows cycleway:traffic_sign=BE:D7;BE:M7 with a fixed text, namely '<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7;BE:M7"
},
{
"key": "cycleway:traffic_sign",
"description": "Layer 'Cycleways' shows cycleway:traffic_sign=BE:D7;BE:M15 with a fixed text, namely '<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7;BE:M15"
},
{
"key": "cycleway:traffic_sign",
"description": "Layer 'Cycleways' shows cycleway:traffic_sign=BE:D7;BE:M16 with a fixed text, namely '<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7;BE:M16"
},
{
"key": "cycleway:traffic_sign:supplementary",
"description": "Layer 'Cycleways' shows cycleway:traffic_sign:supplementary=none with a fixed text, namely 'No supplementary traffic sign present' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "none"
},
{
"key": "traffic_sign",
"description": "Layer 'Cycleways' shows traffic_sign=BE:D7;BE:M6 with a fixed text, namely '<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7;BE:M6"
},
{
"key": "traffic_sign",
"description": "Layer 'Cycleways' shows traffic_sign=BE:D7;BE:M13 with a fixed text, namely '<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7;BE:M13"
},
{
"key": "traffic_sign",
"description": "Layer 'Cycleways' shows traffic_sign=BE:D7;BE:M14 with a fixed text, namely '<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7;BE:M14"
},
{
"key": "traffic_sign",
"description": "Layer 'Cycleways' shows traffic_sign=BE:D7;BE:M7 with a fixed text, namely '<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7;BE:M7"
},
{
"key": ":traffic_sign",
"description": "Layer 'Cycleways' shows :traffic_sign=BE:D7;BE:M15 with a fixed text, namely '<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7;BE:M15"
},
{
"key": "traffic_sign",
"description": "Layer 'Cycleways' shows traffic_sign=BE:D7;BE:M16 with a fixed text, namely '<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "BE:D7;BE:M16"
},
{
"key": "traffic_sign:supplementary",
"description": "Layer 'Cycleways' shows traffic_sign:supplementary=none with a fixed text, namely 'No supplementary traffic sign present' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "none"
},
{
"key": "cycleway:buffer",
"description": "Layer 'Cycleways' shows and asks freeform values for key 'cycleway:buffer' (in the MapComplete.osm.be theme 'Bicycle infrastructure')"
},
{
"key": "cycleway:seperation",
"description": "Layer 'Cycleways' shows cycleway:seperation=dashed_line with a fixed text, namely 'This cycleway is seperated by a dashed line' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "dashed_line"
},
{
"key": "cycleway:seperation",
"description": "Layer 'Cycleways' shows cycleway:seperation=solid_line with a fixed text, namely 'This cycleway is seperated by a solid line' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "solid_line"
},
{
"key": "cycleway:seperation",
"description": "Layer 'Cycleways' shows cycleway:seperation=parking_lane with a fixed text, namely 'This cycleway is seperated by a parking lane' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "parking_lane"
},
{
"key": "cycleway:seperation",
"description": "Layer 'Cycleways' shows cycleway:seperation=kerb with a fixed text, namely 'This cycleway is seperated by a kerb' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "kerb"
},
{
"key": "seperation",
"description": "Layer 'Cycleways' shows seperation=dashed_line with a fixed text, namely 'This cycleway is seperated by a dashed line' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "dashed_line"
},
{
"key": "seperation",
"description": "Layer 'Cycleways' shows seperation=solid_line with a fixed text, namely 'This cycleway is seperated by a solid line' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "solid_line"
},
{
"key": "seperation",
"description": "Layer 'Cycleways' shows seperation=parking_lane with a fixed text, namely 'This cycleway is seperated by a parking lane' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "parking_lane"
},
{
"key": "seperation",
"description": "Layer 'Cycleways' shows seperation=kerb with a fixed text, namely 'This cycleway is seperated by a kerb' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "kerb"
},
{
"key": "highway",
"description": "The MapComplete theme Bicycle infrastructure has a layer All streets showing features with this tag",
"value": "residential"
},
{
"key": "highway",
"description": "The MapComplete theme Bicycle infrastructure has a layer All streets showing features with this tag",
"value": "tertiary"
},
{
"key": "highway",
"description": "The MapComplete theme Bicycle infrastructure has a layer All streets showing features with this tag",
"value": "unclassified"
},
{
"key": "highway",
"description": "The MapComplete theme Bicycle infrastructure has a layer All streets showing features with this tag",
"value": "primary"
},
{
"key": "highway",
"description": "The MapComplete theme Bicycle infrastructure has a layer All streets showing features with this tag",
"value": "secondary"
},
{
"key": "cycleway",
"description": "Layer 'All streets' shows and asks freeform values for key 'cycleway' (in the MapComplete.osm.be theme 'Bicycle infrastructure')"
},
{
"key": "cycleway",
"description": "Layer 'All streets' shows cycleway=shared_lane with a fixed text, namely 'There is a shared lane' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "shared_lane"
},
{
"key": "cycleway",
"description": "Layer 'All streets' shows cycleway=lane with a fixed text, namely 'There is a lane next to the road (seperated with paint)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "lane"
},
{
"key": "cycleway",
"description": "Layer 'All streets' shows cycleway=track with a fixed text, namely 'There is a track, but no cycleway drawn seperately from this road on the map.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "track"
},
{
"key": "cycleway",
"description": "Layer 'All streets' shows cycleway=seperate with a fixed text, namely 'There is a seperately drawn cycleway' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "seperate"
},
{
"key": "cycleway",
"description": "Layer 'All streets' shows cycleway= with a fixed text, namely 'There is no cycleway known here' (in the MapComplete.osm.be theme 'Bicycle infrastructure') Picking this answer will delete the key cycleway.",
"value": ""
},
{
"key": "cycleway",
"description": "Layer 'All streets' shows cycleway=no with a fixed text, namely 'There is no cycleway' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "no"
},
{
"key": "cycleway",
"description": "Layer 'All streets' shows cycleway=no with a fixed text, namely 'There is no cycleway' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "no"
},
{
"key": "cyclestreet",
"description": "Layer 'All streets' shows cyclestreet=yes with a fixed text, namely 'This is a cyclestreet, and a 30km/h zone.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "cyclestreet",
"description": "Layer 'All streets' shows cyclestreet=yes with a fixed text, namely 'This is a cyclestreet' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "cyclestreet",
"description": "Layer 'All streets' shows cyclestreet= with a fixed text, namely 'This is not a cyclestreet.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure') Picking this answer will delete the key cyclestreet.",
"value": ""
},
{
"key": "barrier",
"description": "The MapComplete theme Bicycle infrastructure has a layer Barriers showing features with this tag",
"value": "bollard"
},
{
"key": "barrier",
"description": "The MapComplete theme Bicycle infrastructure has a layer Barriers showing features with this tag",
"value": "cycle_barrier"
},
{
"key": "bicycle",
"description": "Layer 'Barriers' shows bicycle=yes with a fixed text, namely 'A cyclist can go past this.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "bicycle",
"description": "Layer 'Barriers' shows bicycle=no with a fixed text, namely 'A cyclist can not go past this.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "no"
},
{
"key": "bollard",
"description": "Layer 'Barriers' shows bollard=removable with a fixed text, namely 'Removable bollard' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "removable"
},
{
"key": "bollard",
"description": "Layer 'Barriers' shows bollard=fixed with a fixed text, namely 'Fixed bollard' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "fixed"
},
{
"key": "bollard",
"description": "Layer 'Barriers' shows bollard=foldable with a fixed text, namely 'Bollard that can be folded down' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "foldable"
},
{
"key": "bollard",
"description": "Layer 'Barriers' shows bollard=flexible with a fixed text, namely 'Flexible bollard, usually plastic' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "flexible"
},
{
"key": "bollard",
"description": "Layer 'Barriers' shows bollard=rising with a fixed text, namely 'Rising bollard' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "rising"
},
{
"key": "cycle_barrier:type",
"description": "Layer 'Barriers' shows cycle_barrier:type=single with a fixed text, namely 'Single, just two barriers with a space inbetween <img src='./assets/themes/cycle_infra/Cycle_barrier_single.png' style='width:8em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "single"
},
{
"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')",
"value": "double"
},
{
"key": "cycle_barrier:type",
"description": "Layer 'Barriers' shows cycle_barrier:type=triple with a fixed text, namely 'Triple, three barriers behind each other <img src='./assets/themes/cycle_infra/Cycle_barrier_triple.png' style='width:8em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "triple"
},
{
"key": "cycle_barrier:type",
"description": "Layer 'Barriers' shows cycle_barrier:type=squeeze with a fixed text, namely 'Squeeze gate, gap is smaller at top, than at the bottom <img src='./assets/themes/cycle_infra/Cycle_barrier_squeeze.png' style='width:8em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "squeeze"
},
{
"key": "maxwidth:physical",
"description": "Layer 'Barriers' shows and asks freeform values for key 'maxwidth:physical' (in the MapComplete.osm.be theme 'Bicycle infrastructure')"
},
{
"key": "width:seperation",
"description": "Layer 'Barriers' shows and asks freeform values for key 'width:seperation' (in the MapComplete.osm.be theme 'Bicycle infrastructure')"
},
{
"key": "width:opening",
"description": "Layer 'Barriers' shows and asks freeform values for key 'width:opening' (in the MapComplete.osm.be theme 'Bicycle infrastructure')"
},
{
"key": "overlap",
"description": "Layer 'Barriers' shows and asks freeform values for key 'overlap' (in the MapComplete.osm.be theme 'Bicycle infrastructure')"
},
{
"key": "highway",
"description": "The MapComplete theme Bicycle infrastructure has a layer Crossings showing features with this tag",
"value": "traffic_signals"
},
{
"key": "highway",
"description": "The MapComplete theme Bicycle infrastructure has a layer Crossings showing features with this tag",
"value": "crossing"
},
{
"key": "crossing",
"description": "Layer 'Crossings' shows crossing=uncontrolled with a fixed text, namely 'Crossing, without traffic lights' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "uncontrolled"
},
{
"key": "crossing",
"description": "Layer 'Crossings' shows crossing=traffic_signals with a fixed text, namely 'Crossing with traffic signals' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "traffic_signals"
},
{
"key": "crossing",
"description": "Layer 'Crossings' shows crossing=zebra with a fixed text, namely 'Zebra crossing' (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "zebra"
},
{
"key": "bicycle",
"description": "Layer 'Crossings' shows bicycle=yes with a fixed text, namely 'A cyclist can use this crossing' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "bicycle",
"description": "Layer 'Crossings' shows bicycle=no with a fixed text, namely 'A cyclist can not use this crossing' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "no"
},
{
"key": "crossing:island",
"description": "Layer 'Crossings' shows crossing:island=yes with a fixed text, namely 'This crossing has an island in the middle' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "crossing:island",
"description": "Layer 'Crossings' shows crossing:island=no with a fixed text, namely 'This crossing does not have an island in the middle' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "no"
},
{
"key": "tactile_paving",
"description": "Layer 'Crossings' shows tactile_paving=yes with a fixed text, namely 'This crossing has tactile paving' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "tactile_paving",
"description": "Layer 'Crossings' shows tactile_paving=no with a fixed text, namely 'This crossing does not have tactile paving' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "no"
},
{
"key": "tactile_paving",
"description": "Layer 'Crossings' shows tactile_paving=incorrect with a fixed text, namely 'This crossing has tactile paving, but is not correct' (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "incorrect"
},
{
"key": "button_operated",
"description": "Layer 'Crossings' shows button_operated=yes with a fixed text, namely 'This traffic light has a button to request green light' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "button_operated",
"description": "Layer 'Crossings' shows button_operated=no with a fixed text, namely 'This traffic light does not have a button to request green light' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "no"
},
{
"key": "red_turn:right:bicycle",
"description": "Layer 'Crossings' shows red_turn:right:bicycle=yes with a fixed text, namely 'A cyclist can turn right if the light is red <img src='./assets/layers/crossings/Belgian_road_sign_B22.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "red_turn:right:bicycle",
"description": "Layer 'Crossings' shows red_turn:right:bicycle=yes with a fixed text, namely 'A cyclist can turn right if the light is red' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "red_turn:right:bicycle",
"description": "Layer 'Crossings' shows red_turn:right:bicycle=no with a fixed text, namely 'A cyclist can not turn right if the light is red' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "no"
},
{
"key": "red_turn:straight:bicycle",
"description": "Layer 'Crossings' shows red_turn:straight:bicycle=yes with a fixed text, namely 'A cyclist can go straight on if the light is red <img src='./assets/layers/crossings/Belgian_road_sign_B23.svg' style='height: 3em'>' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "red_turn:straight:bicycle",
"description": "Layer 'Crossings' shows red_turn:straight:bicycle=yes with a fixed text, namely 'A cyclist can go straight on if the light is red' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "yes"
},
{
"key": "red_turn:straight:bicycle",
"description": "Layer 'Crossings' shows red_turn:straight:bicycle=no with a fixed text, namely 'A cyclist can not go straight on if the light is red' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Bicycle infrastructure')",
"value": "no"
}
]
}

View file

@ -0,0 +1,264 @@
{
"data_format": 1,
"project": {
"name": "MapComplete Cyclestreets",
"description": "A map of cyclestreets",
"project_url": "https://mapcomplete.osm.be/cyclestreets",
"doc_url": "https://github.com/pietervdvn/MapComplete/tree/master/assets/themes/",
"icon_url": "https://mapcomplete.osm.be/assets/themes/cyclestreets/F111.svg",
"contact_name": "Pieter Vander Vennet, MapComplete",
"contact_email": "pietervdvn@posteo.net"
},
"tags": [
{
"key": "cyclestreet",
"description": "The MapComplete theme Cyclestreets has a layer Cyclestreets showing features with this tag",
"value": "yes"
},
{
"key": "image",
"description": "The layer 'Cyclestreets 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 'Cyclestreets 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 'Cyclestreets 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 'Cyclestreets 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": "cyclestreet",
"description": "Layer 'Cyclestreets' shows cyclestreet=yes&maxspeed=30&overtaking:motor_vehicle=no&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet (and has a speed limit of 30 km/h)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "yes"
},
{
"key": "maxspeed",
"description": "Layer 'Cyclestreets' shows cyclestreet=yes&maxspeed=30&overtaking:motor_vehicle=no&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet (and has a speed limit of 30 km/h)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "30"
},
{
"key": "overtaking:motor_vehicle",
"description": "Layer 'Cyclestreets' shows cyclestreet=yes&maxspeed=30&overtaking:motor_vehicle=no&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet (and has a speed limit of 30 km/h)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "no"
},
{
"key": "proposed:cyclestreet",
"description": "Layer 'Cyclestreets' shows cyclestreet=yes&maxspeed=30&overtaking:motor_vehicle=no&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet (and has a speed limit of 30 km/h)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key proposed:cyclestreet.",
"value": ""
},
{
"key": "cyclestreet",
"description": "Layer 'Cyclestreets' shows cyclestreet=yes&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet' (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "yes"
},
{
"key": "proposed:cyclestreet",
"description": "Layer 'Cyclestreets' shows cyclestreet=yes&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet' (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key proposed:cyclestreet.",
"value": ""
},
{
"key": "cyclestreet",
"description": "Layer 'Cyclestreets' shows cyclestreet=&proposed:cyclestreet=yes with a fixed text, namely 'This street will become a cyclstreet soon' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key cyclestreet.",
"value": ""
},
{
"key": "proposed:cyclestreet",
"description": "Layer 'Cyclestreets' shows cyclestreet=&proposed:cyclestreet=yes with a fixed text, namely 'This street will become a cyclstreet soon' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "yes"
},
{
"key": "cyclestreet",
"description": "Layer 'Cyclestreets' shows cyclestreet=&proposed:cyclestreet=&overtaking:motor_vehicle= with a fixed text, namely 'This street is not a cyclestreet' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key cyclestreet.",
"value": ""
},
{
"key": "proposed:cyclestreet",
"description": "Layer 'Cyclestreets' shows cyclestreet=&proposed:cyclestreet=&overtaking:motor_vehicle= with a fixed text, namely 'This street is not a cyclestreet' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key proposed:cyclestreet.",
"value": ""
},
{
"key": "overtaking:motor_vehicle",
"description": "Layer 'Cyclestreets' shows cyclestreet=&proposed:cyclestreet=&overtaking:motor_vehicle= with a fixed text, namely 'This street is not a cyclestreet' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key overtaking:motor_vehicle.",
"value": ""
},
{
"key": "cyclestreet:start_date",
"description": "Layer 'Cyclestreets' shows and asks freeform values for key 'cyclestreet:start_date' (in the MapComplete.osm.be theme 'Cyclestreets')"
},
{
"key": "proposed:cyclestreet",
"description": "The MapComplete theme Cyclestreets has a layer Future cyclestreet showing features with this tag",
"value": "yes"
},
{
"key": "image",
"description": "The layer 'Future cyclestreet 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 'Future cyclestreet 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 'Future cyclestreet 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 'Future cyclestreet 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": "cyclestreet",
"description": "Layer 'Future cyclestreet' shows cyclestreet=yes&maxspeed=30&overtaking:motor_vehicle=no&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet (and has a speed limit of 30 km/h)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "yes"
},
{
"key": "maxspeed",
"description": "Layer 'Future cyclestreet' shows cyclestreet=yes&maxspeed=30&overtaking:motor_vehicle=no&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet (and has a speed limit of 30 km/h)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "30"
},
{
"key": "overtaking:motor_vehicle",
"description": "Layer 'Future cyclestreet' shows cyclestreet=yes&maxspeed=30&overtaking:motor_vehicle=no&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet (and has a speed limit of 30 km/h)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "no"
},
{
"key": "proposed:cyclestreet",
"description": "Layer 'Future cyclestreet' shows cyclestreet=yes&maxspeed=30&overtaking:motor_vehicle=no&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet (and has a speed limit of 30 km/h)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key proposed:cyclestreet.",
"value": ""
},
{
"key": "cyclestreet",
"description": "Layer 'Future cyclestreet' shows cyclestreet=yes&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet' (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "yes"
},
{
"key": "proposed:cyclestreet",
"description": "Layer 'Future cyclestreet' shows cyclestreet=yes&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet' (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key proposed:cyclestreet.",
"value": ""
},
{
"key": "cyclestreet",
"description": "Layer 'Future cyclestreet' shows cyclestreet=&proposed:cyclestreet=yes with a fixed text, namely 'This street will become a cyclstreet soon' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key cyclestreet.",
"value": ""
},
{
"key": "proposed:cyclestreet",
"description": "Layer 'Future cyclestreet' shows cyclestreet=&proposed:cyclestreet=yes with a fixed text, namely 'This street will become a cyclstreet soon' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "yes"
},
{
"key": "cyclestreet",
"description": "Layer 'Future cyclestreet' shows cyclestreet=&proposed:cyclestreet=&overtaking:motor_vehicle= with a fixed text, namely 'This street is not a cyclestreet' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key cyclestreet.",
"value": ""
},
{
"key": "proposed:cyclestreet",
"description": "Layer 'Future cyclestreet' shows cyclestreet=&proposed:cyclestreet=&overtaking:motor_vehicle= with a fixed text, namely 'This street is not a cyclestreet' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key proposed:cyclestreet.",
"value": ""
},
{
"key": "overtaking:motor_vehicle",
"description": "Layer 'Future cyclestreet' shows cyclestreet=&proposed:cyclestreet=&overtaking:motor_vehicle= with a fixed text, namely 'This street is not a cyclestreet' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key overtaking:motor_vehicle.",
"value": ""
},
{
"key": "cyclestreet:start_date",
"description": "Layer 'Future cyclestreet' shows and asks freeform values for key 'cyclestreet:start_date' (in the MapComplete.osm.be theme 'Cyclestreets')"
},
{
"key": "highway",
"description": "The MapComplete theme Cyclestreets has a layer All streets showing features with this tag",
"value": "residential"
},
{
"key": "highway",
"description": "The MapComplete theme Cyclestreets has a layer All streets showing features with this tag",
"value": "tertiary"
},
{
"key": "highway",
"description": "The MapComplete theme Cyclestreets has a layer All streets showing features with this tag",
"value": "unclassified"
},
{
"key": "image",
"description": "The layer 'All streets 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 'All streets 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 'All streets 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 'All streets 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": "cyclestreet",
"description": "Layer 'All streets' shows cyclestreet=yes&maxspeed=30&overtaking:motor_vehicle=no&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet (and has a speed limit of 30 km/h)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "yes"
},
{
"key": "maxspeed",
"description": "Layer 'All streets' shows cyclestreet=yes&maxspeed=30&overtaking:motor_vehicle=no&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet (and has a speed limit of 30 km/h)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "30"
},
{
"key": "overtaking:motor_vehicle",
"description": "Layer 'All streets' shows cyclestreet=yes&maxspeed=30&overtaking:motor_vehicle=no&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet (and has a speed limit of 30 km/h)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "no"
},
{
"key": "proposed:cyclestreet",
"description": "Layer 'All streets' shows cyclestreet=yes&maxspeed=30&overtaking:motor_vehicle=no&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet (and has a speed limit of 30 km/h)' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key proposed:cyclestreet.",
"value": ""
},
{
"key": "cyclestreet",
"description": "Layer 'All streets' shows cyclestreet=yes&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet' (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "yes"
},
{
"key": "proposed:cyclestreet",
"description": "Layer 'All streets' shows cyclestreet=yes&proposed:cyclestreet= with a fixed text, namely 'This street is a cyclestreet' (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key proposed:cyclestreet.",
"value": ""
},
{
"key": "cyclestreet",
"description": "Layer 'All streets' shows cyclestreet=&proposed:cyclestreet=yes with a fixed text, namely 'This street will become a cyclstreet soon' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key cyclestreet.",
"value": ""
},
{
"key": "proposed:cyclestreet",
"description": "Layer 'All streets' shows cyclestreet=&proposed:cyclestreet=yes with a fixed text, namely 'This street will become a cyclstreet soon' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets')",
"value": "yes"
},
{
"key": "cyclestreet",
"description": "Layer 'All streets' shows cyclestreet=&proposed:cyclestreet=&overtaking:motor_vehicle= with a fixed text, namely 'This street is not a cyclestreet' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key cyclestreet.",
"value": ""
},
{
"key": "proposed:cyclestreet",
"description": "Layer 'All streets' shows cyclestreet=&proposed:cyclestreet=&overtaking:motor_vehicle= with a fixed text, namely 'This street is not a cyclestreet' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key proposed:cyclestreet.",
"value": ""
},
{
"key": "overtaking:motor_vehicle",
"description": "Layer 'All streets' shows cyclestreet=&proposed:cyclestreet=&overtaking:motor_vehicle= with a fixed text, namely 'This street is not a cyclestreet' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclestreets') Picking this answer will delete the key overtaking:motor_vehicle.",
"value": ""
},
{
"key": "cyclestreet:start_date",
"description": "Layer 'All streets' shows and asks freeform values for key 'cyclestreet:start_date' (in the MapComplete.osm.be theme 'Cyclestreets')"
}
]
}

View file

@ -5,7 +5,7 @@
"description": "Surveillance cameras and other means of surveillance",
"project_url": "https://mapcomplete.osm.be/surveillance",
"doc_url": "https://github.com/pietervdvn/MapComplete/tree/master/assets/themes/",
"icon_url": "https://mapcomplete.osm.be/assets/themes/surveillance_cameras/logo.svg",
"icon_url": "https://mapcomplete.osm.be/assets/themes/surveillance/logo.svg",
"contact_name": "Pieter Vander Vennet, ",
"contact_email": "pietervdvn@posteo.net"
},

View file

@ -29,6 +29,16 @@ To check if a key does _not_ equal a certain value, use `key!=value`. This is co
This implies that, to check if a key is present, `key!=` can be used. This will only match if the key is present and not empty.
Number comparison
-----------------
If the value of a tag is a number (e.g. `key=42`), one can use a filter `key<=42`, `key>=35`, `key>40` or `key<50` to match this, e.g. in conditions for renderings.
These tags cannot be used to generate an answer nor can they be used to request data upstream from overpass.
Note that the value coming from OSM will first be stripped by removing all non-numeric characters. For example, `length=42 meter` will be interpreted as `length=42` and will thus match `length<=42` and `length>=42`.
In special circumstances (e.g. `surface_area=42 m2` or `length=100 feet`), this will result in erronous values (`surface=422` or if a length in meters is compared to).
However, this can be partially alleviated by using 'Units' to rewrite to a default format.
Regex equals
------------

View file

@ -15,7 +15,7 @@ import {LocalStorageSource} from "./Logic/Web/LocalStorageSource";
import {Utils} from "./Utils";
import Svg from "./Svg";
import Link from "./UI/Base/Link";
import * as personal from "./assets/themes/personalLayout/personalLayout.json"
import * as personal from "./assets/themes/personal/personal.json"
import LayoutConfig from "./Customizations/JSON/LayoutConfig";
import * as L from "leaflet";
import Img from "./UI/Base/Img";

View file

@ -6,6 +6,8 @@ import {Utils} from "../Utils";
import BaseUIElement from "../UI/BaseUIElement";
import List from "../UI/Base/List";
import Title from "../UI/Base/Title";
import {UIEventSourceTools} from "./UIEventSource";
import AspectedRouting from "./Osm/aspectedRouting";
export class ExtraFunction {
@ -38,12 +40,14 @@ export class ExtraFunction {
]),
"Some advanced functions are available on **feat** as well:"
]).SetClass("flex-col").AsMarkdown();
private static readonly OverlapFunc = new ExtraFunction(
"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",
["...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)"],
{
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. 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",
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 = []
@ -62,9 +66,11 @@ export class ExtraFunction {
}
)
private static readonly DistanceToFunc = new ExtraFunction(
"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",
["longitude", "latitude"],
{
name: "distanceTo",
doc: "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",
args: ["longitude", "latitude"]
},
(featuresPerLayer, feature) => {
return (arg0, lat) => {
if (typeof arg0 === "number") {
@ -88,9 +94,11 @@ export class ExtraFunction {
)
private static readonly ClosestObjectFunc = new ExtraFunction(
"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.",
["list of features"],
{
name: "closest",
doc: "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.",
args: ["list of features"]
},
(params, feature) => {
return (features) => {
if (typeof features === "string") {
@ -139,28 +147,56 @@ export class ExtraFunction {
private static readonly Memberships = new ExtraFunction(
"memberships",
"Gives a list of `{role: string, relation: Relation}`-objects, containing all the relations that this feature is part of. " +
"\n\n" +
"For example: `_part_of_walking_routes=feat.memberships().map(r => r.relation.tags.name).join(';')`",
[],
{
name: "memberships",
doc: "Gives a list of `{role: string, relation: Relation}`-objects, containing all the relations that this feature is part of. " +
"\n\n" +
"For example: `_part_of_walking_routes=feat.memberships().map(r => r.relation.tags.name).join(';')`",
args: []
},
(params, _) => {
return () => params.relations ?? [];
}
)
private static readonly allFuncs: ExtraFunction[] = [ExtraFunction.DistanceToFunc, ExtraFunction.OverlapFunc, ExtraFunction.ClosestObjectFunc, ExtraFunction.Memberships];
private static readonly AspectedRouting = new ExtraFunction(
{
name: "score",
doc: "Given the path of an aspected routing json file, will calculate the score. This score is wrapped in a UIEventSource, so for further calculations, use `.map(score => ...)`" +
"\n\n" +
"For example: `_comfort_score=feat.score('https://raw.githubusercontent.com/pietervdvn/AspectedRouting/master/Examples/bicycle/aspects/bicycle.comfort.json')`",
args: ["path"]
},
(_, feature) => {
return (path) => {
return UIEventSourceTools.downloadJsonCached(path).map(config => {
if (config === undefined) {
return
}
return new AspectedRouting(config).evaluate(feature.properties)
})
}
}
)
private static readonly allFuncs: ExtraFunction[] = [
ExtraFunction.DistanceToFunc,
ExtraFunction.OverlapFunc,
ExtraFunction.ClosestObjectFunc,
ExtraFunction.Memberships,
ExtraFunction.AspectedRouting
];
private readonly _name: string;
private readonly _args: string[];
private readonly _doc: string;
private readonly _f: (params: { featuresPerLayer: Map<string, any[]>, relations: { role: string, relation: Relation }[] }, feat: any) => any;
constructor(name: string, doc: string, args: string[], f: ((params: { featuresPerLayer: Map<string, any[]>, relations: { role: string, relation: Relation }[] }, feat: any) => any)) {
this._name = name;
this._doc = doc;
this._args = args;
constructor(options: { name: string, doc: string, args: string[] },
f: ((params: { featuresPerLayer: Map<string, any[]>, relations: { role: string, relation: Relation }[] }, feat: any) => any)) {
this._name = options.name;
this._doc = options.doc;
this._args = options.args;
this._f = f;
}
public static FullPatchFeature(featuresPerLayer: Map<string, any[]>, relations: { role: string, relation: Relation }[], feature) {
@ -186,7 +222,6 @@ export class ExtraFunction {
}
public PatchFeature(featuresPerLayer: Map<string, any[]>, relations: { role: string, relation: Relation }[], feature: any) {
feature[this._name] = this._f({featuresPerLayer: featuresPerLayer, relations: relations}, feature);
feature[this._name] = this._f({featuresPerLayer: featuresPerLayer, relations: relations}, feature)
}
}

View file

@ -273,14 +273,61 @@ export class GeoOperations {
}
return undefined;
}
/**
* Generates the closest point on a way from a given point
* @param way The road on which you want to find a point
* @param point Point defined as [lon, lat]
*/
public static nearestPoint(way, point: [number, number]){
public static nearestPoint(way, point: [number, number]) {
return turf.nearestPointOnLine(way, point, {units: "kilometers"});
}
public static toCSV(features: any[]): string {
const headerValuesSeen = new Set<string>();
const headerValuesOrdered: string[] = []
function addH(key) {
if (!headerValuesSeen.has(key)) {
headerValuesSeen.add(key)
headerValuesOrdered.push(key)
}
}
addH("_lat")
addH("_lon")
const lines: string[] = []
for (const feature of features) {
const properties = feature.properties;
for (const key in properties) {
if (!properties.hasOwnProperty(key)) {
continue;
}
addH(key)
}
}
headerValuesOrdered.sort()
for (const feature of features) {
const properties = feature.properties;
let line = ""
for (const key of headerValuesOrdered) {
const value = properties[key]
if (value === undefined) {
line += ","
} else {
line += JSON.stringify(value)+","
}
}
lines.push(line)
}
return headerValuesOrdered.map(v => JSON.stringify(v)).join(",") + "\n" + lines.join("\n")
}
}

View file

@ -27,8 +27,8 @@ export default class MetaTagging {
relations: Map<string, { role: string, relation: Relation }[]>,
layers: LayerConfig[],
includeDates = true) {
if(features === undefined || features.length === 0){
if (features === undefined || features.length === 0) {
return;
}
@ -79,14 +79,10 @@ export default class MetaTagging {
}
}
})
}
@ -115,6 +111,17 @@ export default class MetaTagging {
const f = (featuresPerLayer, feature: any) => {
try {
let result = func(feature);
if(result instanceof UIEventSource){
result.addCallbackAndRunD(d => {
if (typeof d !== "string") {
// Make sure it is a string!
d = JSON.stringify(d);
}
feature.properties[key] = d;
})
result = result.data
}
if (result === undefined || result === "") {
return;
}
@ -124,11 +131,11 @@ export default class MetaTagging {
}
feature.properties[key] = result;
} catch (e) {
if(MetaTagging. errorPrintCount < MetaTagging.stopErrorOutputAt){
if (MetaTagging.errorPrintCount < MetaTagging.stopErrorOutputAt) {
console.warn("Could not calculate a calculated tag defined by " + code + " due to " + e + ". This is code defined in the theme. Are you the theme creator? Doublecheck your code. Note that the metatags might not be stable on new features", e)
MetaTagging. errorPrintCount ++;
if(MetaTagging. errorPrintCount == MetaTagging.stopErrorOutputAt){
console.error("Got ",MetaTagging.stopErrorOutputAt," errors calculating this metatagging - stopping output now")
MetaTagging.errorPrintCount++;
if (MetaTagging.errorPrintCount == MetaTagging.stopErrorOutputAt) {
console.error("Got ", MetaTagging.stopErrorOutputAt, " errors calculating this metatagging - stopping output now")
}
}
}

View file

@ -0,0 +1,194 @@
export default class AspectedRouting {
public readonly name: string
public readonly description: string
public readonly units: string
public readonly program: any
public constructor(program) {
this.name = program.name;
this.description = program.description;
this.units = program.unit
this.program = JSON.parse(JSON.stringify(program))
delete this.program.name
delete this.program.description
delete this.program.unit
}
public evaluate(properties){
return AspectedRouting.interpret(this.program, properties)
}
/**
* Interprets the given Aspected-routing program for the given properties
*/
public static interpret(program: any, properties: any) {
if (typeof program !== "object") {
return program;
}
let functionName /*: string*/ = undefined;
let functionArguments /*: any */ = undefined
let otherValues = {}
// @ts-ignore
Object.entries(program).forEach(tag => {
const [key, value] = tag;
if (key.startsWith("$")) {
functionName = key
functionArguments = value
} else {
otherValues[key] = value
}
}
)
if (functionName === undefined) {
return AspectedRouting.interpretAsDictionary(program, properties)
}
if (functionName === '$multiply') {
return AspectedRouting.multiplyScore(properties, functionArguments);
} else if (functionName === '$firstMatchOf') {
return AspectedRouting.getFirstMatchScore(properties, functionArguments);
} else if (functionName === '$min') {
return AspectedRouting.getMinValue(properties, functionArguments);
} else if (functionName === '$max') {
return AspectedRouting.getMaxValue(properties, functionArguments);
} else if (functionName === '$default') {
return AspectedRouting.defaultV(functionArguments, otherValues, properties)
} else {
console.error(`Error: Program ${functionName} is not implemented yet. ${JSON.stringify(program)}`);
}
}
/**
* Given a 'program' without function invocation, interprets it as a dictionary
*
* E.g., given the program
*
* {
* highway: {
* residential: 30,
* living_street: 20
* },
* surface: {
* sett : 0.9
* }
*
* }
*
* in combination with the tags {highway: residential},
*
* the result should be [30, undefined];
*
* For the tags {highway: residential, surface: sett} we should get [30, 0.9]
*
*
* @param program
* @param tags
* @return {(undefined|*)[]}
*/
private static interpretAsDictionary(program, tags) {
// @ts-ignore
return Object.entries(tags).map(tag => {
const [key, value] = tag;
const propertyValue = program[key]
if (propertyValue === undefined) {
return undefined
}
if (typeof propertyValue !== "object") {
return propertyValue
}
// @ts-ignore
return propertyValue[value]
});
}
private static defaultV(subProgram, otherArgs, tags) {
// @ts-ignore
const normalProgram = Object.entries(otherArgs)[0][1]
const value = AspectedRouting.interpret(normalProgram, tags)
if (value !== undefined) {
return value;
}
return AspectedRouting.interpret(subProgram, tags)
}
/**
* Multiplies the default score with the proper values
* @param tags {object} the active tags to check against
* @param subprograms which should generate a list of values
* @returns score after multiplication
*/
private static multiplyScore(tags, subprograms) {
let number = 1
let subResults: any[]
if (subprograms.length !== undefined) {
subResults = AspectedRouting.concatMap(subprograms, subprogram => AspectedRouting.interpret(subprogram, tags))
} else {
subResults = AspectedRouting.interpret(subprograms, tags)
}
subResults.filter(r => r !== undefined).forEach(r => number *= parseFloat(r))
return number.toFixed(2);
}
private static getFirstMatchScore(tags, order: any) {
/*Order should be a list of arguments after evaluation*/
order = <string[]>AspectedRouting.interpret(order, tags)
for (let key of order) {
// @ts-ignore
for (let entry of Object.entries(JSON.parse(tags))) {
const [tagKey, value] = entry;
if (key === tagKey) {
// We have a match... let's evaluate the subprogram
const evaluated = AspectedRouting.interpret(value, tags)
if (evaluated !== undefined) {
return evaluated;
}
}
}
}
// Not a single match found...
return undefined
}
private static getMinValue(tags, subprogram) {
const minArr = subprogram.map(part => {
if (typeof (part) === 'object') {
const calculatedValue = this.interpret(part, tags)
return parseFloat(calculatedValue)
} else {
return parseFloat(part);
}
}).filter(v => !isNaN(v));
return Math.min(...minArr);
}
private static getMaxValue(tags, subprogram) {
const maxArr = subprogram.map(part => {
if (typeof (part) === 'object') {
return parseFloat(AspectedRouting.interpret(part, tags))
} else {
return parseFloat(part);
}
}).filter(v => !isNaN(v));
return Math.max(...maxArr);
}
private static concatMap(list, f): any[] {
const result = []
list = list.map(f)
for (const elem of list) {
if (elem.length !== undefined) {
// This is a list
result.push(...elem)
} else {
result.push(elem)
}
}
return result;
}
}

View file

@ -0,0 +1,42 @@
import {TagsFilter} from "./TagsFilter";
export default class ComparingTag implements TagsFilter {
private readonly _key: string;
private readonly _predicate: (value: string) => boolean;
private readonly _representation: string;
constructor(key: string, predicate : (value:string | undefined) => boolean, representation: string = "") {
this._key = key;
this._predicate = predicate;
this._representation = representation;
}
asChange(properties: any): { k: string; v: string }[] {
throw "A comparable tag can not be used to be uploaded to OSM"
}
asHumanString(linkToWiki: boolean, shorten: boolean, properties: any) {
return this._key+this._representation
}
asOverpass(): string[] {
throw "A comparable tag can not be used as overpass filter"
}
isEquivalent(other: TagsFilter): boolean {
return other === this;
}
isUsableAsAnswer(): boolean {
return false;
}
matchesProperties(properties: any): boolean {
return this._predicate(properties[this._key]);
}
usedKeys(): string[] {
return [this._key];
}
}

View file

@ -1,7 +1,6 @@
import {Utils} from "../../Utils";
import {RegexTag} from "./RegexTag";
import {TagsFilter} from "./TagsFilter";
import {TagUtils} from "./TagUtils";
export class Tag extends TagsFilter {
public key: string
@ -46,11 +45,6 @@ export class Tag extends TagsFilter {
}
return [`["${this.key}"="${this.value}"]`];
}
substituteValues(tags: any) {
return new Tag(this.key, TagUtils.ApplyTemplate(this.value as string, tags));
}
asHumanString(linkToWiki?: boolean, shorten?: boolean) {
let v = this.value;
if (shorten) {

View file

@ -166,4 +166,21 @@ export class UIEventSource<T> {
}
})
}
}
export class UIEventSourceTools {
private static readonly _download_cache = new Map<string, UIEventSource<any>>()
public static downloadJsonCached(url: string): UIEventSource<any>{
const cached = UIEventSourceTools._download_cache.get(url)
if(cached !== undefined){
return cached;
}
const src = new UIEventSource<any>(undefined)
UIEventSourceTools._download_cache.set(url, src)
Utils.downloadJson(url).then(r => src.setData(r))
return src;
}
}

View file

@ -100,7 +100,7 @@ export default class State {
public readonly featureSwitchFakeUser: UIEventSource<boolean>;
public readonly featurePipeline: FeaturePipeline;
public featurePipeline: FeaturePipeline;
/**

View file

@ -0,0 +1,55 @@
import {SubtleButton} from "../Base/SubtleButton";
import Svg from "../../Svg";
import Translations from "../i18n/Translations";
import State from "../../State";
import {FeatureSourceUtils} from "../../Logic/FeatureSource/FeatureSource";
import {Utils} from "../../Utils";
import Combine from "../Base/Combine";
import CheckBoxes from "../Input/Checkboxes";
import {GeoOperations} from "../../Logic/GeoOperations";
import Toggle from "../Input/Toggle";
import Title from "../Base/Title";
export class DownloadPanel extends Toggle {
constructor() {
const t = Translations.t.general.download
const somethingLoaded = State.state.featurePipeline.features.map(features => features.length > 0);
const includeMetaToggle = new CheckBoxes([t.includeMetaData.Clone()])
const metaisIncluded = includeMetaToggle.GetValue().map(selected => selected.length > 0)
const buttonGeoJson = new SubtleButton(Svg.floppy_ui(),
new Combine([t.downloadGeojson.Clone().SetClass("font-bold"),
t.downloadGeoJsonHelper.Clone()]).SetClass("flex flex-col"))
.onClick(() => {
const geojson = FeatureSourceUtils.extractGeoJson(State.state.featurePipeline, {metadata: metaisIncluded.data})
const name = State.state.layoutToUse.data.id;
Utils.offerContentsAsDownloadableFile(JSON.stringify(geojson),
`MapComplete_${name}_export_${new Date().toISOString().substr(0, 19)}.geojson`, {
mimetype: "application/vnd.geo+json"
});
})
const buttonCSV = new SubtleButton(Svg.floppy_ui(), new Combine(
[t.downloadCSV.Clone().SetClass("font-bold"),
t.downloadCSVHelper.Clone()]).SetClass("flex flex-col"))
.onClick(() => {
const geojson = FeatureSourceUtils.extractGeoJson(State.state.featurePipeline, {metadata: metaisIncluded.data})
const csv = GeoOperations.toCSV(geojson.features)
Utils.offerContentsAsDownloadableFile(csv,
`MapComplete_${name}_export_${new Date().toISOString().substr(0, 19)}.csv`, {
mimetype: "text/csv"
});
})
const downloadButtons = new Combine(
[new Title(t.title), buttonGeoJson, buttonCSV, includeMetaToggle, t.licenseInfo.Clone().SetClass("link-underline")])
.SetClass("w-full flex flex-col border-4 border-gray-300 rounded-3xl p-4")
super(
downloadButtons,
t.noDataLoaded.Clone(),
somethingLoaded)
}
}

View file

@ -1,21 +0,0 @@
import {SubtleButton} from "../Base/SubtleButton";
import Svg from "../../Svg";
import Translations from "../i18n/Translations";
import State from "../../State";
import {FeatureSourceUtils} from "../../Logic/FeatureSource/FeatureSource";
import {Utils} from "../../Utils";
import Combine from "../Base/Combine";
export class ExportDataButton extends Combine {
constructor() {
const t = Translations.t.general.download
const button = new SubtleButton(Svg.floppy_ui(), t.downloadGeojson.Clone().SetClass("font-bold"))
.onClick(() => {
const geojson = FeatureSourceUtils.extractGeoJson(State.state.featurePipeline)
const name = State.state.layoutToUse.data.id;
Utils.offerContentsAsDownloadableFile(JSON.stringify(geojson), `MapComplete_${name}_export_${new Date().toISOString().substr(0,19)}.geojson`);
})
super([button, t.licenseInfo.Clone().SetClass("link-underline")])
}
}

View file

@ -1,6 +1,6 @@
import State from "../../State";
import ThemeIntroductionPanel from "./ThemeIntroductionPanel";
import * as personal from "../../assets/themes/personalLayout/personalLayout.json";
import * as personal from "../../assets/themes/personal/personal.json";
import PersonalLayersPanel from "./PersonalLayersPanel";
import Svg from "../../Svg";
import Translations from "../i18n/Translations";

View file

@ -7,7 +7,7 @@ import Translations from "../i18n/Translations";
import {UIEventSource} from "../../Logic/UIEventSource";
import BaseUIElement from "../BaseUIElement";
import Toggle from "../Input/Toggle";
import {ExportDataButton} from "./ExportDataButton";
import {DownloadPanel} from "./DownloadPanel";
export default class LayerControlPanel extends ScrollableFullScreen {
@ -37,7 +37,7 @@ export default class LayerControlPanel extends ScrollableFullScreen {
))
elements.push(new Toggle(
new ExportDataButton(),
new DownloadPanel(),
undefined,
State.state.featureSwitchEnableExport
))

View file

@ -6,7 +6,7 @@ import State from "../../State";
import Combine from "../Base/Combine";
import {SubtleButton} from "../Base/SubtleButton";
import Translations from "../i18n/Translations";
import * as personal from "../../assets/themes/personalLayout/personalLayout.json"
import * as personal from "../../assets/themes/personal/personal.json"
import Constants from "../../Models/Constants";
import LanguagePicker from "../LanguagePicker";
import IndexText from "./IndexText";

View file

@ -135,7 +135,7 @@ export class Utils {
}
return newArr;
}
public static MergeTags(a: any, b: any) {
const t = {};
for (const k in a) {
@ -356,12 +356,12 @@ export class Utils {
/**
* Triggers a 'download file' popup which will download the contents
* @param contents
* @param fileName
*/
public static offerContentsAsDownloadableFile(contents: string, fileName: string = "download.txt") {
public static offerContentsAsDownloadableFile(contents: string, fileName: string = "download.txt", options?: {
mimetype: string
}) {
const element = document.createElement("a");
const file = new Blob([contents], {type: 'text/plain'});
const file = new Blob([contents], {type: options?.mimetype ?? 'text/plain'});
element.href = URL.createObjectURL(file);
element.download = fileName;
document.body.appendChild(element); // Required for this to work in FireFox
@ -449,8 +449,8 @@ export class Utils {
}
}
public static setDefaults(options, defaults){
for (let key in defaults){
public static setDefaults(options, defaults) {
for (let key in defaults) {
if (!(key in options)) options[key] = defaults[key];
}
return options;

View file

@ -422,19 +422,19 @@
}
],
"icon": {
"render": "./assets/themes/surveillance_cameras/logo.svg",
"render": "./assets/themes/surveillance/logo.svg",
"mappings": [
{
"if": "camera:type=dome",
"then": "./assets/themes/surveillance_cameras/dome.svg"
"then": "./assets/themes/surveillance/dome.svg"
},
{
"if": "_direction:leftright=right",
"then": "./assets/themes/surveillance_cameras/cam_right.svg"
"then": "./assets/themes/surveillance/cam_right.svg"
},
{
"if": "_direction:leftright=left",
"then": "./assets/themes/surveillance_cameras/cam_left.svg"
"then": "./assets/themes/surveillance/cam_left.svg"
}
]
},

View file

@ -33,7 +33,7 @@
"fr": "Une vélothèque est un endroit où on peut emprunter des vélos, souvent moyennant une petite somme annuelle. Un cas d'utilisation notable est celui des vélothèques pour les enfants, qui leur permettent de passer à un vélo plus grand quand ils sont trop grands pour leur vélo actuel",
"zh_Hant": "單車圖書館是指每年支付小額費用,然後可以租用單車的地方。最有名的單車圖書館案例是給小孩的,能夠讓長大的小孩用目前的單車換成比較大的單車"
},
"icon": "./assets/themes/bicycle_library/logo.svg",
"icon": "./assets/themes/bicyclelib/logo.svg",
"socialImage": null,
"startLat": 0,
"startLon": 0,

View file

@ -38,13 +38,13 @@
"nb_NO"
],
"maintainer": "joost schouppe",
"icon": "./assets/themes/campersites/caravan.svg",
"icon": "./assets/themes/campersite/caravan.svg",
"version": "0",
"startLat": 43.14,
"startLon": 3.14,
"startZoom": 14,
"widenFactor": 0.05,
"socialImage": "./assets/themes/campersites/Bar%C3%9Fel_Wohnmobilstellplatz.jpg",
"socialImage": "./assets/themes/campersite/Bar%C3%9Fel_Wohnmobilstellplatz.jpg",
"layers": [
{
"id": "caravansites",
@ -522,7 +522,7 @@
"reviews"
],
"icon": {
"render": "circle:white;./assets/themes/campersites/caravan.svg",
"render": "circle:white;./assets/themes/campersite/caravan.svg",
"mappings": [
{
"if": {
@ -530,7 +530,7 @@
"fee=no"
]
},
"then": "circle:white;./assets/themes/campersites/caravan_green.svg"
"then": "circle:white;./assets/themes/campersite/caravan_green.svg"
}
]
},
@ -862,7 +862,7 @@
}
],
"icon": {
"render": "circle:white;./assets/themes/campersites/sanitary_dump_station.svg"
"render": "circle:white;./assets/themes/campersite/sanitary_dump_station.svg"
},
"width": {
"render": "8"

View file

@ -25,7 +25,7 @@
"startZoom": 11,
"widenFactor": 0.05,
"socialImage": "./assets/themes/cycle_infra/cycle-infra.svg",
"enableDownload": true,
"enableExportButton": true,
"layers": [
{
"id": "cycleways",
@ -51,6 +51,9 @@
]
}
},
"calculatedTags": [
"_comfort_score=feat.score('https://raw.githubusercontent.com/pietervdvn/AspectedRouting/master/Examples/bicycle/aspects/bicycle.comfort.json')"
],
"title": {
"render": {
"en": "Cycleways",
@ -1025,7 +1028,6 @@
]
}
],
"hideUnderlayingFeaturesMinPercentage": 0,
"icon": {
"render": "./assets/themes/cycle_infra/bicycleway.svg"
},
@ -1122,6 +1124,9 @@
]
}
},
"calculatedTags": [
"_comfort_score=feat.score('https://raw.githubusercontent.com/pietervdvn/AspectedRouting/master/Examples/bicycle/aspects/bicycle.comfort.json')"
],
"minzoom": 14,
"wayHandling": 0,
"title": {

View file

@ -25,7 +25,7 @@
"zh_Hant"
],
"maintainer": "",
"icon": "./assets/themes/surveillance_cameras/logo.svg",
"icon": "./assets/themes/surveillance/logo.svg",
"version": "0",
"startLat": 0,
"startLon": 0,

View file

@ -150,8 +150,14 @@
"title": "Select layers"
},
"download": {
"title": "Download visible data",
"downloadGeojson": "Download visible data as geojson",
"licenseInfo": "<h3>Copyright notice</h3>The provided is available under ODbL. Reusing this data is free for any purpose, but <ul><li>the attribution <b>© OpenStreetMap contributors</b></li><li>Any change to this data must be republished under the same license</li></ul>. Please see the full <a href='https://www.openstreetmap.org/copyright' target='_blank'>copyright notice</a> for details"
"downloadGeoJsonHelper": "Compatible with QGIS, OsmAnd, ArcGIS, ESRI, ...",
"downloadCSV": "Download as CSV",
"downloadCSVHelper": "Compatible with LibreOffice Calc, Excel, ...",
"includeMetaData": "Include metadata (last editor, calculated values, ...)",
"licenseInfo": "<h3>Copyright notice</h3>The provided is available under ODbL. Reusing this data is free for any purpose, but <ul><li>the attribution <b>© OpenStreetMap contributors</b> is required</li><li>Any change to this data must be republished under the same license</li></ul> Please read the full <a href='https://www.openstreetmap.org/copyright' target='_blank'>copyright notice</a> for details",
"noDataLoaded": "No data is loaded yet. Download will be available soon"
},
"weekdays": {
"abbreviations": {

15132
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -79,8 +79,6 @@
"parcel": "^1.2.4",
"postcss": "^7.0.36",
"prompt-sync": "^4.2.0",
"sharp": "^0.27.0",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.2",
"tslint": "^6.1.3"
},
"devDependencies": {
@ -90,6 +88,8 @@
"fs": "0.0.1-security",
"marked": "^2.0.0",
"read-file": "^0.2.0",
"sharp": "^0.28.3",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.7",
"ts-node": "^9.0.0",
"ts-node-dev": "^1.0.0-pre.63",
"tslint-no-circular-imports": "^0.7.0",

View file

@ -1,6 +1,5 @@
import {lstatSync, readdirSync, readFileSync} from "fs";
import {Utils} from "../Utils";
Utils.runningFromConsole = true
import * as https from "https";
import {LayerConfigJson} from "../Customizations/JSON/LayerConfigJson";

View file

@ -4,20 +4,17 @@ import T from "./TestHelper";
import {FromJSON} from "../Customizations/JSON/FromJSON";
import Locale from "../UI/i18n/Locale";
import Translations from "../UI/i18n/Translations";
import {UIEventSource} from "../Logic/UIEventSource";
import TagRenderingConfig from "../Customizations/JSON/TagRenderingConfig";
import EditableTagRendering from "../UI/Popup/EditableTagRendering";
import {Translation} from "../UI/i18n/Translation";
import {OH, OpeningHour} from "../UI/OpeningHours/OpeningHours";
import PublicHolidayInput from "../UI/OpeningHours/PublicHolidayInput";
import {SubstitutedTranslation} from "../UI/SubstitutedTranslation";
import {Tag} from "../Logic/Tags/Tag";
import {And} from "../Logic/Tags/And";
import {centerOfMass} from "@turf/turf";
Utils.runningFromConsole = true;
export default class TagSpec extends T{
export default class TagSpec extends T {
constructor() {
super("Tags", [
["Tag replacement works in translation", () => {
@ -88,11 +85,37 @@ export default class TagSpec extends T{
equal(assign.matchesProperties({"survey:date": "2021-03-29"}), false);
equal(assign.matchesProperties({"_date:now": "2021-03-29"}), false);
equal(assign.matchesProperties({"some_key": "2021-03-29"}), false);
const notEmptyList = FromJSON.Tag("xyz!~\\[\\]")
equal(notEmptyList.matchesProperties({"xyz":undefined}), true);
equal(notEmptyList.matchesProperties({"xyz":"[]"}), false);
equal(notEmptyList.matchesProperties({"xyz":"[\"abc\"]"}), true);
equal(notEmptyList.matchesProperties({"xyz": undefined}), true);
equal(notEmptyList.matchesProperties({"xyz": "[]"}), false);
equal(notEmptyList.matchesProperties({"xyz": "[\"abc\"]"}), true);
let compare = FromJSON.Tag("key<=5")
equal(compare.matchesProperties({"key": undefined}), false);
equal(compare.matchesProperties({"key": "6"}), false);
equal(compare.matchesProperties({"key": "5"}), true);
equal(compare.matchesProperties({"key": "4"}), true);
compare = FromJSON.Tag("key<5")
equal(compare.matchesProperties({"key": undefined}), false);
equal(compare.matchesProperties({"key": "6"}), false);
equal(compare.matchesProperties({"key": "5"}), false);
equal(compare.matchesProperties({"key": "4.2"}), true);
compare = FromJSON.Tag("key>5")
equal(compare.matchesProperties({"key": undefined}), false);
equal(compare.matchesProperties({"key": "6"}), true);
equal(compare.matchesProperties({"key": "5"}), false);
equal(compare.matchesProperties({"key": "4.2"}), false);
compare = FromJSON.Tag("key>=5")
equal(compare.matchesProperties({"key": undefined}), false);
equal(compare.matchesProperties({"key": "6"}), true);
equal(compare.matchesProperties({"key": "5"}), true);
equal(compare.matchesProperties({"key": "4.2"}), false);
})],
@ -358,27 +381,27 @@ export default class TagSpec extends T{
]);
equal(rules, "Tu 10:00-12:00; Su 13:00-17:00");
}],
["JOIN OH with end hours", () =>{
["JOIN OH with end hours", () => {
const rules = OH.ToString(
OH.MergeTimes([
{
weekday: 1,
endHour: 23,
endMinutes: 30,
startHour: 23,
startMinutes: 0
}, {
weekday: 1,
endHour: 24,
endMinutes: 0,
startHour: 23,
startMinutes: 30
},
{
weekday: 1,
endHour: 23,
endMinutes: 30,
startHour: 23,
startMinutes: 0
}, {
weekday: 1,
endHour: 24,
endMinutes: 0,
startHour: 23,
startMinutes: 30
},
]));
]));
equal(rules, "Tu 23:00-00:00");
}], ["JOIN OH with overflowed hours", () =>{
}], ["JOIN OH with overflowed hours", () => {
const rules = OH.ToString(
OH.MergeTimes([
@ -464,10 +487,10 @@ export default class TagSpec extends T{
]
};
const tagRendering = new TagRenderingConfig(config, null, "test");
const tagRendering = new TagRenderingConfig(config, null, "test");
equal(true, tagRendering.IsKnown({bottle: "yes"}))
equal(false, tagRendering.IsKnown({}))
}]]);
}
}