forked from MapComplete/MapComplete
Add a nature reserve oriented quest layout
This commit is contained in:
parent
a7d356c263
commit
fe4fa9dd0e
24 changed files with 591 additions and 1307 deletions
|
@ -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(),
|
||||
|
|
|
@ -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 {
|
||||
|
|
146
Customizations/Layers/Birdhide.ts
Normal file
146
Customizations/Layers/Birdhide.ts
Normal 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)"},
|
||||
|
||||
]
|
||||
})
|
||||
|
||||
|
||||
];
|
||||
|
||||
}
|
||||
}
|
112
Customizations/Layers/InformationBoard.ts
Normal file
112
Customizations/Layers/InformationBoard.ts
Normal 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"))
|
||||
]
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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"}
|
||||
]
|
||||
}),
|
||||
|
||||
|
|
20
Customizations/Layouts/Natuurpunt.ts
Normal file
20
Customizations/Layouts/Natuurpunt.ts
Normal 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>",
|
||||
"",
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue