Add a nature reserve oriented quest layout

This commit is contained in:
Pieter Vander Vennet 2020-07-18 20:40:51 +02:00
parent a7d356c263
commit fe4fa9dd0e
24 changed files with 591 additions and 1307 deletions

View file

@ -10,6 +10,8 @@ import { Layout } from "./Layout";
import {MetaMap} from "./Layouts/MetaMap";
import {Widths} from "./Layers/Widths";
import {StreetWidth} from "./Layouts/StreetWidth";
import {NatureReserves} from "./Layers/NatureReserves";
import {Natuurpunt} from "./Layouts/Natuurpunt";
export class AllKnownLayouts {
public static allSets: any = AllKnownLayouts.AllLayouts();
@ -24,6 +26,7 @@ export class AllKnownLayouts {
new WalkByBrussels(),
new MetaMap(),
new StreetWidth(),
new Natuurpunt(),
all
/*new Toilets(),
new Statues(),

View file

@ -62,9 +62,9 @@ export class LayerDefinition {
* icon is the Leaflet icon
* Note that this is passed entirely to leaflet, so other leaflet attributes work too
*/
style: (tags: any) => {
color: string,
icon: any ,
style: (tags: any) => {
color: string,
icon: any,
};
/**
@ -73,6 +73,36 @@ export class LayerDefinition {
maxAllowedOverlapPercentage: number = undefined;
constructor(options: {
name: string,
newElementTags: Tag[],
icon: string,
minzoom: number,
overpassFilter: TagsFilter,
title?: TagRenderingOptions,
elementsToShow?: TagDependantUIElementConstructor[],
maxAllowedOverlapPercentage?: number,
style?: (tags: any) => {
color: string,
icon: any
}
} = undefined) {
if (options === undefined) {
console.log("No options!")
return;
}
this.name = options.name;
this.maxAllowedOverlapPercentage = options.maxAllowedOverlapPercentage ?? 0;
this.newElementTags = options.newElementTags;
this.icon = options.icon;
this.minzoom = options.minzoom;
this.overpassFilter = options.overpassFilter;
this.title = options.title;
this.elementsToShow = options.elementsToShow;
this.style = options.style;
console.log(this)
}
asLayer(basemap: Basemap, allElements: ElementStorage, changes: Changes, userDetails: UIEventSource<UserDetails>, selectedElement: UIEventSource<any>,
showOnPopup: (tags: UIEventSource<(any)>) => UIElement):
FilteredLayer {

View file

@ -0,0 +1,146 @@
import {LayerDefinition} from "../LayerDefinition";
import {And, Or, Tag} from "../../Logic/TagsFilter";
import {TagRenderingOptions} from "../TagRendering";
import FixedText from "../Questions/FixedText";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
import L from "leaflet";
export class Birdhide extends LayerDefinition {
private static readonly birdhide = new Tag("leisure", "bird_hide");
constructor() {
super({
name: "vogelkijkplaats",
overpassFilter: Birdhide.birdhide,
elementsToShow: [new FixedText("hi")],
icon: "assets/nature/birdhide.svg",
minzoom: 12,
newElementTags: [Birdhide.birdhide],
style(tags: any): { color: string; icon: any } {
return {color: "", icon: undefined};
},
});
function rmStart(toRemove: string, title: string): string {
if (title.toLowerCase().indexOf(toRemove.toLowerCase()) == 0) {
return title.substr(toRemove.length).trim();
}
return title;
}
function rmStarts(toRemove: string[], title: string) {
for (const toRm of toRemove) {
title = rmStart(toRm, title);
}
return title;
}
this.title = new TagRenderingOptions({
tagsPreprocessor: (tags) => {
if (tags.name) {
const nm =
rmStarts(
["Vogelkijkhut", "Vogelkijkwand", "Kijkwand", "Kijkhut"],
tags.name);
tags.name = " '" + nm + "'";
} else {
tags.name = "";
}
},
mappings: [
{
k: new And([new Tag("shelter", "no"), new Tag("building", "")]),
txt: "Vogelkijkwand{name}"
},
{
k: new And([new Tag("amenity", "shelter"), new Tag("building", "yes")]),
txt: "Vogelijkhut{name}"
},
{
k: new Tag("amenity", "shelter"),
txt: "Vogelijkhut{name}"
},
{
k: new Tag("building", "yes"),
txt: "Vogelijkhut{name}"
},
{k: null, txt: "Vogelkijkplaats{name}"}
]
});
this.style = (properties) => {
let icon = "assets/nature/birdhide.svg";
if (new Or([new Tag("amenity", "shelter"), new Tag("building", "yes"), new Tag("shelter", "yes")]).matchesProperties(properties)) {
icon = "assets/nature/birdshelter.svg";
}
return {
color: "#0000bb",
icon: L.icon({
iconUrl: icon,
iconSize: [40,40],
iconAnchor: [20,20]
})
}
}
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
new TagRenderingOptions({
question: "Is dit een kijkwand of kijkhut?",
mappings: [
{
k: new And([new Tag("shelter", "no"), new Tag("building", ""), new Tag("amenity", "")]),
txt: "Vogelkijkwand"
},
{
k: new And([new Tag("amenity", "shelter"), new Tag("building", "yes"), new Tag("shelter", "yes")]),
txt: "Vogelijkhut"
}
]
}),
new TagRenderingOptions({
question: "Is ze rolstoeltoegankelijk?",
mappings: [
{
k: new Tag("wheelchair", "no"),
txt: "Niet rolstoeltoegankelijk"
},
{
k: new Tag("wheelchair", "limited"),
txt: "Een rolstoel raakt er, maar het is niet makkelijk"
},
{
k: new Tag("wheelchair", "yes"),
txt: "Een rolstoel raakt er gemakkelijk"
}
]
}),
new TagRenderingOptions({
question: "Wie beheert deze?",
freeform: {
key: "operator",
template: "Beheer door $$$",
renderTemplate: "Beheer door {operator}",
placeholder: "organisatie"
},
mappings: [
{k: new Tag("operator", "Natuurpunt"), txt: "Natuurpunt"},
{k: new Tag("operator", "Agentschap Natuur en Bos"), txt: "het Agentschap Natuur en Bos (ANB)"},
]
})
];
}
}

View file

@ -0,0 +1,112 @@
import {LayerDefinition} from "../LayerDefinition";
import FixedText from "../Questions/FixedText";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
import {TagRenderingOptions} from "../TagRendering";
import {And, Tag} from "../../Logic/TagsFilter";
import L from "leaflet";
export class InformationBoard extends LayerDefinition {
constructor() {
super({
name: "Informatiebord",
minzoom: 12,
overpassFilter: new Tag("tourism", "information"),
newElementTags: [new Tag("tourism", "information")],
maxAllowedOverlapPercentage: 0,
icon: "assets/nature/info.png",
});
const isMap = new Tag("information", "map");
const isOsmSource = new Tag("map_source", "OpenStreetMap");
this.title = new TagRenderingOptions({
mappings: [
{k: isMap, txt: "Kaart"},
{k:null, txt: "Informatiebord"}
]
});
this.style = (properties) => {
let icon = "assets/nature/info.png";
if (isMap.matchesProperties(properties)) {
icon = "assets/map.svg";
if (isOsmSource.matchesProperties(properties)) {
icon = "assets/osm-logo-white-bg.svg";
const attr = properties["map_source:attribution"];
if (attr == "sticker") {
icon = "assets/map-stickered.svg"
} else if (attr == "no") {
icon = "assets/osm-logo-buggy-attr.svg"
}
}
}
return {
color: "#000000",
icon: L.icon(
{
iconUrl: icon,
iconSize: [50, 50]
}
)
};
}
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
new TagRenderingOptions({
question: "Heeft dit informatiebord een kaart?",
mappings: [
{k: new Tag("information","board"), txt: "Dit is een informatiebord"},
{k: isMap, txt: "Dit is een kaart"}
]
}),
new TagRenderingOptions({
question: "Is this map based on OpenStreetMap?",
mappings: [
{
k: isOsmSource,
txt: "This map is based on OpenStreetMap"
},
],
freeform: {
key: "map_source",
renderTemplate: "The map data is based on {map_source}",
template: "The map data is based on $$$"
}
}).OnlyShowIf(isMap),
new TagRenderingOptions({
question: "Is the attribution present?",
mappings: [
{
k: new Tag("map_source:attribution", "yes"),
txt: "OpenStreetMap is clearly attribute, including the ODBL-license"
},
{
k: new Tag("map_source:attribution", "incomplete"),
txt: "OpenStreetMap is clearly attribute, but the license is not mentioned"
},
{
k: new Tag("map_source:attribution", "sticker"),
txt: "OpenStreetMap wasn't mentioned, but someone put an OpenStreetMap-sticker on it"
},
{
k: new Tag("map_source:attribution", "no"),
txt: "There is no attribution at all"
},
{
k: new Tag("map_source:attribution", "none"),
txt: "There is no attribution at all"
}
]
}).OnlyShowIf(new Tag("map_source", "OpenStreetMap"))
]
}
}

View file

@ -10,18 +10,18 @@ import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWi
export class NatureReserves extends LayerDefinition {
constructor() {
constructor(moreQuests: boolean = false) {
super();
this.name = "natuurgebied";
this.icon = "./assets/tree_white_background.svg";
this.overpassFilter =
new Or([new Tag("leisure", "nature_reserve"), new Tag("boundary","protected_area")]);
new Or([new Tag("leisure", "nature_reserve"), new Tag("boundary", "protected_area")]);
this.maxAllowedOverlapPercentage = 10;
this.newElementTags = [new Tag("leisure", "nature_reserve"),
new Tag("fixme", "Toegevoegd met MapComplete, geometry nog uit te tekenen")]
this.minzoom = 13;
this.title = new NameInline("natuurreservaat");
this.title = new NameInline("natuurreservaat");
this.style = this.generateStyleFunction();
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
@ -30,6 +30,67 @@ export class NatureReserves extends LayerDefinition {
new OperatorTag(),
new DescriptionQuestion("natuurgebied")
];
const extraRenderings = [
new TagRenderingOptions({
question: "Mogen honden in dit natuurgebied?",
mappings: [
{k: new Tag("dog", "leashed"), txt: "Honden moeten aan de leiband"},
{k: new Tag("dog", "no"), txt: "Honden zijn niet toegestaan"},
{k: new Tag("dog", "yes"), txt: "Honden zijn welkom"},
]
}).OnlyShowIf(new Tag("access", "yes")),
new TagRenderingOptions({
question: "Op welke website kunnen we meer informatie vinden over dit natuurgebied?",
freeform: {
key:"website",
renderTemplate: "<a href='{website}' target='_blank'>Meer informatie</a>",
template: "$$$"
}
}),
new TagRenderingOptions({
question: "Wie is de conservator van dit gebied?<br>" +
"<span class='question-subtext'>Geef de naam van de conservator énkel als die duidelijk online staat gepubliceerd.</span>",
freeform: {
renderTemplate: "De conservator van dit gebied is {curator}",
template: "$$$",
key: "curator"
}
}),
new TagRenderingOptions(
{
question: "Wat is het email-adres van de beheerder?<br>" +
"<span class='question-subtext'>Geef bij voorkeur het emailadres van de Natuurpunt-afdeling; geef enkel een email-adres van de conservator als dit duidelijk is gepubliceerd</span>",
freeform: {
renderTemplate: "Bij problemen of vragen, de {conservator} kan bereikt worden via " +
"<a href='mailto:{email}'>{email}</a>",
template: "$$$",
key: "email"
}
}),
new TagRenderingOptions(
{
question: "Wat is het telefoonnummer van de beheerder?<br>" +
"<span class='question-subtext'>Geef bij voorkeur het telefoonnummer van de Natuurpunt-afdeling; geef enkel een email-adres van de conservator als dit duidelijk is gepubliceerd</span>",
freeform: {
renderTemplate: "Bij problemen of vragen, de {conservator} kan bereikt worden via " +
"<a href='tel:{phone}'>{phone}</a>",
template: "$$$",
key: "phone"
}
}),
];
if (moreQuests) {
this.elementsToShow =
this.elementsToShow.concat(extraRenderings);
}
}

View file

@ -101,6 +101,7 @@ export class Widths extends LayerDefinition {
this.carWidth = carWidth;
this.cyclistWidth = cyclistWidth;
this.pedestrianWidth = pedestrianWidth;
this.minzoom = 12;
function r(n: number) {
const pre = Math.floor(n);
@ -254,7 +255,7 @@ export class Widths extends LayerDefinition {
new TagRenderingOptions({
mappings: [
{k:new Tag("highway","living_street"),txt: "Dit is een woonerf"},
{k:new Tag("highway","pedestrian"),txt: "Hier mogen enkel voetgangers komen"}
{k:new Tag("highway","pedestrian"),txt: "Deze weg is autovrij"}
]
}),

View file

@ -0,0 +1,20 @@
import {Layout} from "../Layout";
import {Birdhide} from "../Layers/Birdhide";
import {InformationBoard} from "../Layers/InformationBoard";
import {NatureReserves} from "../Layers/NatureReserves";
export class Natuurpunt extends Layout{
constructor() {
super(
"natuurpunt",
"De natuur in",
[new Birdhide(), new InformationBoard(), new NatureReserves(true)],
12,
51.20875,
3.22435,
"<h3>Natuurpuntstuff</h3>",
"",
""
);
}
}