feat: improve html/js (similar style, add animations, center columns)

This commit is contained in:
Mark 2025-10-29 14:55:10 +01:00
parent 5bb76c99d3
commit 87836948ba

View File

@ -4,6 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark">
<link rel="icon" href="./favicon.ico">
<title>ulm öpnv abfahrten</title>
<style>
.dbflex {
@ -38,7 +39,7 @@
<body>
<a id="nojslink" href="./nojs" style="position:fixed"><br>no javascript? use the nojs version</a>
<div style="background:darkviolet; width: 100%; height:4px;" id="untilNextUpdateProgressBarBackground"><span style="display:block; background:purple; width:100%; height: 100%;" id="untilNextUpdateProgressBar"></span></div>
<table style="width:99vw; height: 72vh; max-height: 72vh; display: block; overflow: hidden;" id="routesTable"></table>
<table style="width:99vw; height: 72vh; max-height: 72vh; display: block; overflow-y: hidden;" id="routesTable"></table>
<div style="width:99vw; height: 24vh; max-height: 24vh; display:block; overflow: hidden;" id="bahnhofPart"></div>
<script>
// https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep
@ -60,7 +61,12 @@ function getDirectionColor(direction) {
}
}
function getRouteColumn(route) {
function resizeRouteColumns() {
let minWidthPerColumn = (80 / (routesTable.childElementCount)) + "vw";
for (let child of routesTable.children) child.style["min-width"] = minWidthPerColumn;
}
function getRouteColumn(route, first) {
const desiredId = "routeColumn" + route;
const column = document.getElementById(desiredId);
if (column) {
@ -70,8 +76,11 @@ function getRouteColumn(route) {
const newColumn = document.createElement("table");
const columnHeaderRow = document.createElement("tr");
const columnHeaderData = document.createElement("td");
newColumn.style.marginLeft = "auto";
newColumn.style.marginRight = "auto";
columnHeaderData.innerHTML = "<small><small>Linie</small></small> ";
columnHeaderData.append(route);
columnHeaderData.style.whiteSpace = "nowrap";
columnHeaderData.style.fontSize = "3em";
columnHeaderData.style.textDecoration = "underline gray";
columnHeaderRow.appendChild(columnHeaderData);
@ -88,21 +97,20 @@ function getRouteColumn(route) {
}
}
routesTable.insertBefore(newColumnWrapper, beforeWhich);
let columnWidthPercent = (99 / routesTable.childElementCount) + "vw";
for (const column of routesTable.children) {
column.style.width = columnWidthPercent;
}
fadeInColumn(newColumnWrapper, first);
return newColumn;
}
}
function getTripRow(route, vehicle, scheduledTime) {
function getTripRow(route, vehicle, scheduledTime, first) {
const desiredId = "tripRow" + route + "#" + vehicle + "#" + scheduledTime;
const tripRow = document.getElementById(desiredId);
if (tripRow) {
tripRowsUsed.set(desiredId, tripRow);
tripRowsUnused.delete(desiredId);
return tripRow;
} else {
const newTripRow = document.createElement("tr");
const column = getRouteColumn(route);
const column = getRouteColumn(route, first);
let isFirst = true;
let beforeWhich = null;
for (row of column.children) {
@ -117,12 +125,17 @@ function getTripRow(route, vehicle, scheduledTime) {
}
newTripRow.id = desiredId;
column.insertBefore(newTripRow, beforeWhich);
fadeInRow(newTripRow, first);
tripRowsUsed.set(desiredId, newTripRow);
tripRowsUnused.delete(desiredId);
return newTripRow;
}
}
var currentSeq = 0;
var resUniAll = [];
var tripRowsUsed = new Map();
var tripRowsUnused = new Map();
var secondsUntilNextUpdate = 0;
async function fetchUniAllRepeated(firstTime) {
@ -165,11 +178,10 @@ async function fetchUniAll(first) {
const resUniAllText = await (await fetch("./uni/all")).text();
const prevResUniAll = resUniAll;
resUniAll = [];
tripRowsUnused = tripRowsUsed;
tripRowsUsed = new Map();
var resUniThis = {};
const now = new Date();
for (const departure of prevResUniAll) {
departure.elem.remove();
}
for (const resUniAllLine of resUniAllText.split("\n")) {
if (resUniAllLine.startsWith("#")) {
const furtherSplitLine = resUniAllLine.substring(1).split("#");
@ -180,7 +192,8 @@ async function fetchUniAll(first) {
}
} else if (resUniAllLine.startsWith("-")) {
resUniThis.elem = document.createElement("td");
getTripRow(resUniThis.route, resUniThis.vehicle, resUniThis.scheduledTime).replaceChildren(resUniThis.elem);
resUniThis.tripRow = getTripRow(resUniThis.route, resUniThis.vehicle, resUniThis.scheduledTime, first);
resUniThis.tripRow.replaceChildren(resUniThis.elem);
resUniAll.push(resUniThis);
resUniThis = {};
} else if (resUniAllLine.startsWith("R")) {
@ -199,22 +212,22 @@ async function fetchUniAll(first) {
resUniThis[resUniAllLine.substring(0, 1)] = resUniAllLine.substring(1);
}
}
let columnsContainer = document.getElementById("routesTable").firstChild;
if (columnsContainer) {
for (const column of columnsContainer.children) {
if (column.childElementCount <= 1) {
column.remove();
let columnWidthPercent = (99 / routesTable.childElementCount) + "vw";
for (const column of routesTable.children) {
column.style.width = columnWidthPercent;
}
}
}
}
let nojslink = document.getElementById("nojslink");
if (nojslink) {
nojslink.remove();
}
let removeRows = new Array();
for (const tripRow of tripRowsUnused.values()) {
removeRows.push(fadeThenRemoveRow(tripRow));
}
(async function() {
for (let promise of removeRows) await promise;
for (let child of routesTable.children) {
if (child.firstChild.childElementCount <= 1) {
fadeThenRemoveColumn(child);
}
}
})();
await rebuildDepartureElements();
await updateBahnhofAll();
}
@ -238,6 +251,61 @@ async function rebuildDepartureElements() {
resUniThis.elem.children[2].style.color = "hsl(" + Math.round(100 * timeScaledP) + "," + Math.round(100 - 100 * timeScaledP) + "%,50%)";
}
}
async function fadeThenRemoveColumn(child) {
let width = child.getBoundingClientRect().width;
for (let p = 1; p <= 20; ++p) {
let q = 1 - 3*p*p/400-2*p*p*p/8000;
child.style.opacity = Math.floor(100*q) + "%";
await sleep(20);
}
for (let p = 0; p < 17; ++p) {
let q = 1 - 3*p*p/400-2*p*p*p/8000;
child.style.maxWidth = Math.floor(width*q) + "px";
await sleep(20);
}
child.style.maxWidth = "0px";
await sleep(20);
child.remove();
resizeRouteColumns();
}
async function fadeInColumn(child, first) {
resizeRouteColumns();
let width = child.getBoundingClientRect().width;
child.style.opacity = "0%";
if (!first) {
child.style.maxWidth = "0px";
for (let p = 2; p < 20; ++p) {
let q = 3*p*p/400-2*p*p*p/8000;
child.style.maxWidth = Math.floor(width*q) + "px";
await sleep(20);
}
child.style.removeProperty("max-width");
}
for (let p = 0; p < 20; ++p) {
let q = 3*p*p/400-2*p*p*p/8000;
child.style.opacity = Math.floor(100*q) + "%";
await sleep(20);
}
await sleep(20);
child.style.removeProperty("opacity");
}
async function fadeThenRemoveRow(child) {
let width = child.getBoundingClientRect().width;
for (let p = 1; p < 17; ++p) {
let q = 1 - 3*p*p/400-2*p*p*p/8000;
child.style.fontSize = q + "em";
await sleep(20);
}
child.remove();
}
async function fadeInRow(child, first) {
for (let p = first ? 20 : 1; p <= 20; ++p) {
let q = 3*p*p/400-2*p*p*p/8000;
child.style.fontSize = q + "em";
await sleep(20);
}
}
</script>
</body>
</html>