only render Elements in renderData

This commit is contained in:
kritzl 2024-06-04 16:08:44 +02:00
parent dc84436346
commit 7673265167

View file

@ -1,3 +1,11 @@
const internalData = {
lastUpdate: 0,
stations: [],
};
let geolocationPermission = false;
let geolocation = [null, null];
Object.defineProperty(String.prototype, 'capitalize', { Object.defineProperty(String.prototype, 'capitalize', {
value: function () { value: function () {
return this.charAt(0).toUpperCase() + this.toLowerCase().slice(1); return this.charAt(0).toUpperCase() + this.toLowerCase().slice(1);
@ -9,7 +17,90 @@ async function loadElevators() {
const res = await fetch('https://www.hvv.de/elevators', {referrer: ""}); const res = await fetch('https://www.hvv.de/elevators', {referrer: ""});
const data = await res.json(); const data = await res.json();
localStorage.setItem("elevator_data", JSON.stringify(data));
const stations = data['stations'];
stations.sort(sortStations)
internalData.lastUpdate = new Date(data['lastUpdate']);
let stationIndex = 0;
for (const station of stations) {
const stationName = station['mainSubStation']['stationName'];
const lines = new Set();
const elevators = [];
for (const elevatorKey of Object.keys(station.elevators)) {
const elevatorApi = station.elevators[elevatorKey];
const elevatorLines = [];
for (let line of elevatorApi.lines) {
line = line.replace(/[()]/g, "");
lines.add(line);
elevatorLines.push({
line: line,
type: getType(line),
});
}
// try to detect levels from description
let levels = [];
if (elevatorApi.description.search('<->') >= 0) {
levels = elevatorApi.description.split('<->').map(level => level.trim());
} else if (elevatorApi.description.search('<>') >= 0) {
levels = elevatorApi.description.split('<>').map(level => level.trim());
} else if (elevatorApi.description.search('/ ') >= 0) {
levels = elevatorApi.description.split('/ ').map(level => level.trim());
}
const elevator = {
working: elevatorApi['state'] === 1,
stateUnavailable: elevatorApi['state'] === -1,
dimensions: {
width: elevatorApi['cabinWidth'],
length: elevatorApi['cabinLength'],
door: elevatorApi['doorWidth'],
},
description: elevatorApi['description'],
label: elevatorApi['label'],
type: elevatorApi['type'].replace('_', ' ').capitalize(),
braille: elevatorApi['tasterType'] === 'UNBEKANNT' ? -1 : elevatorApi['tasterType'] === 'KOMBI' || elevatorApi['tasterType'] === 'BRAILLE',
speaker: elevatorApi['tasterType'] === 'UNBEKANNT' ? -1 : elevatorApi['tasterType'] === 'KOMBI',
lines: elevatorLines,
levels: levels,
instCause: elevatorApi['instCause'],
osmNodeId: elevatorApi['osmId'],
}
elevators.push(elevator);
}
let stationState = {
unavailable: 0,
working: 0,
outOfOrder: 0,
}
for (const elevator of elevators) {
if (elevator.stateUnavailable) {
stationState.unavailable++;
} else if (elevator.working) {
stationState.working++;
} else {
stationState.outOfOrder++;
}
}
const stationLines = Array.from(lines);
const stationTypes = Array.from(getTypes(stationLines));
internalData.stations[stationIndex++] = {
name: stationName,
state: stationState,
lines: stationLines,
types: stationTypes,
elevators: elevators,
}
}
localStorage.setItem("internal_data", JSON.stringify(internalData));
} }
const dateTimeStyle = new Intl.DateTimeFormat('de-DE', { const dateTimeStyle = new Intl.DateTimeFormat('de-DE', {
@ -18,19 +109,11 @@ const dateTimeStyle = new Intl.DateTimeFormat('de-DE', {
timeZone: 'Europe/Berlin', timeZone: 'Europe/Berlin',
}) })
const internalData = []
let geolocationPermission = false;
let geolocation = [null, null];
async function loadOsmData() { async function loadOsmData() {
const elevatorNodes = document.querySelectorAll('.elevator');
const nodeIdList = []; const nodeIdList = [];
for (const elevator of elevatorNodes) { for (const station of internalData.stations) {
const osmContainer = elevator.querySelector('.osm'); for (const elevator of station.elevators) {
const nodeId = osmContainer.dataset.nodeid; nodeIdList.push(elevator.osmNodeId)
if (nodeId > 0) {
elevator.querySelector('.osm').insertAdjacentHTML("beforeend", '<dl class="osmTags">loading...</dl>');
nodeIdList.push(nodeId)
} }
} }
@ -39,44 +122,7 @@ async function loadOsmData() {
if (!osmJson.hasOwnProperty('elements')) return; if (!osmJson.hasOwnProperty('elements')) return;
for (const elevator of elevatorNodes) { localStorage.setItem("osm_data", JSON.stringify(osmJson));
const tagContainer = elevator.querySelector('.osmTags');
const nodeId = elevator.querySelector('.osm').dataset.nodeid;
const nodes = osmJson.elements.filter(node => node.id === parseInt(nodeId))
if (!nodes.length) {
tagContainer.innerHTML = 'keine Daten';
continue;
}
const nodeInfo = nodes[0];
if (!nodeInfo.hasOwnProperty('tags')) {
tagContainer.innerHTML = 'keine Daten';
continue;
}
const tags = nodeInfo['tags'];
if (tags['highway'] === 'elevator') {
let osmTemplate = '';
osmTemplate += `<div><dt><span data-icon="location" class="size-l"></span>Link zur Karte</dt><dd><a href="https://www.openstreetmap.org/node/${nodeId}" target="_blank">
Auf Karte anzeigen
</a></dd></div>`;
if (tags.hasOwnProperty('description')) {
osmTemplate += `<div><dt><span data-icon="info" class="size-l"></span>Beschreibung</dt><dd>${tags['description']}</dd></div>`;
}
if (tags.hasOwnProperty('level')) {
osmTemplate += `<div><dt><span data-icon="up-down" class="size-l"></span>Ebenen</dt><dd>${tags['level'].split(';').sort().join(', ')}</dd></div>`;
}
if (tags.hasOwnProperty('wheelchair')) {
osmTemplate += `<div><dt><span data-icon="wheelchair" class="size-l"></span>Rollstühle</dt><dd>${tags['wheelchair'] === 'yes' ? 'Ja' : 'Nein'}</dd></div>`;
}
if (tags.hasOwnProperty('bicycle')) {
osmTemplate += `<div><dt><span data-icon="bicycle" class="size-l"></span>Fahrräder</dt><dd>${tags['bicycle'] === 'yes' ? 'Ja' : 'Nein'}</dd></div>`;
}
tagContainer.innerHTML = ''; // clear loading state
tagContainer.insertAdjacentHTML('beforeend', osmTemplate);
}
}
} }
function distance([lat1, lon1], [lat2, lon2]) { function distance([lat1, lon1], [lat2, lon2]) {
@ -171,85 +217,34 @@ function getTypes(lines) {
} }
function renderData() { function renderData() {
const data = JSON.parse(localStorage.getItem("elevator_data")); const ls = JSON.parse(localStorage.getItem("internal_data"));
if (!ls) return;
internalData.lastUpdate = ls['lastUpdate'];
internalData.stations = ls['stations'];
const osmData = JSON.parse(localStorage.getItem("osm_data"));
if (!data) { if (!internalData || !internalData.stations.length) {
console.error('No Data available!') console.error('No Data available!')
return; return;
} }
let stations = data.stations;
stations.sort(sortStations)
const date = new Date(data.lastUpdate);
document.querySelector('#loadElevators').innerHTML = 'Daten aktualisieren'; document.querySelector('#loadElevators').innerHTML = 'Daten aktualisieren';
const listContainer = document.querySelector('#stationList');
const dateContainer = document.querySelector('#lastUpdated'); const dateContainer = document.querySelector('#lastUpdated');
dateContainer.innerHTML = dateTimeStyle.format(new Date(internalData.lastUpdate));
dateContainer.innerHTML = dateTimeStyle.format(date); const listContainer = document.querySelector('#stationList');
let stationIndex = 0;
//clear list before update //clear list before update
listContainer.innerHTML = ''; listContainer.innerHTML = '';
for (const station of stations) {
const stationName = station.mainSubStation.stationName;
const lines = new Set();
const elevators = [];
for (const elevatorKey of Object.keys(station.elevators)) {
const elevatorApi = station.elevators[elevatorKey];
const elevatorLines = [];
for (let line of elevatorApi.lines) {
line = line.replace(/[\(\)]/g, "");
lines.add(line);
elevatorLines.push({
line: line,
type: getType(line),
});
}
// try to detect levels from description const stations = internalData['stations'];
let levels = [];
if (elevatorApi.description.search('<->') >= 0) {
levels = elevatorApi.description.split('<->').map(level => level.trim());
} else if (elevatorApi.description.search('<>') >= 0) {
levels = elevatorApi.description.split('<>').map(level => level.trim());
} else if (elevatorApi.description.search('/ ') >= 0) {
levels = elevatorApi.description.split('/ ').map(level => level.trim());
}
const elevator = { for (const stationIndex in stations) {
working: elevatorApi['state'] === 1, const station = stations[stationIndex];
stateUnavailable: elevatorApi['state'] === -1,
dimensions: {
width: elevatorApi['cabinWidth'],
length: elevatorApi['cabinLength'],
door: elevatorApi['doorWidth'],
},
description: elevatorApi['description'],
label: elevatorApi['label'],
type: elevatorApi['type'].replace('_', ' ').capitalize(),
braille: elevatorApi['tasterType'] === 'UNBEKANNT' ? -1 : elevatorApi['tasterType'] === 'KOMBI' || elevatorApi['tasterType'] === 'BRAILLE',
speaker: elevatorApi['tasterType'] === 'UNBEKANNT' ? -1 : elevatorApi['tasterType'] === 'KOMBI',
lines: elevatorLines,
levels: levels,
instCause: elevatorApi['instCause'],
osmNodeId: elevatorApi['osmId'],
}
elevators.push(elevator);
}
const stationTypes = getTypes(Array.from(lines));
let elevatorsTemplate = ''; let elevatorsTemplate = '';
let previewTemplate = ''; let previewTemplate = '';
let stationState = {
unavailable: 0, for (const elevator of station.elevators) {
working: 0,
outOfOrder: 0,
}
for (const elevator of elevators) {
let linesTemplate = '<div class="lineList">Linien: '; let linesTemplate = '<div class="lineList">Linien: ';
for (const line of elevator.lines) { for (const line of elevator.lines) {
linesTemplate += `<span data-type="${line.type}" data-line="${line.line}" class="lineChip">${line.line}</span>`; linesTemplate += `<span data-type="${line.type}" data-line="${line.line}" class="lineChip">${line.line}</span>`;
@ -262,16 +257,45 @@ function renderData() {
} }
levelsTemplate += '</ol>'; levelsTemplate += '</ol>';
let osmTemplate = '';
if (osmData) {
const nodes = osmData.elements.filter(node => node.id === elevator.osmNodeId)
if (nodes.length) {
const nodeInfo = nodes[0];
if (nodeInfo.hasOwnProperty('tags')) {
const tags = nodeInfo['tags'];
if (tags['highway'] === 'elevator') {
osmTemplate = '<dl>';
osmTemplate += `<div><dt><span data-icon="location" class="size-l"></span>Link zur Karte</dt><dd><a href="https://www.openstreetmap.org/node/${elevator.osmNodeId}" target="_blank">
Auf Karte anzeigen
</a></dd></div>`;
if (tags.hasOwnProperty('description')) {
osmTemplate += `<div><dt><span data-icon="info" class="size-l"></span>Beschreibung</dt><dd>${tags['description']}</dd></div>`;
}
if (tags.hasOwnProperty('level')) {
osmTemplate += `<div><dt><span data-icon="up-down" class="size-l"></span>Ebenen</dt><dd>${tags['level'].split(';').sort().join(', ')}</dd></div>`;
}
if (tags.hasOwnProperty('wheelchair')) {
osmTemplate += `<div><dt><span data-icon="wheelchair" class="size-l"></span>Rollstühle</dt><dd>${tags['wheelchair'] === 'yes' ? 'Ja' : 'Nein'}</dd></div>`;
}
if (tags.hasOwnProperty('bicycle')) {
osmTemplate += `<div><dt><span data-icon="bicycle" class="size-l"></span>Fahrräder</dt><dd>${tags['bicycle'] === 'yes' ? 'Ja' : 'Nein'}</dd></div>`;
}
osmTemplate += '<dl>';
}
} else {
osmTemplate = 'keine Daten';
}
} else {
osmTemplate = 'keine Daten';
}
}
previewTemplate += `<span data-icon="${elevator.working || elevator.stateUnavailable ? 'elevator' : 'elevator-slash'}" previewTemplate += `<span data-icon="${elevator.working || elevator.stateUnavailable ? 'elevator' : 'elevator-slash'}"
class="size-l ${elevator.working ? 'text-green' : elevator.stateUnavailable ? 'text-orange' : 'text-red'}"></span>` class="size-l ${elevator.working ? 'text-green' : elevator.stateUnavailable ? 'text-orange' : 'text-red'}"></span>`
if (elevator.stateUnavailable) {
stationState.unavailable++;
} else if (elevator.working) {
stationState.working++;
} else {
stationState.outOfOrder++;
}
elevatorsTemplate += `<li class="elevator"> elevatorsTemplate += `<li class="elevator">
<span data-icon="${elevator.working || elevator.stateUnavailable ? 'elevator' : 'elevator-slash'}" <span data-icon="${elevator.working || elevator.stateUnavailable ? 'elevator' : 'elevator-slash'}"
@ -311,6 +335,7 @@ function renderData() {
${elevator.lines.length ? `${linesTemplate}` : ''} ${elevator.lines.length ? `${linesTemplate}` : ''}
<div class="osm" data-nodeid="${elevator.osmNodeId}"> <div class="osm" data-nodeid="${elevator.osmNodeId}">
<h4>Daten von OpenStreetMap</h4> <h4>Daten von OpenStreetMap</h4>
${osmTemplate}
</div> </div>
</div> </div>
</li>`; </li>`;
@ -319,14 +344,14 @@ function renderData() {
const template = `<li class="station" id="station_${stationIndex}"> const template = `<li class="station" id="station_${stationIndex}">
<div class="stationSummary"> <div class="stationSummary">
<div class="typeList"> <div class="typeList">
${Array.from(stationTypes).sort().map(t => `<span class="typeChip" data-type="${t}">${t}</span>`).join('')} ${station.types.sort().map(t => `<span class="typeChip" data-type="${t}">${t}</span>`).join('')}
</div> </div>
<div class="stationTitle"> <div class="stationTitle">
<h3>${stationName}</h3> <h3>${station.name}</h3>
<div class="elevator-preview" role="img" <div class="elevator-preview" role="img"
aria-label="${stationState.working ? `${stationState.working} ${stationState.working > 1 ? 'Aufzüge sind' : 'Aufzug ist'} funktionstüchtig.` : ''} aria-label="${station.state.working ? `${station.state.working} ${station.state.working > 1 ? 'Aufzüge sind' : 'Aufzug ist'} funktionstüchtig.` : ''}
${stationState.outOfOrder ? `${stationState.outOfOrder} ${stationState.outOfOrder > 1 ? 'Aufzüge sind' : 'Aufzug ist'} außer Betrieb.` : ''} ${station.state.outOfOrder ? `${station.state.outOfOrder} ${station.state.outOfOrder > 1 ? 'Aufzüge sind' : 'Aufzug ist'} außer Betrieb.` : ''}
${stationState.unavailable ? `Bei ${stationState.unavailable} ${stationState.unavailable > 1 ? 'Aufzügen' : 'Aufzug'} ist der Funktionsstatus unbekannt.` : ''}"> ${station.state.unavailable ? `Bei ${station.state.unavailable} ${station.state.unavailable > 1 ? 'Aufzügen' : 'Aufzug'} ist der Funktionsstatus unbekannt.` : ''}">
${previewTemplate} ${previewTemplate}
</div> </div>
</div> </div>
@ -349,38 +374,39 @@ ${stationState.unavailable ? `Bei ${stationState.unavailable} ${stationState.una
// .addEventListener('click', () => toggleElevatorList(stationId)) // .addEventListener('click', () => toggleElevatorList(stationId))
// }()); // }());
internalData[stationIndex++] = {
name: stationName,
state: stationState,
elevators: elevators,
}
} }
} }
document.querySelector('#loadElevators') document.querySelector('#loadElevators')
.addEventListener('click', (e) => { .addEventListener('click', (e) => {
loadElevators().then(() => renderData()); loadElevators().then(() => {
renderData();
filterData();
});
}) })
document.querySelector('#loadOSM') document.querySelector('#loadOSM')
.addEventListener('click', (e) => { .addEventListener('click', (e) => {
loadOsmData(); loadOsmData().then(() => {
renderData();
});
}) })
renderData(); renderData();
function filterData(searchString) { function filterData() {
for (const stationIndex in internalData) { const searchString = document.querySelector('#searchStation').value;
const matches = internalData[stationIndex].name.toLowerCase().search(searchString.toLowerCase()) >= 0; if (internalData) {
document.querySelector(`#station_${stationIndex}`).classList.toggle('hidden', !matches); for (const stationIndex in internalData.stations) {
const matches = internalData.stations[stationIndex].name.toLowerCase().search(searchString.toLowerCase()) >= 0;
document.querySelector(`#station_${stationIndex}`).classList.toggle('hidden', !matches);
}
} }
} }
document.querySelector('#searchStation').addEventListener('input', (e) => { document.querySelector('#searchStation').addEventListener('input', (e) => {
filterData(e.target.value); filterData();
}) })
filterData(document.querySelector('#searchStation').value) filterData()