Merge branches

This commit is contained in:
Pieter Vander Vennet 2020-07-29 15:08:29 +02:00
commit 19f69b31a4
24 changed files with 676 additions and 110 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@ dist/*
node_modules node_modules
.cache/* .cache/*
.idea/* .idea/*
scratch

View file

View file

@ -0,0 +1,114 @@
import { LayerDefinition } from "../LayerDefinition";
import Translations from "../../UI/i18n/Translations";
import {And, Tag, Or} from "../../Logic/TagsFilter";
import { ImageCarouselWithUploadConstructor } from "../../UI/Image/ImageCarouselWithUpload";
import ShopRetail from "../Questions/bike/ShopRetail";
import ShopPump from "../Questions/bike/ShopPump";
import ShopRental from "../Questions/bike/ShopRental";
import ShopRepair from "../Questions/bike/ShopRepair";
import ShopDiy from "../Questions/bike/ShopDiy";
import ShopName from "../Questions/bike/ShopName";
import ShopSecondHand from "../Questions/bike/ShopSecondHand";
import { TagRenderingOptions } from "../TagRendering";
import { PhoneNumberQuestion } from "../Questions/PhoneNumberQuestion";
import Website from "../Questions/Website";
function anyValueExcept(key: string, exceptValue: string) {
return new And([
new Tag(key, "*"),
new Tag(key, exceptValue, true)
])
}
export default class BikeOtherShops extends LayerDefinition {
private readonly sellsBikes = new Tag("service:bicycle:retail", "yes")
private readonly repairsBikes = anyValueExcept("service:bicycle:repair", "no")
private readonly rentsBikes = new Tag("service:bicycle:rental", "yes")
private readonly hasPump = new Tag("service:bicycle:pump", "yes")
private readonly hasDiy = new Tag("service:bicycle:diy", "yes")
private readonly sellsSecondHand = anyValueExcept("service:bicycle:repair", "no")
private readonly hasBikeServices = new Or([
this.sellsBikes,
this.repairsBikes,
// this.rentsBikes,
// this.hasPump,
// this.hasDiy,
// this.sellsSecondHand
])
private readonly to = Translations.t.cyclofix.nonBikeShop
constructor() {
super();
this.name = this.to.name
this.icon = "./assets/bike/non_bike_repair_shop.svg"
this.overpassFilter = new And([
anyValueExcept("shop", "bicycle"),
this.hasBikeServices
])
this.newElementTags = undefined
this.maxAllowedOverlapPercentage = 10
this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY
this.minzoom = 13;
this.style = this.generateStyleFunction();
this.title = new TagRenderingOptions({
mappings: [
{
k: new And([new Tag("name", "*"), this.sellsBikes]),
txt: this.to.titleShopNamed
},
{
k: new And([new Tag("name", "*"), new Tag("service:bicycle:retail", "")]),
txt: this.to.titleShop
},
{
k: new And([new Tag("name", "*"), new Tag("service:bicycle:retail", "no")]),
txt: this.to.titleRepairNamed
},
{k: this.sellsBikes, txt: this.to.titleShop},
{k: new Tag("service:bicycle:retail", " "), txt: this.to.title},
{k: new Tag("service:bicycle:retail", "no"), txt: this.to.titleRepair},
{
k: new And([new Tag("name", "*")]),
txt: this.to.titleNamed
},
{k: null, txt: this.to.title},
]
})
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
new ShopName(),
new PhoneNumberQuestion("{name}"),
new Website("{name}"),
new ShopRetail(),
new ShopRental(),
new ShopRepair(),
new ShopPump(),
new ShopDiy(),
new ShopSecondHand()
]
}
private generateStyleFunction() {
const self = this;
return function (tags: any) {
let icon = "assets/bike/non_bike_repair_shop.svg";
if (self.sellsBikes.matchesProperties(tags)) {
icon = "assets/bike/non_bike_shop.svg";
}
return {
color: "#00bb00",
icon: {
iconUrl: icon,
iconSize: [50, 50],
iconAnchor: [25, 50]
}
}
}
}
}

View file

@ -1,16 +1,19 @@
import {LayerDefinition} from "../LayerDefinition"; import {LayerDefinition} from "../LayerDefinition";
import {And, Or, Tag} from "../../Logic/TagsFilter"; import {And, Or, Tag, TagsFilter} from "../../Logic/TagsFilter";
import {OperatorTag} from "../Questions/OperatorTag"; import {OperatorTag} from "../Questions/OperatorTag";
import FixedText from "../Questions/FixedText"; import FixedText from "../Questions/FixedText";
import ParkingType from "../Questions/bike/ParkingType"; import ParkingType from "../Questions/bike/ParkingType";
import ParkingCapacity from "../Questions/bike/ParkingCapacity";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload"; import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
import BikeStationOperator from "../Questions/bike/StationOperator";
import Translations from "../../UI/i18n/Translations"; import Translations from "../../UI/i18n/Translations";
import ParkingOperator from "../Questions/bike/ParkingOperator"; import ParkingOperator from "../Questions/bike/ParkingOperator";
import {TagRenderingOptions} from "../TagRendering"; import ParkingAccessCargo from "../Questions/bike/ParkingAccessCargo";
import ParkingCapacityCargo from "../Questions/bike/ParkingCapacityCargo";
export default class BikeParkings extends LayerDefinition { export default class BikeParkings extends LayerDefinition {
private readonly accessCargoDesignated = new Tag("cargo_bike", "designated");
constructor() { constructor() {
super(); super();
this.name = Translations.t.cyclofix.parking.name; this.name = Translations.t.cyclofix.parking.name;
@ -28,14 +31,9 @@ export default class BikeParkings extends LayerDefinition {
new ImageCarouselWithUploadConstructor(), new ImageCarouselWithUploadConstructor(),
//new ParkingOperator(), //new ParkingOperator(),
new ParkingType(), new ParkingType(),
new TagRenderingOptions({ new ParkingCapacity(),
question: "How many bicycles fit in this bicycle parking?", new ParkingAccessCargo(),
freeform: { new ParkingCapacityCargo().OnlyShowIf(this.accessCargoDesignated)
key: "capacity",
renderTemplate: "Place for {capacity} bikes",
template: "$nat$ bikes fit in here"
}
})
]; ];
this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY; this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY;

View file

@ -1,6 +1,6 @@
import { LayerDefinition } from "../LayerDefinition"; import { LayerDefinition } from "../LayerDefinition";
import Translations from "../../UI/i18n/Translations"; import Translations from "../../UI/i18n/Translations";
import {And, Tag} from "../../Logic/TagsFilter"; import {And, Tag, Or} from "../../Logic/TagsFilter";
import FixedText from "../Questions/FixedText"; import FixedText from "../Questions/FixedText";
import { ImageCarouselWithUploadConstructor } from "../../UI/Image/ImageCarouselWithUpload"; import { ImageCarouselWithUploadConstructor } from "../../UI/Image/ImageCarouselWithUpload";
import ShopRetail from "../Questions/bike/ShopRetail"; import ShopRetail from "../Questions/bike/ShopRetail";
@ -12,6 +12,7 @@ import ShopName from "../Questions/bike/ShopName";
import ShopSecondHand from "../Questions/bike/ShopSecondHand"; import ShopSecondHand from "../Questions/bike/ShopSecondHand";
import { TagRenderingOptions } from "../TagRendering"; import { TagRenderingOptions } from "../TagRendering";
import {PhoneNumberQuestion} from "../Questions/PhoneNumberQuestion"; import {PhoneNumberQuestion} from "../Questions/PhoneNumberQuestion";
import Website from "../Questions/Website";
export default class BikeShops extends LayerDefinition { export default class BikeShops extends LayerDefinition {
@ -52,6 +53,7 @@ export default class BikeShops extends LayerDefinition {
new ImageCarouselWithUploadConstructor(), new ImageCarouselWithUploadConstructor(),
new ShopName(), new ShopName(),
new PhoneNumberQuestion("{name}"), new PhoneNumberQuestion("{name}"),
new Website("{name}"),
new ShopRetail(), new ShopRetail(),
new ShopRental(), new ShopRental(),
new ShopRepair(), new ShopRepair(),

View file

@ -12,6 +12,7 @@ import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWi
import PumpOperational from "../Questions/bike/PumpOperational"; import PumpOperational from "../Questions/bike/PumpOperational";
import PumpValves from "../Questions/bike/PumpValves"; import PumpValves from "../Questions/bike/PumpValves";
import Translations from "../../UI/i18n/Translations"; import Translations from "../../UI/i18n/Translations";
import { TagRenderingOptions } from "../TagRendering";
export default class BikeStations extends LayerDefinition { export default class BikeStations extends LayerDefinition {
@ -19,6 +20,7 @@ export default class BikeStations extends LayerDefinition {
private readonly pumpOperationalAny = new Tag("service:bicycle:pump:operational_status", "yes"); private readonly pumpOperationalAny = new Tag("service:bicycle:pump:operational_status", "yes");
private readonly pumpOperationalOk = new Or([new Tag("service:bicycle:pump:operational_status", "yes"), new Tag("service:bicycle:pump:operational_status", "operational"), new Tag("service:bicycle:pump:operational_status", "ok"), new Tag("service:bicycle:pump:operational_status", "")]); private readonly pumpOperationalOk = new Or([new Tag("service:bicycle:pump:operational_status", "yes"), new Tag("service:bicycle:pump:operational_status", "operational"), new Tag("service:bicycle:pump:operational_status", "ok"), new Tag("service:bicycle:pump:operational_status", "")]);
private readonly tools = new Tag("service:bicycle:tools", "yes"); private readonly tools = new Tag("service:bicycle:tools", "yes");
private readonly to = Translations.t.cyclofix.station
constructor() { constructor() {
super(); super();
@ -36,7 +38,19 @@ export default class BikeStations extends LayerDefinition {
this.minzoom = 13; this.minzoom = 13;
this.style = this.generateStyleFunction(); this.style = this.generateStyleFunction();
this.title = new FixedText(Translations.t.cyclofix.station.title) this.title = new TagRenderingOptions({
mappings: [
{
k: new And([this.pump, this.tools]),
txt: this.to.titlePumpAndRepair
},
{
k: new And([this.pump]),
txt: this.to.titlePump
},
{k: null, txt: this.to.titleRepair},
]
})
this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY
this.elementsToShow = [ this.elementsToShow = [
@ -65,9 +79,9 @@ export default class BikeStations extends LayerDefinition {
let iconName = "repair_station.svg"; let iconName = "repair_station.svg";
if (hasTools && hasPump && isOperational) { if (hasTools && hasPump && isOperational) {
iconName = "repair_station_pump.svg" iconName = "repair_station_pump.svg"
}else if(hasTools){ } else if(hasTools) {
iconName = "repair_station.svg" iconName = "repair_station.svg"
}else if(hasPump){ } else if(hasPump) {
if (isOperational) { if (isOperational) {
iconName = "pump.svg" iconName = "pump.svg"
} else { } else {

View file

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

View file

@ -0,0 +1,17 @@
import {TagRenderingOptions} from "../TagRendering";
import {UIElement} from "../../UI/UIElement";
import Translations from "../../UI/i18n/Translations";
export default class Website extends TagRenderingOptions {
constructor(category: string | UIElement) {
super({
question: Translations.t.general.questions.websiteOf.Subs({category: category}),
freeform: {
renderTemplate: Translations.t.general.questions.websiteIs.Subs({category: category}),
template: "$phone$",
key: "phone"
}
});
}
}

View file

@ -0,0 +1,20 @@
import { TagRenderingOptions } from "../../TagRendering";
import { Tag } from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class ParkingAccessCargo extends TagRenderingOptions {
constructor() {
const key = "cargo_bike"
const to = Translations.t.cyclofix.parking.access_cargo
super({
priority: 15,
question: to.question.Render(),
mappings: [
{k: new Tag(key, "yes"), txt: to.yes},
{k: new Tag(key, "designated"), txt: to.designated},
{k: new Tag(key, "no"), txt: to.no}
]
});
}
}

View file

@ -0,0 +1,18 @@
import Translations from "../../../UI/i18n/Translations";
import { TagRenderingOptions } from "../../TagRendering";
export default class ParkingCapacity extends TagRenderingOptions {
constructor() {
const to = Translations.t.cyclofix.parking.capacity
super({
priority: 15,
question: to.question,
freeform: {
key: "capacity",
renderTemplate: to.render,
template: to.template
}
});
}
}

View file

@ -0,0 +1,19 @@
import Translations from "../../../UI/i18n/Translations";
import { TagRenderingOptions } from "../../TagRendering";
import Combine from "../../../UI/Base/Combine";
export default class ParkingCapacityCargo extends TagRenderingOptions {
constructor() {
const to = Translations.t.cyclofix.parking.capacity_cargo
super({
priority: 10,
question: to.question,
freeform: {
key: "capacity:cargo_bike",
renderTemplate: to.render,
template: to.template
}
});
}
}

View file

@ -0,0 +1,19 @@
import { TagRenderingOptions } from "../../TagRendering";
import { Tag } from "../../../Logic/TagsFilter";
import Translations from "../../../UI/i18n/Translations";
export default class ParkingCovered extends TagRenderingOptions {
constructor() {
const key = 'covered'
const to = Translations.t.cyclofix.parking.covered
super({
priority: 15,
question: to.question.Render(),
mappings: [
{k: new Tag(key, "yes"), txt: to.yes},
{k: new Tag(key, "no"), txt: to.no}
]
});
}
}

View file

@ -1,37 +1,34 @@
import {TagsFilter} from "./TagsFilter"; import {TagsFilter} from "./TagsFilter";
import * as OsmToGeoJson from "osmtogeojson"; import * as OsmToGeoJson from "osmtogeojson";
import * as $ from "jquery"; import * as $ from "jquery";
import {Basemap} from "./Basemap";
import {UIEventSource} from "../UI/UIEventSource";
/** /**
* Interfaces overpass to get all the latest data * Interfaces overpass to get all the latest data
*/ */
export class Overpass { export class Overpass {
private _filter: TagsFilter
public static testUrl: string = null
private _filter: TagsFilter;
public static testUrl: string = null;
constructor(filter: TagsFilter) { constructor(filter: TagsFilter) {
this._filter = filter; this._filter = filter
} }
private buildQuery(bbox: string): string { public buildQuery(bbox: string): string {
const filters = this._filter.asOverpass(); const filters = this._filter.asOverpass()
let filter = ""; console.log(filters)
let filter = ""
for (const filterOr of filters) { for (const filterOr of filters) {
filter += 'nwr' + filterOr + ';'; filter += 'nwr' + filterOr + ';'
} }
const query = const query =
'[out:json][timeout:25]' + bbox + ';(' + filter + ');out body;>;out skel qt;'; '[out:json][timeout:25]' + bbox + ';(' + filter + ');out body;>;out skel qt;'
console.log(query); console.log(query)
return "https://overpass-api.de/api/interpreter?data=" + encodeURIComponent(query); return "https://overpass-api.de/api/interpreter?data=" + encodeURIComponent(query)
} }
queryGeoJson(bbox: string, continuation: ((any) => void), onFail: ((reason) => void)): void { queryGeoJson(bbox: string, continuation: ((any) => void), onFail: ((reason) => void)): void {
let query = this.buildQuery(bbox); let query = this.buildQuery(bbox)
if(Overpass.testUrl !== null){ if(Overpass.testUrl !== null){
console.log("Using testing URL") console.log("Using testing URL")
@ -53,9 +50,5 @@ export class Overpass {
const geojson = OsmToGeoJson.default(json); const geojson = OsmToGeoJson.default(json);
continuation(geojson); continuation(geojson);
}).fail(onFail) }).fail(onFail)
;
} }
}
}

