Fix all the bugs, feature-complete with the non-refactored version
This commit is contained in:
parent
5adc355a48
commit
25f2aa8e92
11 changed files with 467 additions and 99 deletions
|
@ -1,5 +1,4 @@
|
||||||
import {Layout} from "./Layout";
|
import {Layout} from "./Layout";
|
||||||
import {FromJSON} from "./JSON/FromJSON";
|
|
||||||
import * as bookcases from "../assets/themes/bookcases/Bookcases.json";
|
import * as bookcases from "../assets/themes/bookcases/Bookcases.json";
|
||||||
import * as aed from "../assets/themes/aed/aed.json";
|
import * as aed from "../assets/themes/aed/aed.json";
|
||||||
import * as toilets from "../assets/themes/toilets/toilets.json";
|
import * as toilets from "../assets/themes/toilets/toilets.json";
|
||||||
|
@ -15,6 +14,7 @@ import * as bike_monitoring_stations from "../assets/themes/bike_monitoring_stat
|
||||||
import * as fritures from "../assets/themes/fritures/fritures.json"
|
import * as fritures from "../assets/themes/fritures/fritures.json"
|
||||||
import * as benches from "../assets/themes/benches/benches.json";
|
import * as benches from "../assets/themes/benches/benches.json";
|
||||||
import * as charging_stations from "../assets/themes/charging_stations/charging_stations.json"
|
import * as charging_stations from "../assets/themes/charging_stations/charging_stations.json"
|
||||||
|
import * as widths from "../assets/themes/widths/width.json"
|
||||||
|
|
||||||
import {PersonalLayout} from "../Logic/PersonalLayout";
|
import {PersonalLayout} from "../Logic/PersonalLayout";
|
||||||
import LayerConfig from "./JSON/LayerConfig";
|
import LayerConfig from "./JSON/LayerConfig";
|
||||||
|
@ -41,11 +41,20 @@ export class AllKnownLayouts {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static GenerateWidths(): Layout {
|
||||||
|
const layout = Layout.LayoutFromJSON(widths, SharedLayers.sharedLayers);
|
||||||
|
|
||||||
|
layout.enableUserBadge = false;
|
||||||
|
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
private static GenerateBuurtNatuur(): Layout {
|
private static GenerateBuurtNatuur(): Layout {
|
||||||
const layout = Layout.LayoutFromJSON(buurtnatuur, SharedLayers.sharedLayers);
|
const layout = Layout.LayoutFromJSON(buurtnatuur, SharedLayers.sharedLayers);
|
||||||
layout.enableMoreQuests = false;
|
layout.enableMoreQuests = false;
|
||||||
layout.enableShareScreen = false;
|
layout.enableShareScreen = false;
|
||||||
layout.hideFromOverview = true;
|
layout.hideFromOverview = true;
|
||||||
|
console.log("Buurtnatuur:",layout)
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +82,7 @@ export class AllKnownLayouts {
|
||||||
Layout.LayoutFromJSON(fritures, SharedLayers.sharedLayers),
|
Layout.LayoutFromJSON(fritures, SharedLayers.sharedLayers),
|
||||||
Layout.LayoutFromJSON(benches, SharedLayers.sharedLayers),
|
Layout.LayoutFromJSON(benches, SharedLayers.sharedLayers),
|
||||||
Layout.LayoutFromJSON(charging_stations, SharedLayers.sharedLayers),
|
Layout.LayoutFromJSON(charging_stations, SharedLayers.sharedLayers),
|
||||||
|
AllKnownLayouts.GenerateWidths(),
|
||||||
AllKnownLayouts.GenerateBuurtNatuur(),
|
AllKnownLayouts.GenerateBuurtNatuur(),
|
||||||
AllKnownLayouts.GenerateBikeMonitoringStations(),
|
AllKnownLayouts.GenerateBikeMonitoringStations(),
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import Translation from "../../UI/i18n/Translation";
|
import Translations, {Translation} from "../../UI/i18n/Translations";
|
||||||
import TagRenderingConfig from "./TagRenderingConfig";
|
import TagRenderingConfig from "./TagRenderingConfig";
|
||||||
import {Tag, TagsFilter} from "../../Logic/Tags";
|
import {Tag, TagsFilter} from "../../Logic/Tags";
|
||||||
import {LayerConfigJson} from "./LayerConfigJson";
|
import {LayerConfigJson} from "./LayerConfigJson";
|
||||||
import Translations from "../../UI/i18n/Translations";
|
|
||||||
import {FromJSON} from "./FromJSON";
|
import {FromJSON} from "./FromJSON";
|
||||||
import SharedTagRenderings from "../SharedTagRenderings";
|
import SharedTagRenderings from "../SharedTagRenderings";
|
||||||
import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
|
import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
|
||||||
|
@ -25,6 +24,7 @@ export default class LayerConfig {
|
||||||
iconSize: TagRenderingConfig;
|
iconSize: TagRenderingConfig;
|
||||||
color: TagRenderingConfig;
|
color: TagRenderingConfig;
|
||||||
width: TagRenderingConfig;
|
width: TagRenderingConfig;
|
||||||
|
dashArray: TagRenderingConfig;
|
||||||
|
|
||||||
|
|
||||||
wayHandling: number;
|
wayHandling: number;
|
||||||
|
@ -54,11 +54,12 @@ export default class LayerConfig {
|
||||||
this.wayHandling = json.wayHandling ?? 0;
|
this.wayHandling = json.wayHandling ?? 0;
|
||||||
this.hideUnderlayingFeaturesMinPercentage = json.hideUnderlayingFeaturesMinPercentage ?? 0;
|
this.hideUnderlayingFeaturesMinPercentage = json.hideUnderlayingFeaturesMinPercentage ?? 0;
|
||||||
this.title = new TagRenderingConfig(json.title);
|
this.title = new TagRenderingConfig(json.title);
|
||||||
this.presets = (json.presets ?? []).map(pr => ({
|
this.presets = (json.presets ?? []).map(pr =>
|
||||||
title: Translations.T(pr.title),
|
({
|
||||||
tags: pr.tags.map(t => FromJSON.SimpleTag(t)),
|
title: Translations.T(pr.title),
|
||||||
description: Translations.T(pr.description)
|
tags: pr.tags.map(t => FromJSON.SimpleTag(t)),
|
||||||
}))
|
description: Translations.T(pr.description)
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -108,6 +109,7 @@ export default class LayerConfig {
|
||||||
this.iconSize = tr("iconSize", "40,40,center");
|
this.iconSize = tr("iconSize", "40,40,center");
|
||||||
this.color = tr("color", "#0000ff");
|
this.color = tr("color", "#0000ff");
|
||||||
this.width = tr("width", "7");
|
this.width = tr("width", "7");
|
||||||
|
this.dashArray = tr("dashArray", "");
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,13 @@ export interface LayerConfigJson {
|
||||||
*/
|
*/
|
||||||
width?: string | TagRenderingConfigJson;
|
width?: string | TagRenderingConfigJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dasharray, e.g. "5 6"
|
||||||
|
* The dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',
|
||||||
|
* Default value: "" (empty string == full line)
|
||||||
|
*/
|
||||||
|
dashArray?: string | TagRenderingConfigJson
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wayhandling: should a way/area be displayed as:
|
* Wayhandling: should a way/area be displayed as:
|
||||||
* 0) The way itself
|
* 0) The way itself
|
||||||
|
|
|
@ -56,6 +56,9 @@ export class FilteredLayer {
|
||||||
|
|
||||||
const iconUrl = layerDef.icon?.GetRenderValue(tags)?.txt ?? "./assets/bug.svg";
|
const iconUrl = layerDef.icon?.GetRenderValue(tags)?.txt ?? "./assets/bug.svg";
|
||||||
const iconSize = (layerDef.iconSize?.GetRenderValue(tags)?.txt ?? "40,40,center").split(",");
|
const iconSize = (layerDef.iconSize?.GetRenderValue(tags)?.txt ?? "40,40,center").split(",");
|
||||||
|
|
||||||
|
|
||||||
|
const dashArray = layerDef.dashArray.GetRenderValue(tags)?.txt.split(" ").map(Number);
|
||||||
|
|
||||||
function num(str, deflt = 40) {
|
function num(str, deflt = 40) {
|
||||||
const n = Number(str);
|
const n = Number(str);
|
||||||
|
@ -97,7 +100,8 @@ export class FilteredLayer {
|
||||||
popupAnchor: [0, 3 - anchorH]
|
popupAnchor: [0, 3 - anchorH]
|
||||||
},
|
},
|
||||||
color: color,
|
color: color,
|
||||||
weight: weight
|
weight: weight,
|
||||||
|
dashArray: dashArray
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
|
@ -2,6 +2,8 @@ import {GeoOperations} from "./GeoOperations";
|
||||||
import CodeGrid from "./Web/CodeGrid";
|
import CodeGrid from "./Web/CodeGrid";
|
||||||
import State from "../State";
|
import State from "../State";
|
||||||
import opening_hours from "opening_hours";
|
import opening_hours from "opening_hours";
|
||||||
|
import {And, Or, Tag} from "./Tags";
|
||||||
|
import {Utils} from "../Utils";
|
||||||
|
|
||||||
|
|
||||||
class SimpleMetaTagger {
|
class SimpleMetaTagger {
|
||||||
|
@ -40,90 +42,201 @@ class SimpleMetaTagger {
|
||||||
export default class MetaTagging {
|
export default class MetaTagging {
|
||||||
|
|
||||||
|
|
||||||
|
private static latlon = new SimpleMetaTagger(["_lat", "_lon"], "The latitude and longitude of the point (or centerpoint in the case of a way/area)",
|
||||||
|
(feature => {
|
||||||
|
const centerPoint = GeoOperations.centerpoint(feature);
|
||||||
|
const lat = centerPoint.geometry.coordinates[1];
|
||||||
|
const lon = centerPoint.geometry.coordinates[0];
|
||||||
|
feature.properties["_lat"] = "" + lat;
|
||||||
|
feature.properties["_lon"] = "" + lon;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
private static surfaceArea = new SimpleMetaTagger(
|
||||||
|
["_surface", "_surface:ha"], "The surface area of the feature, in square meters and in hectare. Not set on points and ways",
|
||||||
|
(feature => {
|
||||||
|
const sqMeters = GeoOperations.surfaceAreaInSqMeters(feature);
|
||||||
|
feature.properties["_surface"] = "" + sqMeters;
|
||||||
|
feature.properties["_surface:ha"] = "" + Math.floor(sqMeters / 1000) / 10;
|
||||||
|
|
||||||
|
})
|
||||||
|
);
|
||||||
|
private static country = new SimpleMetaTagger(
|
||||||
|
["_country"], "The country code of the point",
|
||||||
|
((feature, index) => {
|
||||||
|
const centerPoint = GeoOperations.centerpoint(feature);
|
||||||
|
const lat = centerPoint.geometry.coordinates[1];
|
||||||
|
const lon = centerPoint.geometry.coordinates[0]
|
||||||
|
// But the codegrid SHOULD be a number!
|
||||||
|
CodeGrid.getCode(lat, lon, (error, code) => {
|
||||||
|
if (error === null) {
|
||||||
|
feature.properties["_country"] = code;
|
||||||
|
|
||||||
|
// There is a huge performance issue: if there are ~1000 features receiving a ping at the same time,
|
||||||
|
// The application hangs big time
|
||||||
|
// So we disable pinging all together
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.warn("Could not determine country for", feature.properties.id, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
)
|
||||||
|
private static isOpen = new SimpleMetaTagger(
|
||||||
|
["_isOpen", "_isOpen:description"], "If 'opening_hours' is present, it will add the current state of the feature (being 'yes' or 'no",
|
||||||
|
(feature => {
|
||||||
|
const tagsSource = State.state.allElements.addOrGetElement(feature);
|
||||||
|
tagsSource.addCallback(tags => {
|
||||||
|
|
||||||
|
if (tags["opening_hours"] !== undefined && tags["_country"] !== undefined) {
|
||||||
|
|
||||||
|
if (tags._isOpen !== undefined) {
|
||||||
|
// Already defined
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oh = new opening_hours(tags["opening_hours"], {
|
||||||
|
lat: tags._lat,
|
||||||
|
lon: tags._lon,
|
||||||
|
address: {
|
||||||
|
country_code: tags._country
|
||||||
|
}
|
||||||
|
}, {tag_key: "opening_hours"});
|
||||||
|
|
||||||
|
const updateTags = () => {
|
||||||
|
tags["_isOpen"] = oh.getState() ? "yes" : "no";
|
||||||
|
const comment = oh.getComment();
|
||||||
|
if (comment) {
|
||||||
|
tags["_isOpen:description"] = comment;
|
||||||
|
}
|
||||||
|
const nextChange = oh.getNextChange() as Date;
|
||||||
|
if (nextChange !== undefined) {
|
||||||
|
window.setTimeout(
|
||||||
|
updateTags,
|
||||||
|
(nextChange.getTime() - (new Date()).getTime())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
public static carriageWayWidth = new SimpleMetaTagger(
|
||||||
|
["_width:needed","_width:needed:no_pedestrians", "_width:difference"],
|
||||||
|
"Legacy for a specific project calculating the needed width for safe traffic on a road",
|
||||||
|
(feature: any, index: number) => {
|
||||||
|
|
||||||
|
const carWidth = 2;
|
||||||
|
const cyclistWidth = 1.5;
|
||||||
|
const pedestrianWidth = 0.75;
|
||||||
|
|
||||||
|
const properties = feature.properties;
|
||||||
|
|
||||||
|
const _leftSideParking =
|
||||||
|
new And([new Tag("parking:lane:left", "parallel"), new Tag("parking:lane:right", "no_parking")]);
|
||||||
|
const _rightSideParking =
|
||||||
|
new And([new Tag("parking:lane:right", "parallel"), new Tag("parking:lane:left", "no_parking")]);
|
||||||
|
|
||||||
|
const _bothSideParking = new Tag("parking:lane:both", "parallel");
|
||||||
|
const _noSideParking = new Tag("parking:lane:both", "no_parking");
|
||||||
|
const _otherParkingMode =
|
||||||
|
new Or([
|
||||||
|
new Tag("parking:lane:both", "perpendicular"),
|
||||||
|
new Tag("parking:lane:left", "perpendicular"),
|
||||||
|
new Tag("parking:lane:right", "perpendicular"),
|
||||||
|
new Tag("parking:lane:both", "diagonal"),
|
||||||
|
new Tag("parking:lane:left", "diagonal"),
|
||||||
|
new Tag("parking:lane:right", "diagonal"),
|
||||||
|
])
|
||||||
|
|
||||||
|
const _sidewalkBoth = new Tag("sidewalk", "both");
|
||||||
|
const _sidewalkLeft = new Tag("sidewalk", "left");
|
||||||
|
const _sidewalkRight = new Tag("sidewalk", "right");
|
||||||
|
const _sidewalkNone = new Tag("sidewalk", "none");
|
||||||
|
|
||||||
|
|
||||||
|
let parkingStateKnown = true;
|
||||||
|
let parallelParkingCount = 0;
|
||||||
|
|
||||||
|
|
||||||
|
const _oneSideParking = new Or([_leftSideParking, _rightSideParking]);
|
||||||
|
|
||||||
|
if (_oneSideParking.matchesProperties(properties)) {
|
||||||
|
parallelParkingCount = 1;
|
||||||
|
} else if (_bothSideParking.matchesProperties(properties)) {
|
||||||
|
parallelParkingCount = 2;
|
||||||
|
} else if (_noSideParking.matchesProperties(properties)) {
|
||||||
|
parallelParkingCount = 0;
|
||||||
|
} else if (_otherParkingMode.matchesProperties(properties)) {
|
||||||
|
parallelParkingCount = 0;
|
||||||
|
} else {
|
||||||
|
parkingStateKnown = false;
|
||||||
|
console.log("No parking data for ", properties.name, properties.id, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let pedestrianFlowNeeded;
|
||||||
|
if (_sidewalkBoth.matchesProperties(properties)) {
|
||||||
|
pedestrianFlowNeeded = 0;
|
||||||
|
} else if (_sidewalkNone.matchesProperties(properties)) {
|
||||||
|
pedestrianFlowNeeded = 2;
|
||||||
|
} else if (_sidewalkLeft.matchesProperties(properties) || _sidewalkRight.matchesProperties(properties)) {
|
||||||
|
pedestrianFlowNeeded = 1;
|
||||||
|
} else {
|
||||||
|
pedestrianFlowNeeded = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let onewayCar = properties.oneway === "yes";
|
||||||
|
let onewayBike = properties["oneway:bicycle"] === "yes" ||
|
||||||
|
(onewayCar && properties["oneway:bicycle"] === undefined)
|
||||||
|
|
||||||
|
let cyclingAllowed =
|
||||||
|
!(properties.bicycle === "use_sidepath"
|
||||||
|
|| properties.bicycle === "no");
|
||||||
|
|
||||||
|
let carWidthUsed = (onewayCar ? 1 : 2) * carWidth;
|
||||||
|
properties["_width:needed:cars"] = Utils.Round(carWidthUsed);
|
||||||
|
properties["_width:needed:parking"] = Utils.Round(parallelParkingCount * carWidth)
|
||||||
|
|
||||||
|
|
||||||
|
let cyclistWidthUsed = 0;
|
||||||
|
if (cyclingAllowed) {
|
||||||
|
cyclistWidthUsed = (onewayBike ? 1 : 2) * cyclistWidth;
|
||||||
|
}
|
||||||
|
properties["_width:needed:cyclists"] = Utils.Round(cyclistWidthUsed)
|
||||||
|
|
||||||
|
|
||||||
|
const width = parseFloat(properties["width:carriageway"]);
|
||||||
|
|
||||||
|
|
||||||
|
const targetWidthIgnoringPedestrians =
|
||||||
|
carWidthUsed +
|
||||||
|
cyclistWidthUsed +
|
||||||
|
parallelParkingCount * carWidthUsed;
|
||||||
|
properties["_width:needed:no_pedestrians"] =Utils.Round(targetWidthIgnoringPedestrians);
|
||||||
|
|
||||||
|
const pedestriansNeed = Math.max(0, pedestrianFlowNeeded) * pedestrianWidth;
|
||||||
|
const targetWidth = targetWidthIgnoringPedestrians + pedestriansNeed ;
|
||||||
|
properties["_width:needed"] = Utils.Round(targetWidth);
|
||||||
|
properties["_width:needed:pedestrians"] = Utils.Round(pedestriansNeed)
|
||||||
|
|
||||||
|
|
||||||
|
properties["_width:difference"] = Utils.Round(targetWidth - width );
|
||||||
|
properties["_width:difference:no_pedestrians"] = Utils.Round(targetWidthIgnoringPedestrians - width) ;
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
public static metatags = [
|
public static metatags = [
|
||||||
new SimpleMetaTagger(["_lat", "_lon"], "The latitude and longitude of the point (or centerpoint in the case of a way/area)",
|
MetaTagging.latlon,
|
||||||
(feature => {
|
MetaTagging.surfaceArea,
|
||||||
const centerPoint = GeoOperations.centerpoint(feature);
|
MetaTagging.country,
|
||||||
const lat = centerPoint.geometry.coordinates[1];
|
MetaTagging.isOpen,
|
||||||
const lon = centerPoint.geometry.coordinates[0];
|
MetaTagging.carriageWayWidth
|
||||||
feature.properties["_lat"] = "" + lat;
|
|
||||||
feature.properties["_lon"] = "" + lon;
|
|
||||||
})
|
|
||||||
),
|
|
||||||
new SimpleMetaTagger(
|
|
||||||
["_surface", "_surface:ha"], "The surface area of the feature, in square meters and in hectare. Not set on points and ways",
|
|
||||||
(feature => {
|
|
||||||
const sqMeters = GeoOperations.surfaceAreaInSqMeters(feature);
|
|
||||||
feature.properties["_surface"] = "" + sqMeters;
|
|
||||||
feature.properties["_surface:ha"] = "" + Math.floor(sqMeters / 1000) / 10;
|
|
||||||
|
|
||||||
})
|
|
||||||
),
|
|
||||||
|
|
||||||
|
|
||||||
new SimpleMetaTagger(
|
|
||||||
["_country"], "The country code of the point",
|
|
||||||
((feature, index) => {
|
|
||||||
const centerPoint = GeoOperations.centerpoint(feature);
|
|
||||||
const lat = centerPoint.geometry.coordinates[1];
|
|
||||||
const lon = centerPoint.geometry.coordinates[0]
|
|
||||||
// But the codegrid SHOULD be a number!
|
|
||||||
CodeGrid.getCode(lat, lon, (error, code) => {
|
|
||||||
if (error === null) {
|
|
||||||
feature.properties["_country"] = code;
|
|
||||||
|
|
||||||
// There is a huge performance issue: if there are ~1000 features receiving a ping at the same time,
|
|
||||||
// The application hangs big time
|
|
||||||
// So we disable pinging all together
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.warn("Could not determine country for", feature.properties.id, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
),
|
|
||||||
new SimpleMetaTagger(
|
|
||||||
["_isOpen", "_isOpen:description"], "If 'opening_hours' is present, it will add the current state of the feature (being 'yes' or 'no",
|
|
||||||
(feature => {
|
|
||||||
const tagsSource = State.state.allElements.addOrGetElement(feature);
|
|
||||||
tagsSource.addCallback(tags => {
|
|
||||||
|
|
||||||
if (tags["opening_hours"] !== undefined && tags["_country"] !== undefined) {
|
|
||||||
|
|
||||||
if (tags._isOpen !== undefined) {
|
|
||||||
// Already defined
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const oh = new opening_hours(tags["opening_hours"], {
|
|
||||||
lat: tags._lat,
|
|
||||||
lon: tags._lon,
|
|
||||||
address: {
|
|
||||||
country_code: tags._country
|
|
||||||
}
|
|
||||||
}, {tag_key: "opening_hours"});
|
|
||||||
|
|
||||||
const updateTags = () => {
|
|
||||||
tags["_isOpen"] = oh.getState() ? "yes" : "no";
|
|
||||||
const comment = oh.getComment();
|
|
||||||
if (comment) {
|
|
||||||
tags["_isOpen:description"] = comment;
|
|
||||||
}
|
|
||||||
const nextChange = oh.getNextChange() as Date;
|
|
||||||
if (nextChange !== undefined) {
|
|
||||||
window.setTimeout(
|
|
||||||
updateTags,
|
|
||||||
(nextChange.getTime() - (new Date()).getTime())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateTags();
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
static addMetatags(features: any[]) {
|
static addMetatags(features: any[]) {
|
||||||
|
|
|
@ -15,9 +15,9 @@ import {TagRenderingConfigJson} from "../../Customizations/JSON/TagRenderingConf
|
||||||
import {UserDetails} from "../../Logic/Osm/OsmConnection";
|
import {UserDetails} from "../../Logic/Osm/OsmConnection";
|
||||||
import State from "../../State";
|
import State from "../../State";
|
||||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||||
import {FromJSON} from "../../Customizations/JSON/FromJSON";
|
|
||||||
import ValidatedTextField from "../Input/ValidatedTextField";
|
import ValidatedTextField from "../Input/ValidatedTextField";
|
||||||
import SpecialVisualizations from "../SpecialVisualizations";
|
import SpecialVisualizations from "../SpecialVisualizations";
|
||||||
|
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||||
|
|
||||||
export default class TagRenderingPanel extends InputElement<TagRenderingConfigJson> {
|
export default class TagRenderingPanel extends InputElement<TagRenderingConfigJson> {
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ export default class TagRenderingPanel extends InputElement<TagRenderingConfigJs
|
||||||
|
|
||||||
this.validText = new VariableUiElement(value.map((json: TagRenderingConfigJson) => {
|
this.validText = new VariableUiElement(value.map((json: TagRenderingConfigJson) => {
|
||||||
try{
|
try{
|
||||||
FromJSON.TagRendering(json, options?.title ?? "");
|
new TagRenderingConfig(json, options?.title ?? "");
|
||||||
return "";
|
return "";
|
||||||
}catch(e){
|
}catch(e){
|
||||||
return "<span class='alert'>"+e+"</span>"
|
return "<span class='alert'>"+e+"</span>"
|
||||||
|
|
|
@ -2,9 +2,10 @@ import {UIElement} from "../UIElement";
|
||||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||||
import TagRenderingPanel from "./TagRenderingPanel";
|
import TagRenderingPanel from "./TagRenderingPanel";
|
||||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||||
import {FromJSON} from "../../Customizations/JSON/FromJSON";
|
|
||||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||||
import Combine from "../Base/Combine";
|
import Combine from "../Base/Combine";
|
||||||
|
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||||
|
import EditableTagRendering from "../Popup/EditableTagRendering";
|
||||||
|
|
||||||
export default class TagRenderingPreview extends UIElement {
|
export default class TagRenderingPreview extends UIElement {
|
||||||
|
|
||||||
|
@ -39,8 +40,7 @@ export default class TagRenderingPreview extends UIElement {
|
||||||
rendering =
|
rendering =
|
||||||
new VariableUiElement(es.map(tagRenderingConfig => {
|
new VariableUiElement(es.map(tagRenderingConfig => {
|
||||||
try {
|
try {
|
||||||
const tr = FromJSON.TagRendering(tagRenderingConfig, "preview")
|
const tr = new EditableTagRendering(self.previewTagValue, new TagRenderingConfig(tagRenderingConfig, "preview"));
|
||||||
.construct(self.previewTagValue);
|
|
||||||
return tr.Render();
|
return tr.Render();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return new Combine(["Could not show this tagrendering:", e.message]).Render();
|
return new Combine(["Could not show this tagrendering:", e.message]).Render();
|
||||||
|
|
|
@ -46,10 +46,12 @@ export class SimpleAddUI extends UIElement {
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
for (const layer of State.state.filteredLayers.data) {
|
for (const layer of State.state.filteredLayers.data) {
|
||||||
|
|
||||||
this.ListenTo(layer.isDisplayed);
|
this.ListenTo(layer.isDisplayed);
|
||||||
|
|
||||||
for (const preset of layer.layerDef.presets) {
|
const presets = layer.layerDef.presets;
|
||||||
|
for (const preset of presets) {
|
||||||
|
console.log("Preset:", preset)
|
||||||
|
|
||||||
let icon: string = layer.layerDef.icon.GetRenderValue(
|
let icon: string = layer.layerDef.icon.GetRenderValue(
|
||||||
TagUtils.KVtoProperties(preset.tags ?? [])).txt ??
|
TagUtils.KVtoProperties(preset.tags ?? [])).txt ??
|
||||||
|
|
11
Utils.ts
11
Utils.ts
|
@ -39,6 +39,17 @@ export class Utils {
|
||||||
return "" + i;
|
return "" + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Round(i: number) {
|
||||||
|
if(i < 0){
|
||||||
|
return "-" + Utils.Round(-i);
|
||||||
|
}
|
||||||
|
const j = "" + Math.floor(i * 10);
|
||||||
|
if (j.length == 1) {
|
||||||
|
return "0." + j;
|
||||||
|
}
|
||||||
|
return j.substr(0, j.length - 1) + "." + j.substr(j.length - 1, j.length);
|
||||||
|
}
|
||||||
|
|
||||||
public static Times(f: ((i: number) => string), count: number): string {
|
public static Times(f: ((i: number) => string), count: number): string {
|
||||||
let res = "";
|
let res = "";
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
|
|
204
assets/themes/widths/width.json
Normal file
204
assets/themes/widths/width.json
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
{
|
||||||
|
"id": "width",
|
||||||
|
"title": {
|
||||||
|
"nl": "Straatbreedtes"
|
||||||
|
},
|
||||||
|
"shortDescription": {
|
||||||
|
"nl": "Is de straat breed genoeg?"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"nl": " <h3>De straat is opgebruikt</h3>\n <p>Er is steeds meer druk op de openbare ruimte. Voetgangers, fietsers, steps, auto's, bussen, bestelwagens, buggies, cargobikes, ... willen allemaal hun deel van de openbare ruimte.</p>\n <p>In deze studie nemen we Brugge onder de loep en kijken we hoe breed elke straat is én hoe breed elke straat zou moeten zijn voor een veilig én vlot verkeer.</p>\n <h3>Legende</h3>\n <span style='background: red'>   </span> Straat te smal voor veilig verkeer<br/>\n <span style='background: #0f0'>   </span> Straat is breed genoeg veilig verkeer<br/>\n <span style='background: orange'>   </span> Straat zonder voetpad, te smal als ook voetgangers plaats krijgen<br/>\n <span style='background: lightgrey'>   </span> Woonerf, autoluw, autoloos of enkel plaatselijk verkeer<br/>\n <br/>\n <br/>\n Een gestippelde lijn is een straat waar ook voor fietsers éénrichtingsverkeer geldt.<br/>\n Klik op een straat om meer informatie te zien.\n <h3>Hoe gaan we verder?</h3>\n Verschillende ingrepen kunnen de stad teruggeven aan de inwoners en de stad leefbaarder en levendiger maken.<br/>\n Denk aan:\n <ul>\n <li>De autovrije zone's uitbreiden</li>\n <li>De binnenstad fietszone maken</li>\n <li>Het aantal woonerven uitbreiden</li>\n <li>Grotere auto's meer belasten - ze nemen immers meer parkeerruimte in.</li>\n <li>Laat toeristen verplicht parkeren onder het zand; een (fiets)taxi kan hen naar hun hotel brengen</li>\n <li>Voorzie in elke straat enkele parkeerplaatsen voor kortparkeren. Zo kunnen leveringen, iemand afzetten,... gebeuren zonder op het voetpad en fietspad te parkeren</li>\n </ul>\""
|
||||||
|
},
|
||||||
|
"language": [
|
||||||
|
"nl"
|
||||||
|
],
|
||||||
|
"maintainer": "",
|
||||||
|
"icon": "./assets/themes/widths/icon.svg",
|
||||||
|
"version": "0",
|
||||||
|
"startLat": 51.20875,
|
||||||
|
"startLon": 3.22435,
|
||||||
|
"startZoom": 14,
|
||||||
|
"widenFactor": 0.05,
|
||||||
|
"socialImage": "",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"id": "widths",
|
||||||
|
"name": {
|
||||||
|
"nl": "Straten met een breedte"
|
||||||
|
},
|
||||||
|
"minzoom": 14,
|
||||||
|
"overpassTags": {
|
||||||
|
"and": [
|
||||||
|
"width:carriageway~*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"titleIcons": [],
|
||||||
|
"title": {
|
||||||
|
"render": {
|
||||||
|
"nl": "{name}"
|
||||||
|
},
|
||||||
|
"condition": {
|
||||||
|
"and": []
|
||||||
|
},
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"and": [
|
||||||
|
"name="
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"then": {
|
||||||
|
"nl": "Naamloos segmet"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": {},
|
||||||
|
"tagRenderings": [
|
||||||
|
{
|
||||||
|
"render": "Deze straat is <b>{width:carriageway}m</b> breed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"render": "Deze straat heeft <span class='alert'>{_width:difference}m</span> te weinig:",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"or": [
|
||||||
|
"_width:difference~-.*",
|
||||||
|
"_width:difference=0.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"then": "Deze straat is breed genoeg:"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"render": "<b>{_width:needed:cars}m</b> voor het autoverkeer",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": "oneway=yes",
|
||||||
|
"then": "<b>{_width:needed:cars}m</b> voor het éénrichtings-autoverkeer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "oneway=no",
|
||||||
|
"then": "<b>{_width:needed:cars}m</b> voor het tweerichtings-autoverkeer"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"render": "<b>{_width:needed:parking}m</b> voor het geparkeerde wagens",
|
||||||
|
"condition": "_width:needed:parking!=0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"render": "<b>{_width:needed:cyclists}m</b> voor fietsers",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": "bicycle=use_sidepath",
|
||||||
|
"then": "Fietsers hebben hier een vrijliggend fietspad en worden dus niet meegerekend"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "oneway:bicycle=yes",
|
||||||
|
"then": "<b>{_width:needed:cyclists}m</b> voor fietsers, die met de rijrichting mee moeten"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"render": "<b>{_width:needed:pedestrians}m</b> voor voetgangers",
|
||||||
|
"condition": "_width:needed:pedestrians!=0.0",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"or": [
|
||||||
|
"sidewalk=none",
|
||||||
|
"sidewalk=no"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"then": "<b>{_width:needed:pedestrians}m</b> voor voetgangers: er zijn hier geen voetpaden"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"or": [
|
||||||
|
"sidewalk=left",
|
||||||
|
"sidewalk=right"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"then": "<b>{_width:needed:pedestrians}m</b> voor voetgangers: er is slechts aan één kant een voetpad"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"render": "<span style='border: 1px solid black; border-radius: 0.5em; padding: 0.25em;'><b>{_width:needed}m</b> nodig in het totaal</span>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"render": "{all_tags()}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||||
|
"icon": {
|
||||||
|
"render": "./assets/themes/widths/icon.svg"
|
||||||
|
},
|
||||||
|
"width": {
|
||||||
|
"render": "4"
|
||||||
|
},
|
||||||
|
"iconSize": {
|
||||||
|
"render": "40,40,center"
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"render": "#00f",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"or": [
|
||||||
|
"access=destination",
|
||||||
|
"highway=living_street",
|
||||||
|
"highway=pedestrian",
|
||||||
|
"motor_vehicle=no",
|
||||||
|
"motor_vehicle=destination"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"then": "lightgrey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "_width:difference~-.*",
|
||||||
|
"then": "#0f0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"and": [
|
||||||
|
"_width:difference!~-.*",
|
||||||
|
"_width:difference:no_pedestrians~-.*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"then": "orange"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "_width:difference!~-.*",
|
||||||
|
"then": "#f00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dashArray": {
|
||||||
|
"render": "",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"and": [
|
||||||
|
"oneway=yes",
|
||||||
|
{
|
||||||
|
"or": [
|
||||||
|
"oneway:bicycle=yes",
|
||||||
|
"oneway:bicycle="
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"then": "5 6"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"presets": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"roamingRenderings": [],
|
||||||
|
"defaultBackgroundId": "Stadia.AlidadeSmoothDark"
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import PublicHolidayInput from "../UI/Input/OpeningHours/PublicHolidayInput";
|
||||||
import TagRenderingConfig from "../Customizations/JSON/TagRenderingConfig";
|
import TagRenderingConfig from "../Customizations/JSON/TagRenderingConfig";
|
||||||
import EditableTagRendering from "../UI/Popup/EditableTagRendering";
|
import EditableTagRendering from "../UI/Popup/EditableTagRendering";
|
||||||
import {SubstitutedTranslation} from "../UI/SpecialVisualizations";
|
import {SubstitutedTranslation} from "../UI/SpecialVisualizations";
|
||||||
|
import {Utils} from "../Utils";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -323,5 +324,19 @@ new T([
|
||||||
["OH Parse PH 12:00-17:00", () => {
|
["OH Parse PH 12:00-17:00", () => {
|
||||||
const rules = PublicHolidayInput.LoadValue("PH 12:00-17:00");
|
const rules = PublicHolidayInput.LoadValue("PH 12:00-17:00");
|
||||||
equal(rules.mode, " ");
|
equal(rules.mode, " ");
|
||||||
|
}],
|
||||||
|
["Round", () => {
|
||||||
|
equal(Utils.Round(15), "15.0")
|
||||||
|
equal(Utils.Round(1), "1.0")
|
||||||
|
equal(Utils.Round(1.5), "1.5")
|
||||||
|
equal(Utils.Round(0.5), "0.5")
|
||||||
|
equal(Utils.Round(1.6), "1.6")
|
||||||
|
|
||||||
|
equal(Utils.Round(-15), "-15.0")
|
||||||
|
equal(Utils.Round(-1), "-1.0")
|
||||||
|
equal(Utils.Round(-1.5), "-1.5")
|
||||||
|
equal(Utils.Round(-0.5), "-0.5")
|
||||||
|
equal(Utils.Round(-1.6), "-1.6")
|
||||||
|
|
||||||
}]
|
}]
|
||||||
]);
|
]);
|
||||||
|
|
Loading…
Reference in a new issue