Add possibility to use a cutom overpass script, add 'grassfields in parks'-layer

This commit is contained in:
pietervdvn 2021-03-20 23:45:52 +01:00
parent 0d51015cc8
commit f659bc1141
40 changed files with 499 additions and 222 deletions

View file

@ -28,6 +28,8 @@ import * as sport_pitch from "../assets/layers/sport_pitch/sport_pitch.json"
import * as slow_roads from "../assets/layers/slow_roads/slow_roads.json"
import LayerConfig from "./JSON/LayerConfig";
import {LayerConfigJson} from "./JSON/LayerConfigJson";
import * as grass_in_parks from "../assets/layers/village_green/grass_in_parks.json"
import * as village_green from "../assets/layers/village_green/village_green.json"
export default class AllKnownLayers {
@ -60,7 +62,9 @@ export default class AllKnownLayers {
play_forest,
playground,
sport_pitch,
slow_roads
slow_roads,
grass_in_parks,
village_green
];
// Must be below the list...

View file

@ -9,7 +9,6 @@ export class FromJSON {
const tag = Utils.SplitFirst(json, "=");
return new Tag(tag[0], tag[1]);
}
public static Tag(json: AndOrTagConfigJson | string, context: string = ""): TagsFilter {
try{
return this.TagUnsafe(json, context);

View file

@ -15,6 +15,7 @@ import {UIEventSource} from "../../Logic/UIEventSource";
import {FixedUiElement} from "../../UI/Base/FixedUiElement";
import {UIElement} from "../../UI/UIElement";
import {SubstitutedTranslation} from "../../UI/SubstitutedTranslation";
import SourceConfig from "./SourceConfig";
export default class LayerConfig {
@ -25,7 +26,7 @@ export default class LayerConfig {
id: string;
name: Translation
description: Translation;
overpassTags: TagsFilter;
source: SourceConfig;
doNotDownload: boolean;
passAllFeatures: boolean;
minzoom: number;
@ -49,8 +50,6 @@ export default class LayerConfig {
tagRenderings: TagRenderingConfig [];
private readonly configuration_warnings: string[] = []
constructor(json: LayerConfigJson,
context?: string) {
context = context + "." + json.id;
@ -58,8 +57,38 @@ export default class LayerConfig {
this.id = json.id;
this.name = Translations.T(json.name, context + ".name");
this.description = Translations.T(json.description, context + ".description");
this.overpassTags = FromJSON.Tag(json.overpassTags, context + ".overpasstags");
this.doNotDownload = json.doNotDownload ?? false,
let legacy = undefined;
if (json["overpassTags"] !== undefined) {
// @ts-ignore
legacy = FromJSON.Tag(json["overpassTags"], context + ".overpasstags");
}
if(json.source !== undefined){
if (legacy !== undefined ) {
throw context+"Both the legacy 'layer.overpasstags' and the new 'layer.source'-field are defined"
}
let osmTags: TagsFilter = legacy;
if (json.source["osmTags"]) {
osmTags = FromJSON.Tag(json.source["osmTags"], context + "source.osmTags");
}
this.source = new SourceConfig({
osmTags: osmTags,
geojsonSource: json.source["geoJsonSource"],
overpassScript: json.source["overpassScript"],
});
}else{
this.source = new SourceConfig({
osmTags : legacy
})
}
this.doNotDownload = json.doNotDownload ?? false;
this.passAllFeatures = json.passAllFeatures ?? false;
this.minzoom = json.minzoom;
this.wayHandling = json.wayHandling ?? 0;
@ -82,16 +111,15 @@ export default class LayerConfig {
if (deflt === undefined) {
return undefined;
}
return new TagRenderingConfig(deflt, self.overpassTags, `${context}.${key}.default value`);
return new TagRenderingConfig(deflt, self.source.osmTags, `${context}.${key}.default value`);
}
if (typeof v === "string") {
const shared = SharedTagRenderings.SharedTagRendering[v];
if (shared) {
console.log("Got shared TR:", v, "-->", shared)
return shared;
}
}
return new TagRenderingConfig(v, self.overpassTags, `${context}.${key}`);
return new TagRenderingConfig(v, self.source.osmTags, `${context}.${key}`);
}
/**
@ -119,7 +147,7 @@ export default class LayerConfig {
}
throw `Predefined tagRendering ${renderingJson} not found in ${context}`;
}
return new TagRenderingConfig(renderingJson, self.overpassTags, `${context}.tagrendering[${i}]`);
return new TagRenderingConfig(renderingJson, self.source.osmTags, `${context}.tagrendering[${i}]`);
});
}
@ -142,7 +170,7 @@ export default class LayerConfig {
this.title = tr("title", undefined);
this.icon = tr("icon", Img.AsData(Svg.pin));
this.iconOverlays = (json.iconOverlays ?? []).map((overlay, i) => {
let tr = new TagRenderingConfig(overlay.then, self.overpassTags, `iconoverlays.${i}`);
let tr = new TagRenderingConfig(overlay.then, self.source.osmTags, `iconoverlays.${i}`);
if (typeof overlay.then === "string" && SharedTagRenderings.SharedIcons[overlay.then] !== undefined) {
tr = SharedTagRenderings.SharedIcons[overlay.then];
}
@ -281,7 +309,7 @@ export default class LayerConfig {
const iconUrlStatic = render(this.icon);
const self = this;
var mappedHtml = tags.map(tgs => {
const mappedHtml = tags.map(tgs => {
// What do you mean, 'tgs' is never read?
// It is read implicitly in the 'render' method
const iconUrl = render(self.icon);

View file

@ -26,8 +26,23 @@ export interface LayerConfigJson {
/**
* The tags to load from overpass. Either a simple 'key=value'-string, otherwise an advanced configuration
* DEPRECATED
* shorthand for source: {osmTags: "key=value"}
*/
overpassTags: AndOrTagConfigJson | string;
//overpassTags: AndOrTagConfigJson | string;
/**
* This determines where the data for the layer is fetched.
* There are some options:
*
* source: {osmTags: "key=value"} will fetch all objects with given tags from OSM. Currently, this will create a query to overpass and fetch the data - in the future this might fetch from the OSM API
* source: {geoJsonSource: "https://my.source.net/some-geo-data.geojson"} to fetch a geojson from a third party source
*
* source: {overpassScript: "<custom overpass tags>"} when you want to do special things. _This should be really rare_.
* This means that the data will be pulled from overpass with this script, and will ignore the osmTags for the query
* However, for the rest of the pipeline, the OsmTags will _still_ be used. This is important to enable layers etc...
*/
source: {osmTags: AndOrTagConfigJson | string} | {geoJsonSource: string} | {overpassScript: string}
/**
* If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.

View file

@ -0,0 +1,32 @@
import {TagsFilter} from "../../Logic/Tags";
export default class SourceConfig {
osmTags?: TagsFilter;
overpassScript?: string;
geojsonSource?: string;
constructor(params: {
osmTags?: TagsFilter,
overpassScript?: string,
geojsonSource?: string
}) {
let defined = 0;
if (params.osmTags) {
defined++;
}
if (params.overpassScript) {
defined++;
}
if (params.geojsonSource) {
defined++;
}
if (defined == 0) {
throw "Source: nothing correct defined in the source"
}
this.osmTags = params.osmTags;
this.overpassScript = params.overpassScript;
this.geojsonSource = params.geojsonSource;
}
}

View file

@ -5,6 +5,7 @@ import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
import {Overpass} from "../Osm/Overpass";
import Bounds from "../../Models/Bounds";
import FeatureSource from "../FeatureSource/FeatureSource";
import {Utils} from "../../Utils";
export default class UpdateFromOverpass implements FeatureSource {
@ -71,11 +72,12 @@ export default class UpdateFromOverpass implements FeatureSource {
this.update();
}
private GetFilter() {
const filters: TagsFilter[] = [];
private GetFilter(): Overpass {
let filters: TagsFilter[] = [];
let extraScripts: string[] = [];
for (const layer of this._layoutToUse.data.layers) {
if (typeof (layer) === "string") {
continue;
throw "A layer was not expanded!"
}
if (this._location.data.zoom < layer.minzoom) {
continue;
@ -102,20 +104,21 @@ export default class UpdateFromOverpass implements FeatureSource {
if (previouslyLoaded) {
continue;
}
filters.push(layer.overpassTags);
if (layer.source.overpassScript !== undefined) {
extraScripts.push(layer.source.overpassScript)
} else {
filters.push(layer.source.osmTags);
}
if (filters.length === 0) {
}
filters = Utils.NoNull(filters)
extraScripts = Utils.NoNull(extraScripts)
if (filters.length + extraScripts.length === 0) {
return undefined;
}
return new Or(filters);
return new Overpass(new Or(filters), extraScripts);
}
private update(): void {
const filter = this.GetFilter();
if (filter === undefined) {
return;
}
if (this.runningQuery.data) {
console.log("Still running a query, skip");
return;
@ -133,9 +136,12 @@ export default class UpdateFromOverpass implements FeatureSource {
const z = Math.floor(this._location.data.zoom ?? 0);
this.runningQuery.setData(true);
const self = this;
const overpass = new Overpass(filter);
const overpass = this.GetFilter();
if (overpass === undefined) {
return;
}
this.runningQuery.setData(true);
overpass.queryGeoJson(queryBounds,
function (data, date) {
self._previousBounds.get(z).push(queryBounds);
@ -168,6 +174,7 @@ export default class UpdateFromOverpass implements FeatureSource {
}, 1000
)
}
countDown();
}

View file

@ -30,7 +30,7 @@ export default class FeatureDuplicatorPerLayer implements FeatureSource {
let foundALayer = false;
for (const layer of layers.data) {
if (layer.layerDef.overpassTags.matchesProperties(f.feature.properties)) {
if (layer.layerDef.source.osmTags.matchesProperties(f.feature.properties)) {
foundALayer = true;
if (layer.layerDef.passAllFeatures) {

View file

@ -9,9 +9,11 @@ import Bounds from "../../Models/Bounds";
export class Overpass {
private _filter: TagsFilter
public static testUrl: string = null
private readonly _extraScripts: string[];
constructor(filter: TagsFilter) {
constructor(filter: TagsFilter, extraScripts: string[]) {
this._filter = filter
this._extraScripts = extraScripts;
}
@ -21,6 +23,9 @@ export class Overpass {
for (const filterOr of filters) {
filter += 'nwr' + filterOr + ';'
}
for (const extraScript of this._extraScripts){
filter += '('+extraScript+');';
}
const query =
'[out:json][timeout:25]' + bbox + ';(' + filter + ');out body;>;out skel qt;'
return "https://overpass-api.de/api/interpreter?data=" + encodeURIComponent(query)
@ -48,6 +53,7 @@ export class Overpass {
}
// @ts-ignore
const geojson = OsmToGeoJson.default(json);
console.log("Received geojson", geojson)
const osmTime = new Date(json.osm3s.timestamp_osm_base);
continuation(geojson, osmTime);
}).fail(onFail)

View file

@ -2,7 +2,7 @@ import { Utils } from "../Utils";
export default class Constants {
public static vNumber = "0.5.14";
public static vNumber = "0.6.0";
// The user journey states thresholds when a new feature gets unlocked
public static userJourney = {

View file

@ -6,7 +6,9 @@
"fr": "Bancs"
},
"minzoom": 14,
"overpassTags": "amenity=bench",
"source": {
"osmTags": "amenity=bench"
},
"title": {
"render": {
"en": "Bench",

View file

@ -6,11 +6,13 @@
"fr": "Bancs des arrêts de transport en commun"
},
"minzoom": 14,
"overpassTags": {
"source": {
"osmTags": {
"or": [
"bench=yes",
"bench=stand_up_bench"
]
}
},
"title": {
"render": {

View file

@ -5,7 +5,9 @@
"nl": "Picnictafels"
},
"minzoom": 12,
"overpassTags": "leisure=picnic_table",
"source": {
"osmTags": "leisure=picnic_table"
},
"title": {
"render": {
"en": "Picnic table",

View file

@ -5,7 +5,8 @@
"nl": "Fietsbibliotheek"
},
"minzoom": 8 ,
"overpassTags": "amenity=bicycle_library",
"source": {
"osmTags": "amenity=bicycle_library"},
"title": {
"render": {
"en": "Bicycle library",

View file

@ -37,11 +37,13 @@
}
],
"iconSize": "50,50,bottom",
"overpassTags": {
"source": {
"osmTags": {
"and": [
"amenity=vending_machine",
"vending~.*bicycle_tube.*"
]
}
},
"minzoom": 13,
"wayHandling": 2,

View file

@ -8,7 +8,8 @@
"de": "Fahrrad-Café"
},
"minzoom": 13,
"overpassTags": {
"source": {
"osmTags": {
"and": [
"amenity~pub|bar|cafe|restaurant",
{
@ -20,6 +21,7 @@
]
}
]
}
},
"title": {
"render": {

View file

@ -23,12 +23,14 @@
"render": "./assets/layers/bike_cleaning/bike_cleaning.svg"
},
"iconSize": "50,50,bottom",
"overpassTags": {
"source": {
"osmTags": {
"or": [
"service:bicycle:cleaning=yes",
"service:bicycle:cleaning=diy",
"amenity=bicycle_wash"
]
}
},
"minzoom": 13,
"wayHandling": 1,

View file

@ -1,14 +1,16 @@
{
{
"id": "bike_monitoring_station",
"name": {
"en": "Monitoring stations"
},
"minzoom": 12,
"overpassTags": {
"source": {
"osmTags": {
"and": [
"man_made=monitoring_station",
"monitoring:bicycle=yes"
]
}
},
"title": {
"render": {
@ -32,12 +34,15 @@
}
]
},
"tagRenderings": [ "images",
"tagRenderings": [
"images",
{
"render": "<b>{live({url},{url:format},hour)}</b> cyclists last hour<br/><b>{live({url},{url:format},day)}</b> cyclists today<br/><b>{live({url},{url:format},year)}</b> cyclists this year<br/>",
"condition": {
"and": ["url~*","url:format~*"]
"and": [
"url~*",
"url:format~*"
]
}
}
],

View file

@ -8,10 +8,12 @@
"de": "Fahrrad-Parkplätze"
},
"minzoom": 17,
"overpassTags": {
"source": {
"osmTags": {
"and": [
"amenity=bicycle_parking"
]
}
},
"icon": {
"render": {

View file

@ -8,10 +8,12 @@
"de": "Fahrradstationen (Reparatur, Pumpe oder beides)"
},
"minzoom": 13,
"overpassTags": {
"source": {
"osmTags": {
"and": [
"amenity=bicycle_repair_station"
]
}
},
"title": {
"render": {
@ -71,7 +73,8 @@
"gl": "Bomba de ar estragada",
"de": "Kaputte Pumpe"
}
},{
},
{
"if": {
"and": [
"service:bicycle:pump=yes",

View file

@ -8,7 +8,8 @@
"de": "Fahrradwerkstatt/geschäft"
},
"minzoom": 13,
"overpassTags": {
"source": {
"osmTags": {
"#": "We select all bicycle shops, sport shops (but we try to weed out non-bicycle related shops), and any shop with a bicycle related tag",
"or": [
"shop=bicycle",
@ -43,6 +44,7 @@
]
}
]
}
},
"title": {
"render": {

View file

@ -4,10 +4,12 @@
"nl": "Vogelkijkhutten"
},
"minzoom": 14,
"overpassTags": {
"source": {
"osmTags": {
"and": [
"leisure=bird_hide"
]
}
},
"title": {
"render": {

View file

@ -7,7 +7,8 @@
"de": "Mit Fahrrad zusammenhängendes Objekt"
},
"minzoom": 13,
"overpassTags": {
"source": {
"osmTags": {
"or": [
"theme~cycling|bicycle",
"sport=cycling",
@ -15,6 +16,7 @@
"ngo~cycling|bicycle",
"club~bicycle|cycling"
]
}
},
"title": {
"render": {

View file

@ -4,11 +4,13 @@
"en": "Direction visualization"
},
"minzoom": 16,
"overpassTags": {
"source": {
"osmTags": {
"or": [
"camera:direction~*",
"direction~*"
]
}
},
"doNotDownload": true,
"passAllFeatures": true,

View file

@ -31,14 +31,15 @@
"badge": true
}
],
"iconSize": "40,40,bottom",
"overpassTags": {
"source": {
"osmTags": {
"and": [
"amenity=drinking_water",
"access!=permissive",
"access!=private"
]
}
},
"minzoom": 13,
"wayHandling": 1,

View file

@ -5,7 +5,9 @@
"nl": "Witte Fietsen",
"de": "Geisterrad"
},
"overpassTags": "memorial=ghost_bike",
"source": {
"osmTags": "memorial=ghost_bike"
},
"minzoom": 0,
"title": {
"render": {

View file

@ -5,10 +5,12 @@
"en": "Information boards"
},
"minzoom": 12,
"overpassTags": {
"source": {
"osmTags": {
"and": [
"information=board"
]
}
},
"title": {
"render": {
@ -16,7 +18,9 @@
"en": "Information board"
}
},
"tagRenderings": [ "images"],
"tagRenderings": [
"images"
],
"hideUnderlayingFeaturesMinPercentage": 0,
"icon": {
"render": "./assets/layers/information_board/board.svg"

View file

@ -5,11 +5,13 @@
"nl": "Kaarten"
},
"minzoom": 12,
"overpassTags": {
"source": {
"osmTags": {
"or": [
"tourism=map",
"information=map"
]
}
},
"title": {
"render": {

View file

@ -4,11 +4,13 @@
"nl": "Natuurgebied"
},
"minzoom": 12,
"overpassTags": {
"source": {
"osmTags": {
"or": [
"leisure=nature_reserve",
"boundary=protected_area"
]
}
},
"title": {
"render": {
@ -330,7 +332,8 @@
"key": "description:0"
}
},
{"#": "Surface are",
{
"#": "Surface are",
"render": {
"en": "Surface area: {_surface:ha}Ha",
"mappings": {

View file

@ -4,10 +4,12 @@
"nl": "Speelbossen"
},
"minzoom": 13,
"overpassTags": {
"source": {
"osmTags": {
"and": [
"playground=forest"
]
}
},
"title": {
"render": {

View file

@ -5,11 +5,13 @@
"en": "Playgrounds"
},
"minzoom": 13,
"overpassTags": {
"source": {
"osmTags": {
"and": [
"leisure=playground",
"playground!=forest"
]
}
},
"description": {
"nl": "Speeltuinen",
@ -299,7 +301,7 @@
"render": "https://upload.wikimedia.org/wikipedia/commons/0/00/Map_icons_by_Scott_de_Jonge_-_playground.svg"
},
"width": {
"render": "3"
"render": "1"
},
"iconSize": {
"render": "40,40,center"

View file

@ -12,7 +12,9 @@
"de": "Ein Bücherschrank am Straßenrand mit Büchern, für jedermann zugänglich",
"fr": "Une armoire ou une boite contenant des livres en libre accès"
},
"overpassTags": "amenity=public_bookcase",
"source": {
"osmTags": "amenity=public_bookcase"
},
"minzoom": 12,
"wayHandling": 2,
"title": {
@ -256,8 +258,11 @@
"de": "Teil des Netzwerks 'Little Free Library'",
"fr": "Fait partie du réseau 'Little Free Library'"
},
"if":{
"and": ["brand=Little Free Library","nobrand="]
"if": {
"and": [
"brand=Little Free Library",
"nobrand="
]
}
},
{

View file

@ -4,7 +4,8 @@
"nl": "Trage wegen"
},
"minzoom": 14,
"overpassTags": {
"source": {
"osmTags": {
"or": [
"highway=pedestrian",
"highway=cycleway",
@ -14,6 +15,7 @@
"highway=living_street",
"highway=track"
]
}
},
"title": {
"render": {

View file

@ -5,10 +5,11 @@
},
"wayHandling": 2,
"minzoom": 12,
"overpassTags": {
"source": {
"osmTags": {
"and": [
"leisure=pitch"
]
]}
},
"title": {
"render": {
@ -211,13 +212,13 @@
"render": "./assets/layers/sport_pitch/tabletennis.svg"
},
"width": {
"render": "8"
"render": "1"
},
"iconSize": {
"render": "40,40,center"
},
"color": {
"render": "#00f"
"render": "#009"
},
"presets": [
{

View file

@ -5,7 +5,8 @@
"nl": "Bewakingscamera's"
},
"minzoom": 12,
"overpassTags": {
"source": {
"osmTags": {
"and": [
"man_made=surveillance",
{
@ -16,6 +17,7 @@
]
}
]
}
},
"title": {
"render": {

View file

@ -5,7 +5,9 @@
"de": "Toiletten",
"fr": "Toilettes"
},
"overpassTags": "amenity=toilets",
"source": {
"osmTags": "amenity=toilets"
},
"title": {
"render": {
"en": "Toilet",

View file

@ -5,8 +5,12 @@
"en": "Tree"
},
"minzoom": 14,
"overpassTags": {
"and": ["natural=tree"]
"source": {
"osmTags": {
"and": [
"natural=tree"
]
}
},
"title": {
"render": {
@ -38,7 +42,9 @@
"mappings": [
{
"if": {
"and": ["height~^[0-9.]+$"]
"and": [
"height~^[0-9.]+$"
]
},
"then": {
"nl": "Hoogte: {height}&nbsp;m",
@ -55,7 +61,9 @@
"mappings": [
{
"if": {
"and": ["leaf_type=broadleaved"]
"and": [
"leaf_type=broadleaved"
]
},
"then": {
"nl": "<img src=\"./assets/themes/trees/broadleaved.svg\" style=\"width:1.5em;height:1.5em\" alt=\"\"/> Loofboom",
@ -64,7 +72,9 @@
},
{
"if": {
"and": ["leaf_type=needleleaved"]
"and": [
"leaf_type=needleleaved"
]
},
"then": {
"nl": "<img src=\"./assets/themes/trees/needleleaved.svg\" style=\"width:1.5em;height:1.5em\" alt=\"\"/> Naaldboom",
@ -73,7 +83,9 @@
},
{
"if": {
"and": ["leaf_type=leafless"]
"and": [
"leaf_type=leafless"
]
},
"then": {
"nl": "<img src=\"./assets/themes/trees/leafless.svg\" style=\"width:1.5em;height:1.5em\" alt=\"\"/> Permanent bladloos",
@ -91,7 +103,9 @@
"mappings": [
{
"if": {
"and": ["denotation=landmark"]
"and": [
"denotation=landmark"
]
},
"then": {
"nl": "De boom valt op door zijn grootte of prominente locatie. Hij is nuttig voor navigatie.",
@ -100,7 +114,9 @@
},
{
"if": {
"and": ["denotation=natural_monument"]
"and": [
"denotation=natural_monument"
]
},
"then": {
"nl": "De boom is een natuurlijk monument, bijvoorbeeld doordat hij bijzonder oud of van een waardevolle soort is.",
@ -109,7 +125,9 @@
},
{
"if": {
"and": ["denotation=agricultural"]
"and": [
"denotation=agricultural"
]
},
"then": {
"nl": "De boom wordt voor landbouwdoeleinden gebruikt, bijvoorbeeld in een boomgaard.",
@ -118,7 +136,9 @@
},
{
"if": {
"and": ["denotation=park"]
"and": [
"denotation=park"
]
},
"then": {
"nl": "De boom staat in een park of dergelijke (begraafplaats, schoolterrein, …).",
@ -127,7 +147,9 @@
},
{
"if": {
"and": ["denotation=garden"]
"and": [
"denotation=garden"
]
},
"then": {
"nl": "De boom staat in de tuin bij een woning/flatgebouw.",
@ -136,7 +158,9 @@
},
{
"if": {
"and": ["denotation=avenue"]
"and": [
"denotation=avenue"
]
},
"then": {
"nl": "Dit is een laanboom.",
@ -145,7 +169,9 @@
},
{
"if": {
"and": ["denotation=urban"]
"and": [
"denotation=urban"
]
},
"then": {
"nl": "De boom staat in een woonkern.",
@ -154,7 +180,9 @@
},
{
"if": {
"and": ["denotation=none"]
"and": [
"denotation=none"
]
},
"then": {
"nl": "De boom staat buiten een woonkern.",
@ -171,7 +199,9 @@
"mappings": [
{
"if": {
"and": ["leaf_cycle=deciduous"]
"and": [
"leaf_cycle=deciduous"
]
},
"then": {
"nl": "Bladverliezend: de boom is een periode van het jaar kaal.",
@ -180,7 +210,9 @@
},
{
"if": {
"and": ["leaf_cycle=evergreen"]
"and": [
"leaf_cycle=evergreen"
]
},
"then": {
"nl": "Groenblijvend.",
@ -189,7 +221,9 @@
}
],
"condition": {
"and": ["leaf_type!~^leafless$"]
"and": [
"leaf_type!~^leafless$"
]
}
},
{
@ -351,13 +385,17 @@
"mappings": [
{
"if": {
"and": ["leaf_type=broadleaved"]
"and": [
"leaf_type=broadleaved"
]
},
"then": "circle:#ffffff;./assets/themes/trees/broadleaved.svg"
},
{
"if": {
"and": ["leaf_type=needleleaved"]
"and": [
"leaf_type=needleleaved"
]
},
"then": "circle:#ffffff;./assets/themes/trees/needleleaved.svg"
}

View file

@ -10,7 +10,9 @@
"nl": "Een mooi uitzicht - ideaal om een foto toe te voegen wanneer iets niet in een andere categorie past",
"de": "Ein schöner Aussichtspunkt oder eine schöne Aussicht. Ideal zum Hinzufügen eines Bildes, wenn keine andere Kategorie passt"
},
"overpassTags": "tourism=viewpoint",
"source": {
"osmTags": "tourism=viewpoint"
},
"minzoom": 14,
"icon": "./assets/layers/viewpoint/viewpoint.svg",
"iconSize": "20,20,center",

View file

@ -0,0 +1,48 @@
{
"id": "grass_in_parks",
"name": {
"nl": "Toegankelijke grasvelden in parken"
},
"source": {
"osmTags": {
"and": [
"landuse=grass",
{
"or": [
"access=public",
"access=yes"
]
}
]
},
"overpassScript": "way[\"leisure\"=\"park\"];node(w);is_in;area._[\"leisure\"=\"park\"];(way(area)[\"landuse\"=\"grass\"]; node(w); );"
},
"minzoom": 0,
"title": {
"render": {
"nl": "Speelweide in een park"
},
"mappings": [
{
"if": "name~*",
"then": {
"nl": "{name}"
}
}
]
},
"icon": "./assets/themes/playgrounds/playground.svg",
"iconSize": "40,40,bottom",
"width": "1",
"color": "#0f0",
"wayHandling": 2,
"tagRenderings": [
"images",
{
"render": "Op dit grasveld in het park mag je spelen, picnicken, zitten, ..."
},
{
"render": "{reviews(name, landuse=grass )}"
}
]
}

View file

@ -0,0 +1,37 @@
{
"id": "village_green",
"name": {
"nl": "Speelweide"
},
"source": {
"osmTags": "landuse=village_green"
},
"minzoom": 0,
"title": {
"render": {
"nl": "Speelweide"
},
"mappings": [
{
"if": "name~*",
"then": {
"nl": "{name}"
}
}
]
},
"icon": "./assets/themes/playgrounds/playground.svg",
"iconSize": "40,40,bottom",
"width": "1",
"color": "#0f0",
"wayHandling": 2,
"tagRenderings": [
"images",
{
"render": "Dit is een klein stukje openbaar groen waar je mag spelen, picnicken, zitten, ..."
},
{
"render": "{reviews(name, landuse=village_green )}"
}
]
}

View file

@ -27,7 +27,9 @@
"play_forest",
"playground",
"sport_pitch",
"slow_roads"
"slow_roads",
"grass_in_parks",
"village_green"
],
"roamingRenderings": []
}