const MAX_DISPLAYED_VIAS = 4 function searchStation(query) { return fetch(`https://displays.api.sbb.ch/internal/api/v1/betriebspunkt?query=${query}`, { headers: { "X-API-Key": API_KEY } }).then(res => { return res.json() }) } function fetchInfo(bpuic) { return fetch(`https://displays.api.sbb.ch/internal/api/v1/data/${bpuic}`, { headers: { "X-API-Key": API_KEY } }).then(res => { return res.json() /* }).then(res => { const trains = res.contents[0].verkehrsmittels console.log(`${trains.length} trains`) let platforms = trains.map(t => t.gleisAbIst) platforms = [... new Set(platforms)] console.log(`Platforms: ${platforms.sort()}`) return res*/ }) } const example = { config: { stationName: "" }, contents: [ { type: "GA", verkehrsmittels: [ { vmArt: "IR", liniennummer: 90, dsVmArt: { vmArt: "IR", ttsTexte: { FR: "InterRegio" } }, zeitAbKb: "2024-04-08T18:32:00", // heure de départ prévue zeitAbErw: "2024-04-08T18:33:00", // heure de départ réelle gleisAbKb: 1, // voie prévue gleisAbIst: 1, // voie réelle verspaetungsminutenAb: 0, // au moins n minutes de retard verspaetungsminutenAn: 0, // au plus n minutes de retard ziele: [ { betriebspunkt: { bpuic: 8501609, bezeichnungOffiziell: "Brig" } } ], vias: [ { betriebspunkt: { bpuic: 8501500, bezeichnungOffiziell: "Martigny" }, prio: 601, trennung: false // séparation } ], formation: { richtung: "RECHTS", waggons: [ { sektor: "A", form: "MITTE", // icône (MITTE, START_LINKS, END_RECHT) typ: "FIKTIV", // classe (FIKTIV = rien, ERSTE, ZWEITE, ERSTE_ZWEITE, RESTAURANT_ERSTE, FAMILIENWAGEN, TRIEBFAHRZEUG = loco) angebote: [], // services (vélos, resto, etc.) statusList: [], // status (GESCHLOSSEN) nummer: null, zielIndex: null // terminus (utile si séparation) }, { sektor: "A", form: "MITTE", typ: "ZWEITE", angebote: [ "VELOHAKEN" // NIEDERFLUREINSTIEG, ROLLSTUHLSTELLPLAETZE, KINDERWAGEN, RESERVATIONSPFLICHTIGE ], nummer: null, zielIndex: 0 }, { sektor: "A", form: "MITTE", typ: "ZWEITE", angebote: [ "VELOHAKEN" ], nummer: null, zielIndex: 0 } ], ziele: [ { zielIndex: 0, betriebspunkt: { bpuic: 8501609, bezeichnungOffiziell: "Brig" }, fromPos: 1, // premier wagon concerné toPos: 10 // dernier wagon concerné } ] } } ] } ] } function getTimeFromTS(timestamp) { const date = new Date(timestamp) const hours = date.getHours().toString().padStart(2, "0") const minutes = date.getMinutes().toString().padStart(2, "0") return `${hours}:${minutes}` } function selectVias(vias) { if (vias.length <= MAX_DISPLAYED_VIAS) return vias let priorities = vias.map((via, index) => [via.prio, index]) priorities = priorities.sort((a, b) => a[0] - b[0]) let selectedVias = [] let selectedPrio = priorities.slice(0, MAX_DISPLAYED_VIAS).sort((a, b) => a[1] - b[1]) selectedPrio.forEach(([prio, index]) => { selectedVias.push(vias[index]) }) return selectedVias } function buildComposition(formation) { const template = document.getElementById("waggon-template").cloneNode(true) template.removeAttribute("id") template.classList.remove("template") const composition = document.getElementById("composition") const sectors = document.getElementById("sectors") sectors.innerHTML = "" const carriages = document.getElementById("carriages") carriages.innerHTML = "" carriages.dataset.direction = formation.richtung === "RECHTS" ? "right" : "left" const weights = {} let first = true for (let i = 0; i < formation.waggons.length; i++) { const waggon = formation.waggons[i] if (!(waggon.sektor in weights)) { weights[waggon.sektor] = 0 } weights[waggon.sektor]++ if (waggon.typ === "FIKTIV") { continue } const elmt = template.cloneNode(true) if (first) { first = false carriages.style.setProperty("--offset", i.toString()) } elmt.classList.add("form-" + waggon.form.toLowerCase()) const cls = { ERSTE: ["1", "first"], ZWEITE: ["2", "second"], ERSTE_ZWEITE: ["1|2", "first-second"], RESTAURANT_ERSTE: ["1", "first"], RESTAURANT_ZWEITE: ["1", "first"], FAMILIENWAGEN: ["", "familie"], TRIEBFAHRZEUG: ["", "loc"] }[waggon.typ] elmt.querySelector(".class").innerText = cls[0] elmt.classList.add("class-" + cls[1]) if (waggon.nummer !== null) { elmt.querySelector(".number").innerText = waggon.nummer } carriages.appendChild(elmt) } composition.style.setProperty("--n-waggons", formation.waggons.length.toString()) const sectorLetters = Object.keys(weights).sort() sectorLetters.forEach(letter => { const sector = document.createElement("div") sector.classList.add("sector") sector.style.setProperty("--weight", weights[letter].toString()) sector.innerText = letter sectors.appendChild(sector) }) console.log(weights) } function updateDisplay(result, idx=0, platform=null) { document.getElementById("station").innerText = result.config.stationName let trains = result.contents[0].verkehrsmittels if (platform !== null) { trains = trains.filter(t => t.gleisAbIst === platform) } const train = trains[idx] let icon = train.vmArt let iconTxt = train.dsVmArt.ttsTexte.FR if (train.liniennummer !== null) { icon += "-" + train.liniennummer iconTxt += " " + train.liniennummer } icon = "icons/" + icon.toLowerCase() + "-negative.svg" document.getElementById("train-type").src = icon document.getElementById("train-type").alt = iconTxt document.getElementById("departure").innerText = getTimeFromTS(train.zeitAbKb) document.getElementById("destination").innerText = train.ziele[0].betriebspunkt.bezeichnungOffiziell const stopsList = document.getElementById("stops") stopsList.innerHTML = "" const vias = selectVias(train.vias) vias.forEach(via => { const stop = document.createElement("div") stop.classList.add("stop") stop.innerText = via.betriebspunkt.bezeichnungOffiziell stopsList.appendChild(stop) }) buildComposition(train.formation) }