First steps for a decent custom theme generator

This commit is contained in:
Pieter Vander Vennet 2020-08-31 02:59:47 +02:00
parent a57b7d93fa
commit 2052976909
82 changed files with 1880 additions and 1311 deletions

View file

@ -4,41 +4,35 @@ import {Groen} from "./Layouts/Groen";
import Cyclofix from "./Layouts/Cyclofix";
import {StreetWidth} from "./Layouts/StreetWidth";
import {GRB} from "./Layouts/GRB";
import {ClimbingTrees} from "./Layouts/ClimbingTrees";
import {Smoothness} from "./Layouts/Smoothness";
import {MetaMap} from "./Layouts/MetaMap";
import {Natuurpunt} from "./Layouts/Natuurpunt";
import {GhostBikes} from "./Layouts/GhostBikes";
import {FromJSON} from "./JSON/FromJSON";
import * as bookcases from "../assets/themes/bookcases/Bookcases.json";
import * as aed from "../assets/themes/aed/aed.json";
import * as toilets from "../assets/themes/toilets/toilets.json";
import * as artworks from "../assets/themes/artwork/artwork.json";
import * as cyclestreets from "../assets/themes/cyclestreets/cyclestreets.json";
import * as ghostbikes from "../assets/themes/ghostbikes/ghostbikes.json"
import {PersonalLayout} from "../Logic/PersonalLayout";
export class AllKnownLayouts {
public static allLayers: Map<string, LayerDefinition> = undefined;
public static layoutsList: Layout[] = [
new PersonalLayout(),
new Natuurpunt(),
new GRB(),
new Cyclofix(),
new GhostBikes(),
FromJSON.LayoutFromJSON(bookcases),
// FromJSON.LayoutFromJSON(aed),
// FromJSON.LayoutFromJSON(toilets),
// FromJSON.LayoutFromJSON(artworks),
// FromJSON.LayoutFromJSON(cyclestreets),
FromJSON.LayoutFromJSON(aed),
FromJSON.LayoutFromJSON(toilets),
FromJSON.LayoutFromJSON(artworks),
FromJSON.LayoutFromJSON(cyclestreets),
FromJSON.LayoutFromJSON(ghostbikes),
new MetaMap(),
new StreetWidth(),
new ClimbingTrees(),
new Smoothness(),
new Groen(),
];
@ -47,11 +41,15 @@ export class AllKnownLayouts {
public static allSets: Map<string, Layout> = AllKnownLayouts.AllLayouts();
private static AllLayouts(): Map<string, Layout> {
this.allLayers = new Map<string, LayerDefinition>();
for (const layout of this.layoutsList) {
for (const layer of layout.layers) {
for (let i = 0; i < layout.layers.length; i++) {
let layer = layout.layers[i];
if (typeof (layer) === "string") {
layer = layout.layers[i] = FromJSON.sharedLayers.get(layer);
}
if (this.allLayers[layer.id] !== undefined) {
continue;
}

View file

@ -13,10 +13,31 @@ import Translations from "../../UI/i18n/Translations";
import Combine from "../../UI/Base/Combine";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
import {ImageCarouselConstructor} from "../../UI/Image/ImageCarousel";
import * as drinkingWater from "../../assets/layers/drinking_water/drinking_water.json";
import * as ghostbikes from "../../assets/layers/ghost_bike/ghost_bike.json"
import * as viewpoint from "../../assets/layers/viewpoint/viewpoint.json"
import {Utils} from "../../Utils";
export class FromJSON {
public static sharedLayers: Map<string, LayerDefinition> = FromJSON.getSharedLayers();
private static getSharedLayers() {
const sharedLayers = new Map<string, LayerDefinition>();
const sharedLayersList = [
FromJSON.Layer(drinkingWater),
FromJSON.Layer(ghostbikes),
FromJSON.Layer(viewpoint),
];
for (const layer of sharedLayersList) {
sharedLayers.set(layer.id, layer);
}
return sharedLayers;
}
public static FromBase64(layoutFromBase64: string): Layout {
return FromJSON.LayoutFromJSON(JSON.parse(atob(layoutFromBase64)));
@ -139,19 +160,27 @@ export class FromJSON {
{
k: FromJSON.Tag(mapping.if),
txt: FromJSON.Translation(mapping.then),
hideInAnswer: mapping.hideInAnswer
hideInAnswer: mapping.hideInAnswer
})
);
return new TagRenderingOptions({
let rendering = new TagRenderingOptions({
question: FromJSON.Translation(json.question),
freeform: freeform,
mappings: mappings
});
if (json.condition) {
console.log("Applying confition ", json.condition)
return rendering.OnlyShowIf(FromJSON.Tag(json.condition));
}
return rendering;
}
public static SimpleTag(json: string): Tag {
const tag = json.split("=");
const tag = Utils.SplitFirst(json, "=");
return new Tag(tag[0], tag[1]);
}
@ -159,35 +188,39 @@ export class FromJSON {
if (typeof (json) == "string") {
const tag = json as string;
if (tag.indexOf("!~") >= 0) {
const split = tag.split("!~");
if(split[1] == "*"){
const split = Utils.SplitFirst(tag, "!~");
if (split[1] === "*") {
split[1] = ".*"
}
console.log(split)
return new RegexTag(
new RegExp(split[0]),
new RegExp(split[1]),
split[0],
new RegExp("^" + split[1] + "$"),
true
);
}
if (tag.indexOf("!=") >= 0) {
const split = tag.split("!=");
const split = Utils.SplitFirst(tag, "!=");
if (split[1] === "*") {
split[1] = ".*"
}
return new RegexTag(
new RegExp(split[0]),
new RegExp(split[1]),
split[0],
new RegExp("^" + split[1] + "$"),
true
);
}
if (tag.indexOf("~") >= 0) {
const split = tag.split("~");
if(split[1] == "*"){
const split = Utils.SplitFirst(tag, "~");
if (split[1] === "*") {
split[1] = ".*"
}
return new RegexTag(
new RegExp("^"+split[0]+"$"),
new RegExp("^"+split[1]+"$")
split[0],
new RegExp("^" + split[1] + "$")
);
}
const split = tag.split("=");
const split = Utils.SplitFirst(tag, "=");
return new Tag(split[0], split[1])
}
if (json.and !== undefined) {
@ -208,11 +241,23 @@ export class FromJSON {
}
}
public static Layer(json: LayerConfigJson): LayerDefinition {
console.log("Parsing ",json.name);
public static Layer(json: LayerConfigJson | string): LayerDefinition {
if (typeof (json) === "string") {
const cached = FromJSON.sharedLayers.get(json);
if (cached) {
return cached;
}
throw "Layer not yet loaded..."
}
console.log("Parsing ", json.name);
const tr = FromJSON.Translation;
const overpassTags = FromJSON.Tag(json.overpassTags);
const icon = FromJSON.TagRenderingWithDefault(json.icon, "layericon", "./assets/bug.svg");
const iconSize = FromJSON.TagRenderingWithDefault(json.iconSize, "iconSize", "40,40,center");
const color = FromJSON.TagRenderingWithDefault(json.color, "layercolor", "#0000ff");
const width = FromJSON.TagRenderingWithDefault(json.width, "layerwidth", "10");
const renderTags = {"id": "node/-1"}
@ -225,11 +270,38 @@ export class FromJSON {
}) ?? [];
function style(tags) {
const iconSizeStr = iconSize.GetContent(tags).txt.split(",");
const iconwidth = Number(iconSizeStr[0]);
const iconheight = Number(iconSizeStr[1]);
const iconmode = iconSizeStr[2];
const iconAnchor = [iconwidth / 2, iconheight / 2] // x, y
// If iconAnchor is set to [0,0], then the top-left of the icon will be placed at the geographical location
if (iconmode.indexOf("left") >= 0) {
iconAnchor[0] = 0;
}
if (iconmode.indexOf("right") >= 0) {
iconAnchor[0] = iconwidth;
}
if (iconmode.indexOf("top") >= 0) {
iconAnchor[1] = 0;
}
if (iconmode.indexOf("bottom") >= 0) {
iconAnchor[1] = iconheight;
}
// the anchor is always set from the center of the point
// x, y with x going right and y going down if the values are bigger
const popupAnchor = [0, -iconAnchor[1]+3];
return {
color: color.GetContent(tags).txt,
weight: width.GetContent(tags).txt,
icon: {
iconUrl: icon.GetContent(tags).txt
iconUrl: icon.GetContent(tags).txt,
iconSize: [iconwidth, iconheight],
popupAnchor: popupAnchor,
iconAnchor: iconAnchor
},
}
}

View file

@ -46,6 +46,13 @@ export interface LayerConfigJson {
* Note that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.
*/
icon?: string | TagRenderingConfigJson;
/**
* A string containing "width,height" or "width,height,anchorpoint" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...
* Default is '40,40,center'
*/
iconSize?: string | TagRenderingConfigJson;
/**
* The color for way-elements
*/
@ -67,8 +74,8 @@ export interface LayerConfigJson {
* Presets for this layer
*/
presets?: {
tags: string[],
title: string | any,
tags: string[],
description?: string | any,
}[],

View file

@ -83,12 +83,12 @@ export interface LayoutConfigJson {
* In order to prevent them to do too much damage, all the overpass-tags of the layers are taken and combined as OR.
* These tag renderings will only show up if the object matches this filter.
*/
roamingRenderings?: TagRenderingConfigJson[],
roamingRenderings?: (TagRenderingConfigJson | string)[],
/**
* The layers to display
*/
layers: LayerConfigJson[],
layers: (LayerConfigJson | string)[],

View file

@ -1,14 +0,0 @@
/**
* Read a tagconfig and converts it into a TagsFilter value
*/
import {AndOrTagConfigJson} from "./TagConfigJson";
export default class TagConfig {
public static fromJson(json: any): TagConfig {
const config: AndOrTagConfigJson = json;
return config;
}
}

View file

@ -75,7 +75,10 @@ export class LayerDefinition {
color: string,
weight?: number,
icon: {
iconUrl: string, iconSize?: number[], popupAnchor?: number[], iconAnchor?: number[]
iconUrl: string,
iconSize?: number[],
popupAnchor?: number[],
iconAnchor?: number[]
},
};

View file

@ -24,7 +24,7 @@ export default class BikeOtherShops extends LayerDefinition {
this.name = this.to.name
this.icon = "./assets/bike/non_bike_repair_shop.svg"
this.overpassFilter = new And([
new RegexTag(/^shop$/, /^bicycle$/, true),
new RegexTag("shop", /^bicycle$/, true),
new RegexTag(/^service:bicycle:/, /.*/),
])
this.presets = []

View file

@ -1,43 +0,0 @@
import {LayerDefinition} from "../LayerDefinition";
import Translations from "../../UI/i18n/Translations";
import FixedText from "../Questions/FixedText";
import {And, Tag} from "../../Logic/Tags";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
export class ClimbingTree extends LayerDefinition {
constructor() {
super("climbingtree");
const t = Translations.t.climbingTrees.layer;
this.title = new FixedText(t.title);
const icon = "./assets/themes/nature/tree.svg";
this.icon = icon;
this.description = t.description;
this.style = (tags) => {
return {
color: "#00aa00",
icon: {
iconUrl: icon,
iconSize: [50, 50]
}
}
}
const tags = [new Tag("natural","tree"),new Tag("sport","climbing")];
this.overpassFilter = new And(tags);
this.presets = [
{
title: t.title,
description: t.description,
tags: tags
}
]
this.minzoom = 12;
this.elementsToShow = [
new ImageCarouselWithUploadConstructor()
]
}
}

View file

@ -1,62 +0,0 @@
import {LayerDefinition} from "../LayerDefinition";
import {And, Or, Tag} from "../../Logic/Tags";
import {OperatorTag} from "../Questions/OperatorTag";
import FixedText from "../Questions/FixedText";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
import Translations from "../../UI/i18n/Translations";
import {TagRenderingOptions} from "../TagRenderingOptions";
export class DrinkingWater extends LayerDefinition {
constructor() {
super("drinkingwater");
this.name = Translations.t.cyclofix.drinking_water.title;
this.icon = "./assets/bike/drinking_water.svg";
this.overpassFilter = new Or([
new And([
new Tag("amenity", "drinking_water")
])
]);
this.presets = [{
title: Translations.t.cyclofix.drinking_water.title,
tags: [new Tag("amenity", "drinking_water")]
}];
this.maxAllowedOverlapPercentage = 10;
this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY
this.minzoom = 13;
this.style = DrinkingWater.generateStyleFunction();
this.title = new FixedText("Drinking water");
this.elementsToShow = [
new OperatorTag(),
];
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
new TagRenderingOptions({
question: "How easy is it to fill water bottles?",
mappings: [
{ k: new Tag("bottle", "yes"), txt: "It is easy to refill water bottles" },
{ k: new Tag("bottle", "no"), txt: "Water bottles may not fit" }
],
})];
}
private static generateStyleFunction() {
return function () {
return {
color: "#00bb00",
icon: {
iconUrl: "./assets/bike/drinking_water.svg",
iconSize: [50, 50],
iconAnchor: [25,50]
}
};
};
}
}

View file

@ -1,78 +0,0 @@
import {LayerDefinition} from "../LayerDefinition";
import {Tag} from "../../Logic/Tags";
import FixedText from "../Questions/FixedText";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
import {TagRenderingOptions} from "../TagRenderingOptions";
export class GhostBike extends LayerDefinition {
constructor() {
super("ghost bike");
this.name = "Ghost bike";
this.overpassFilter = new Tag("memorial", "ghost_bike")
this.title = new FixedText("Ghost bike");
this.description = "A <b>ghost bike</b> is a memorial for a cyclist who died in a traffic accident," +
" in the form of a white bicycle placed permanently near the accident location.";
this.minzoom = 1;
this.icon = "./assets/bike/ghost.svg"
this.presets = [
{
title: "Ghost bike",
description: "Add a missing ghost bike to the map",
tags: [new Tag("historic", "memorial"), new Tag("memorial", "ghost_bike")]
}
]
this.elementsToShow = [
new FixedText(this.description),
new ImageCarouselWithUploadConstructor(),
new TagRenderingOptions({
question: "Whom is remembered by this ghost bike?" +
"<span class='question-subtext'>" +
"<br/>" +
"Please respect privacy - only fill out the name if it is widely published or marked on the cycle." +
"</span>",
mappings: [{k: new Tag("noname", "yes"), txt: "There is no name marked on the bike"},],
freeform: {
key: "name",
extraTags: new Tag("noname", ""),
template: "$$$",
renderTemplate: "In the remembrance of <b>{name}</b>",
}
}),
new TagRenderingOptions({
question: "When was the ghost bike installed?",
freeform: {
key: "start_date",
template: "The ghost bike was placed on $$$", // TODO create a date picker
renderTemplate: "The ghost bike was placed on <b>{start_date}</b>",
}
}),
new TagRenderingOptions({
question: "On what URL can more information be found?" +
"<span class='question-subtext'>If available, add a link to a news report about the accident or about the placing of the ghost bike</span>",
freeform: {
key: "source",
template: "More information available on $$$",
renderTemplate: "<a href='{source}' target='_blank'>More information</a>",
}
}),
];
this.style = (tags: any) => {
return {
color: "#000000",
icon: {
iconUrl: 'assets/bike/ghost.svg',
iconSize: [40, 40],
iconAnchor: [20, 20],
}
}
};
}
}

View file

@ -1,49 +0,0 @@
import {LayerDefinition} from "../LayerDefinition";
import FixedText from "../Questions/FixedText";
import {Tag} from "../../Logic/Tags";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
import {TagRenderingOptions} from "../TagRenderingOptions";
export class Viewpoint extends LayerDefinition {
constructor() {
super("viewpoint",{
name: "Bezienswaardigheid",
description: "Wil je een foto toevoegen van iets dat geen park, bos of natuurgebied is? Dit kan hiermee",
presets: [{
title: "Bezienswaardigheid (andere)",
description: "Wens je een foto toe te voegen dat geen park, bos of (erkend) natuurreservaat is? Dit kan hiermee",
tags: [new Tag("tourism", "viewpoint"),
new Tag("fixme", "Added with mapcomplete. This viewpoint should probably me merged with some existing feature")]
}],
icon: "assets/viewpoint.svg",
wayHandling: LayerDefinition.WAYHANDLING_CENTER_ONLY,
style: _ => {
return {
color: undefined, icon: {
iconUrl: "assets/viewpoint.svg",
iconSize: [20, 20]
}
}
},
maxAllowedOverlapPercentage: 0,
overpassFilter: new Tag("tourism", "viewpoint"),
minzoom: 13,
title: new FixedText("Bezienswaardigheid")
});
this.elementsToShow = [
new FixedText(this.description),
new ImageCarouselWithUploadConstructor(),
new TagRenderingOptions({
question: "Zijn er bijzonderheden die je wilt toevoegen?",
freeform:{
key: "description:0",
template: "$$$",
renderTemplate: "<h3>Bijzonderheden</h3>{description:0}"
}
})
]
}
}

View file

@ -1,6 +1,7 @@
import {LayerDefinition} from "../LayerDefinition";
import {And, Or, Tag} from "../../Logic/Tags";
import {TagRenderingOptions} from "../TagRenderingOptions";
import {FromJSON} from "../JSON/FromJSON";
export class Widths extends LayerDefinition {
@ -39,6 +40,13 @@ export class Widths extends LayerDefinition {
[new Tag("highway", "pedestrian"), new Tag("highway", "living_street"),
new Tag("access","destination"), new Tag("motor_vehicle", "destination")])
private readonly _notCarfree =
FromJSON.Tag({"and":[
"highway!~pedestrian|living_street",
"access!~destination",
"motor_vehicle!~destination|no"
]});
private calcProps(properties) {
let parkingStateKnown = true;
let parallelParkingCount = 0;
@ -195,7 +203,7 @@ export class Widths extends LayerDefinition {
renderTemplate: "{note:width:carriageway}",
template: "$$$",
}
}).OnlyShowIf(this._carfree, true),
}).OnlyShowIf(this._notCarfree),
new TagRenderingOptions({
@ -215,7 +223,7 @@ export class Widths extends LayerDefinition {
renderTemplate: "{note:width:carriageway}",
template: "$$$",
}
}).OnlyShowIf(this._carfree, true),
}).OnlyShowIf(this._notCarfree),
new TagRenderingOptions({
@ -245,7 +253,7 @@ export class Widths extends LayerDefinition {
txt: "Tweerichtingsverkeer voor iedereen. Dit gebruikt <b>" + r(2 * this.carWidth + 2 * this.cyclistWidth) + "m</b>"
}
]
}).OnlyShowIf(this._carfree, true),
}).OnlyShowIf(this._notCarfree),
new TagRenderingOptions(
{
@ -263,7 +271,7 @@ export class Widths extends LayerDefinition {
{k: new Tag("short",""), txt: "De totale nodige ruimte voor vlot en veilig verkeer is dus <span class='thanks'>{targetWidth}m</span>"}
]
}
).OnlyShowIf(this._carfree, true),
).OnlyShowIf(this._notCarfree),
new TagRenderingOptions({

View file

@ -18,7 +18,7 @@ export class Layout {
public changesetMessage: string;
public socialImage: string = "";
public layers: LayerDefinition[];
public layers: (LayerDefinition | string)[];
public welcomeMessage: UIElement;
public gettingStartedPlzLogin: UIElement;
public welcomeBackMessage: UIElement;
@ -63,7 +63,7 @@ export class Layout {
id: string,
supportedLanguages: string[],
title: UIElement | string,
layers: LayerDefinition[],
layers: (LayerDefinition | string)[],
startzoom: number,
startLat: number,
startLon: number,

View file

@ -1,20 +0,0 @@
import Translations from "../../UI/i18n/Translations";
import {Layout} from "../Layout";
import {ClimbingTree} from "../Layers/ClimbingTree";
export class ClimbingTrees extends Layout {
constructor() {
super(
"climbing_trees",
["nl"],
Translations.t.climbingTrees.layout.title,
[new ClimbingTree()],
12,
50.8435,
4.3688,
Translations.t.climbingTrees.layout.welcome
);
this.icon = "./assets/themes/nature/tree.svg"
this.hideFromOverview = true;
}
}

View file

@ -3,7 +3,6 @@ import BikeParkings from "../Layers/BikeParkings";
import BikeServices from "../Layers/BikeStations";
import BikeShops from "../Layers/BikeShops";
import Translations from "../../UI/i18n/Translations";
import {DrinkingWater} from "../Layers/DrinkingWater";
import Combine from "../../UI/Base/Combine";
import BikeOtherShops from "../Layers/BikeOtherShops";
import BikeCafes from "../Layers/BikeCafes";
@ -15,7 +14,7 @@ export default class Cyclofix extends Layout {
"cyclofix",
["en", "nl", "fr","gl"],
Translations.t.cyclofix.title,
[new BikeServices(), new BikeShops(), new DrinkingWater(), new BikeParkings(), new BikeOtherShops(), new BikeCafes()],
[new BikeServices(), new BikeShops(), "drinking_water", new BikeParkings(), new BikeOtherShops(), new BikeCafes()],
16,
50.8465573,
4.3516970,

View file

@ -1,22 +0,0 @@
import {Layout} from "../Layout";
import {GhostBike} from "../Layers/GhostBike";
import Combine from "../../UI/Base/Combine";
export class GhostBikes extends Layout {
constructor() {
super("ghostbikes",
["en"],
"Ghost Bike Map",
[new GhostBike()],
6,
50.423,
5.493,
new Combine(["<h3>", "A map of Ghost Bikes", "</h3>",
"A <b>ghost bike</b> is a memorial for a cyclist who died in a traffic accident," +
" in the form of a white bicycle placed permanently near the accident location.",
"On this map, one can see the location of known ghost bikes, and (with a free OpenStreetMap account) easily add missing and new Ghost Bikes"])
);
this.icon = "./assets/bike/ghost.svg";
}
}

View file

@ -2,7 +2,6 @@ import {NatureReserves} from "../Layers/NatureReserves";
import {Park} from "../Layers/Park";
import {Bos} from "../Layers/Bos";
import {Layout} from "../Layout";
import {Viewpoint} from "../Layers/Viewpoint";
export class Groen extends Layout {
@ -10,12 +9,12 @@ export class Groen extends Layout {
super("buurtnatuur",
["nl"],
"Buurtnatuur.be",
[new NatureReserves(), new Park(), new Bos(), new Viewpoint()],
[new NatureReserves(), new Park(), new Bos(), "viewpoint"],
10,
50.8435,
4.3688,
"\n" +
"<img src='assets/groen.svg' alt='logo-groen' class='logo'> <br />" +
"<img src='./assets/themes/buurtnatuur/groen_logo.svg' alt='logo-groen' class='logo'> <br />" +
"<h3>Breng jouw buurtnatuur in kaart</h3>" +
"<b>Natuur maakt gelukkig.</b> Aan de hand van deze website willen we de natuur dicht bij ons beter inventariseren. Met als doel meer mensen te laten genieten van toegankelijke natuur én te strijden voor meer natuur in onze buurten. \n" +
"<ul>" +
@ -52,9 +51,8 @@ export class Groen extends Layout {
"</small>"
);
this.icon = "./assets/groen.svg"
this.locationContains = ["buurtnatuur.be"]
this.socialImage = "assets/BuurtnatuurFront.jpg"
this.icon = "./assets/themes/buurtnatuur/groen_logo.svg"
this.socialImage = "assets/themes/buurtnatuur/social_image.jpg"
this.description = "Met deze tool kan je natuur in je buurt in kaart brengen en meer informatie geven over je favoriete plekje"
this.enableMoreQuests = false;
this.enableShareScreen = false

View file

@ -2,7 +2,6 @@ import {Layout} from "../Layout";
import {Birdhide} from "../Layers/Birdhide";
import {InformationBoard} from "../Layers/InformationBoard";
import {NatureReserves} from "../Layers/NatureReserves";
import {DrinkingWater} from "../Layers/DrinkingWater";
export class Natuurpunt extends Layout{
constructor() {
@ -10,7 +9,7 @@ export class Natuurpunt extends Layout{
"natuurpunt",
["nl"],
"De natuur in",
[new Birdhide(), new InformationBoard(), new NatureReserves(true), new DrinkingWater()],
[new Birdhide(), new InformationBoard(), new NatureReserves(true), "drinking_water"],
12,
51.20875,
3.22435,

View file

@ -1,82 +0,0 @@
import {Layout} from "../Layout";
import {LayerDefinition} from "../LayerDefinition";
import {Or, Tag} from "../../Logic/Tags";
import {TagRenderingOptions} from "../TagRenderingOptions";
export class SmoothnessLayer extends LayerDefinition {
constructor() {
super("smoothness");
this.name = "smoothness";
this.minzoom = 17;
this.overpassFilter = new Or([
new Tag("highway","unclassified"),
new Tag("highway", "residential"),
new Tag("highway", "cycleway"),
new Tag("highway", "footway"),
new Tag("highway", "path"),
new Tag("highway", "tertiary")
]);
this.elementsToShow = [
new TagRenderingOptions({
question: "How smooth is this road to rollerskate on",
mappings: [
{k: new Tag("smoothness","bad"), txt: "It's horrible"},
{k: new Tag("smoothness","intermediate"), txt: "It is passable by rollerscate, but only if you have to"},
{k: new Tag("smoothness","good"), txt: "Good, but it has some friction or holes"},
{k: new Tag("smoothness","very_good"), txt: "Quite good and enjoyable"},
{k: new Tag("smoothness","excellent"), txt: "Excellent - this is where you'd want to drive 24/7"},
]
})
]
this.style = (properties) => {
let color = "#000000";
if(new Tag("smoothness","bad").matchesProperties(properties)){
color = "#ff0000";
}
if(new Tag("smoothness","intermediate").matchesProperties(properties)){
color = "#ffaa00";
}
if(new Tag("smoothness","good").matchesProperties(properties)){
color = "#ccff00";
}
if(new Tag("smoothness","very_good").matchesProperties(properties)){
color = "#00aa00";
}
if(new Tag("smoothness","excellent").matchesProperties(properties)){
color = "#00ff00";
}
return {
color: color,
icon: undefined,
weight: 8
}
}
}
}
export class Smoothness extends Layout {
constructor() {
super(
"smoothness",
["en" ],
"Smoothness while rollerskating",
[new SmoothnessLayer()],
17,
51.2,
3.2,
"Give smoothness feedback for rollerskating"
);
this.widenFactor = 0.005
this.hideFromOverview = true;
this.enableAdd = false;
}
}

View file

@ -10,19 +10,16 @@ import Translation from "../UI/i18n/Translation";
export class OnlyShowIfConstructor implements TagDependantUIElementConstructor{
private readonly _tagsFilter: TagsFilter;
private readonly _embedded: TagDependantUIElementConstructor;
private readonly _invert: boolean;
constructor(tagsFilter: TagsFilter, embedded: TagDependantUIElementConstructor, invert: boolean = false) {
constructor(tagsFilter: TagsFilter, embedded: TagDependantUIElementConstructor) {
this._tagsFilter = tagsFilter;
this._embedded = embedded;
this._invert = invert;
}
construct(dependencies): TagDependantUIElement {
return new OnlyShowIf(dependencies.tags,
this._embedded.construct(dependencies),
this._tagsFilter,
this._invert);
this._tagsFilter);
}
IsKnown(properties: any): boolean {
@ -51,7 +48,7 @@ export class OnlyShowIfConstructor implements TagDependantUIElementConstructor{
}
private Matches(properties: any) : boolean{
return this._tagsFilter.matches(TagUtils.proprtiesToKV(properties)) != this._invert;
return this._tagsFilter.matches(TagUtils.proprtiesToKV(properties));
}
}
@ -59,22 +56,18 @@ export class OnlyShowIfConstructor implements TagDependantUIElementConstructor{
class OnlyShowIf extends UIElement implements TagDependantUIElement {
private readonly _embedded: TagDependantUIElement;
private readonly _filter: TagsFilter;
private readonly _invert: boolean;
constructor(
tags: UIEventSource<any>,
embedded: TagDependantUIElement,
filter: TagsFilter,
invert: boolean) {
filter: TagsFilter) {
super(tags);
this._filter = filter;
this._embedded = embedded;
this._invert = invert;
}
private Matches() : boolean{
return this._filter.matches(TagUtils.proprtiesToKV(this._source.data)) != this._invert;
return this._filter.matches(TagUtils.proprtiesToKV(this._source.data));
}
InnerRender(): string {

View file

@ -0,0 +1,3 @@
export default class SharedLayers {
}

View file

@ -81,8 +81,8 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor {
this.options = options;
}
OnlyShowIf(tagsFilter: TagsFilter, invert: boolean = false): TagDependantUIElementConstructor {
return new OnlyShowIfConstructor(tagsFilter, this, invert);
OnlyShowIf(tagsFilter: TagsFilter): TagDependantUIElementConstructor {
return new OnlyShowIfConstructor(tagsFilter, this);
}