diff --git a/proxy/css/ui.css b/proxy/css/ui.css
index 64fc83c9..fe179bae 100644
--- a/proxy/css/ui.css
+++ b/proxy/css/ui.css
@@ -161,3 +161,7 @@ body {
input[type=url] {
font-family: monospace;
}
+
+.badge {
+ white-space: normal;
+}
diff --git a/proxy/js/features.mjs b/proxy/js/features.mjs
index 1bec0a70..a07413ad 100644
--- a/proxy/js/features.mjs
+++ b/proxy/js/features.mjs
@@ -33,19 +33,7 @@ const generateSignalFeatures = features =>
),
));
-const trainProtection = signals_railway_line.train_protections.map(feature => ({
- feature: feature.train_protection,
- description: feature.legend,
-}));
-
-const loadingGauges = loading_gauges.loading_gauges.map(feature => ({
- feature: feature.value,
- description: feature.legend,
-}));
-
// TODO move icon SVGs to proxy
-// TODO lookup train protection name
-// TODO lookup loading gauge
const railwayLineFeatures = {
labelProperty: 'standard_label',
features: {
@@ -102,31 +90,86 @@ const railwayLineFeatures = {
type: 'line',
},
},
- // TODO formatting / lookup table of values
properties: {
// TODO replace railway with `state`
- railway: 'Railway',
- usage: 'Usage',
- service: 'Service',
- highspeed: 'Highspeed',
- preferred_direction: 'Preferred direction',
- tunnel: 'Tunnel',
- bridge: 'Bridge',
- ref: 'Reference',
- track_ref: 'Track',
- speed_label: 'Speed',
- train_protection: 'Train protection',
- electrification_state: 'Electrification',
- // TODO format with 2 digits and Hz
- frequency: 'Frequency',
- // TODO format with V
- voltage: 'Voltage',
- future_frequency: 'Future frequency',
- future_voltage: 'Future voltage',
- gauge_label: 'Gauge',
- loading_gauge: 'Loading gauge',
- track_class: 'Track class',
- reporting_marks: 'Reporting marks',
+ railway: {
+ name: 'Railway',
+ },
+ usage: {
+ name: 'Usage',
+ },
+ service: {
+ name: 'Service',
+ },
+ highspeed: {
+ name: 'Highspeed',
+ },
+ preferred_direction: {
+ name: 'Preferred direction',
+ },
+ tunnel: {
+ name: 'Tunnel',
+ },
+ bridge: {
+ name: 'Bridge',
+ },
+ ref: {
+ name: 'Reference',
+ },
+ track_ref: {
+ name: 'Track',
+ },
+ speed_label: {
+ name: 'Speed',
+ },
+ train_protection: {
+ name: 'Train protection',
+ format: {
+ lookup: 'train_protection',
+ }
+ },
+ electrification_state: {
+ name: 'Electrification',
+ },
+ frequency: {
+ name: 'Frequency',
+ format: {
+ template: '%.2d Hz',
+ },
+ },
+ voltage: {
+ name: 'Voltage',
+ format: {
+ template: '%d V',
+ },
+ },
+ future_frequency: {
+ name: 'Future frequency',
+ format: {
+ template: '%.2d Hz',
+ },
+ },
+ future_voltage: {
+ name: 'Future voltage',
+ format: {
+ template: '%d V',
+ },
+ },
+ gauge_label: {
+ name: 'Gauge',
+ },
+ loading_gauge: {
+ name: 'Loading gauge',
+ format: {
+ lookup: 'loading_gauge',
+ },
+ },
+ track_class: {
+ name: 'Track class',
+ },
+ reporting_marks: {
+ name: 'Reporting marks',
+ },
// TODO import operator
},
};
@@ -139,14 +182,16 @@ const stationFeatures = {
stations.features.map(feature => [feature.feature, {name: feature.description}])
),
properties: {
- station: 'Type',
- label: 'Reference',
+ station: {
+ name: 'Type',
+ },
+ label: {
+ name: 'Reference',
+ },
// TODO Add UIC ref
},
}
-// TODO add properties for use in labels
-// TODO add name / label property of feature
// TODO move examples here
// TODO add icon
const features = {
@@ -193,7 +238,9 @@ const features = {
},
},
properties: {
- pos: 'Position',
+ pos: {
+ name: 'Position',
+ },
},
},
'openrailwaymap_standard-standard_railway_switch_ref': {
@@ -207,7 +254,9 @@ const features = {
}
},
properties: {
- railway_local_operated: 'Operated locally',
+ railway_local_operated: {
+ name: 'Operated locally',
+ },
},
},
'openrailwaymap_speed-speed_railway_signals': {
@@ -223,10 +272,18 @@ const features = {
'openrailwaymap_signals-signals_railway_signals': {
features: generateSignalFeatures(signals_railway_signals.features),
properties: {
- direction_both: 'both directions',
- ref: 'Reference',
- type: 'Type',
- deactivated: 'Deactivated',
+ direction_both: {
+ name: 'both directions',
+ },
+ ref: {
+ name: 'Reference',
+ },
+ type: {
+ name: 'Type',
+ },
+ deactivated: {
+ name: 'Deactivated',
+ },
},
},
'openrailwaymap_signals-signals_signal_boxes': {
@@ -243,20 +300,47 @@ const features = {
}
},
properties: {
- ref: 'Reference',
+ ref: {
+ name: 'Reference',
+ },
},
},
'openrailwaymap_electrification-electrification_signals': {
features: generateSignalFeatures(electrification_signals.features),
properties: {
- direction_both: 'both directions',
- ref: 'Reference',
- type: 'Type',
+ direction_both: {
+ name: 'both directions',
+ },
+ ref: {
+ name: 'Reference',
+ },
+ type: {
+ name: 'Type',
+ },
// TODO add deactivated
// TODO add voltage
// TODO add frequency
},
},
+
+ // Features not part of a data source but for lookups
+
+ train_protection: {
+ features: Object.fromEntries(signals_railway_line.train_protections.map(feature => [
+ feature.train_protection,
+ {
+ name: feature.legend,
+ },
+ ])),
+ },
+ loading_gauge: {
+ features: Object.fromEntries(loading_gauges.loading_gauges.map(feature => [
+ feature.value,
+ {
+ name: feature.legend,
+ },
+ ])),
+ },
};
if (import.meta.url.endsWith(process.argv[1])) {
diff --git a/proxy/js/ui.js b/proxy/js/ui.js
index 5ad0010b..32d14807 100644
--- a/proxy/js/ui.js
+++ b/proxy/js/ui.js
@@ -703,8 +703,32 @@ function popupContent(feature) {
const featureType = featureContent && featureContent.type || 'point';
const osmType = featureType === 'point' ? 'node' : 'way';
+ const formatPropertyValue = (value, format) => {
+ if (!format) {
+ return String(value);
+ } else if (format.template) {
+ return format.template.replace('%s', () => String(value)).replace(/%(\.(\d+))?d/, (_1, _2, decimals) => value.toFixed(Number(decimals)));
+ } else if (format.lookup) {
+ const lookupCatalog = features && features[format.lookup];
+ if (!lookupCatalog) {
+ console.warn('Lookup catalog', format.lookup, 'not found for feature', feature);
+ return String(value);
+ } else {
+ const lookedUpValue = lookupCatalog.features[value];
+ if (!lookedUpValue) {
+ console.warn('Lookup catalog', format.lookup, 'did not contain value', value, 'for feature', feature);
+ return String(value);
+ } else {
+ return lookedUpValue.name;
+ }
+ }
+ } else {
+ return String(value);
+ }
+ }
+
const propertyValues = Object.entries(featureCatalog.properties || {})
- .map(([property, description]) => properties[property] ? `${description}${properties[property] === true ? '' : `: ${properties[property]}`}` : '')
+ .map(([property, {name, format}]) => (properties[property] !== undefined && properties[property] !== null && properties[property] !== '' && properties[property] !== false) ? `${name}${properties[property] === true ? '' : `: ${formatPropertyValue(properties[property], format)}`}` : '')
.filter(it => it)
.join('')