Merge develop
This commit is contained in:
commit
897c59f97a
35 changed files with 1792 additions and 1172 deletions
|
@ -114,6 +114,7 @@ export default class SelectedFeatureHandler {
|
|||
// Hash has been cleared - we clear the selected element
|
||||
state.selectedElement.setData(undefined);
|
||||
} else {
|
||||
|
||||
// we search the element to select
|
||||
const feature = state.allElements.ContainingFeatures.get(h)
|
||||
if (feature === undefined) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as turf from "@turf/turf";
|
||||
import {TileRange, Tiles} from "../Models/TileRange";
|
||||
import {GeoOperations} from "./GeoOperations";
|
||||
|
||||
export class BBox {
|
||||
|
||||
|
@ -22,7 +23,7 @@ export class BBox {
|
|||
this.minLon = Math.min(this.minLon, coordinate[0]);
|
||||
this.minLat = Math.min(this.minLat, coordinate[1]);
|
||||
}
|
||||
|
||||
|
||||
this.maxLon = Math.min(this.maxLon, 180)
|
||||
this.maxLat = Math.min(this.maxLat, 90)
|
||||
this.minLon = Math.max(this.minLon, -180)
|
||||
|
@ -117,12 +118,12 @@ export class BBox {
|
|||
}
|
||||
|
||||
pad(factor: number, maxIncrease = 2): BBox {
|
||||
|
||||
|
||||
const latDiff = Math.min(maxIncrease / 2, Math.abs(this.maxLat - this.minLat) * factor)
|
||||
const lonDiff =Math.min(maxIncrease / 2, Math.abs(this.maxLon - this.minLon) * factor)
|
||||
const lonDiff = Math.min(maxIncrease / 2, Math.abs(this.maxLon - this.minLon) * factor)
|
||||
return new BBox([[
|
||||
this.minLon - lonDiff,
|
||||
this.minLat - latDiff
|
||||
this.minLat - latDiff
|
||||
], [this.maxLon + lonDiff,
|
||||
this.maxLat + latDiff]])
|
||||
}
|
||||
|
@ -161,4 +162,16 @@ export class BBox {
|
|||
const boundslr = Tiles.tile_bounds_lon_lat(lr.z, lr.x, lr.y)
|
||||
return new BBox([].concat(boundsul, boundslr))
|
||||
}
|
||||
|
||||
toMercator(): { minLat: number, maxLat: number, minLon: number, maxLon: number } {
|
||||
const [minLon, minLat] = GeoOperations.ConvertWgs84To900913([this.minLon, this.minLat])
|
||||
const [maxLon, maxLat] = GeoOperations.ConvertWgs84To900913([this.maxLon, this.maxLat])
|
||||
|
||||
return {
|
||||
minLon, maxLon,
|
||||
minLat, maxLat
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@ export default class DetermineLayout {
|
|||
*/
|
||||
public static async GetLayout(): Promise<[LayoutConfig, string]> {
|
||||
|
||||
|
||||
const loadCustomThemeParam = QueryParameters.GetQueryParameter("userlayout", "false", "If not 'false', a custom (non-official) theme is loaded. This custom layout can be done in multiple ways: \n\n- The hash of the URL contains a base64-encoded .json-file containing the theme definition\n- The hash of the URL contains a lz-compressed .json-file, as generated by the custom theme generator\n- The parameter itself is an URL, in which case that URL will be downloaded. It should point to a .json of a theme")
|
||||
const layoutFromBase64 = decodeURIComponent(loadCustomThemeParam.data);
|
||||
|
||||
|
@ -73,17 +72,13 @@ export default class DetermineLayout {
|
|||
|
||||
try {
|
||||
|
||||
const data = await Utils.downloadJson(link)
|
||||
const parsed = await Utils.downloadJson(link)
|
||||
console.log("Got ", parsed)
|
||||
try {
|
||||
let parsed = data;
|
||||
if (typeof parsed == "string") {
|
||||
parsed = JSON.parse(parsed);
|
||||
}
|
||||
// Overwrite the id to the url
|
||||
parsed.id = link;
|
||||
return new LayoutConfig(parsed, false).patchImages(link, data);
|
||||
return new LayoutConfig(parsed, false).patchImages(link, JSON.stringify(parsed));
|
||||
} catch (e) {
|
||||
|
||||
console.error(e)
|
||||
DetermineLayout.ShowErrorOnCustomTheme(
|
||||
`<a href="${link}">${link}</a> is invalid:`,
|
||||
new FixedUiElement(e)
|
||||
|
@ -92,6 +87,7 @@ export default class DetermineLayout {
|
|||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
DetermineLayout.ShowErrorOnCustomTheme(
|
||||
`<a href="${link}">${link}</a> is invalid - probably not found or invalid JSON:`,
|
||||
new FixedUiElement(e)
|
||||
|
@ -107,7 +103,7 @@ export default class DetermineLayout {
|
|||
try {
|
||||
// layoutFromBase64 contains the name of the theme. This is partly to do tracking with goat counter
|
||||
const dedicatedHashFromLocalStorage = LocalStorageSource.Get(
|
||||
"user-layout-" + userLayoutParam.data.replace(" ", "_")
|
||||
"user-layout-" + userLayoutParam.data?.replace(" ", "_")
|
||||
);
|
||||
if (dedicatedHashFromLocalStorage.data?.length < 10) {
|
||||
dedicatedHashFromLocalStorage.setData(undefined);
|
||||
|
@ -134,6 +130,7 @@ export default class DetermineLayout {
|
|||
try {
|
||||
json = JSON.parse(Utils.UnMinify(LZString.decompressFromBase64(hash)))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
DetermineLayout.ShowErrorOnCustomTheme("Could not decode the hash", new FixedUiElement("Not a valid (LZ-compressed) JSON"))
|
||||
return null;
|
||||
}
|
||||
|
@ -143,6 +140,7 @@ export default class DetermineLayout {
|
|||
userLayoutParam.setData(layoutToUse.id);
|
||||
return [layoutToUse, btoa(Utils.MinifyJSON(JSON.stringify(json)))];
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
if (hash === undefined || hash.length < 10) {
|
||||
DetermineLayout.ShowErrorOnCustomTheme("Could not load a theme from the hash", new FixedUiElement("Hash does not contain data"))
|
||||
}
|
||||
|
|
|
@ -222,7 +222,6 @@ export class ExtraFunction {
|
|||
const maxFeatures = options?.maxFeatures ?? 1
|
||||
const maxDistance = options?.maxDistance ?? 500
|
||||
const uniqueTag: string | undefined = options?.uniqueTag
|
||||
console.log("Requested closestN")
|
||||
if (typeof features === "string") {
|
||||
const name = features
|
||||
const bbox = GeoOperations.bbox(GeoOperations.buffer(GeoOperations.bbox(feature), maxDistance))
|
||||
|
@ -238,7 +237,7 @@ export class ExtraFunction {
|
|||
let closestFeatures: { feat: any, distance: number }[] = [];
|
||||
for (const featureList of features) {
|
||||
for (const otherFeature of featureList) {
|
||||
if (otherFeature === feature || otherFeature.id === feature.id) {
|
||||
if (otherFeature === feature || otherFeature.properties.id === feature.properties.id) {
|
||||
continue; // We ignore self
|
||||
}
|
||||
const distance = GeoOperations.distanceBetween(
|
||||
|
@ -249,6 +248,11 @@ export class ExtraFunction {
|
|||
console.error("Could not calculate the distance between", feature, "and", otherFeature)
|
||||
throw "Undefined distance!"
|
||||
}
|
||||
|
||||
if(distance === 0){
|
||||
console.trace("Got a suspiciously zero distance between", otherFeature, "and self-feature",feature)
|
||||
}
|
||||
|
||||
if (distance > maxDistance) {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ export default class FeaturePipeline {
|
|||
this.osmSourceZoomLevel = state.osmApiTileSize.data;
|
||||
const useOsmApi = state.locationControl.map(l => l.zoom > (state.overpassMaxZoom.data ?? 12))
|
||||
this.relationTracker = new RelationsTracker()
|
||||
|
||||
|
||||
state.changes.allChanges.addCallbackAndRun(allChanges => {
|
||||
allChanges.filter(ch => ch.id < 0 && ch.changes !== undefined)
|
||||
.map(ch => ch.changes)
|
||||
|
@ -203,7 +203,9 @@ export default class FeaturePipeline {
|
|||
neededTiles: neededTilesFromOsm,
|
||||
handleTile: tile => {
|
||||
new RegisteringAllFromFeatureSourceActor(tile)
|
||||
new SaveTileToLocalStorageActor(tile, tile.tileIndex)
|
||||
if (tile.layer.layerDef.maxAgeOfCache > 0) {
|
||||
new SaveTileToLocalStorageActor(tile, tile.tileIndex)
|
||||
}
|
||||
perLayerHierarchy.get(tile.layer.layerDef.id).registerTile(tile)
|
||||
tile.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(tile))
|
||||
|
||||
|
@ -211,7 +213,9 @@ export default class FeaturePipeline {
|
|||
state: state,
|
||||
markTileVisited: (tileId) =>
|
||||
state.filteredLayers.data.forEach(flayer => {
|
||||
SaveTileToLocalStorageActor.MarkVisited(flayer.layerDef.id, tileId, new Date())
|
||||
if (flayer.layerDef.maxAgeOfCache > 0) {
|
||||
SaveTileToLocalStorageActor.MarkVisited(flayer.layerDef.id, tileId, new Date())
|
||||
}
|
||||
self.freshnesses.get(flayer.layerDef.id).addTileLoad(tileId, new Date())
|
||||
})
|
||||
})
|
||||
|
@ -260,7 +264,7 @@ export default class FeaturePipeline {
|
|||
|
||||
|
||||
// Whenever fresh data comes in, we need to update the metatagging
|
||||
self.newDataLoadedSignal.stabilized(1000).addCallback(_ => {
|
||||
self.newDataLoadedSignal.stabilized(250).addCallback(src => {
|
||||
self.updateAllMetaTagging()
|
||||
})
|
||||
|
||||
|
@ -385,7 +389,7 @@ export default class FeaturePipeline {
|
|||
window.setTimeout(
|
||||
() => {
|
||||
const layerDef = src.layer.layerDef;
|
||||
MetaTagging.addMetatags(
|
||||
const somethingChanged = MetaTagging.addMetatags(
|
||||
src.features.data,
|
||||
{
|
||||
memberships: this.relationTracker,
|
||||
|
@ -406,9 +410,10 @@ export default class FeaturePipeline {
|
|||
|
||||
private updateAllMetaTagging() {
|
||||
const self = this;
|
||||
console.debug("Updating the meta tagging of all tiles as new data got loaded")
|
||||
this.perLayerHierarchy.forEach(hierarchy => {
|
||||
hierarchy.loadedTiles.forEach(src => {
|
||||
self.applyMetaTags(src)
|
||||
hierarchy.loadedTiles.forEach(tile => {
|
||||
self.applyMetaTags(tile)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {UIEventSource} from "../../UIEventSource";
|
||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig";
|
||||
import FilteredLayer from "../../../Models/FilteredLayer";
|
||||
import {FeatureSourceForLayer, Tiled} from "../FeatureSource";
|
||||
import Hash from "../../Web/Hash";
|
||||
|
@ -12,6 +11,8 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
|
|||
public readonly layer: FilteredLayer;
|
||||
public readonly tileIndex: number
|
||||
public readonly bbox: BBox
|
||||
private readonly upstream: FeatureSourceForLayer;
|
||||
private readonly state: { locationControl: UIEventSource<{ zoom: number }>; selectedElement: UIEventSource<any> };
|
||||
|
||||
constructor(
|
||||
state: {
|
||||
|
@ -21,70 +22,63 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
|
|||
tileIndex,
|
||||
upstream: FeatureSourceForLayer
|
||||
) {
|
||||
const self = this;
|
||||
this.name = "FilteringFeatureSource(" + upstream.name + ")"
|
||||
this.tileIndex = tileIndex
|
||||
this.bbox = BBox.fromTileIndex(tileIndex)
|
||||
this.upstream = upstream
|
||||
this.state = state
|
||||
|
||||
this.layer = upstream.layer;
|
||||
const layer = upstream.layer;
|
||||
|
||||
function update() {
|
||||
|
||||
const features: { feature: any; freshness: Date }[] = upstream.features.data;
|
||||
const newFeatures = features.filter((f) => {
|
||||
if (
|
||||
state.selectedElement.data?.id === f.feature.id ||
|
||||
f.feature.id === Hash.hash.data) {
|
||||
// This is the selected object - it gets a free pass even if zoom is not sufficient or it is filtered away
|
||||
return true;
|
||||
}
|
||||
|
||||
const isShown = layer.layerDef.isShown;
|
||||
const tags = f.feature.properties;
|
||||
if (isShown.IsKnown(tags)) {
|
||||
const result = layer.layerDef.isShown.GetRenderValue(
|
||||
f.feature.properties
|
||||
).txt;
|
||||
if (result !== "yes") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const tagsFilter = layer.appliedFilters.data;
|
||||
for (const filter of tagsFilter ?? []) {
|
||||
const neededTags = filter.filter.options[filter.selected].osmTags
|
||||
if (!neededTags.matchesProperties(f.feature.properties)) {
|
||||
// Hidden by the filter on the layer itself - we want to hide it no matter wat
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
self.features.setData(newFeatures);
|
||||
}
|
||||
|
||||
|
||||
upstream.features.addCallback(() => {
|
||||
update();
|
||||
this. update();
|
||||
});
|
||||
|
||||
|
||||
layer.appliedFilters.addCallback(_ => {
|
||||
update()
|
||||
this.update()
|
||||
})
|
||||
|
||||
update();
|
||||
this.update();
|
||||
}
|
||||
public update() {
|
||||
|
||||
const layer = this.upstream.layer;
|
||||
const features: { feature: any; freshness: Date }[] = this.upstream.features.data;
|
||||
const newFeatures = features.filter((f) => {
|
||||
if (
|
||||
this.state.selectedElement.data?.id === f.feature.id ||
|
||||
f.feature.id === Hash.hash.data) {
|
||||
// This is the selected object - it gets a free pass even if zoom is not sufficient or it is filtered away
|
||||
return true;
|
||||
}
|
||||
|
||||
const isShown = layer.layerDef.isShown;
|
||||
const tags = f.feature.properties;
|
||||
if (isShown.IsKnown(tags)) {
|
||||
const result = layer.layerDef.isShown.GetRenderValue(
|
||||
f.feature.properties
|
||||
).txt;
|
||||
if (result !== "yes") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const tagsFilter = layer.appliedFilters.data;
|
||||
for (const filter of tagsFilter ?? []) {
|
||||
const neededTags = filter.filter.options[filter.selected].osmTags
|
||||
if (!neededTags.matchesProperties(f.feature.properties)) {
|
||||
// Hidden by the filter on the layer itself - we want to hide it no matter wat
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
this.features.setData(newFeatures);
|
||||
}
|
||||
|
||||
private static showLayer(
|
||||
layer: {
|
||||
isDisplayed: UIEventSource<boolean>;
|
||||
layerDef: LayerConfig;
|
||||
}) {
|
||||
return layer.isDisplayed.data;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import {Utils} from "../../../Utils";
|
|||
import {FeatureSourceForLayer, Tiled} from "../FeatureSource";
|
||||
import {Tiles} from "../../../Models/TileRange";
|
||||
import {BBox} from "../../BBox";
|
||||
import {GeoOperations} from "../../GeoOperations";
|
||||
|
||||
|
||||
export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
|
||||
|
@ -14,7 +15,6 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
|
|||
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>;
|
||||
public readonly name;
|
||||
public readonly isOsmCache: boolean
|
||||
private onFail: ((errorMsg: any, url: string) => void) = undefined;
|
||||
private readonly seenids: Set<string> = new Set<string>()
|
||||
public readonly layer: FilteredLayer;
|
||||
|
||||
|
@ -44,10 +44,20 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
|
|||
let url = flayer.layerDef.source.geojsonSource.replace("{layer}", flayer.layerDef.id);
|
||||
if (zxy !== undefined) {
|
||||
const [z, x, y] = zxy;
|
||||
let tile_bbox = BBox.fromTile(z, x, y)
|
||||
let bounds : { minLat: number, maxLat: number, minLon: number, maxLon: number } = tile_bbox
|
||||
if(this.layer.layerDef.source.mercatorCrs){
|
||||
bounds = tile_bbox.toMercator()
|
||||
}
|
||||
url = url
|
||||
.replace('{z}', "" + z)
|
||||
.replace('{x}', "" + x)
|
||||
.replace('{y}', "" + y)
|
||||
.replace('{y_min}',""+bounds.minLat)
|
||||
.replace('{y_max}',""+bounds.maxLat)
|
||||
.replace('{x_min}',""+bounds.minLon)
|
||||
.replace('{x_max}',""+bounds.maxLon)
|
||||
|
||||
this.tileIndex = Tiles.tile_index(z, x, y)
|
||||
this.bbox = BBox.fromTile(z, x, y)
|
||||
} else {
|
||||
|
@ -71,6 +81,10 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
|
|||
if(json.features === undefined || json.features === null){
|
||||
return;
|
||||
}
|
||||
|
||||
if(self.layer.layerDef.source.mercatorCrs){
|
||||
json = GeoOperations.GeoJsonToWGS84(json)
|
||||
}
|
||||
|
||||
const time = new Date();
|
||||
const newFeatures: { feature: any, freshness: Date } [] = []
|
||||
|
|
|
@ -31,7 +31,6 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
|
|||
// Already handled
|
||||
!seenChanges.has(ch)))
|
||||
.addCallbackAndRunD(changes => {
|
||||
|
||||
if (changes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -20,24 +20,28 @@ export default class DynamicGeoJsonTileSource extends DynamicTileSource {
|
|||
if (source.geojsonSource === undefined) {
|
||||
throw "Invalid layer: geojsonSource expected"
|
||||
}
|
||||
|
||||
const whitelistUrl = source.geojsonSource
|
||||
.replace("{z}", ""+source.geojsonZoomLevel)
|
||||
.replace("{x}_{y}.geojson", "overview.json")
|
||||
.replace("{layer}",layer.layerDef.id)
|
||||
|
||||
|
||||
let whitelist = undefined
|
||||
Utils.downloadJson(whitelistUrl).then(
|
||||
json => {
|
||||
const data = new Map<number, Set<number>>();
|
||||
for (const x in json) {
|
||||
data.set(Number(x), new Set(json[x]))
|
||||
if (source.geojsonSource.indexOf("{x}_{y}.geojson") > 0) {
|
||||
|
||||
const whitelistUrl = source.geojsonSource
|
||||
.replace("{z}", "" + source.geojsonZoomLevel)
|
||||
.replace("{x}_{y}.geojson", "overview.json")
|
||||
.replace("{layer}", layer.layerDef.id)
|
||||
|
||||
Utils.downloadJson(whitelistUrl).then(
|
||||
json => {
|
||||
const data = new Map<number, Set<number>>();
|
||||
for (const x in json) {
|
||||
data.set(Number(x), new Set(json[x]))
|
||||
}
|
||||
console.log("The whitelist is", data, "based on ", json, "from", whitelistUrl)
|
||||
whitelist = data
|
||||
}
|
||||
whitelist = data
|
||||
}
|
||||
).catch(err => {
|
||||
console.warn("No whitelist found for ", layer.layerDef.id, err)
|
||||
})
|
||||
).catch(err => {
|
||||
console.warn("No whitelist found for ", layer.layerDef.id, err)
|
||||
})
|
||||
}
|
||||
|
||||
const seenIds = new Set<string>();
|
||||
const blackList = new UIEventSource(seenIds)
|
||||
|
@ -45,14 +49,14 @@ export default class DynamicGeoJsonTileSource extends DynamicTileSource {
|
|||
layer,
|
||||
source.geojsonZoomLevel,
|
||||
(zxy) => {
|
||||
if(whitelist !== undefined){
|
||||
if (whitelist !== undefined) {
|
||||
const isWhiteListed = whitelist.get(zxy[1])?.has(zxy[2])
|
||||
if(!isWhiteListed){
|
||||
if (!isWhiteListed) {
|
||||
console.log("Not downloading tile", ...zxy, "as it is not on the whitelist")
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const src = new GeoJsonSource(
|
||||
layer,
|
||||
zxy,
|
||||
|
|
|
@ -226,7 +226,7 @@ export class GeoOperations {
|
|||
|
||||
/**
|
||||
* Generates the closest point on a way from a given point
|
||||
*
|
||||
*
|
||||
* The properties object will contain three values:
|
||||
// - `index`: closest point was found on nth line part,
|
||||
// - `dist`: distance between pt and the closest point (in kilometer),
|
||||
|
@ -283,6 +283,34 @@ export class GeoOperations {
|
|||
return headerValuesOrdered.map(v => JSON.stringify(v)).join(",") + "\n" + lines.join("\n")
|
||||
}
|
||||
|
||||
|
||||
private static readonly _earthRadius = 6378137;
|
||||
private static readonly _originShift = 2 * Math.PI * GeoOperations._earthRadius / 2;
|
||||
|
||||
//Converts given lat/lon in WGS84 Datum to XY in Spherical Mercator EPSG:900913
|
||||
public static ConvertWgs84To900913(lonLat: [number, number]): [number, number] {
|
||||
const lon = lonLat[0];
|
||||
const lat = lonLat[1];
|
||||
const x = lon * GeoOperations._originShift / 180;
|
||||
let y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
|
||||
y = y * GeoOperations._originShift / 180;
|
||||
return [x, y];
|
||||
}
|
||||
|
||||
//Converts XY point from (Spherical) Web Mercator EPSG:3785 (unofficially EPSG:900913) to lat/lon in WGS84 Datum
|
||||
public static Convert900913ToWgs84(lonLat: [number, number]): [number, number] {
|
||||
const lon = lonLat[0]
|
||||
const lat = lonLat[1]
|
||||
const x = 180 * lon / GeoOperations._originShift;
|
||||
let y = 180 * lat / GeoOperations._originShift;
|
||||
y = 180 / Math.PI * (2 * Math.atan(Math.exp(y * Math.PI / 180)) - Math.PI / 2);
|
||||
return [x, y];
|
||||
}
|
||||
|
||||
public static GeoJsonToWGS84(geojson){
|
||||
return turf.toWgs84(geojson)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the intersection between two features.
|
||||
* Returns the length if intersecting a linestring and a (multi)polygon (in meters), returns a surface area (in m²) if intersecting two (multi)polygons
|
||||
|
|
|
@ -18,6 +18,8 @@ export default class MetaTagging {
|
|||
/**
|
||||
* This method (re)calculates all metatags and calculated tags on every given object.
|
||||
* The given features should be part of the given layer
|
||||
*
|
||||
* Returns true if at least one feature has changed properties
|
||||
*/
|
||||
public static addMetatags(features: { feature: any; freshness: Date }[],
|
||||
params: ExtraFuncParams,
|
||||
|
@ -25,7 +27,7 @@ export default class MetaTagging {
|
|||
options?: {
|
||||
includeDates?: true | boolean,
|
||||
includeNonDates?: true | boolean
|
||||
}) {
|
||||
}): boolean {
|
||||
|
||||
if (features === undefined || features.length === 0) {
|
||||
return;
|
||||
|
@ -48,6 +50,7 @@ export default class MetaTagging {
|
|||
// The calculated functions - per layer - which add the new keys
|
||||
const layerFuncs = this.createRetaggingFunc(layer)
|
||||
|
||||
let atLeastOneFeatureChanged = false;
|
||||
|
||||
for (let i = 0; i < features.length; i++) {
|
||||
const ff = features[i];
|
||||
|
@ -95,8 +98,10 @@ export default class MetaTagging {
|
|||
|
||||
if (somethingChanged) {
|
||||
State.state?.allElements?.getEventSourceById(feature.properties.id)?.ping()
|
||||
atLeastOneFeatureChanged = true
|
||||
}
|
||||
}
|
||||
return atLeastOneFeatureChanged
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -55,6 +55,8 @@ export interface LayerConfigJson {
|
|||
* source: {geoJson: "https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson", geoJsonZoomLevel: 14}
|
||||
* to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer
|
||||
*
|
||||
* Some API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}
|
||||
* Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this
|
||||
*
|
||||
* Note that both geojson-options might set a flag 'isOsmCache' indicating that the data originally comes from OSM too
|
||||
*
|
||||
|
@ -63,7 +65,7 @@ export interface LayerConfigJson {
|
|||
* While still supported, this is considered deprecated
|
||||
*/
|
||||
source: ({ osmTags: AndOrTagConfigJson | string, overpassScript?: string } |
|
||||
{ osmTags: AndOrTagConfigJson | string, geoJson: string, geoJsonZoomLevel?: number, isOsmCache?: boolean }) & ({
|
||||
{ osmTags: AndOrTagConfigJson | string, geoJson: string, geoJsonZoomLevel?: number, isOsmCache?: boolean, mercatorCrs?: boolean }) & ({
|
||||
/**
|
||||
* The maximum amount of seconds that a tile is allowed to linger in the cache
|
||||
*/
|
||||
|
|
|
@ -89,6 +89,7 @@ export interface TagRenderingConfigJson {
|
|||
* Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes
|
||||
*/
|
||||
mappings?: {
|
||||
|
||||
/**
|
||||
* If this condition is met, then the text under `then` will be shown.
|
||||
* If no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.
|
||||
|
@ -173,5 +174,12 @@ export interface TagRenderingConfigJson {
|
|||
* If this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`
|
||||
*/
|
||||
ifnot?: AndOrTagConfigJson | string
|
||||
|
||||
/**
|
||||
* If chosen as answer, these tags will be applied as well onto the object.
|
||||
* Not compatible with multiAnswer
|
||||
*/
|
||||
addExtraTags: string[]
|
||||
|
||||
}[]
|
||||
}
|
|
@ -96,6 +96,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
geojsonSourceLevel: json.source["geoJsonZoomLevel"],
|
||||
overpassScript: json.source["overpassScript"],
|
||||
isOsmCache: json.source["isOsmCache"],
|
||||
mercatorCrs: json.source["mercatorCrs"]
|
||||
},
|
||||
json.id
|
||||
);
|
||||
|
|
|
@ -270,7 +270,6 @@ export default class LayoutConfig {
|
|||
}
|
||||
rewriting.forEach((value, key) => {
|
||||
console.log("Rewriting", key, "==>", value)
|
||||
|
||||
originalJson = originalJson.replace(new RegExp(key, "g"), value)
|
||||
})
|
||||
return new LayoutConfig(JSON.parse(originalJson), false, "Layout rewriting")
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import {RegexTag} from "../../Logic/Tags/RegexTag";
|
||||
|
||||
export default class SourceConfig {
|
||||
|
||||
|
@ -7,8 +8,10 @@ export default class SourceConfig {
|
|||
public readonly geojsonSource?: string;
|
||||
public readonly geojsonZoomLevel?: number;
|
||||
public readonly isOsmCacheLayer: boolean;
|
||||
public readonly mercatorCrs: boolean;
|
||||
|
||||
constructor(params: {
|
||||
mercatorCrs?: boolean;
|
||||
osmTags?: TagsFilter,
|
||||
overpassScript?: string,
|
||||
geojsonSource?: string,
|
||||
|
@ -33,10 +36,15 @@ export default class SourceConfig {
|
|||
console.error(params)
|
||||
throw `Source said it is a OSM-cached layer, but didn't define the actual source of the cache (in context ${context})`
|
||||
}
|
||||
this.osmTags = params.osmTags;
|
||||
if(params.geojsonSource !== undefined && params.geojsonSourceLevel !== undefined){
|
||||
if(! ["x","y","x_min","x_max","y_min","Y_max"].some(toSearch => params.geojsonSource.indexOf(toSearch) > 0)){
|
||||
throw `Source defines a geojson-zoomLevel, but does not specify {x} nor {y} (or equivalent), this is probably a bug (in context ${context})`
|
||||
}}
|
||||
this.osmTags = params.osmTags ?? new RegexTag("id",/.*/);
|
||||
this.overpassScript = params.overpassScript;
|
||||
this.geojsonSource = params.geojsonSource;
|
||||
this.geojsonZoomLevel = params.geojsonSourceLevel;
|
||||
this.isOsmCacheLayer = params.isOsmCache ?? false;
|
||||
this.mercatorCrs = params.mercatorCrs ?? false;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import {TagUtils} from "../../Logic/Tags/TagUtils";
|
|||
import {And} from "../../Logic/Tags/And";
|
||||
import ValidatedTextField from "../../UI/Input/ValidatedTextField";
|
||||
import {Utils} from "../../Utils";
|
||||
import {Tag} from "../../Logic/Tags/Tag";
|
||||
|
||||
/***
|
||||
* The parsed version of TagRenderingConfigJSON
|
||||
|
@ -37,6 +38,7 @@ export default class TagRenderingConfig {
|
|||
readonly ifnot?: TagsFilter,
|
||||
readonly then: Translation
|
||||
readonly hideInAnswer: boolean | TagsFilter
|
||||
readonly addExtraTags: Tag[]
|
||||
}[]
|
||||
|
||||
constructor(json: string | TagRenderingConfigJson, context?: string) {
|
||||
|
@ -118,21 +120,24 @@ export default class TagRenderingConfig {
|
|||
|
||||
this.mappings = json.mappings.map((mapping, i) => {
|
||||
|
||||
|
||||
const ctx = `${context}.mapping[${i}]`
|
||||
if (mapping.then === undefined) {
|
||||
throw `${context}.mapping[${i}]: Invalid mapping: if without body`
|
||||
throw `${ctx}: Invalid mapping: if without body`
|
||||
}
|
||||
if (mapping.ifnot !== undefined && !this.multiAnswer) {
|
||||
throw `${context}.mapping[${i}]: Invalid mapping: ifnot defined, but the tagrendering is not a multianswer`
|
||||
throw `${ctx}: Invalid mapping: ifnot defined, but the tagrendering is not a multianswer`
|
||||
}
|
||||
|
||||
if (mapping.if === undefined) {
|
||||
throw `${context}.mapping[${i}]: Invalid mapping: "if" is not defined, but the tagrendering is not a multianswer`
|
||||
throw `${ctx}: Invalid mapping: "if" is not defined, but the tagrendering is not a multianswer`
|
||||
}
|
||||
if (typeof mapping.if !== "string" && mapping.if["length"] !== undefined) {
|
||||
throw `${context}.mapping[${i}]: Invalid mapping: "if" is defined as an array. Use {"and": <your conditions>} or {"or": <your conditions>} instead`
|
||||
throw `${ctx}: Invalid mapping: "if" is defined as an array. Use {"and": <your conditions>} or {"or": <your conditions>} instead`
|
||||
}
|
||||
|
||||
if(mapping.addExtraTags !== undefined && this.multiAnswer){
|
||||
throw `${ctx}: Invalid mapping: got a multi-Answer with addExtraTags; this is not allowed`
|
||||
}
|
||||
|
||||
|
||||
let hideInAnswer: boolean | TagsFilter = false;
|
||||
if (typeof mapping.hideInAnswer === "boolean") {
|
||||
|
@ -140,12 +145,12 @@ export default class TagRenderingConfig {
|
|||
} else if (mapping.hideInAnswer !== undefined) {
|
||||
hideInAnswer = TagUtils.Tag(mapping.hideInAnswer, `${context}.mapping[${i}].hideInAnswer`);
|
||||
}
|
||||
const mappingContext = `${context}.mapping[${i}]`
|
||||
const mp = {
|
||||
if: TagUtils.Tag(mapping.if, `${mappingContext}.if`),
|
||||
ifnot: (mapping.ifnot !== undefined ? TagUtils.Tag(mapping.ifnot, `${mappingContext}.ifnot`) : undefined),
|
||||
then: Translations.T(mapping.then, `${mappingContext}.then`),
|
||||
hideInAnswer: hideInAnswer
|
||||
if: TagUtils.Tag(mapping.if, `${ctx}.if`),
|
||||
ifnot: (mapping.ifnot !== undefined ? TagUtils.Tag(mapping.ifnot, `${ctx}.ifnot`) : undefined),
|
||||
then: Translations.T(mapping.then, `${ctx}.then`),
|
||||
hideInAnswer: hideInAnswer,
|
||||
addExtraTags: (mapping.addExtraTags??[]).map((str, j) => TagUtils.SimpleTag(str, `${ctx}.addExtraTags[${j}]`))
|
||||
};
|
||||
if (this.question) {
|
||||
if (hideInAnswer !== true && mp.if !== undefined && !mp.if.isUsableAsAnswer()) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import Img from "./Img";
|
|||
export default class ScrollableFullScreen extends UIElement {
|
||||
private static readonly empty = new FixedUiElement("");
|
||||
private static _currentlyOpen: ScrollableFullScreen;
|
||||
private hashToShow: string;
|
||||
public isShown: UIEventSource<boolean>;
|
||||
private _component: BaseUIElement;
|
||||
private _fullscreencomponent: BaseUIElement;
|
||||
|
@ -28,6 +29,7 @@ export default class ScrollableFullScreen extends UIElement {
|
|||
isShown: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||
) {
|
||||
super();
|
||||
this.hashToShow = hashToShow;
|
||||
this.isShown = isShown;
|
||||
|
||||
if (hashToShow === undefined) {
|
||||
|
@ -45,24 +47,25 @@ export default class ScrollableFullScreen extends UIElement {
|
|||
self.Activate();
|
||||
Hash.hash.setData(hashToShow)
|
||||
} else {
|
||||
ScrollableFullScreen.clear();
|
||||
self.clear();
|
||||
}
|
||||
})
|
||||
|
||||
Hash.hash.addCallback(hash => {
|
||||
if (hash === hashToShow) {
|
||||
return
|
||||
if (!isShown.data) {
|
||||
return;
|
||||
}
|
||||
if (hash === undefined || hash === "") {
|
||||
isShown.setData(false)
|
||||
}
|
||||
isShown.setData(false)
|
||||
})
|
||||
}
|
||||
|
||||
private static clear() {
|
||||
private clear() {
|
||||
ScrollableFullScreen.empty.AttachTo("fullscreen")
|
||||
const fs = document.getElementById("fullscreen");
|
||||
ScrollableFullScreen._currentlyOpen?.isShown?.setData(false);
|
||||
fs.classList.add("hidden")
|
||||
Hash.hash.setData(undefined);
|
||||
}
|
||||
|
||||
InnerRender(): BaseUIElement {
|
||||
|
|
|
@ -21,6 +21,9 @@ export class TabbedComponent extends Combine {
|
|||
let element = elements[i];
|
||||
const header = Translations.W(element.header).onClick(() => openedTabSrc.setData(i))
|
||||
openedTabSrc.addCallbackAndRun(selected => {
|
||||
if(selected >= elements.length){
|
||||
selected = 0
|
||||
}
|
||||
if (selected === i) {
|
||||
header.SetClass("tab-active")
|
||||
header.RemoveClass("tab-non-active")
|
||||
|
|
|
@ -114,10 +114,8 @@ export default class DefaultGUI {
|
|||
Utils.LoadCustomCss(state.layoutToUse.customCss);
|
||||
}
|
||||
|
||||
|
||||
this.SetupUIElements();
|
||||
this.SetupMap()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ export default class FeatureInfoBox extends ScrollableFullScreen {
|
|||
layerConfig.allowMove
|
||||
);
|
||||
})
|
||||
)
|
||||
).SetClass("text-base")
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -122,14 +122,14 @@ export default class FeatureInfoBox extends ScrollableFullScreen {
|
|||
id,
|
||||
layerConfig.deletion
|
||||
))
|
||||
))
|
||||
).SetClass("text-base"))
|
||||
}
|
||||
|
||||
if (layerConfig.allowSplit) {
|
||||
editElements.push(
|
||||
new VariableUiElement(tags.map(tags => tags.id).map(id =>
|
||||
new SplitRoadWizard(id))
|
||||
))
|
||||
).SetClass("text-base"))
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import Lazy from "../Base/Lazy";
|
|||
export default class QuestionBox extends VariableUiElement {
|
||||
|
||||
constructor(tagsSource: UIEventSource<any>, tagRenderings: TagRenderingConfig[], units: Unit[]) {
|
||||
|
||||
const skippedQuestions: UIEventSource<number[]> = new UIEventSource<number[]>([])
|
||||
|
||||
tagRenderings = tagRenderings
|
||||
|
@ -33,7 +34,7 @@ export default class QuestionBox extends VariableUiElement {
|
|||
{
|
||||
units: units,
|
||||
afterSave: () => {
|
||||
// We save
|
||||
// We save and indicate progress by pinging and recalculating
|
||||
skippedQuestions.ping();
|
||||
},
|
||||
cancelButton: Translations.t.general.skip.Clone()
|
||||
|
@ -45,7 +46,7 @@ export default class QuestionBox extends VariableUiElement {
|
|||
}
|
||||
)));
|
||||
|
||||
const skippedQuestionsButton = Translations.t.general.skippedQuestions.Clone()
|
||||
const skippedQuestionsButton = Translations.t.general.skippedQuestions
|
||||
.onClick(() => {
|
||||
skippedQuestions.setData([]);
|
||||
})
|
||||
|
|
|
@ -48,7 +48,7 @@ export default class TagRenderingQuestion extends Combine {
|
|||
|
||||
const applicableMappingsSrc =
|
||||
UIEventSource.ListStabilized(tags.map(tags => {
|
||||
const applicableMappings: { if: TagsFilter, then: any, ifnot?: TagsFilter }[] = []
|
||||
const applicableMappings: { if: TagsFilter, then: any, ifnot?: TagsFilter, addExtraTags: Tag[] }[] = []
|
||||
for (const mapping of configuration.mappings ?? []) {
|
||||
if (mapping.hideInAnswer === true) {
|
||||
continue
|
||||
|
@ -107,9 +107,9 @@ export default class TagRenderingQuestion extends Combine {
|
|||
|
||||
const saveButton = new Combine([
|
||||
options.saveButtonConstr(inputElement.GetValue()),
|
||||
new Toggle(Translations.t.general.testing, undefined, State.state.featureSwitchIsTesting).SetClass("alert")
|
||||
new Toggle(Translations.t.general.testing.SetClass("alert"), undefined, State.state.featureSwitchIsTesting)
|
||||
])
|
||||
|
||||
|
||||
let bottomTags: BaseUIElement;
|
||||
if (options.bottomText !== undefined) {
|
||||
bottomTags = options.bottomText(inputElement.GetValue())
|
||||
|
@ -146,7 +146,7 @@ export default class TagRenderingQuestion extends Combine {
|
|||
|
||||
|
||||
private static GenerateInputElement(configuration: TagRenderingConfig,
|
||||
applicableMappings: { if: TagsFilter, then: any, ifnot?: TagsFilter }[],
|
||||
applicableMappings: { if: TagsFilter, then: any, ifnot?: TagsFilter, addExtraTags: Tag[] }[],
|
||||
applicableUnit: Unit,
|
||||
tagsSource: UIEventSource<any>)
|
||||
: InputElement<TagsFilter> {
|
||||
|
@ -340,12 +340,16 @@ export default class TagRenderingQuestion extends Combine {
|
|||
mapping: {
|
||||
if: TagsFilter,
|
||||
then: Translation,
|
||||
addExtraTags: Tag[]
|
||||
}, ifNot?: TagsFilter[]): InputElement<TagsFilter> {
|
||||
|
||||
let tagging: TagsFilter = mapping.if;
|
||||
if (ifNot !== undefined) {
|
||||
tagging = new And([mapping.if, ...ifNot])
|
||||
}
|
||||
if (mapping.addExtraTags) {
|
||||
tagging = new And([tagging, ...mapping.addExtraTags])
|
||||
}
|
||||
|
||||
return new FixedInputElement(
|
||||
new SubstitutedTranslation(mapping.then, tagsSource),
|
||||
|
|
|
@ -281,7 +281,6 @@ export default class ShowDataLayer {
|
|||
|
||||
infobox.isShown.addCallback(isShown => {
|
||||
if (!isShown) {
|
||||
this._selectedElement?.setData(undefined);
|
||||
leafletLayer.closePopup()
|
||||
}
|
||||
});
|
||||
|
@ -293,7 +292,7 @@ export default class ShowDataLayer {
|
|||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Add the feature to the index to open the popup when needed
|
||||
this.leafletLayersPerId.set(feature.properties.id + feature.geometry.type, {
|
||||
|
|
|
@ -508,7 +508,7 @@ There are also some technicalities in your theme to keep in mind:
|
|||
return new Combine([new FixedUiElement("The import button is disabled for unofficial themes to prevent accidents.").SetClass("alert"),
|
||||
new FixedUiElement("To test, add 'test=true' to the URL. The changeset will be printed in the console. Please open a PR to officialize this theme to actually enable the import button.")])
|
||||
}
|
||||
const tgsSpec = args[0].split(",").map(spec => {
|
||||
const tgsSpec = args[0].split(";").map(spec => {
|
||||
const kv = spec.split("=").map(s => s.trim());
|
||||
if (kv.length != 2) {
|
||||
throw "Invalid key spec: multiple '=' found in " + spec
|
||||
|
|
|
@ -32,7 +32,8 @@
|
|||
"#": "Allowed vehicle types",
|
||||
"question": {
|
||||
"en": "Which vehicles are allowed to charge here?",
|
||||
"nl": "Welke voertuigen kunnen hier opgeladen worden?"
|
||||
"nl": "Welke voertuigen kunnen hier opgeladen worden?",
|
||||
"de": "Welche Fahrzeuge dürfen hier geladen werden?"
|
||||
},
|
||||
"multiAnswer": true,
|
||||
"mappings": [
|
||||
|
@ -40,8 +41,9 @@
|
|||
"if": "bicycle=yes",
|
||||
"ifnot": "bicycle=no",
|
||||
"then": {
|
||||
"en": "<b>Bcycles</b> can be charged here",
|
||||
"nl": "<b>Fietsen</b> kunnen hier opgeladen worden"
|
||||
"en": "<b>bicycles</b> can be charged here",
|
||||
"nl": "<b>Fietsen</b> kunnen hier opgeladen worden",
|
||||
"de": "<b>Fahrräder</b> können hier geladen werden"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -49,7 +51,8 @@
|
|||
"ifnot": "motorcar=no",
|
||||
"then": {
|
||||
"en": "<b>Cars</b> can be charged here",
|
||||
"nl": "<b>Elektrische auto's</b> kunnen hier opgeladen worden"
|
||||
"nl": "<b>Elektrische auto's</b> kunnen hier opgeladen worden",
|
||||
"de": "<b>Autos</b> können hier geladen werden"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -57,7 +60,8 @@
|
|||
"ifnot": "scooter=no",
|
||||
"then": {
|
||||
"en": "<b>Scooters</b> can be charged here",
|
||||
"nl": "<b>Electrische scooters</b> (snorfiets of bromfiets) kunnen hier opgeladen worden"
|
||||
"nl": "<b>Electrische scooters</b> (snorfiets of bromfiets) kunnen hier opgeladen worden",
|
||||
"de": "<b> Roller</b> können hier geladen werden"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -65,7 +69,8 @@
|
|||
"ifnot": "hgv=no",
|
||||
"then": {
|
||||
"en": "<b>Heavy good vehicles</b> (such as trucks) can be charged here",
|
||||
"nl": "<b>Vrachtwagens</b> kunnen hier opgeladen worden"
|
||||
"nl": "<b>Vrachtwagens</b> kunnen hier opgeladen worden",
|
||||
"de": "<b>Lastkraftwagen</b> (LKW) können hier geladen werden"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -73,7 +78,8 @@
|
|||
"ifnot": "bus=no",
|
||||
"then": {
|
||||
"en": "<b>Buses</b> can be charged here",
|
||||
"nl": "<b>Bussen</b> kunnen hier opgeladen worden"
|
||||
"nl": "<b>Bussen</b> kunnen hier opgeladen worden",
|
||||
"de": "<b>Busse</b> können hier geladen werden"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -82,11 +88,13 @@
|
|||
"id": "access",
|
||||
"question": {
|
||||
"en": "Who is allowed to use this charging station?",
|
||||
"nl": "Wie mag er dit oplaadpunt gebruiken?"
|
||||
"nl": "Wie mag er dit oplaadpunt gebruiken?",
|
||||
"de": "Wer darf diese Ladestation benutzen?"
|
||||
},
|
||||
"render": {
|
||||
"en": "Access is {access}",
|
||||
"nl": "Toegang voor {access}"
|
||||
"nl": "Toegang voor {access}",
|
||||
"de": "Zugang ist {access}"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "access",
|
||||
|
@ -119,14 +127,14 @@
|
|||
"if": "access=customers",
|
||||
"then": {
|
||||
"en": "Only customers of the place this station belongs to can use this charging station<br/><span class='subtle'>E.g. a charging station operated by hotel which is only usable by their guests</span>",
|
||||
"nl": "Enkel <b>klanten van de bijhorende plaats</b> mogen dit oplaadpunt gebruiken<br/><span class='subtle'>Bv. op de parking van een hotel en enkel toegankelijk voor klanten van dit hotel</span>"
|
||||
"nl": "Enkel <b>klanten van de bijhorende plaats</b> mogen dit oplaadpunt gebruiken<br/><span class='subtle'>Bijvoorbeeld een oplaadpunt op de parking van een restaurant dat enkel door klanten van het restaurant gebruikt mag worden</span>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "access=private",
|
||||
"then": {
|
||||
"en": "Not accessible to the general public (e.g. only accessible to the owners, employees, ...)",
|
||||
"nl": "Niet toegankelijk voor het publiek <br/><span class='subtle'>Bv. enkel toegankelijk voor de eigenaar, medewerkers ,...</span> "
|
||||
"nl": "Niet toegankelijk voor het publiek <span class='subtle'>Enkel toegankelijk voor de eigenaar, medewerkers ,...</span> "
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -135,11 +143,13 @@
|
|||
"id": "capacity",
|
||||
"render": {
|
||||
"en": "{capacity} vehicles can be charged here at the same time",
|
||||
"nl": "{capacity} voertuigen kunnen hier op hetzelfde moment opgeladen worden"
|
||||
"nl": "{capacity} voertuigen kunnen hier op hetzelfde moment opgeladen worden",
|
||||
"de": "{capacity} Fahrzeuge können hier gleichzeitig geladen werden"
|
||||
},
|
||||
"question": {
|
||||
"en": "How much vehicles can be charged here at the same time?",
|
||||
"nl": "Hoeveel voertuigen kunnen hier opgeladen worden?"
|
||||
"nl": "Hoeveel voertuigen kunnen hier opgeladen worden?",
|
||||
"de": "Wie viele Fahrzeuge können hier gleichzeitig geladen werden?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "capacity",
|
||||
|
@ -149,8 +159,9 @@
|
|||
{
|
||||
"id": "Available_charging_stations (generated)",
|
||||
"question": {
|
||||
"en": "Which charging connections are available here?",
|
||||
"nl": "Welke aansluitingen zijn hier beschikbaar?"
|
||||
"en": "Which charging stations are available here?",
|
||||
"nl": "Welke aansluitingen zijn hier beschikbaar?",
|
||||
"de": "Welche Ladestationen gibt es hier?"
|
||||
},
|
||||
"multiAnswer": true,
|
||||
"mappings": [
|
||||
|
@ -251,7 +262,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Chademo_type4.svg'/> <span><b>Chademo</b></span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Chademo_type4.svg'/> <span><b>Chademo</b></span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Chademo_type4.svg'/> <span><b>Chademo</b></span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Chademo_type4.svg'/> <span><b>Chademo</b></span></div>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -260,7 +272,8 @@
|
|||
"ifnot": "socket:type1_cable=",
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Type 1 with cable</b> (J1772)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Type 1 met kabel</b> (J1772)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Type 1 met kabel</b> (J1772)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Typ 1 mit Kabel</b> (J1772)</span></div>"
|
||||
},
|
||||
"hideInAnswer": {
|
||||
"or": [
|
||||
|
@ -298,7 +311,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Type 1 with cable</b> (J1772)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Type 1 met kabel</b> (J1772)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Type 1 met kabel</b> (J1772)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Typ 1 mit Kabel</b> (J1772)</span></div>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -307,7 +321,8 @@
|
|||
"ifnot": "socket:type1=",
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Type 1 <i>without</i> cable</b> (J1772)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Type 1 <i>zonder</i> kabel</b> (J1772)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Type 1 <i>zonder</i> kabel</b> (J1772)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Typ 1 <i>ohne</i> Kabel</b> (J1772)</span></div>"
|
||||
},
|
||||
"hideInAnswer": {
|
||||
"or": [
|
||||
|
@ -345,7 +360,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Type 1 <i>without</i> cable</b> (J1772)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Type 1 <i>zonder</i> kabel</b> (J1772)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Type 1 <i>zonder</i> kabel</b> (J1772)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1_J1772.svg'/> <span><b>Typ 1 <i>ohne</i> Kabel</b> (J1772)</span></div>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -354,7 +370,8 @@
|
|||
"ifnot": "socket:type1_combo=",
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1-ccs.svg'/> <span><b>Type 1 CCS</b> (aka Type 1 Combo)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1-ccs.svg'/> <span><b>Type 1 CCS</b> (ook gekend als Type 1 Combo)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1-ccs.svg'/> <span><b>Type 1 CCS</b> (ook gekend als Type 1 Combo)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1-ccs.svg'/> <span><b>Typ 1 CCS</b> (auch bekannt als Typ 1 Combo)</span></div>"
|
||||
},
|
||||
"hideInAnswer": {
|
||||
"or": [
|
||||
|
@ -392,7 +409,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1-ccs.svg'/> <span><b>Type 1 CCS</b> (aka Type 1 Combo)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1-ccs.svg'/> <span><b>Type 1 CCS</b> (ook gekend als Type 1 Combo)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1-ccs.svg'/> <span><b>Type 1 CCS</b> (ook gekend als Type 1 Combo)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type1-ccs.svg'/> <span><b>Typ 1 CCS</b> (auch bekannt als Typ 1 Combo)</span></div>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -401,7 +419,8 @@
|
|||
"ifnot": "socket:tesla_supercharger=",
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/> <span><b>Tesla Supercharger</b></span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/> <span><b>Tesla Supercharger</b></span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/> <span><b>Tesla Supercharger</b></span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/> <span><b>Tesla Supercharger</b></span></div>"
|
||||
},
|
||||
"hideInAnswer": {
|
||||
"or": [
|
||||
|
@ -439,7 +458,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/> <span><b>Tesla Supercharger</b></span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/> <span><b>Tesla Supercharger</b></span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/> <span><b>Tesla Supercharger</b></span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/> <span><b>Tesla Supercharger</b></span></div>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -448,7 +468,8 @@
|
|||
"ifnot": "socket:type2=",
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_socket.svg'/> <span><b>Type 2</b> (mennekes)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_socket.svg'/> <span><b>Type 2</b> (mennekes)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_socket.svg'/> <span><b>Type 2</b> (mennekes)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_socket.svg'/> <span><b>Typ 2</b> (Mennekes)</span></div>"
|
||||
},
|
||||
"hideInAnswer": {
|
||||
"or": [
|
||||
|
@ -486,7 +507,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_socket.svg'/> <span><b>Type 2</b> (mennekes)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_socket.svg'/> <span><b>Type 2</b> (mennekes)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_socket.svg'/> <span><b>Type 2</b> (mennekes)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_socket.svg'/> <span><b>Typ 2</b> (Mennekes)</span></div>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -495,7 +517,8 @@
|
|||
"ifnot": "socket:type2_combo=",
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Type 2 CCS</b> (mennekes)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Type 2 CCS</b> (mennekes)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Type 2 CCS</b> (mennekes)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Typ 2 CCS</b> (Mennekes)</span></div>"
|
||||
},
|
||||
"hideInAnswer": {
|
||||
"or": [
|
||||
|
@ -533,7 +556,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Type 2 CCS</b> (mennekes)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Type 2 CCS</b> (mennekes)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Type 2 CCS</b> (mennekes)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Typ 2 CCS</b> (Mennekes)</span></div>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -542,7 +566,8 @@
|
|||
"ifnot": "socket:type2_cable=",
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_tethered.svg'/> <span><b>Type 2 with cable</b> (mennekes)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_tethered.svg'/> <span><b>Type 2 met kabel</b> (J1772)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_tethered.svg'/> <span><b>Type 2 met kabel</b> (J1772)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_tethered.svg'/> <span><b>Typ 2 mit Kabel</b> (Mennekes)</span></div>"
|
||||
},
|
||||
"hideInAnswer": {
|
||||
"or": [
|
||||
|
@ -580,7 +605,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_tethered.svg'/> <span><b>Type 2 with cable</b> (mennekes)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_tethered.svg'/> <span><b>Type 2 met kabel</b> (J1772)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_tethered.svg'/> <span><b>Type 2 met kabel</b> (J1772)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_tethered.svg'/> <span><b>Typ 2 mit Kabel</b> (Mennekes)</span></div>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -589,7 +615,8 @@
|
|||
"ifnot": "socket:tesla_supercharger_ccs=",
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Tesla Supercharger CCS</b> (a branded type2_css)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Tesla Supercharger CCS</b> (Typ 2 CSS)</span></div>"
|
||||
},
|
||||
"hideInAnswer": {
|
||||
"or": [
|
||||
|
@ -627,7 +654,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Tesla Supercharger CCS</b> (a branded type2_css)</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/Type2_CCS.svg'/> <span><b>Tesla Supercharger CCS</b> (Typ 2 CSS)</span></div>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -740,7 +768,8 @@
|
|||
"ifnot": "socket:USB-A=",
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/usb_port.svg'/> <span><b>USB</b> to charge phones and small electronics</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/usb_port.svg'/> <span><b>USB</b> om GSMs en kleine electronica op te laden</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/usb_port.svg'/> <span><b>USB</b> om GSMs en kleine electronica op te laden</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/usb_port.svg'/> <span><b>USB</b> zum Laden von Smartphones oder Elektrokleingeräten</span></div>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -752,7 +781,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/usb_port.svg'/> <span><b>USB</b> to charge phones and small electronics</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/usb_port.svg'/> <span><b>USB</b> om GSMs en kleine electronica op te laden</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/usb_port.svg'/> <span><b>USB</b> om GSMs en kleine electronica op te laden</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/usb_port.svg'/> <span><b>USB</b> zum Laden von Smartphones und Elektrokleingeräten</span></div>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -804,7 +834,8 @@
|
|||
"ifnot": "socket:bosch_5pin=",
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/bosch-5pin.svg'/> <span><b>Bosch Active Connect with 5 pins</b> and cable</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/bosch-5pin.svg'/> <span><b>Bosch Active Connect met 5 pinnen</b> aan een kabel</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/bosch-5pin.svg'/> <span><b>Bosch Active Connect met 5 pinnen</b> aan een kabel</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/bosch-5pin.svg'/> <span><b>Bosch Active Connect mit 5 Pins</b> und Kabel</span></div>"
|
||||
},
|
||||
"hideInAnswer": {
|
||||
"or": [
|
||||
|
@ -838,7 +869,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/bosch-5pin.svg'/> <span><b>Bosch Active Connect with 5 pins</b> and cable</span></div>",
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/bosch-5pin.svg'/> <span><b>Bosch Active Connect met 5 pinnen</b> aan een kabel</span></div>"
|
||||
"nl": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/bosch-5pin.svg'/> <span><b>Bosch Active Connect met 5 pinnen</b> aan een kabel</span></div>",
|
||||
"de": "<div class='flex'><img class='w-12 mx-4' src='./assets/layers/charging_station/bosch-5pin.svg'/> <span><b>Bosch Active Connect mit 5 Pins</b> und Kabel</span></div>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
}
|
||||
|
@ -1189,14 +1221,21 @@
|
|||
},
|
||||
"question": {
|
||||
"en": "When is this charging station opened?",
|
||||
"nl": "Wanneer is dit oplaadpunt beschikbaar??"
|
||||
"nl": "Wanneer is dit oplaadpunt beschikbaar??",
|
||||
"de": "Wann ist diese Ladestation geöffnet?",
|
||||
"it": "Quali sono gli orari di apertura di questa stazione di ricarica?",
|
||||
"ja": "この充電ステーションはいつオープンしますか?",
|
||||
"nb_NO": "Når åpnet denne ladestasjonen?",
|
||||
"ru": "В какое время работает эта зарядная станция?",
|
||||
"zh_Hant": "何時是充電站開放使用的時間?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "opening_hours=24/7",
|
||||
"then": {
|
||||
"en": "24/7 opened (including holidays)",
|
||||
"nl": "24/7 open - ook tijdens vakanties"
|
||||
"nl": "24/7 open - ook tijdens vakanties",
|
||||
"de": "durchgehend geöffnet (auch an Feiertagen)"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1305,7 +1344,8 @@
|
|||
"ifnot": "payment:app=no",
|
||||
"then": {
|
||||
"en": "Payment is done using a dedicated app",
|
||||
"nl": "Betalen via een app van het netwerk"
|
||||
"nl": "Betalen via een app van het netwerk",
|
||||
"de": "Bezahlung mit einer speziellen App"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1313,7 +1353,8 @@
|
|||
"ifnot": "payment:membership_card=no",
|
||||
"then": {
|
||||
"en": "Payment is done using a membership card",
|
||||
"nl": "Betalen via een lidkaart van het netwerk"
|
||||
"nl": "Betalen via een lidkaart van het netwerk",
|
||||
"de": "Bezahlung mit einer Mitgliedskarte"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1324,7 +1365,8 @@
|
|||
"#": "In some cases, charging is free but one has to be authenticated. We only ask for authentication if fee is no (or unset). By default one sees the questions for either the payment options or the authentication options, but normally not both",
|
||||
"question": {
|
||||
"en": "What kind of authentication is available at the charging station?",
|
||||
"nl": "Hoe kan men zich aanmelden aan dit oplaadstation?"
|
||||
"nl": "Hoe kan men zich aanmelden aan dit oplaadstation?",
|
||||
"de": "Welche Authentifizierung ist an der Ladestation möglich?"
|
||||
},
|
||||
"multiAnswer": true,
|
||||
"mappings": [
|
||||
|
@ -1333,7 +1375,8 @@
|
|||
"ifnot": "authentication:membership_card=no",
|
||||
"then": {
|
||||
"en": "Authentication by a membership card",
|
||||
"nl": "Aanmelden met een lidkaart is mogelijk"
|
||||
"nl": "Aanmelden met een lidkaart is mogelijk",
|
||||
"de": "Authentifizierung durch eine Mitgliedskarte"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1341,7 +1384,8 @@
|
|||
"ifnot": "authentication:app=no",
|
||||
"then": {
|
||||
"en": "Authentication by an app",
|
||||
"nl": "Aanmelden via een applicatie is mogelijk"
|
||||
"nl": "Aanmelden via een applicatie is mogelijk",
|
||||
"de": "Authentifizierung durch eine App"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1349,15 +1393,17 @@
|
|||
"ifnot": "authentication:phone_call=no",
|
||||
"then": {
|
||||
"en": "Authentication via phone call is available",
|
||||
"nl": "Aanmelden door te bellen naar een telefoonnummer is mogelijk"
|
||||
"nl": "Aanmelden door te bellen naar een telefoonnummer is mogelijk",
|
||||
"de": "Authentifizierung per Anruf ist möglich"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "authentication:short_message=yes",
|
||||
"ifnot": "authentication:short_message=no",
|
||||
"then": {
|
||||
"en": "Authentication via SMS is available",
|
||||
"nl": "Aanmelden via SMS is mogelijk"
|
||||
"en": "Authentication via phone call is available",
|
||||
"nl": "Aanmelden via SMS is mogelijk",
|
||||
"de": "Authentifizierung per Anruf ist möglich"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1365,7 +1411,8 @@
|
|||
"ifnot": "authentication:nfc=no",
|
||||
"then": {
|
||||
"en": "Authentication via NFC is available",
|
||||
"nl": "Aanmelden via NFC is mogelijk"
|
||||
"nl": "Aanmelden via NFC is mogelijk",
|
||||
"de": "Authentifizierung über NFC ist möglich"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1373,7 +1420,8 @@
|
|||
"ifnot": "authentication:money_card=no",
|
||||
"then": {
|
||||
"en": "Authentication via Money Card is available",
|
||||
"nl": "Aanmelden met Money Card is mogelijk"
|
||||
"nl": "Aanmelden met Money Card is mogelijk",
|
||||
"de": "Authentifizierung über Geldkarte ist möglich"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1381,7 +1429,8 @@
|
|||
"ifnot": "authentication:debit_card=no",
|
||||
"then": {
|
||||
"en": "Authentication via debit card is available",
|
||||
"nl": "Aanmelden met een betaalkaart is mogelijk"
|
||||
"nl": "Aanmelden met een betaalkaart is mogelijk",
|
||||
"de": "Authentifizierung per Debitkarte ist möglich"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1389,7 +1438,8 @@
|
|||
"ifnot": "authentication:none=no",
|
||||
"then": {
|
||||
"en": "Charging here is (also) possible without authentication",
|
||||
"nl": "Hier opladen is (ook) mogelijk zonder aan te melden"
|
||||
"nl": "Hier opladen is (ook) mogelijk zonder aan te melden",
|
||||
"de": "Das Aufladen ist hier (auch) ohne Authentifizierung möglich"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -1404,11 +1454,13 @@
|
|||
"id": "Auth phone",
|
||||
"render": {
|
||||
"en": "Authenticate by calling or SMS'ing to <a href='tel:{authentication:phone_call:number}'>{authentication:phone_call:number}</a>",
|
||||
"nl": "Aanmelden door te bellen of te SMS'en naar <a href='tel:{authentication:phone_call:number}'>{authentication:phone_call:number}</a>"
|
||||
"nl": "Aanmelden door te bellen of te SMS'en naar <a href='tel:{authentication:phone_call:number}'>{authentication:phone_call:number}</a>",
|
||||
"de": "Authentifizierung durch Anruf oder SMS an <a href='tel:{authentication:phone_call:number}'>{authentication:phone_call:number}</a>"
|
||||
},
|
||||
"question": {
|
||||
"en": "What's the phone number for authentication call or SMS?",
|
||||
"nl": "Wat is het telefoonnummer dat men moet bellen of SMS'en om zich aan te melden?"
|
||||
"nl": "Wat is het telefoonnummer dat men moet bellen of SMS'en om zich aan te melden?",
|
||||
"de": "Wie lautet die Telefonnummer für den Authentifizierungsanruf oder die SMS?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "authentication:phone_call:number",
|
||||
|
@ -1425,21 +1477,24 @@
|
|||
"id": "maxstay",
|
||||
"question": {
|
||||
"en": "What is the maximum amount of time one is allowed to stay here?",
|
||||
"nl": "Hoelang mag een voertuig hier blijven staan?"
|
||||
"nl": "Hoelang mag een voertuig hier blijven staan?",
|
||||
"de": "Was ist die Höchstdauer des Aufenthalts hier?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "maxstay"
|
||||
},
|
||||
"render": {
|
||||
"en": "One can stay at most <b>{canonical(maxstay)}</b>",
|
||||
"nl": "De maximale parkeertijd hier is <b>{canonical(maxstay)}</b>"
|
||||
"nl": "De maximale parkeertijd hier is <b>{canonical(maxstay)}</b>",
|
||||
"de": "Die maximale Parkzeit beträgt <b>{canonical(maxstay)}</b>"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "maxstay=unlimited",
|
||||
"then": {
|
||||
"en": "No timelimit on leaving your vehicle here",
|
||||
"nl": "Geen maximum parkeertijd"
|
||||
"nl": "Geen maximum parkeertijd",
|
||||
"de": "Keine Höchstparkdauer"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -1456,11 +1511,22 @@
|
|||
"id": "Network",
|
||||
"render": {
|
||||
"en": "Part of the network <b>{network}</b>",
|
||||
"nl": "Maakt deel uit van het <b>{network}</b>-netwerk"
|
||||
"nl": "Maakt deel uit van het <b>{network}</b>-netwerk",
|
||||
"de": "Teil des Netzwerks <b>{network}</b>",
|
||||
"it": "{network}",
|
||||
"ja": "{network}",
|
||||
"nb_NO": "{network}",
|
||||
"ru": "{network}",
|
||||
"zh_Hant": "{network}"
|
||||
},
|
||||
"question": {
|
||||
"en": "Is this charging station part of a network?",
|
||||
"nl": "Is dit oplaadpunt deel van een groter netwerk?"
|
||||
"nl": "Is dit oplaadpunt deel van een groter netwerk?",
|
||||
"de": "Ist diese Ladestation Teil eines Netzwerks?",
|
||||
"it": "A quale rete appartiene questa stazione di ricarica?",
|
||||
"ja": "この充電ステーションの運営チェーンはどこですか?",
|
||||
"ru": "К какой сети относится эта станция?",
|
||||
"zh_Hant": "充電站所屬的網路是?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "network"
|
||||
|
@ -1470,14 +1536,16 @@
|
|||
"if": "no:network=yes",
|
||||
"then": {
|
||||
"en": "Not part of a bigger network",
|
||||
"nl": "Maakt geen deel uit van een groter netwerk"
|
||||
"nl": "Maakt geen deel uit van een groter netwerk",
|
||||
"de": "Nicht Teil eines größeren Netzwerks"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "network=none",
|
||||
"then": {
|
||||
"en": "Not part of a bigger network",
|
||||
"nl": "Maakt geen deel uit van een groter netwerk"
|
||||
"nl": "Maakt geen deel uit van een groter netwerk",
|
||||
"de": "Nicht Teil eines größeren Netzwerks"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -1499,11 +1567,13 @@
|
|||
"id": "Operator",
|
||||
"question": {
|
||||
"en": "Who is the operator of this charging station?",
|
||||
"nl": "Wie beheert dit oplaadpunt?"
|
||||
"nl": "Wie beheert dit oplaadpunt?",
|
||||
"de": "Wer ist der Betreiber dieser Ladestation?"
|
||||
},
|
||||
"render": {
|
||||
"en": "This charging station is operated by {operator}",
|
||||
"nl": "Wordt beheerd door {operator}"
|
||||
"nl": "Wordt beheerd door {operator}",
|
||||
"de": "Diese Ladestation wird betrieben von {operator}"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "operator"
|
||||
|
@ -1517,7 +1587,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "Actually, {operator} is the network",
|
||||
"nl": "Eigenlijk is {operator} het netwerk waarvan het deel uitmaakt"
|
||||
"nl": "Eigenlijk is {operator} het netwerk waarvan het deel uitmaakt",
|
||||
"de": "Eigentlich ist {operator} das Netzwerk"
|
||||
},
|
||||
"addExtraTags": [
|
||||
"operator="
|
||||
|
@ -1530,11 +1601,13 @@
|
|||
"id": "phone",
|
||||
"question": {
|
||||
"en": "What number can one call if there is a problem with this charging station?",
|
||||
"nl": "Wat is het telefoonnummer van de beheerder van dit oplaadpunt?"
|
||||
"nl": "Wat is het telefoonnummer van de beheerder van dit oplaadpunt?",
|
||||
"de": "Welche Nummer kann man anrufen, wenn es ein Problem mit dieser Ladestation gibt?"
|
||||
},
|
||||
"render": {
|
||||
"en": "In case of problems, call <a href='tel:{phone}'>{phone}</a>",
|
||||
"nl": "Bij problemen, bel naar <a href='tel:{phone}'>{phone}</a>"
|
||||
"nl": "Bij problemen, bel naar <a href='tel:{phone}'>{phone}</a>",
|
||||
"de": "Bei Problemen, anrufen unter <a href='tel:{phone}'>{phone}</a>"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "phone",
|
||||
|
@ -1545,11 +1618,13 @@
|
|||
"id": "email",
|
||||
"question": {
|
||||
"en": "What is the email address of the operator?",
|
||||
"nl": "Wat is het email-adres van de operator?"
|
||||
"nl": "Wat is het email-adres van de operator?",
|
||||
"de": "Wie ist die Email-Adresse des Betreibers?"
|
||||
},
|
||||
"render": {
|
||||
"en": "In case of problems, send an email to <a href='mailto:{email}'>{email}</a>",
|
||||
"nl": "Bij problemen, email naar <a href='mailto:{email}'>{email}</a>"
|
||||
"nl": "Bij problemen, email naar <a href='mailto:{email}'>{email}</a>",
|
||||
"de": "Bei Problemen senden Sie eine E-Mail an <a href='mailto:{email}'>{email}</a>"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "email",
|
||||
|
@ -1559,12 +1634,14 @@
|
|||
{
|
||||
"id": "website",
|
||||
"question": {
|
||||
"en": "What is the website where one can find more information about this charging station?",
|
||||
"nl": "Wat is de website waar men meer info kan vinden over dit oplaadpunt?"
|
||||
"en": "What is the website of the operator?",
|
||||
"nl": "Wat is de website waar men meer info kan vinden over dit oplaadpunt?",
|
||||
"de": "Wie ist die Webseite des Betreibers?"
|
||||
},
|
||||
"render": {
|
||||
"en": "More info on <a href='{website}'>{website}</a>",
|
||||
"nl": "Meer informatie op <a href='{website}'>{website}</a>"
|
||||
"nl": "Meer informatie op <a href='{website}'>{website}</a>",
|
||||
"de": "Weitere Informationen auf <a href='{website}'>{website}</a>"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "website",
|
||||
|
@ -1576,11 +1653,13 @@
|
|||
"id": "ref",
|
||||
"question": {
|
||||
"en": "What is the reference number of this charging station?",
|
||||
"nl": "Wat is het referentienummer van dit oplaadstation?"
|
||||
"nl": "Wat is het referentienummer van dit oplaadstation?",
|
||||
"de": "Wie lautet die Kennung dieser Ladestation?"
|
||||
},
|
||||
"render": {
|
||||
"en": "Reference number is <b>{ref}</b>",
|
||||
"nl": "Het referentienummer van dit oplaadpunt is <b>{ref}</b>"
|
||||
"nl": "Het referentienummer van dit oplaadpunt is <b>{ref}</b>",
|
||||
"de": "Die Kennziffer ist <b>{ref}</b>"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "ref"
|
||||
|
@ -1592,7 +1671,8 @@
|
|||
"id": "Operational status",
|
||||
"question": {
|
||||
"en": "Is this charging point in use?",
|
||||
"nl": "Is dit oplaadpunt operationeel?"
|
||||
"nl": "Is dit oplaadpunt operationeel?",
|
||||
"de": "Ist dieser Ladepunkt in Betrieb?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
|
@ -1607,7 +1687,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "This charging station works",
|
||||
"nl": "Dit oplaadpunt werkt"
|
||||
"nl": "Dit oplaadpunt werkt",
|
||||
"de": "Diese Ladestation funktioniert"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1622,7 +1703,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "This charging station is broken",
|
||||
"nl": "Dit oplaadpunt is kapot"
|
||||
"nl": "Dit oplaadpunt is kapot",
|
||||
"de": "Diese Ladestation ist kaputt"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1637,7 +1719,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "A charging station is planned here",
|
||||
"nl": "Hier zal binnenkort een oplaadpunt gebouwd worden"
|
||||
"nl": "Hier zal binnenkort een oplaadpunt gebouwd worden",
|
||||
"de": "Hier ist eine Ladestation geplant"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1652,7 +1735,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "A charging station is constructed here",
|
||||
"nl": "Hier wordt op dit moment een oplaadpunt gebouwd"
|
||||
"nl": "Hier wordt op dit moment een oplaadpunt gebouwd",
|
||||
"de": "Hier wird eine Ladestation gebaut"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1667,7 +1751,8 @@
|
|||
},
|
||||
"then": {
|
||||
"en": "This charging station has beed permanently disabled and is not in use anymore but is still visible",
|
||||
"nl": "Dit oplaadpunt is niet meer in gebruik maar is wel nog aanwezig"
|
||||
"nl": "Dit oplaadpunt is niet meer in gebruik maar is wel nog aanwezig",
|
||||
"de": "Diese Ladestation wurde dauerhaft deaktiviert und wird nicht mehr benutzt, ist aber noch sichtbar"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1676,21 +1761,24 @@
|
|||
"id": "Parking:fee",
|
||||
"question": {
|
||||
"en": "Does one have to pay a parking fee while charging?",
|
||||
"nl": "Moet men parkeergeld betalen tijdens het opladen?"
|
||||
"nl": "Moet men parkeergeld betalen tijdens het opladen?",
|
||||
"de": "Muss man beim Laden eine Parkgebühr bezahlen?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "parking:fee=no",
|
||||
"then": {
|
||||
"en": "No additional parking cost while charging",
|
||||
"nl": "Geen extra parkeerkost tijdens het opladen"
|
||||
"nl": "Geen extra parkeerkost tijdens het opladen",
|
||||
"de": "Keine zusätzlichen Parkgebühren beim Laden"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "parking:fee=yes",
|
||||
"then": {
|
||||
"en": "An additional parking fee should be paid while charging",
|
||||
"nl": "Tijdens het opladen moet er parkeergeld betaald worden"
|
||||
"nl": "Tijdens het opladen moet er parkeergeld betaald worden",
|
||||
"de": "Beim Laden ist eine zusätzliche Parkgebühr zu entrichten"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -1705,69 +1793,6 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"mapRendering": [
|
||||
{
|
||||
"location": [
|
||||
"point",
|
||||
"centroid"
|
||||
],
|
||||
"icon": {
|
||||
"render": "pin:#fff;./assets/themes/charging_stations/plug.svg",
|
||||
"mappings": [
|
||||
{
|
||||
"if": "bicycle=yes",
|
||||
"then": "pin:#fff;./assets/themes/charging_stations/bicycle.svg"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"or": [
|
||||
"car=yes",
|
||||
"motorcar=yes"
|
||||
]
|
||||
},
|
||||
"then": "pin:#fff;./assets/themes/charging_stations/car.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"iconBadges": [
|
||||
{
|
||||
"if": {
|
||||
"or": [
|
||||
"disused:amenity=charging_station",
|
||||
"operational_status=broken"
|
||||
]
|
||||
},
|
||||
"then": "cross:#c22;"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"or": [
|
||||
"proposed:amenity=charging_station",
|
||||
"planned:amenity=charging_station"
|
||||
]
|
||||
},
|
||||
"then": "./assets/layers/charging_station/under_construction.svg"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"bicycle=yes",
|
||||
{
|
||||
"or": [
|
||||
"motorcar=yes",
|
||||
"car=yes"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"then": "circle:#fff;./assets/themes/charging_stations/car.svg"
|
||||
}
|
||||
],
|
||||
"iconSize": {
|
||||
"render": "50,50,bottom"
|
||||
}
|
||||
}
|
||||
],
|
||||
"presets": [
|
||||
{
|
||||
"tags": [
|
||||
|
@ -1777,8 +1802,10 @@
|
|||
"socket:typee=1"
|
||||
],
|
||||
"title": {
|
||||
"en": "electrical outlet to charge e-bikes",
|
||||
"nl": "laadpunt met gewone stekker(s) <img src='./assets/layers/charging_station/TypeE.svg' style='width: 2rem; height: 2rem; float: left; background: white; border-radius: 1rem; margin-right: 0.5rem'/> (bedoeld om electrische fietsen op te laden)"
|
||||
"en": "Charging station",
|
||||
"nl": "gewone stekker <img src='./assets/layers/charging_station/TypeE.svg' style='width: 2rem; height: 2rem; float: left; background: white; border-radius: 1rem; margin-right: 0.5rem'/> (bedoeld om electrische fietsen op te laden)",
|
||||
"de": "Ladestation",
|
||||
"ru": "Зарядная станция"
|
||||
},
|
||||
"preciseInput": {
|
||||
"preferredBackground": "map"
|
||||
|
@ -1833,20 +1860,23 @@
|
|||
{
|
||||
"question": {
|
||||
"en": "All vehicle types",
|
||||
"nl": "Alle voertuigen"
|
||||
"nl": "Alle voertuigen",
|
||||
"de": "Alle Fahrzeugtypen"
|
||||
}
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
"en": "Charging station for bicycles",
|
||||
"nl": "Oplaadpunten voor fietsen"
|
||||
"nl": "Oplaadpunten voor fietsen",
|
||||
"de": "Ladestation für Fahrräder"
|
||||
},
|
||||
"osmTags": "bicycle=yes"
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
"en": "Charging station for cars",
|
||||
"nl": "Oplaadpunten voor auto's"
|
||||
"nl": "Oplaadpunten voor auto's",
|
||||
"de": "Ladestation für Autos"
|
||||
},
|
||||
"osmTags": {
|
||||
"or": [
|
||||
|
@ -1863,7 +1893,8 @@
|
|||
{
|
||||
"question": {
|
||||
"en": "Only working charging stations",
|
||||
"nl": "Enkel werkende oplaadpunten"
|
||||
"nl": "Enkel werkende oplaadpunten",
|
||||
"de": "Nur funktionierende Ladestationen"
|
||||
},
|
||||
"osmTags": {
|
||||
"and": [
|
||||
|
@ -1880,7 +1911,8 @@
|
|||
{
|
||||
"question": {
|
||||
"en": "All connectors",
|
||||
"nl": "Alle types"
|
||||
"nl": "Alle types",
|
||||
"de": "Alle Anschlüsse"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1900,7 +1932,8 @@
|
|||
{
|
||||
"question": {
|
||||
"en": "Has a <div style='display: inline-block'><b><b>Chademo</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Chademo_type4.svg'/></div> connector",
|
||||
"nl": "Heeft een <div style='display: inline-block'><b><b>Chademo</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Chademo_type4.svg'/></div>"
|
||||
"nl": "Heeft een <div style='display: inline-block'><b><b>Chademo</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Chademo_type4.svg'/></div>",
|
||||
"de": "Hat einen <div style='display: inline-block'><b><b>Chademo</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Chademo_type4.svg'/></div> Stecker"
|
||||
},
|
||||
"osmTags": "socket:chademo~*"
|
||||
},
|
||||
|
@ -1928,7 +1961,8 @@
|
|||
{
|
||||
"question": {
|
||||
"en": "Has a <div style='display: inline-block'><b><b>Tesla Supercharger</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> connector",
|
||||
"nl": "Heeft een <div style='display: inline-block'><b><b>Tesla Supercharger</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div>"
|
||||
"nl": "Heeft een <div style='display: inline-block'><b><b>Tesla Supercharger</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div>",
|
||||
"de": "Hat einen <div style='display: inline-block'><b><b>Tesla Supercharger</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div> Stecker"
|
||||
},
|
||||
"osmTags": "socket:tesla_supercharger~*"
|
||||
},
|
||||
|
@ -2016,11 +2050,15 @@
|
|||
],
|
||||
"human": {
|
||||
"en": " minutes",
|
||||
"nl": " minuten"
|
||||
"nl": " minuten",
|
||||
"de": " Minuten",
|
||||
"ru": " минут"
|
||||
},
|
||||
"humanSingular": {
|
||||
"en": " minute",
|
||||
"nl": " minuut"
|
||||
"nl": " minuut",
|
||||
"de": " Minute",
|
||||
"ru": " минута"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2036,11 +2074,15 @@
|
|||
],
|
||||
"human": {
|
||||
"en": " hours",
|
||||
"nl": " uren"
|
||||
"nl": " uren",
|
||||
"de": " Stunden",
|
||||
"ru": " часов"
|
||||
},
|
||||
"humanSingular": {
|
||||
"en": " hour",
|
||||
"nl": " uur"
|
||||
"nl": " uur",
|
||||
"de": " Stunde",
|
||||
"ru": " час"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2053,11 +2095,15 @@
|
|||
],
|
||||
"human": {
|
||||
"en": " days",
|
||||
"nl": " day"
|
||||
"nl": " day",
|
||||
"de": " Tage",
|
||||
"ru": " дней"
|
||||
},
|
||||
"humanSingular": {
|
||||
"en": " day",
|
||||
"nl": " dag"
|
||||
"nl": " dag",
|
||||
"de": " Tag",
|
||||
"ru": " день"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -2093,7 +2139,9 @@
|
|||
],
|
||||
"human": {
|
||||
"en": "Volts",
|
||||
"nl": "volt"
|
||||
"nl": "volt",
|
||||
"de": "Volt",
|
||||
"ru": "Вольт"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -2162,7 +2210,9 @@
|
|||
],
|
||||
"human": {
|
||||
"en": "kilowatt",
|
||||
"nl": "kilowatt"
|
||||
"nl": "kilowatt",
|
||||
"de": "Kilowatt",
|
||||
"ru": "киловатт"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2172,7 +2222,9 @@
|
|||
],
|
||||
"human": {
|
||||
"en": "megawatt",
|
||||
"nl": "megawatt"
|
||||
"nl": "megawatt",
|
||||
"de": "Megawatt",
|
||||
"ru": "мегаватт"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -2191,5 +2243,68 @@
|
|||
]
|
||||
},
|
||||
"neededChangesets": 10
|
||||
}
|
||||
},
|
||||
"mapRendering": [
|
||||
{
|
||||
"location": [
|
||||
"point",
|
||||
"centroid"
|
||||
],
|
||||
"icon": {
|
||||
"render": "pin:#fff;./assets/themes/charging_stations/plug.svg",
|
||||
"mappings": [
|
||||
{
|
||||
"if": "bicycle=yes",
|
||||
"then": "pin:#fff;./assets/themes/charging_stations/bicycle.svg"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"or": [
|
||||
"car=yes",
|
||||
"motorcar=yes"
|
||||
]
|
||||
},
|
||||
"then": "pin:#fff;./assets/themes/charging_stations/car.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"iconBadges": [
|
||||
{
|
||||
"if": {
|
||||
"or": [
|
||||
"disused:amenity=charging_station",
|
||||
"operational_status=broken"
|
||||
]
|
||||
},
|
||||
"then": "cross:#c22;"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"or": [
|
||||
"proposed:amenity=charging_station",
|
||||
"planned:amenity=charging_station"
|
||||
]
|
||||
},
|
||||
"then": "./assets/layers/charging_station/under_construction.svg"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"bicycle=yes",
|
||||
{
|
||||
"or": [
|
||||
"motorcar=yes",
|
||||
"car=yes"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"then": "circle:#fff;./assets/themes/charging_stations/car.svg"
|
||||
}
|
||||
],
|
||||
"iconSize": {
|
||||
"render": "50,50,bottom"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -83,7 +83,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"description": {},
|
||||
"tagRenderings": [
|
||||
{
|
||||
"question": {
|
||||
|
@ -102,21 +101,24 @@
|
|||
"if": "cycleway=shared_lane",
|
||||
"then": {
|
||||
"en": "There is a shared lane",
|
||||
"nl": "Er is een fietssuggestiestrook"
|
||||
"nl": "Er is een fietssuggestiestrook",
|
||||
"de": "Es gibt eine geteilte Fahrspur"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "cycleway=lane",
|
||||
"then": {
|
||||
"en": "There is a lane next to the road (separated with paint)",
|
||||
"nl": "Er is een fietspad aangrenzend aan de weg (gescheiden met verf)"
|
||||
"nl": "Er is een fietspad aangrenzend aan de weg (gescheiden met verf)",
|
||||
"de": "Es gibt eine Spur neben der Straße (getrennt durch eine Straßenmarkierung)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "cycleway=track",
|
||||
"then": {
|
||||
"en": "There is a track, but no cycleway drawn separately from this road on the map.",
|
||||
"nl": "Er is een fietspad (los van de weg), maar geen fietspad afzonderlijk getekend naast deze weg."
|
||||
"nl": "Er is een fietspad (los van de weg), maar geen fietspad afzonderlijk getekend naast deze weg.",
|
||||
"de": "Es gibt einen Weg, aber keinen Radweg, der auf der Karte getrennt von dieser Straße eingezeichnet ist."
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -163,7 +165,8 @@
|
|||
"if": "lit=yes",
|
||||
"then": {
|
||||
"en": "This street is lit",
|
||||
"nl": "Deze weg is verlicht"
|
||||
"nl": "Deze weg is verlicht",
|
||||
"de": "Diese Straße ist beleuchtet"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -211,7 +214,8 @@
|
|||
"if": "cyclestreet=yes",
|
||||
"then": {
|
||||
"en": "This is a cyclestreet, and a 30km/h zone.",
|
||||
"nl": "Dit is een fietsstraat, en dus een 30km/h zone"
|
||||
"nl": "Dit is een fietsstraat, en dus een 30km/h zone",
|
||||
"de": "Dies ist eine Fahrradstraße in einer 30km/h Zone."
|
||||
},
|
||||
"addExtraTags": [
|
||||
"overtaking:motor_vehicle=no",
|
||||
|
@ -245,7 +249,8 @@
|
|||
{
|
||||
"render": {
|
||||
"en": "The maximum speed on this road is {maxspeed} km/h",
|
||||
"nl": "De maximumsnelheid op deze weg is {maxspeed} km/u"
|
||||
"nl": "De maximumsnelheid op deze weg is {maxspeed} km/u",
|
||||
"de": "Die Höchstgeschwindigkeit auf dieser Straße beträgt {maxspeed} km/h"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "maxspeed",
|
||||
|
@ -301,7 +306,8 @@
|
|||
],
|
||||
"question": {
|
||||
"en": "What is the maximum speed in this street?",
|
||||
"nl": "Wat is de maximumsnelheid in deze straat?"
|
||||
"nl": "Wat is de maximumsnelheid in deze straat?",
|
||||
"de": "Was ist die Höchstgeschwindigkeit auf dieser Straße?"
|
||||
},
|
||||
"id": "Maxspeed (for road)"
|
||||
},
|
||||
|
@ -352,7 +358,8 @@
|
|||
"if": "cycleway:surface=paving_stones",
|
||||
"then": {
|
||||
"en": "This cycleway is made of smooth paving stones",
|
||||
"nl": "Dit fietspad is gemaakt van straatstenen"
|
||||
"nl": "Dit fietspad is gemaakt van straatstenen",
|
||||
"de": "Dieser Fahrradweg besteht aus ebenen Pflastersteinen"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -367,7 +374,8 @@
|
|||
"if": "cycleway:surface=cobblestone",
|
||||
"then": {
|
||||
"en": "This cycleway is made of cobblestone (unhewn or sett)",
|
||||
"nl": "Dit fietspad is gemaakt van kasseien (natuurlijk of verwerkt)"
|
||||
"nl": "Dit fietspad is gemaakt van kasseien (natuurlijk of verwerkt)",
|
||||
"de": "Dieser Radweg besteht aus Kopfsteinpflaster"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -375,14 +383,16 @@
|
|||
"if": "cycleway:surface=unhewn_cobblestone",
|
||||
"then": {
|
||||
"en": "This cycleway is made of raw, natural cobblestone",
|
||||
"nl": "Dit fietspad is gemaakt van ruwe, natuurlijke kasseien"
|
||||
"nl": "Dit fietspad is gemaakt van ruwe, natuurlijke kasseien",
|
||||
"de": "Dieser Fahrradweg besteht aus unregelmäßigem, unbehauenem Kopfsteinpflaster"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "cycleway:surface=sett",
|
||||
"then": {
|
||||
"en": "This cycleway is made of flat, square cobblestone",
|
||||
"nl": "Dit fietspad is gemaakt van vlakke, rechthoekige kasseien"
|
||||
"nl": "Dit fietspad is gemaakt van vlakke, rechthoekige kasseien",
|
||||
"de": "Dieser Fahrradweg besteht aus regelmäßigem, behauenem Kopfsteinpflaster"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -428,7 +438,8 @@
|
|||
],
|
||||
"question": {
|
||||
"en": "What is the surface of the cycleway made from?",
|
||||
"nl": "Waaruit is het oppervlak van het fietspad van gemaakt?"
|
||||
"nl": "Waaruit is het oppervlak van het fietspad van gemaakt?",
|
||||
"de": "Was ist der Belag dieses Radwegs?"
|
||||
},
|
||||
"id": "Cycleway:surface"
|
||||
},
|
||||
|
@ -466,28 +477,32 @@
|
|||
"if": "cycleway:smoothness=intermediate",
|
||||
"then": {
|
||||
"en": "Usable for normal wheels: city bike, wheelchair, scooter",
|
||||
"nl": "Geschikt voor normale wielen: stadsfiets, rolstoel, scooter"
|
||||
"nl": "Geschikt voor normale wielen: stadsfiets, rolstoel, scooter",
|
||||
"de": "Geeignet für normale Reifen: Fahrrad, Rollstuhl, Scooter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "cycleway:smoothness=bad",
|
||||
"then": {
|
||||
"en": "Usable for robust wheels: trekking bike, car, rickshaw",
|
||||
"nl": "Geschikt voor brede wielen: trekfiets, auto, rickshaw"
|
||||
"nl": "Geschikt voor brede wielen: trekfiets, auto, rickshaw",
|
||||
"de": "Geeignet für breite Reifen: Trekkingfahrrad, Auto, Rikscha"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "cycleway:smoothness=very_bad",
|
||||
"then": {
|
||||
"en": "Usable for vehicles with high clearance: light duty off-road vehicle",
|
||||
"nl": "Geschikt voor voertuigen met hoge banden: lichte terreinwagen"
|
||||
"nl": "Geschikt voor voertuigen met hoge banden: lichte terreinwagen",
|
||||
"de": "Geeignet für Fahrzeuge mit großer Bodenfreiheit: leichte Geländewagen"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "cycleway:smoothness=horrible",
|
||||
"then": {
|
||||
"en": "Usable for off-road vehicles: heavy duty off-road vehicle",
|
||||
"nl": "Geschikt voor terreinwagens: zware terreinwagen"
|
||||
"nl": "Geschikt voor terreinwagens: zware terreinwagen",
|
||||
"de": "Geeignet für Geländefahrzeuge: schwerer Geländewagen"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -523,7 +538,8 @@
|
|||
"if": "surface=unpaved",
|
||||
"then": {
|
||||
"en": "This cycleway is unhardened",
|
||||
"nl": "Dit fietspad is onverhard"
|
||||
"nl": "Dit fietspad is onverhard",
|
||||
"de": "Dieser Radweg ist nicht befestigt"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -548,7 +564,8 @@
|
|||
"if": "surface=paving_stones",
|
||||
"then": {
|
||||
"en": "This cycleway is made of smooth paving stones",
|
||||
"nl": "Dit fietspad is gemaakt van straatstenen"
|
||||
"nl": "Dit fietspad is gemaakt van straatstenen",
|
||||
"de": "Dieser Fahrradweg besteht aus ebenen Pflastersteinen"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -563,7 +580,8 @@
|
|||
"if": "surface=cobblestone",
|
||||
"then": {
|
||||
"en": "This cycleway is made of cobblestone (unhewn or sett)",
|
||||
"nl": "Dit fietspad is gemaakt van kasseien (natuurlijk of verwerkt)"
|
||||
"nl": "Dit fietspad is gemaakt van kasseien (natuurlijk of verwerkt)",
|
||||
"de": "Dieser Radweg besteht aus Kopfsteinpflaster"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -571,14 +589,16 @@
|
|||
"if": "surface=unhewn_cobblestone",
|
||||
"then": {
|
||||
"en": "This cycleway is made of raw, natural cobblestone",
|
||||
"nl": "Dit fietspad is gemaakt van ruwe, natuurlijke kasseien"
|
||||
"nl": "Dit fietspad is gemaakt van ruwe, natuurlijke kasseien",
|
||||
"de": "Dieser Fahrradweg besteht aus unregelmäßigem, unbehauenem Kopfsteinpflaster"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "surface=sett",
|
||||
"then": {
|
||||
"en": "This cycleway is made of flat, square cobblestone",
|
||||
"nl": "Dit fietspad is gemaakt van vlakke, rechthoekige kasseien"
|
||||
"nl": "Dit fietspad is gemaakt van vlakke, rechthoekige kasseien",
|
||||
"de": "Dieser Fahrradweg besteht aus regelmäßigem, behauenem Kopfsteinpflaster"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -624,7 +644,8 @@
|
|||
],
|
||||
"question": {
|
||||
"en": "What is the surface of the street made from?",
|
||||
"nl": "Waaruit is het oppervlak van de straat gemaakt?"
|
||||
"nl": "Waaruit is het oppervlak van de straat gemaakt?",
|
||||
"de": "Was ist der Belag dieser Straße?"
|
||||
},
|
||||
"id": "Surface of the road"
|
||||
},
|
||||
|
@ -658,25 +679,29 @@
|
|||
{
|
||||
"if": "smoothness=intermediate",
|
||||
"then": {
|
||||
"en": "Usable for normal wheels: city bike, wheelchair, scooter"
|
||||
"en": "Usable for normal wheels: city bike, wheelchair, scooter",
|
||||
"de": "Geeignet für normale Reifen: Fahrrad, Rollstuhl, Scooter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "smoothness=bad",
|
||||
"then": {
|
||||
"en": "Usable for robust wheels: trekking bike, car, rickshaw"
|
||||
"en": "Usable for robust wheels: trekking bike, car, rickshaw",
|
||||
"de": "Geeignet für breite Reifen: Trekkingfahrrad, Auto, Rikscha"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "smoothness=very_bad",
|
||||
"then": {
|
||||
"en": "Usable for vehicles with high clearance: light duty off-road vehicle"
|
||||
"en": "Usable for vehicles with high clearance: light duty off-road vehicle",
|
||||
"de": "Geeignet für Fahrzeuge mit großer Bodenfreiheit: leichte Geländewagen"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "smoothness=horrible",
|
||||
"then": {
|
||||
"en": "Usable for off-road vehicles: heavy duty off-road vehicle"
|
||||
"en": "Usable for off-road vehicles: heavy duty off-road vehicle",
|
||||
"de": "Geeignet für Geländefahrzeuge: schwerer Geländewagen"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -748,7 +773,8 @@
|
|||
"if": "cycleway:traffic_sign~BE:D7;.*",
|
||||
"then": {
|
||||
"en": "Compulsory cycleway (with supplementary sign)<br><img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'> ",
|
||||
"nl": "Verplicht fietspad (met onderbord)<br><img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>"
|
||||
"nl": "Verplicht fietspad (met onderbord)<br><img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>",
|
||||
"de": "Vorgeschriebener Radweg (mit Zusatzschild)<br><img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'> "
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -821,7 +847,8 @@
|
|||
"if": "traffic_sign~BE:D7;.*",
|
||||
"then": {
|
||||
"en": "Compulsory cycleway (with supplementary sign)<br><img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'> ",
|
||||
"nl": "Verplicht fietspad (met onderbord)<br><img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>"
|
||||
"nl": "Verplicht fietspad (met onderbord)<br><img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>",
|
||||
"de": "Vorgeschriebener Radweg (mit Zusatzschild)<br><img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'> "
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
|
@ -1055,11 +1082,13 @@
|
|||
{
|
||||
"render": {
|
||||
"en": "The buffer besides this cycleway is {cycleway:buffer} m",
|
||||
"nl": "De schrikafstand van dit fietspad is {cycleway:buffer} m"
|
||||
"nl": "De schrikafstand van dit fietspad is {cycleway:buffer} m",
|
||||
"de": "Der Sicherheitsabstand zu diesem Radweg beträgt {cycleway:buffer} m"
|
||||
},
|
||||
"question": {
|
||||
"en": "How wide is the gap between the cycleway and the road?",
|
||||
"nl": "Hoe breed is de ruimte tussen het fietspad en de weg?"
|
||||
"nl": "Hoe breed is de ruimte tussen het fietspad en de weg?",
|
||||
"de": "Wie breit ist der Abstand zwischen Radweg und Straße?"
|
||||
},
|
||||
"condition": {
|
||||
"or": [
|
||||
|
@ -1081,7 +1110,8 @@
|
|||
"id": "cyclelan-segregation",
|
||||
"question": {
|
||||
"en": "How is this cycleway separated from the road?",
|
||||
"nl": "Hoe is dit fietspad gescheiden van de weg?"
|
||||
"nl": "Hoe is dit fietspad gescheiden van de weg?",
|
||||
"de": "Wie ist der Radweg von der Straße abgegrenzt?"
|
||||
},
|
||||
"condition": {
|
||||
"or": [
|
||||
|
@ -1094,21 +1124,24 @@
|
|||
"if": "cycleway:separation=dashed_line",
|
||||
"then": {
|
||||
"en": "This cycleway is separated by a dashed line",
|
||||
"nl": "Dit fietspad is gescheiden van de weg met een onderbroken streep"
|
||||
"nl": "Dit fietspad is gescheiden van de weg met een onderbroken streep",
|
||||
"de": "Der Radweg ist abgegrenzt durch eine gestrichelte Linie"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "cycleway:separation=solid_line",
|
||||
"then": {
|
||||
"en": "This cycleway is separated by a solid line",
|
||||
"nl": "Dit fietspad is gescheiden van de weg met een doorgetrokken streep"
|
||||
"nl": "Dit fietspad is gescheiden van de weg met een doorgetrokken streep",
|
||||
"de": "Der Radweg ist abgegrenzt durch eine durchgezogene Linie"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "cycleway:separation=parking_lane",
|
||||
"then": {
|
||||
"en": "This cycleway is separated by a parking lane",
|
||||
"nl": "Dit fietspad is gescheiden van de weg met parkeervakken"
|
||||
"nl": "Dit fietspad is gescheiden van de weg met parkeervakken",
|
||||
"de": "Der Radweg ist abgegrenzt durch eine Parkspur"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1125,7 +1158,8 @@
|
|||
"id": "cycleway-segregation",
|
||||
"question": {
|
||||
"en": "How is this cycleway separated from the road?",
|
||||
"nl": "Hoe is dit fietspad gescheiden van de weg?"
|
||||
"nl": "Hoe is dit fietspad gescheiden van de weg?",
|
||||
"de": "Wie ist der Radweg von der Straße abgegrenzt?"
|
||||
},
|
||||
"condition": {
|
||||
"or": [
|
||||
|
@ -1138,21 +1172,24 @@
|
|||
"if": "separation=dashed_line",
|
||||
"then": {
|
||||
"en": "This cycleway is separated by a dashed line",
|
||||
"nl": "Dit fietspad is gescheiden van de weg met een onderbroken streep"
|
||||
"nl": "Dit fietspad is gescheiden van de weg met een onderbroken streep",
|
||||
"de": "Der Radweg ist abgegrenzt durch eine gestrichelte Linie"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "separation=solid_line",
|
||||
"then": {
|
||||
"en": "This cycleway is separated by a solid line",
|
||||
"nl": "Dit fietspad is gescheiden van de weg met een doorgetrokken streep"
|
||||
"nl": "Dit fietspad is gescheiden van de weg met een doorgetrokken streep",
|
||||
"de": "Der Radweg ist abgegrenzt durch eine durchgezogene Linie"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "separation=parking_lane",
|
||||
"then": {
|
||||
"en": "This cycleway is separated by a parking lane",
|
||||
"nl": "Dit fietspad is gescheiden van de weg met parkeervakken"
|
||||
"nl": "Dit fietspad is gescheiden van de weg met parkeervakken",
|
||||
"de": "Der Radweg ist abgegrenzt durch eine Parkspur"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,231 +0,0 @@
|
|||
{
|
||||
"id": "grb",
|
||||
"title": {
|
||||
"nl": "GRB Fixup"
|
||||
},
|
||||
"shortDescription": {
|
||||
"nl": "Grb Fixup"
|
||||
},
|
||||
"description": {
|
||||
"nl": "GRB Fixup"
|
||||
},
|
||||
"language": [
|
||||
"nl"
|
||||
],
|
||||
"maintainer": "",
|
||||
"icon": "./assets/svg/bug.svg",
|
||||
"version": "0",
|
||||
"startLat": 51.2132,
|
||||
"startLon": 3.231,
|
||||
"startZoom": 14,
|
||||
"widenFactor": 2,
|
||||
"socialImage": "",
|
||||
"layers": [
|
||||
{
|
||||
"id": "grb-fixmes",
|
||||
"name": {
|
||||
"nl": "Fixmes op gebouwen"
|
||||
},
|
||||
"minzoom": 12,
|
||||
"source": {
|
||||
"osmTags": {
|
||||
"and": [
|
||||
"fixme~*",
|
||||
"building~*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"calculatedTags": [
|
||||
"_grbNumber=(feat.properties.fixme?.match(/GRB thinks that this has number ([^;]+)/ ) ?? ['','none']) [1]"
|
||||
],
|
||||
"title": {
|
||||
"render": {
|
||||
"nl": "{addr:street} {addr:housenumber}"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"fixme~*"
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "{fixme}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"nl": "Dit gebouw heeft een foutmelding"
|
||||
},
|
||||
"tagRenderings": [
|
||||
{
|
||||
"id": "grb-housenumber",
|
||||
"render": {
|
||||
"nl": "Het huisnummer is <b>{addr:housenumber}</b>"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat is het huisnummer?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "addr:housenumber"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"not:addr:housenumber=yes",
|
||||
"addr:housenumber="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Geen huisnummer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"addr:housenumber:={_grbNumber}",
|
||||
"fixme="
|
||||
]
|
||||
},
|
||||
"then": "Het huisnummer is <b>{_grbNumber}</b>, wat overeenkomt met het GRB",
|
||||
"hideInAnswer": {
|
||||
"or": [
|
||||
"_grbNumber=",
|
||||
"_grbNumber=none",
|
||||
"_grbNumber=no number"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"addr:housenumber=",
|
||||
"not:addr:housenumber=yes",
|
||||
"fixme="
|
||||
]
|
||||
},
|
||||
"then": "Dit gebouw heeft geen nummer, net zoals in het GRB",
|
||||
"hideInAnswer": "_grbNumber!=no number"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-unit",
|
||||
"question": "Wat is de wooneenheid-aanduiding?",
|
||||
"render": {
|
||||
"nl": "De wooneenheid-aanduiding is <b>{addr:unit}</b> "
|
||||
},
|
||||
"freeform": {
|
||||
"key": "addr:unit"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "addr:unit=",
|
||||
"then": "Geen wooneenheid-nummer"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-street",
|
||||
"render": {
|
||||
"nl": "De straat is <b>{addr:street}</b>"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "addr:street"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat is de straat?"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "grb-fixme",
|
||||
"render": {
|
||||
"nl": "De fixme is <b>{fixme}</b>"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat zegt de fixme?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "fixme"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"fixme="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Geen fixme"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-min-level",
|
||||
"render": {
|
||||
"nl": "Dit gebouw begint maar op de {building:min_level} verdieping"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Hoeveel verdiepingen ontbreken?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "building:min_level",
|
||||
"type": "pnat"
|
||||
}
|
||||
}
|
||||
],
|
||||
"label": {
|
||||
"mappings": [
|
||||
{
|
||||
"if": "addr:housenumber~*",
|
||||
"then": "<div style='background-color: white; font: large; width: 1.5em; height: 1.5em; border-radius: 100%'>{addr:housenumber}</div>"
|
||||
}
|
||||
]
|
||||
},
|
||||
"width": {
|
||||
"render": "2"
|
||||
},
|
||||
"iconSize": {
|
||||
"render": "40,40,center"
|
||||
},
|
||||
"dashes": "2 2",
|
||||
"color": {
|
||||
"render": "#00f"
|
||||
},
|
||||
"wayHandling": 2,
|
||||
"presets": [],
|
||||
"mapRendering": [
|
||||
{
|
||||
"label": {
|
||||
"mappings": [
|
||||
{
|
||||
"if": "addr:housenumber~*",
|
||||
"then": "<div style='background-color: white; font: large; width: 1.5em; height: 1.5em; border-radius: 100%'>{addr:housenumber}</div>"
|
||||
}
|
||||
]
|
||||
},
|
||||
"iconSize": {
|
||||
"render": "40,40,center"
|
||||
},
|
||||
"location": [
|
||||
"point",
|
||||
"centroid"
|
||||
]
|
||||
},
|
||||
{
|
||||
"color": {
|
||||
"render": "#00f"
|
||||
},
|
||||
"width": {
|
||||
"render": "2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"hideFromOverview": true,
|
||||
"defaultBackgroundId": "AGIVFlandersGRB"
|
||||
}
|
20
assets/themes/grb_import/README.md
Normal file
20
assets/themes/grb_import/README.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
GRB Import helper
|
||||
===================
|
||||
|
||||
|
||||
Preparing the CRAB dataset
|
||||
--------------------------
|
||||
|
||||
````
|
||||
# The original data is downloaded from https://download.vlaanderen.be/Producten/Detail?id=447&title=CRAB_Adressenlijst# (the GML-file here )
|
||||
wget https://downloadagiv.blob.core.windows.net/crab-adressenlijst/GML/CRAB_Adressenlijst_GML.zip
|
||||
|
||||
# Extract the zip file
|
||||
unzip CRAB_Adressenlijst_GML.zip
|
||||
|
||||
# convert the pesky GML file into geojson
|
||||
ogr2ogr -progress -t_srs WGS84 -f \"GeoJson\" CRAB.geojson CrabAdr.gml
|
||||
|
||||
# When done, this big file is sliced into tiles with the slicer script
|
||||
node --max_old_space_size=8000 $(which ts-node) ~/git/MapComplete/scripts/slice.ts CRAB.geojson 18 ~/git/pietervdvn.github.io/CRAB_2021_10_26
|
||||
````
|
494
assets/themes/grb_import/grb.json
Normal file
494
assets/themes/grb_import/grb.json
Normal file
|
@ -0,0 +1,494 @@
|
|||
{
|
||||
"id": "grb",
|
||||
"title": {
|
||||
"nl": "GRB Fixup"
|
||||
},
|
||||
"shortDescription": {
|
||||
"nl": "Grb Fixup"
|
||||
},
|
||||
"description": {
|
||||
"nl": "GRB Fixup"
|
||||
},
|
||||
"language": [
|
||||
"nl"
|
||||
],
|
||||
"maintainer": "",
|
||||
"icon": "./assets/svg/bug.svg",
|
||||
"version": "0",
|
||||
"startLat": 51.2132,
|
||||
"startLon": 3.231,
|
||||
"startZoom": 14,
|
||||
"widenFactor": 2,
|
||||
"socialImage": "",
|
||||
"layers": [
|
||||
{
|
||||
"id": "OSM-buildings",
|
||||
"name": "All OSM-buildings",
|
||||
"source": {
|
||||
"osmTags": "building~*",
|
||||
"maxCacheAge": 0
|
||||
},
|
||||
"minzoom": 18,
|
||||
"width": {
|
||||
"render": "2"
|
||||
},
|
||||
"color": {
|
||||
"render": "#00c",
|
||||
"mappings": [
|
||||
{
|
||||
"if": "building=house",
|
||||
"then": "#a00"
|
||||
},
|
||||
{
|
||||
"if": "building=shed",
|
||||
"then": "#563e02"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"or": [
|
||||
"building=garage",
|
||||
"building=garages"
|
||||
]
|
||||
},
|
||||
"then": "#f9bfbb"
|
||||
},
|
||||
{
|
||||
"if": "building=yes",
|
||||
"then": "#0774f2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": "OSM-gebouw",
|
||||
"tagRenderings": [
|
||||
"all_tags"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "All OSM objects",
|
||||
"name": "All OSM Objects",
|
||||
"source": {
|
||||
"osmTags": {
|
||||
"and": [
|
||||
"id~*",
|
||||
"landuse=",
|
||||
"place=",
|
||||
"disused:power=",
|
||||
"power=",
|
||||
"type!=boundary",
|
||||
"boundary=",
|
||||
{
|
||||
"or": [
|
||||
"level=",
|
||||
"level=0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"or": [
|
||||
"layer=0",
|
||||
"layer="
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxCacheAge": 0
|
||||
},
|
||||
"minzoom": 18,
|
||||
"color": {
|
||||
"render": "#00c"
|
||||
},
|
||||
"width": {
|
||||
"render": "1"
|
||||
},
|
||||
"title": {
|
||||
"render": {
|
||||
"*": "OSM-Object"
|
||||
}
|
||||
},
|
||||
"tagRenderings": [
|
||||
"all_tags"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "osm-fixmes",
|
||||
"name": {
|
||||
"nl": "Fixmes op gebouwen"
|
||||
},
|
||||
"minzoom": 21,
|
||||
"source": {
|
||||
"maxCacheAge": 0,
|
||||
"osmTags": {
|
||||
"and": [
|
||||
"fixme~*",
|
||||
"building~*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"calculatedTags": [
|
||||
"_grbNumber=(feat.properties.fixme?.match(/GRB thinks that this has number ([^;]+)/ ) ?? ['','none']) [1]"
|
||||
],
|
||||
"title": {
|
||||
"render": {
|
||||
"nl": "{addr:street} {addr:housenumber}"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"fixme~*"
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "{fixme}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"nl": "Dit gebouw heeft een foutmelding"
|
||||
},
|
||||
"tagRenderings": [
|
||||
{
|
||||
"id": "grb-housenumber",
|
||||
"render": {
|
||||
"nl": "Het huisnummer is <b>{addr:housenumber}</b>"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat is het huisnummer?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "addr:housenumber"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"not:addr:housenumber=yes",
|
||||
"addr:housenumber="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Geen huisnummer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"addr:housenumber:={_grbNumber}",
|
||||
"fixme="
|
||||
]
|
||||
},
|
||||
"then": "Het huisnummer is <b>{_grbNumber}</b>, wat overeenkomt met het GRB",
|
||||
"hideInAnswer": {
|
||||
"or": [
|
||||
"_grbNumber=",
|
||||
"_grbNumber=none",
|
||||
"_grbNumber=no number"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"addr:housenumber=",
|
||||
"not:addr:housenumber=yes",
|
||||
"fixme="
|
||||
]
|
||||
},
|
||||
"then": "Dit gebouw heeft geen nummer, net zoals in het GRB",
|
||||
"hideInAnswer": "_grbNumber!=no number"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-unit",
|
||||
"question": "Wat is de wooneenheid-aanduiding?",
|
||||
"render": {
|
||||
"nl": "De wooneenheid-aanduiding is <b>{addr:unit}</b> "
|
||||
},
|
||||
"freeform": {
|
||||
"key": "addr:unit"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "addr:unit=",
|
||||
"then": "Geen wooneenheid-nummer"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-street",
|
||||
"render": {
|
||||
"nl": "De straat is <b>{addr:street}</b>"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "addr:street"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat is de straat?"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "grb-fixme",
|
||||
"render": {
|
||||
"nl": "De fixme is <b>{fixme}</b>"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat zegt de fixme?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "fixme"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"fixme="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Geen fixme"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-min-level",
|
||||
"render": {
|
||||
"nl": "Dit gebouw begint maar op de {building:min_level} verdieping"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Hoeveel verdiepingen ontbreken?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "building:min_level",
|
||||
"type": "pnat"
|
||||
}
|
||||
}
|
||||
],
|
||||
"label": {
|
||||
"mappings": [
|
||||
{
|
||||
"if": "addr:housenumber~*",
|
||||
"then": "<div style='background-color: white; font: large; width: 1.5em; height: 1.5em; border-radius: 100%'>{addr:housenumber}</div>"
|
||||
}
|
||||
]
|
||||
},
|
||||
"width": {
|
||||
"render": "2"
|
||||
},
|
||||
"iconSize": {
|
||||
"render": "40,40,center"
|
||||
},
|
||||
"dashes": "2 2",
|
||||
"color": {
|
||||
"render": "#00f"
|
||||
},
|
||||
"wayHandling": 2,
|
||||
"presets": []
|
||||
},
|
||||
{
|
||||
"id": "crab-addresses 2021-10-26",
|
||||
"source": {
|
||||
"osmTags": "HUISNR~*",
|
||||
"geoJson": "https://raw.githubusercontent.com/pietervdvn/pietervdvn.github.io/master/CRAB_2021_10_26/tile_{z}_{x}_{y}.geojson",
|
||||
"#geoJson": "https://pietervdvn.github.io/CRAB_2021_10_26/tile_{z}_{x}_{y}.geojson",
|
||||
"geoJsonZoomLevel": 18,
|
||||
"maxCacheAge": 0
|
||||
},
|
||||
"minzoom": 19,
|
||||
"name": "CRAB-addressen",
|
||||
"title": "CRAB-adres",
|
||||
"icon": "circle:#bb3322",
|
||||
"iconSize": "15,15,center",
|
||||
"tagRenderings": [
|
||||
"all_tags",
|
||||
{
|
||||
"id": "import-button",
|
||||
"render": "{import_button(addr:street=$STRAATNM; addr:housenumber=$HUISNR)}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-fixmes",
|
||||
"name": {
|
||||
"nl": "Fixmes op gebouwen"
|
||||
},
|
||||
"minzoom": 12,
|
||||
"source": {
|
||||
"maxCacheAge": 0,
|
||||
"osmTags": {
|
||||
"and": [
|
||||
"fixme~*",
|
||||
"building~*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"calculatedTags": [
|
||||
"_grbNumber=(feat.properties.fixme?.match(/GRB thinks that this has number ([^;]+)/ ) ?? ['','none']) [1]"
|
||||
],
|
||||
"title": {
|
||||
"render": {
|
||||
"nl": "{addr:street} {addr:housenumber}"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"fixme~*"
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "{fixme}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"nl": "Dit gebouw heeft een foutmelding"
|
||||
},
|
||||
"tagRenderings": [
|
||||
{
|
||||
"id": "grb-housenumber",
|
||||
"render": {
|
||||
"nl": "Het huisnummer is <b>{addr:housenumber}</b>"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat is het huisnummer?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "addr:housenumber"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"not:addr:housenumber=yes",
|
||||
"addr:housenumber="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Geen huisnummer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"addr:housenumber:={_grbNumber}",
|
||||
"fixme="
|
||||
]
|
||||
},
|
||||
"then": "Het huisnummer is <b>{_grbNumber}</b>, wat overeenkomt met het GRB",
|
||||
"hideInAnswer": {
|
||||
"or": [
|
||||
"_grbNumber=",
|
||||
"_grbNumber=none",
|
||||
"_grbNumber=no number"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"addr:housenumber=",
|
||||
"not:addr:housenumber=yes",
|
||||
"fixme="
|
||||
]
|
||||
},
|
||||
"then": "Dit gebouw heeft geen nummer, net zoals in het GRB",
|
||||
"hideInAnswer": "_grbNumber!=no number"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-unit",
|
||||
"question": "Wat is de wooneenheid-aanduiding?",
|
||||
"render": {
|
||||
"nl": "De wooneenheid-aanduiding is <b>{addr:unit}</b> "
|
||||
},
|
||||
"freeform": {
|
||||
"key": "addr:unit"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "addr:unit=",
|
||||
"then": "Geen wooneenheid-nummer"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-street",
|
||||
"render": {
|
||||
"nl": "De straat is <b>{addr:street}</b>"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "addr:street"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat is de straat?"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "grb-fixme",
|
||||
"render": {
|
||||
"nl": "De fixme is <b>{fixme}</b>"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat zegt de fixme?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "fixme"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"fixme="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Geen fixme"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-min-level",
|
||||
"render": {
|
||||
"nl": "Dit gebouw begint maar op de {building:min_level} verdieping"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Hoeveel verdiepingen ontbreken?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "building:min_level",
|
||||
"type": "pnat"
|
||||
}
|
||||
}
|
||||
],
|
||||
"label": {
|
||||
"mappings": [
|
||||
{
|
||||
"if": "addr:housenumber~*",
|
||||
"then": "<div style='background-color: white; font: large; width: 1.5em; height: 1.5em; border-radius: 100%'>{addr:housenumber}</div>"
|
||||
}
|
||||
]
|
||||
},
|
||||
"width": {
|
||||
"render": "2"
|
||||
},
|
||||
"iconSize": {
|
||||
"render": "40,40,center"
|
||||
},
|
||||
"dashes": "2 2",
|
||||
"color": {
|
||||
"render": "#00f"
|
||||
},
|
||||
"wayHandling": 2,
|
||||
"presets": []
|
||||
}
|
||||
],
|
||||
"hideFromOverview": true,
|
||||
"defaultBackgroundId": "AGIVFlandersGRB",
|
||||
"overpassMaxZoom": 18,
|
||||
"osmApiTileSize": 17
|
||||
}
|
|
@ -1,4 +1,34 @@
|
|||
[
|
||||
{
|
||||
"path": "Commemorative_plaque_on_Elizabeth_House_-_geograph.org.uk_-_2693028.jpg",
|
||||
"license": "CC-BY-SA 2.0 Unported",
|
||||
"authors": [
|
||||
"Basher Eyre"
|
||||
],
|
||||
"sources": [
|
||||
"https://commons.wikimedia.org/wiki/File:Commemorative_plaque_on_Elizabeth_House_-_geograph.org.uk_-_2693028.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "Plaque,_Raphoe_House_-_geograph.org.uk_-_1925685.jpg",
|
||||
"license": "CC-BY-SA 2.0",
|
||||
"authors": [
|
||||
"Kenneth Allen"
|
||||
],
|
||||
"sources": [
|
||||
"https://commons.wikimedia.org/wiki/File:Plaque,_Raphoe_House_-_geograph.org.uk_-_1925685.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "Plaque,_Séamus_Roddy_House_-_geograph.org.uk_-_2000318.jpg",
|
||||
"license": "CC-BY-SA 2.0 Unported",
|
||||
"authors": [
|
||||
"Kenneth Allen"
|
||||
],
|
||||
"sources": [
|
||||
"https://commons.wikimedia.org/wiki/File:Plaque,_S%C3%A9amus_Roddy_House_-_geograph.org.uk_-_2000318.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "housenumber_add.svg",
|
||||
"license": "CC0",
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
"maxZoom": 20,
|
||||
"defaultState": false,
|
||||
"name": {
|
||||
"en": "Property boundaries by osmuk.org"
|
||||
"en": "Property boundaries by osmuk.org",
|
||||
"de": "Grenzverläufe gemäß osmuk.org"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -112,29 +113,6 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"mapRendering": [
|
||||
{
|
||||
"icon": {
|
||||
"render": "./assets/themes/uk_addresses/housenumber_unknown.svg",
|
||||
"mappings": [
|
||||
{
|
||||
"if": "_embedding_object:id~*",
|
||||
"then": "./assets/themes/uk_addresses/housenumber_unknown_small.svg"
|
||||
},
|
||||
{
|
||||
"if": "_imported=yes",
|
||||
"then": "./assets/themes/uk_addresses/housenumber_unknown_small.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"iconSize": {
|
||||
"render": "40,40,center"
|
||||
},
|
||||
"location": [
|
||||
"point"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -290,60 +268,7 @@
|
|||
"then": "#ff0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mapRendering": [
|
||||
{
|
||||
"icon": {
|
||||
"render": "./assets/themes/uk_addresses/housenumber_ok.svg",
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"or": [
|
||||
{
|
||||
"and": [
|
||||
"addr:housenumber=",
|
||||
"nohousenumber!=yes"
|
||||
]
|
||||
},
|
||||
"addr:street="
|
||||
]
|
||||
},
|
||||
"then": "./assets/themes/uk_addresses/housenumber_unknown.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"iconSize": {
|
||||
"render": "40,40,center"
|
||||
},
|
||||
"location": [
|
||||
"point"
|
||||
]
|
||||
},
|
||||
{
|
||||
"color": {
|
||||
"render": "#00f",
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"or": [
|
||||
{
|
||||
"and": [
|
||||
"addr:housenumber=",
|
||||
"nohousenumber!=yes"
|
||||
]
|
||||
},
|
||||
"addr:street="
|
||||
]
|
||||
},
|
||||
"then": "#ff0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"width": {
|
||||
"render": "8"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "named_streets",
|
||||
|
@ -361,22 +286,9 @@
|
|||
},
|
||||
"width": {
|
||||
"render": "0"
|
||||
},
|
||||
"mapRendering": [
|
||||
{
|
||||
"location": [
|
||||
"point"
|
||||
]
|
||||
},
|
||||
{
|
||||
"color": {
|
||||
"render": "#ccc"
|
||||
},
|
||||
"width": {
|
||||
"render": "0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"enableShareScreen": false,
|
||||
"enableMoreQuests": false
|
||||
}
|
2
index.ts
2
index.ts
|
@ -33,8 +33,6 @@ if (location.href.startsWith("http://buurtnatuur.be")) {
|
|||
|
||||
|
||||
class Init {
|
||||
|
||||
|
||||
public static Init(layoutToUse: LayoutConfig, encoded: string) {
|
||||
|
||||
if(layoutToUse === null){
|
||||
|
|
147
scripts/slice.ts
Normal file
147
scripts/slice.ts
Normal file
|
@ -0,0 +1,147 @@
|
|||
import * as fs from "fs";
|
||||
import TiledFeatureSource from "../Logic/FeatureSource/TiledFeatureSource/TiledFeatureSource";
|
||||
import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource";
|
||||
import * as readline from "readline";
|
||||
import ScriptUtils from "./ScriptUtils";
|
||||
|
||||
async function readFeaturesFromLineDelimitedJsonFile(inputFile: string): Promise<any[]> {
|
||||
const fileStream = fs.createReadStream(inputFile);
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: fileStream,
|
||||
crlfDelay: Infinity
|
||||
});
|
||||
// Note: we use the crlfDelay option to recognize all instances of CR LF
|
||||
// ('\r\n') in input.txt as a single line break.
|
||||
|
||||
const allFeatures: any[] = []
|
||||
// @ts-ignore
|
||||
for await (const line of rl) {
|
||||
try {
|
||||
allFeatures.push(JSON.parse(line))
|
||||
} catch (e) {
|
||||
console.error("Could not parse", line)
|
||||
break
|
||||
}
|
||||
if (allFeatures.length % 10000 === 0) {
|
||||
ScriptUtils.erasableLog("Loaded ", allFeatures.length, "features up till now")
|
||||
}
|
||||
}
|
||||
return allFeatures
|
||||
}
|
||||
|
||||
async function readGeojsonLineByLine(inputFile: string): Promise<any[]> {
|
||||
const fileStream = fs.createReadStream(inputFile);
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: fileStream,
|
||||
crlfDelay: Infinity
|
||||
});
|
||||
// Note: we use the crlfDelay option to recognize all instances of CR LF
|
||||
// ('\r\n') in input.txt as a single line break.
|
||||
|
||||
const allFeatures: any[] = []
|
||||
let featuresSeen = false
|
||||
// @ts-ignore
|
||||
for await (let line: string of rl) {
|
||||
if (!featuresSeen && line.startsWith("\"features\":")) {
|
||||
featuresSeen = true;
|
||||
continue;
|
||||
}
|
||||
if (!featuresSeen) {
|
||||
continue
|
||||
}
|
||||
if (line.endsWith(",")) {
|
||||
line = line.substring(0, line.length - 1)
|
||||
}
|
||||
|
||||
try {
|
||||
allFeatures.push(JSON.parse(line))
|
||||
} catch (e) {
|
||||
console.error("Could not parse", line)
|
||||
break
|
||||
}
|
||||
if (allFeatures.length % 10000 === 0) {
|
||||
ScriptUtils.erasableLog("Loaded ", allFeatures.length, "features up till now")
|
||||
}
|
||||
}
|
||||
return allFeatures
|
||||
}
|
||||
|
||||
async function readFeaturesFromGeoJson(inputFile: string): Promise<any[]> {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(inputFile, "UTF-8")).features
|
||||
} catch (e) {
|
||||
// We retry, but with a line-by-line approach
|
||||
return await readGeojsonLineByLine(inputFile)
|
||||
}
|
||||
}
|
||||
|
||||
async function main(args: string[]) {
|
||||
|
||||
console.log("GeoJSON slicer")
|
||||
if (args.length < 3) {
|
||||
console.log("USAGE: <input-file.geojson> <target-zoom-level> <output-directory>")
|
||||
return
|
||||
}
|
||||
|
||||
const inputFile = args[0]
|
||||
const zoomlevel = Number(args[1])
|
||||
const outputDirectory = args[2]
|
||||
|
||||
if (!fs.existsSync(outputDirectory)) {
|
||||
fs.mkdirSync(outputDirectory)
|
||||
console.log("Directory created")
|
||||
}
|
||||
console.log("Using directory ", outputDirectory)
|
||||
|
||||
|
||||
let allFeatures: any [];
|
||||
if (inputFile.endsWith(".geojson")) {
|
||||
allFeatures = await readFeaturesFromGeoJson(inputFile)
|
||||
} else {
|
||||
allFeatures = await readFeaturesFromLineDelimitedJsonFile(inputFile)
|
||||
}
|
||||
|
||||
|
||||
console.log("Loaded all", allFeatures.length, "points")
|
||||
|
||||
const keysToRemove = ["STRAATNMID", "GEMEENTE", "POSTCODE"]
|
||||
for (const f of allFeatures) {
|
||||
for (const keyToRm of keysToRemove) {
|
||||
delete f.properties[keyToRm]
|
||||
}
|
||||
delete f.bbox
|
||||
}
|
||||
|
||||
//const knownKeys = Utils.Dedup([].concat(...allFeatures.map(f => Object.keys(f.properties))))
|
||||
//console.log("Kept keys: ", knownKeys)
|
||||
|
||||
TiledFeatureSource.createHierarchy(
|
||||
new StaticFeatureSource(allFeatures, false),
|
||||
{
|
||||
minZoomLevel: zoomlevel,
|
||||
maxZoomLevel: zoomlevel,
|
||||
maxFeatureCount: Number.MAX_VALUE,
|
||||
registerTile: tile => {
|
||||
const path = `${outputDirectory}/tile_${tile.z}_${tile.x}_${tile.y}.geojson`
|
||||
const features = tile.features.data.map(ff => ff.feature)
|
||||
features.forEach(f => {
|
||||
delete f.bbox
|
||||
})
|
||||
fs.writeFileSync(path, JSON.stringify({
|
||||
"type": "FeatureCollection",
|
||||
"features": features
|
||||
}, null, " "))
|
||||
ScriptUtils.erasableLog("Written ", path, "which has ", tile.features.data.length, "features")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
let args = [...process.argv]
|
||||
args.splice(0, 2)
|
||||
main(args).then(_ => {
|
||||
console.log("All done!")
|
||||
});
|
Loading…
Reference in a new issue