View file

@ -51,17 +51,23 @@ export class Regex extends TagsFilter {
substituteValues(tags: any) : TagsFilter{ substituteValues(tags: any) : TagsFilter{
throw "Substituting values is not supported on regex tags" throw "Substituting values is not supported on regex tags"
} }
} }
export class Tag extends TagsFilter {
public key: string;
public value: string;
constructor(key: string, value: string) { export class Tag extends TagsFilter {
public key: string
public value: string
public invertValue: boolean
constructor(key: string, value: string, invertValue = false) {
super() super()
this.key = key; this.key = key
this.value = value; this.value = value
this.invertValue = invertValue
if (value === "*" && invertValue) {
throw new Error("Invalid combination: invertValue && value == *")
}
} }
matches(tags: { k: string; v: string }[]): boolean { matches(tags: { k: string; v: string }[]): boolean {
@ -69,21 +75,22 @@ export class Tag extends TagsFilter {
if (tag.k === this.key) { if (tag.k === this.key) {
if (tag.v === "") { if (tag.v === "") {
// This tag has been removed // This tag has been removed
return this.value === ""; return this.value === ""
} }
if (this.value === "*") { if (this.value === "*") {
// Any is allowed // Any is allowed
return true; return true;
} }
return this.value === tag.v; return this.value === tag.v !== this.invertValue
} }
} }
if(this.value === ""){
return true; if (this.value === "") {
return true
} }
return false; return this.invertValue
} }
asOverpass(): string[] { asOverpass(): string[] {
@ -94,17 +101,17 @@ export class Tag extends TagsFilter {
// NOT having this key // NOT having this key
return ['[!"' + this.key + '"]']; return ['[!"' + this.key + '"]'];
} }
return ['["' + this.key + '"="' + this.value + '"]']; const compareOperator = this.invertValue ? '!=' : '='
return ['["' + this.key + '"' + compareOperator + '"' + this.value + '"]'];
} }
substituteValues(tags: any) { substituteValues(tags: any) {
return new Tag(this.key, TagUtils.ApplyTemplate(this.value, tags)); return new Tag(this.key, TagUtils.ApplyTemplate(this.value, tags));
} }
} }
export class Or extends TagsFilter {
export class Or extends TagsFilter {
public or: TagsFilter[] public or: TagsFilter[]
constructor(or: TagsFilter[]) { constructor(or: TagsFilter[]) {
@ -112,9 +119,7 @@ export class Or extends TagsFilter {
this.or = or; this.or = or;
} }
matches(tags: { k: string; v: string }[]): boolean { matches(tags: { k: string; v: string }[]): boolean {
for (const tagsFilter of this.or) { for (const tagsFilter of this.or) {
if (tagsFilter.matches(tags)) { if (tagsFilter.matches(tags)) {
return true; return true;
@ -125,7 +130,6 @@ export class Or extends TagsFilter {
} }
asOverpass(): string[] { asOverpass(): string[] {
const choices = []; const choices = [];
for (const tagsFilter of this.or) { for (const tagsFilter of this.or) {
const subChoices = tagsFilter.asOverpass(); const subChoices = tagsFilter.asOverpass();
@ -143,11 +147,10 @@ export class Or extends TagsFilter {
} }
return new Or(newChoices); return new Or(newChoices);
} }
} }
export class And extends TagsFilter {
export class And extends TagsFilter {
public and: TagsFilter[] public and: TagsFilter[]
constructor(and: TagsFilter[]) { constructor(and: TagsFilter[]) {
@ -156,7 +159,6 @@ export class And extends TagsFilter {
} }
matches(tags: { k: string; v: string }[]): boolean { matches(tags: { k: string; v: string }[]): boolean {
for (const tagsFilter of this.and) { for (const tagsFilter of this.and) {
if (!tagsFilter.matches(tags)) { if (!tagsFilter.matches(tags)) {
return false; return false;
@ -175,8 +177,7 @@ export class And extends TagsFilter {
} }
asOverpass(): string[] { asOverpass(): string[] {
var allChoices: string[] = null;
var allChoices = null;
for (const andElement of this.and) { for (const andElement of this.and) {
var andElementFilter = andElement.asOverpass(); var andElementFilter = andElement.asOverpass();
@ -185,10 +186,10 @@ export class And extends TagsFilter {
continue; continue;
} }
var newChoices = [] var newChoices: string[] = []
for (var choice of allChoices) { for (var choice of allChoices) {
newChoices.push( newChoices.push(
this.combine(choice, andElementFilter) ...this.combine(choice, andElementFilter)
) )
} }
allChoices = newChoices; allChoices = newChoices;
@ -205,6 +206,7 @@ export class And extends TagsFilter {
} }
} }
export class Not extends TagsFilter{ export class Not extends TagsFilter{
private not: TagsFilter; private not: TagsFilter;
@ -224,12 +226,10 @@ export class Not extends TagsFilter{
substituteValues(tags: any): TagsFilter { substituteValues(tags: any): TagsFilter {
return new Not(this.not.substituteValues(tags)); return new Not(this.not.substituteValues(tags));
} }
} }
export class TagUtils { export class TagUtils {
static proprtiesToKV(properties: any): { k: string, v: string }[] { static proprtiesToKV(properties: any): { k: string, v: string }[] {
const result = []; const result = [];
for (const k in properties) { for (const k in properties) {
@ -246,5 +246,4 @@ export class TagUtils {
} }
return template; return template;
} }
}
}

View file

@ -2,6 +2,7 @@ import {InputElement} from "./InputElement";
import {UIEventSource} from "../UIEventSource"; import {UIEventSource} from "../UIEventSource";
import {UIElement} from "../UIElement"; import {UIElement} from "../UIElement";
import {FixedUiElement} from "../Base/FixedUiElement"; import {FixedUiElement} from "../Base/FixedUiElement";
import Translations from "../i18n/Translations";
export class InputElementWrapper<T> extends InputElement<T>{ export class InputElementWrapper<T> extends InputElement<T>{
@ -16,9 +17,11 @@ export class InputElementWrapper<T> extends InputElement<T>{
) { ) {
super(undefined); super(undefined);
this.pre = typeof(pre) === 'string' ? new FixedUiElement(pre) : pre // this.pre = typeof(pre) === 'string' ? new FixedUiElement(pre) : pre
this.pre = Translations.W(pre)
this.input = input; this.input = input;
this.post =typeof(post) === 'string' ? new FixedUiElement(post) : post // this.post =typeof(post) === 'string' ? new FixedUiElement(post) : post
this.post = Translations.W(post)
} }

0
UI/MoreScreen.ts Normal file
View file

View file

@ -19,12 +19,21 @@ export default class Translations {
fr: 'Cyclofix - Une carte ouverte pour les cyclistes' fr: 'Cyclofix - Une carte ouverte pour les cyclistes'
}), }),
description: new T({ description: new T({
en: "On this map we want to collect data about the whereabouts of bicycle pumps and public racks in Brussels and everywhere else." + en: "The goal of this map is to present cyclists with an easy-to-use solution to find the appropriate infrastructure for their needs.<br><br>" + //this works in spoken language: ; think about the nearest bike repair station for example
"As a result, cyclists will be able to quickly find the nearest infrastructure for their needs.", "You can track your precise location (mobile only) and select layers that are relevant for you in the bottom left corner. " +
nl: "Op deze kaart willen we gegevens verzamelen over de locatie van fietspompen en openbare stelplaatsen in Brussel en overal ter wereld." + "You can also use this tool to add or edit pins (points of interest) to the map and provide more data by answering the questions.<br><br>" +
"Hierdoor kunnen fietsers snel de dichtstbijzijnde infrastructuur vinden die voldoet aan hun behoeften.", "All changes you make will automatically be saved in the global database of OpenStreetMap and can be freely re-used by others.<br><br>" +
fr: "Sur cette carte, nous voulons collecter des données sur la localisation des pompes à vélo et des supports publics à Bruxelles." + "For more information about the cyclofix project, go to <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>.",
"Les cyclistes pourront ainsi trouver rapidement l'infrastructure la plus proche pour leurs besoins." nl: "Het doel van deze kaart is om fietsers een gebruiksvriendelijke oplossing te bieden voor het vinden van de juiste infrastructuur voor hun behoeften.<br><br>" + //; denk bijvoorbeeld aan de dichtstbijzijnde fietsherstelplaats.
"U kunt uw exacte locatie volgen (enkel mobiel) en in de linkerbenedenhoek categorieën selecteren die voor u relevant zijn. " +
"U kunt deze tool ook gebruiken om 'spelden' aan de kaart toe te voegen of te bewerken en meer gegevens te verstrekken door de vragen te beantwoorden.<br><br>" +
"Alle wijzigingen die u maakt worden automatisch opgeslagen in de wereldwijde database van OpenStreetMap en kunnen door anderen vrij worden hergebruikt.<br><br>" +
"Bekijk voor meer info over cyclofix ook <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>.",
fr: "Le but de cette carte est de présenter aux cyclistes une solution facile à utiliser pour trouver l'infrastructure appropriée à leurs besoins.<br><br>" + //; pensez par exemple à la station de réparation de vélos la plus proche.
"Vous pouvez suivre votre localisation précise (mobile uniquement) et sélectionner les couches qui vous concernent dans le coin inférieur gauche. " +
"Vous pouvez également utiliser cet outil pour ajouter ou modifier des épingles (points d'intérêt) sur la carte et fournir plus de données en répondant aux questions.<br><br>" +
"Toutes les modifications que vous apportez seront automatiquement enregistrées dans la base de données mondiale d'OpenStreetMap et peuvent être librement réutilisées par d'autres.<br><br>" +
"Pour plus d'informations sur le projet cyclofix, rendez-vous sur <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>."
}), }),
freeFormPlaceholder: new T({en: 'specify', nl: 'specifieer', fr: 'TODO: fr'}), freeFormPlaceholder: new T({en: 'specify', nl: 'specifieer', fr: 'TODO: fr'}),
parking: { parking: {
@ -33,13 +42,13 @@ export default class Translations {
type: { type: {
render: new T({ render: new T({
en: 'This is a bicycle parking of the type: {bicycle_parking}', en: 'This is a bicycle parking of the type: {bicycle_parking}',
nl: 'Dit is een fietsenparking van het type: {bicycle_parking}', nl: 'Dit is een fietsparking van het type: {bicycle_parking}',
fr: 'Ceci est un parking à vélo de type {bicycle_parking}' fr: 'Ceci est un parking à vélo de type {bicycle_parking}'
}), }),
template: new T({en: 'Some other type: $$$', nl: 'Een ander type: $$$', fr: "D'autres types: $$$"}), template: new T({en: 'Some other type: $$$', nl: 'Een ander type: $$$', fr: "D'autres types: $$$"}),
question: new T({ question: new T({
en: 'What is the type of this bicycle parking?', en: 'What is the type of this bicycle parking?',
nl: 'Van welk type is deze fietsenparking?', nl: 'Van welk type is deze fietsparking?',
fr: 'Quelle type de parking s\'agit il? ' fr: 'Quelle type de parking s\'agit il? '
}), }),
eg: new T({en: ", for example", nl: ", bijvoorbeeld", fr: ",par example"}), eg: new T({en: ", for example", nl: ", bijvoorbeeld", fr: ",par example"}),
@ -50,11 +59,10 @@ export default class Translations {
rack: new T({en: 'Rack', nl: 'Rek', fr: 'Râtelier'}), rack: new T({en: 'Rack', nl: 'Rek', fr: 'Râtelier'}),
"two-tier": new T({en: 'Two-tiered', nl: 'Dubbel (twee verdiepingen)', fr: 'Superposé'}), "two-tier": new T({en: 'Two-tiered', nl: 'Dubbel (twee verdiepingen)', fr: 'Superposé'}),
}, },
operator: { operator: {
render: new T({ render: new T({
en: 'This bike parking is operated by {operator}', en: 'This bike parking is operated by {operator}',
nl: 'Deze fietsenparking wordt beheerd door {operator}', nl: 'Deze fietsparking wordt beheerd door {operator}',
fr: 'Ce parking est opéré par {operator}' fr: 'Ce parking est opéré par {operator}'
}), }),
template: new T({en: 'A different operator: $$$', nl: 'Een andere beheerder: $$$', fr: 'TODO: fr'}), template: new T({en: 'A different operator: $$$', nl: 'Een andere beheerder: $$$', fr: 'TODO: fr'}),
@ -68,15 +76,95 @@ export default class Translations {
nl: 'Wordt beheerd door een privépersoon', nl: 'Wordt beheerd door een privépersoon',
fr: 'Opéré par un tier privé' fr: 'Opéré par un tier privé'
}), }),
},
covered: {
question: new T({
en: 'Is this parking covered? Also select "covered" for indoor parkings.',
nl: 'Is deze parking overdekt? Selecteer ook "overdekt" voor fietsparkings binnen een gebouw.',
fr: 'TODO: fr'
}),
yes: new T({
en: 'This parking is covered (it has a roof)',
nl: 'Deze parking is overdekt (er is een afdak)',
fr: 'TODO: fr'
}),
no: new T({
en: 'This parking is not covered',
nl: 'Deze parking is niet overdekt',
fr: 'TODO: fr'
})
},
capacity: {
question: new T({
en: "How many bicycles fit in this bicycle parking (including possible cargo bicycles)?",
nl: "Voor hoeveel fietsen is er bij deze fietsparking plaats (inclusief potentiëel bakfietsen)?",
fr: "TODO: fr"
}),
template: new T({
en: "This parking fits $nat$ bikes",
nl: "Deze parking heeft plaats voor $nat$ fietsen",
fr: "TODO: fr"
}),
render: new T({
en: "Place for {capacity} bikes (in total)",
nl: "Plaats voor {capacity} fietsen (in totaal)",
fr: "TODO: fr"
}),
},
capacity_cargo: {
question: new T({
en: "How many cargo bicycles fit in this bicycle parking?",
nl: "Voor hoeveel bakfietsen heeft deze fietsparking plaats?",
fr: "TODO: fr"
}),
template: new T({
en: "This parking fits $nat$ cargo bikes",
nl: "Deze parking heeft plaats voor $nat$ fietsen",
fr: "TODO: fr"
}),
render: new T({
en: "Place for {capacity:cargo_bike} cargo bikes",
nl: "Plaats voor {capacity:cargo_bike} bakfietsen",
fr: "TODO: fr"
}),
},
access_cargo: {
question: new T({
en: "Does this bicycle parking have spots for cargo bikes?",
nl: "Heeft deze fietsparking plaats voor bakfietsen?",
fr: "TODO: fr"
}),
yes: new T({
en: "This parking has room for cargo bikes",
nl: "Deze parking is overdekt (er is een afdak)",
fr: "TODO: fr"
}),
designated: new T({
en: "This parking has designated (official) spots for cargo bikes.",
nl: "Deze parking is overdekt (er is een afdak)",
fr: "TODO: fr"
}),
no: new T({
en: "You're not allowed to park cargo bikes",
nl: "Je mag hier geen bakfietsen parkeren",
fr: "TODO: fr"
})
} }
}, },
station: { station: {
name: new T({ name: new T({
en: 'bike station (repair, pump or both)', en: 'bike station (repair, pump or both)',
nl: 'fietsstation (herstel, pomp of allebei)', nl: 'fietspunt (herstel, pomp of allebei)',
fr: 'station velo (réparation, pompe à vélo)' fr: 'station velo (réparation, pompe à vélo)'
}), }),
title: new T({en: 'Bike station', nl: 'Fietsstation', fr: 'Station vélo'}), // title: new T({en: 'Bike station', nl: 'Fietsstation', fr: 'Station vélo'}), Old, non-dynamic title
titlePump: new T({en: 'Bike pump', nl: 'Fietspomp', fr: 'TODO: fr'}),
titleRepair: new T({en: 'Bike repair station', nl: 'Herstelpunt', fr: 'TODO: fr'}),
titlePumpAndRepair: new T({
en: 'Bike station (pump & repair)',
nl: 'Herstelpunt met pomp',
fr: 'TODO: fr'
}),
manometer: { manometer: {
question: new T({ question: new T({
en: 'Does the pump have a pressure indicator or manometer?', en: 'Does the pump have a pressure indicator or manometer?',
@ -84,7 +172,11 @@ export default class Translations {
fr: 'Est-ce que la pompe à un manomètre integré?' fr: 'Est-ce que la pompe à un manomètre integré?'
}), }),
yes: new T({en: 'There is a manometer', nl: 'Er is een luchtdrukmeter', fr: 'Il y a un manomètre'}), yes: new T({en: 'There is a manometer', nl: 'Er is een luchtdrukmeter', fr: 'Il y a un manomètre'}),
no: new T({en: 'There is no manometer', nl: 'Er is geen luchtdrukmeter', fr: 'Il n\'y a pas de manomètre'}), no: new T({
en: 'There is no manometer',
nl: 'Er is geen luchtdrukmeter',
fr: 'Il n\'y a pas de manomètre'
}),
broken: new T({ broken: new T({
en: 'There is manometer but it is broken', en: 'There is manometer but it is broken',
nl: 'Er is een luchtdrukmeter maar die is momenteel defect', nl: 'Er is een luchtdrukmeter maar die is momenteel defect',
@ -144,8 +236,8 @@ export default class Translations {
}, },
chain: { chain: {
question: new T({ question: new T({
en: 'Does this bike station have a special tool to repair your bike chain?', en: 'Does this bike repair station have a special tool to repair your bike chain?',
nl: 'Heeft dit fietsstation een speciale reparatieset voor je ketting?', nl: 'Heeft dit herstelpunt een speciale reparatieset voor je ketting?',
fr: 'Est-ce que cette station vélo a un outils specifique pour réparer la chaîne du velo?' fr: 'Est-ce que cette station vélo a un outils specifique pour réparer la chaîne du velo?'
}), }),
yes: new T({ yes: new T({
@ -162,7 +254,7 @@ export default class Translations {
operator: { operator: {
render: new T({ render: new T({
en: 'This bike station is operated by {operator}', en: 'This bike station is operated by {operator}',
nl: 'Dit fietsstation wordt beheerd door {operator}', nl: 'Dit fietspunt wordt beheerd door {operator}',
fr: 'Cette station vélo est opéré par {operator}' fr: 'Cette station vélo est opéré par {operator}'
}), }),
template: new T({en: 'A different operator: $$$', nl: 'Een andere beheerder: $$$', fr: 'TODO: fr'}), template: new T({en: 'A different operator: $$$', nl: 'Een andere beheerder: $$$', fr: 'TODO: fr'}),
@ -180,7 +272,7 @@ export default class Translations {
services: { services: {
question: new T({ question: new T({
en: 'Which services are available at this bike station?', en: 'Which services are available at this bike station?',
nl: 'Welke functies biedt dit fietsstation?', nl: 'Welke functies biedt dit fietspunt?',
fr: 'Quels services sont valables à cette station vélo?' fr: 'Quels services sont valables à cette station vélo?'
}), }),
pump: new T({ pump: new T({
@ -203,7 +295,7 @@ export default class Translations {
stand: { stand: {
question: new T({ question: new T({
en: 'Does this bike station have a hook to suspend your bike with or a stand to elevate it?', en: 'Does this bike station have a hook to suspend your bike with or a stand to elevate it?',
nl: 'Heeft dit fietsstation een haak of standaard om je fiets op te hangen/zetten?', nl: 'Heeft dit herstelpunt een haak of standaard om je fiets op te hangen/zetten?',
fr: 'Est-ce que cette station vélo à un crochet pour suspendre son velo ou une accroche pour l\'élevé?' fr: 'Est-ce que cette station vélo à un crochet pour suspendre son velo ou une accroche pour l\'élevé?'
}), }),
yes: new T({en: 'There is a hook or stand', nl: 'Er is een haak of standaard', fr: 'Oui il y a un crochet ou une accroche'}), yes: new T({en: 'There is a hook or stand', nl: 'Er is een haak of standaard', fr: 'Oui il y a un crochet ou une accroche'}),
@ -211,16 +303,23 @@ export default class Translations {
} }
}, },
shop: { shop: {
name: new T({en: 'bike shop', nl: 'fietswinkel', fr: 'magasin de vélo'}), name: new T({en: 'bike repair/shop', nl: 'fietszaak', fr: 'magasin ou réparateur de vélo'}),
title: new T({en: 'Bike shop', nl: 'Fietszaak', fr: 'Magasin de vélo'}),
titleRepair: new T({en: 'Bike repair', nl: 'Fietsenmaker', fr: 'Réparateur de vélo'}),
titleShop: new T({en: 'Bike repair/shop', nl: 'Fietswinkel', fr: 'Magasin et réparateur de vélo'}),
titleNamed: new T({en: 'Bike repair/shop', nl: 'Fietszaak {name}', fr: 'Magasin de vélo'}),
titleRepairNamed: new T({en: 'Bike shop', nl: 'Fietsenmaker {name}', fr: 'Réparateur de vélo'}),
titleShopNamed: new T({en: 'Bike repair/shop', nl: 'Fietswinkel {name}', fr: 'Magasin et réparateur de vélo'}),
title: new T({en: 'Bike repair/shop', nl: 'Fietszaak', fr: 'Magasin et réparateur de vélo'}),
titleRepair: new T({en: 'Bike repair', nl: 'Fietsenmaker', fr: 'Réparateur de vélo'}),
titleShop: new T({en: 'Bike shop', nl: 'Fietswinkel', fr: 'Magasin de vélo'}),
titleNamed: new T({
en: 'Bike repair/shop {name}',
nl: 'Fietszaak {name}',
fr: 'Magasin et réparateur de vélo {name}'
}),
titleRepairNamed: new T({
en: 'Bike repair {name}',
nl: 'Fietsenmaker {name}',
fr: 'Réparateur de vélo {name}'
}),
titleShopNamed: new T({en: 'Bike shop {name}', nl: 'Fietswinkel {name}', fr: 'Magasin de vélo {name}'}),
retail: { retail: {
@ -229,7 +328,11 @@ export default class Translations {
nl: 'Verkoopt deze winkel fietsen?', nl: 'Verkoopt deze winkel fietsen?',
fr: 'Est-ce que ce magasin vend des vélos?' fr: 'Est-ce que ce magasin vend des vélos?'
}), }),
yes: new T({en: 'This shop sells bikes', nl: 'Deze winkel verkoopt fietsen', fr: 'Ce magasin vend des vélos'}), yes: new T({
en: 'This shop sells bikes',
nl: 'Deze winkel verkoopt fietsen',
fr: 'Ce magasin vend des vélos'
}),
no: new T({ no: new T({
en: 'This shop doesn\'t sell bikes', en: 'This shop doesn\'t sell bikes',
nl: 'Deze winkel verkoopt geen fietsen', nl: 'Deze winkel verkoopt geen fietsen',
@ -310,6 +413,33 @@ export default class Translations {
}), }),
} }
}, },
nonBikeShop: {
name: new T({
en: 'shop that sells/repairs bikes',
nl: 'winkel die fietsen verkoopt/herstelt',
fr: 'TODO: fr'
}),
title: new T({
en: 'Shop that sells/repairs bikes',
nl: 'Winkel die fietsen verkoopt/herstelt',
fr: 'TODO: fr'
}),
titleRepair: new T({en: 'Shop that repairs bikes', nl: 'Winkel die fietsen herstelt', fr: 'TODO: fr'}),
titleShop: new T({en: 'Shop that sells bikes', nl: 'Winkel die fietsen verkoopt', fr: 'TODO: fr'}),
titleNamed: new T({
en: '{name} (sells/repairs bikes)',
nl: '{name} (verkoopt/herstelt fietsen)',
fr: 'TODO: fr'
}),
titleRepairNamed: new T({
en: '{name} (repairs bikes)',
nl: '{name} (herstelt fietsen)',
fr: 'TODO: fr'
}),
titleShopNamed: new T({en: '{name} (sells bikes)', nl: '{name} (verkoopt fietsen)', fr: 'TODO: fr'}),
},
drinking_water: { drinking_water: {
title: new T({ title: new T({
en: 'Drinking water', en: 'Drinking water',
@ -526,6 +656,14 @@ export default class Translations {
phoneNumberIs: new T({ phoneNumberIs: new T({
en: "The phone number of this {category} is <a href='tel:{phone}' target='_blank'>{phone}</a>", en: "The phone number of this {category} is <a href='tel:{phone}' target='_blank'>{phone}</a>",
nl: "Het telefoonnummer van {category} is <a href='tel:{phone}' target='_blank'>{phone}</a>" nl: "Het telefoonnummer van {category} is <a href='tel:{phone}' target='_blank'>{phone}</a>"
}),
websiteOf: new T({
en: "What is the website of {category}?",
nl: "Wat is de website van {category}?"
}),
websiteIs: new T({
en: "Website: <a href='{website}' target='_blank'>{website}</a>",
nl: "Website: <a href='{website}' target='_blank'>{website}</a>"
}) })
}, },
@ -553,8 +691,6 @@ export default class Translations {
embedIntro: new T({ embedIntro: new T({
en: "<h3>Embed on your website</h3>Please, embed this map into your website. We encourage you to do it - you don't even have to ask permission. It is free, and always will be. The more people using this, the more valuable it becomes." en: "<h3>Embed on your website</h3>Please, embed this map into your website. We encourage you to do it - you don't even have to ask permission. It is free, and always will be. The more people using this, the more valuable it becomes."
}) })
} }
} }
} }

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1,164 @@
<svg width="98" height="121" viewBox="0 0 98 121" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M53.0445 111.094C51.2614 114.981 45.7386 114.981 43.9555 111.094L13.2124 44.085C11.6928 40.7729 14.1129 37 17.7569 37L79.2431 37C82.8871 37 85.3072 40.7729 83.7876 44.085L53.0445 111.094Z" fill="#805793"/>
<circle cx="49" cy="49" r="49" fill="#805793"/>
<g filter="url(#filter0_d)">
<ellipse cx="20" cy="32.5" rx="7" ry="5.5" fill="white"/>
</g>
<g filter="url(#filter1_d)">
<ellipse cx="63.5" cy="32.5" rx="7.5" ry="5.5" fill="white"/>
</g>
<g filter="url(#filter2_d)">
<ellipse cx="78" cy="32.5" rx="7" ry="5.5" fill="white"/>
</g>
<g filter="url(#filter3_d)">
<ellipse cx="49" cy="32.5" rx="7" ry="5.5" fill="white"/>
</g>
<g filter="url(#filter4_d)">
<ellipse cx="34.5" cy="32.5" rx="7.5" ry="5.5" fill="white"/>
</g>
<path d="M19.5 24.5L30.3253 31.5H8.67468L19.5 24.5Z" fill="white"/>
<path d="M79 24.5L89.3253 31.5H67.6747L79 24.5Z" fill="white"/>
<rect x="19" y="20" width="60" height="14" fill="white"/>
<rect x="6" y="31" width="85" height="1" fill="#805793"/>
<g filter="url(#filter5_d)">
<rect x="21" y="38" width="4" height="34" fill="white"/>
</g>
<g filter="url(#filter6_d)">
<rect x="74" y="39" width="4" height="34" fill="white"/>
</g>
<g filter="url(#filter7_d)">
<rect x="16" y="72" width="67" height="5" fill="white"/>
</g>
<g filter="url(#filter8_d)">
<path d="M43.1579 63.8659H33.5872L38.8076 52.2202H44.028H47.7983H51.8586M51.8586 52.2202L50.4085 48.9355H52.4386H54.4688M51.8586 52.2202L52.4386 53.7132L53.5987 56.1021L56.789 63.8659M51.8586 52.2202L49.1034 56.6993L47.4502 59.3867M46.3481 61.1784L47.4502 59.3867M40.8377 55.5049L43.7379 62.0742L37.9375 48.9355L39.6776 52.5188M45.4781 62.6714L47.4502 59.3867" stroke="white" stroke-width="2"/>
<path d="M46.0937 63.3578C46.0937 64.25 45.395 64.9481 44.5635 64.9481C43.7321 64.9481 43.0334 64.25 43.0334 63.3578C43.0334 62.4657 43.7321 61.7676 44.5635 61.7676C45.395 61.7676 46.0937 62.4657 46.0937 63.3578Z" stroke="white"/>
<path d="M39.7932 62.7607C39.7932 66.359 36.9675 69.2258 33.5427 69.2258C30.1179 69.2258 27.2921 66.359 27.2921 62.7607C27.2921 59.1623 30.1179 56.2955 33.5427 56.2955C36.9675 56.2955 39.7932 59.1623 39.7932 62.7607Z" stroke="white" stroke-width="2"/>
<ellipse cx="60.279" cy="57.3748" rx="0.210172" ry="0.216394" fill="black" fill-opacity="0.49"/>
</g>
<g filter="url(#filter9_d)">
<path d="M43.1579 63.8659H33.5872L38.8076 52.2202H44.028H47.7983H51.8586M51.8586 52.2202L50.4085 48.9355H52.4386H54.4688M51.8586 52.2202L52.4386 53.7132L53.5987 56.1021L56.789 63.8659M51.8586 52.2202L49.1034 56.6993L47.4502 59.3867M46.3481 61.1784L47.4502 59.3867M40.8377 55.5049L43.7379 62.0742L37.9375 48.9355L39.6776 52.5188M45.4781 62.6714L47.4502 59.3867" stroke="white" stroke-width="2"/>
<path d="M46.0937 63.3578C46.0937 64.25 45.395 64.9481 44.5635 64.9481C43.7321 64.9481 43.0334 64.25 43.0334 63.3578C43.0334 62.4657 43.7321 61.7676 44.5635 61.7676C45.395 61.7676 46.0937 62.4657 46.0937 63.3578Z" stroke="white"/>
<path d="M39.7932 62.7607C39.7932 66.359 36.9675 69.2258 33.5427 69.2258C30.1179 69.2258 27.2921 66.359 27.2921 62.7607C27.2921 59.1623 30.1179 56.2955 33.5427 56.2955C36.9675 56.2955 39.7932 59.1623 39.7932 62.7607Z" stroke="white" stroke-width="2"/>
<ellipse cx="60.279" cy="57.3748" rx="0.210172" ry="0.216394" fill="black" fill-opacity="0.49"/>
</g>
<g filter="url(#filter10_d)">
<circle cx="56.5" cy="63.5" r="6.5" stroke="white" stroke-width="2"/>
</g>
<path d="M63.2749 56.3586C62.6089 56.7271 61.7919 56.2445 61.7916 55.4825L61.7903 51.7748C61.79 51.0004 62.6308 50.5198 63.2971 50.9134L66.5391 52.8283C67.2055 53.2219 67.1923 54.1913 66.5155 54.5658L63.2749 56.3586Z" fill="white"/>
<g filter="url(#filter11_d)">
<rect width="7.82366" height="6.20457" rx="1" transform="matrix(0.490888 -0.871223 0.870592 0.492006 61.4893 51.5931)" fill="white"/>
</g>
<path d="M66.0398 53.2049C62.045 51.8388 64.4607 45.5484 68.7455 48.7409" stroke="#805793" stroke-width="0.75"/>
<path d="M63.0112 49.4193L66.8764 51.3548M63.4944 48.4516L67.5528 50.4839" stroke="#805793" stroke-width="0.75"/>
<circle cx="63.5" cy="54.5" r="0.5" fill="#805793"/>
<defs>
<filter id="filter0_d" x="9" y="27" width="22" height="19" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<filter id="filter1_d" x="52" y="27" width="23" height="19" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<filter id="filter2_d" x="67" y="27" width="22" height="19" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<filter id="filter3_d" x="38" y="27" width="22" height="19" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<filter id="filter4_d" x="23" y="27" width="23" height="19" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<filter id="filter5_d" x="17" y="38" width="12" height="42" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<filter id="filter6_d" x="70" y="39" width="12" height="42" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<filter id="filter7_d" x="12" y="72" width="75" height="13" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<filter id="filter8_d" x="22.2921" y="47.9355" width="42.197" height="30.2904" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<filter id="filter9_d" x="22.2921" y="47.9355" width="42.197" height="30.2904" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<filter id="filter10_d" x="45" y="56" width="23" height="23" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<filter id="filter11_d" x="57.8512" y="45.1395" width="16.5185" height="17.1438" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

View file

@ -956,6 +956,10 @@ form {
font-weight: bold; font-weight: bold;
} }
.question-text img {
max-width: 100%;
}
.question-subtext{ .question-subtext{
font-size: medium; font-size: medium;
font-weight: normal; font-weight: normal;

View file

@ -12,7 +12,7 @@
] ]
}, },
"scripts": { "scripts": {
"start": "parcel *.html UI/** Logic/** assets/**/* vendor/* vendor/*/*", "start": "parcel *.html UI/** Logic/** assets/**/* assets/* vendor/* vendor/*/*",
"generate": "ts-node createLayouts.ts", "generate": "ts-node createLayouts.ts",
"build": "rm -rf dist/ && parcel build --public-url ./ *.html assets/* assets/**/* vendor/* vendor/*/*", "build": "rm -rf dist/ && parcel build --public-url ./ *.html assets/* assets/**/* vendor/* vendor/*/*",
"clean": "./clean.sh", "clean": "./clean.sh",

Binary file not shown.

45
test.ts
View file

@ -1,14 +1,37 @@
import {TabbedComponent} from "./UI/Base/TabbedComponent";
import {FixedUiElement} from "./UI/Base/FixedUiElement"; import { And, Tag, Or } from "./Logic/TagsFilter";
import {Bookcases} from "./Customizations/Layouts/Bookcases"; import { Overpass } from "./Logic/Overpass";
import {ShareScreen} from "./UI/ShareScreen";
import {UIEventSource} from "./UI/UIEventSource";
const layout = new Bookcases(); function anyValueExcept(key: string, exceptValue: string) {
return new And([
new Tag(key, "*"),
new Tag(key, exceptValue, true)
])
}
new ShareScreen(layout, new UIEventSource<{zoom: number, lat: number, lon: number}>({ const sellsBikes = new Tag("service:bicycle:retail", "yes")
zoom: 16, const repairsBikes = anyValueExcept("service:bicycle:repair", "no")
lat: 51.5, const rentsBikes = new Tag("service:bicycle:rental", "yes")
lon:3.2 const hasPump = new Tag("service:bicycle:pump", "yes")
})).AttachTo("maindiv") const hasDiy = new Tag("service:bicycle:diy", "yes")
const sellsSecondHand = anyValueExcept("service:bicycle:repair", "no")
const hasBikeServices = new Or([
sellsBikes,
repairsBikes,
rentsBikes,
hasPump,
hasDiy,
sellsSecondHand
])
const overpassFilter = new And([
new Tag("shop", "bicycle", true),
hasBikeServices
])
const overpass = new Overpass(overpassFilter)
// console.log(overpass.buildQuery('bbox:51.12246976163816,3.1045767593383795,51.289518504257174,3.2848313522338866'))
console.log(overpassFilter.asOverpass())