Zeitleiste: Fenster-Etikett nie vor dem Balken, Kettenlinie lotrecht
Passte ein Name hinter einem spaeten Fenster nicht mehr in die Spur, stand das Etikett rechtsbuendig am Balkenende und hing weit vor dessen Beginn - "Hitzeschutz West zurueck" (15:00-18:31) sah aus, als finge es um halb elf an. Jetzt beginnt ein Fenster-Etikett immer am Balken; reicht der Platz nicht, wird der Name gekuerzt, und nur wenn nicht einmal die Uhrzeit Platz hat, rueckt es so wenig wie noetig nach links. Die Kettenlinie verlaesst den Ausloeser lotrecht unter seiner Marke (bzw. unter Laufmarke oder Balkenanfang), laeuft gerade hinunter und biegt mit einer kleinen Rundung von links in den Nachfolger ein. Liegt der Nachfolger links davon, faehrt sie ihn von oben an. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+5
-2
@@ -2974,8 +2974,11 @@ input[type='range']::-webkit-slider-runnable-track {
|
|||||||
background: var(--ton-flaeche, #23282c);
|
background: var(--ton-flaeche, #23282c);
|
||||||
border-color: rgba(var(--zl-farbe-rgb), .3);
|
border-color: rgba(var(--zl-farbe-rgb), .3);
|
||||||
}
|
}
|
||||||
/* Am rechten Rand endet das Etikett am Balkenende statt dahinter. */
|
/* Reicht der Platz bis zum rechten Rand nicht, wird der Name gekuerzt. */
|
||||||
.zl-fenster.links { justify-content: flex-end; }
|
.zl-etikett.gekappt {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
.zl-lauf {
|
.zl-lauf {
|
||||||
margin-left: .25rem;
|
margin-left: .25rem;
|
||||||
color: var(--ton-gut, #4caf7d);
|
color: var(--ton-gut, #4caf7d);
|
||||||
|
|||||||
+58
-25
@@ -113,13 +113,26 @@ function zlStapeln(eintraege, breite) {
|
|||||||
const lang = zlBreite(etikett) + 26;
|
const lang = zlBreite(etikett) + 26;
|
||||||
let links = px(von) - 8;
|
let links = px(von) - 8;
|
||||||
let rechts = a.art === "fenster" ? Math.max(px(bis), px(von) + lang) : px(von) + lang;
|
let rechts = a.art === "fenster" ? Math.max(px(bis), px(von) + lang) : px(von) + lang;
|
||||||
// Am rechten Rand steht das Etikett links vom Punkt bzw. endet am
|
const ueber = px(von) + lang > breite - 4;
|
||||||
// Balkenende - sonst ragte es aus der Spur und der Rahmen bekaeme einen
|
// Ein Punkt am rechten Rand trägt sein Etikett links von sich - das
|
||||||
// Scrollbalken fuer ein paar Buchstaben.
|
// liest sich natürlich, die Marke bleibt, wo die Zeit ist.
|
||||||
const nachLinks = px(von) + lang > breite - 4;
|
const nachLinks = ueber && a.art !== "fenster";
|
||||||
if (nachLinks && a.art !== "fenster") { links = px(von) - lang; rechts = px(von) + 8; }
|
if (nachLinks) { links = px(von) - lang; rechts = px(von) + 8; }
|
||||||
if (nachLinks && a.art === "fenster") { links = Math.min(px(von), px(bis) - lang) - 8; rechts = px(bis); }
|
/*
|
||||||
return { a, links, rechts, nachLinks, etikett };
|
* Ein Fenster-Etikett beginnt dagegen nie vor seinem Balken - sonst sähe
|
||||||
|
* "15:00–18:31" aus, als finge es um halb elf an. Reicht der Platz nicht,
|
||||||
|
* wird der Name gekürzt (voll steht er im Hinweis); nur wenn nicht einmal
|
||||||
|
* die Uhrzeit Platz hat, rückt es so wenig wie nötig nach links.
|
||||||
|
*/
|
||||||
|
let kappe = null, versatz = 0;
|
||||||
|
if (ueber && a.art === "fenster") {
|
||||||
|
const rest = breite - 4 - px(von);
|
||||||
|
kappe = Math.max(96, rest);
|
||||||
|
versatz = Math.min(0, rest - kappe);
|
||||||
|
links = px(von) + versatz - 8;
|
||||||
|
rechts = Math.max(px(bis), px(von) + versatz + kappe);
|
||||||
|
}
|
||||||
|
return { a, links, rechts, nachLinks, kappe, versatz, etikett };
|
||||||
}).sort((x, y) => x.links - y.links);
|
}).sort((x, y) => x.links - y.links);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -322,7 +335,9 @@ function zlEintrag(e, d, prozent) {
|
|||||||
const titel = zlText(zlTitel(a, zustand));
|
const titel = zlText(zlTitel(a, zustand));
|
||||||
const lauf = zustand !== "gelaufen" ? ""
|
const lauf = zustand !== "gelaufen" ? ""
|
||||||
: ' <i class="bi bi-check2"></i>' + (a.art === "fenster" ? '<span class="zl-lauf">' + zlText(a.laeufe[a.laeufe.length - 1]) + "</span>" : "");
|
: ' <i class="bi bi-check2"></i>' + (a.art === "fenster" ? '<span class="zl-lauf">' + zlText(a.laeufe[a.laeufe.length - 1]) + "</span>" : "");
|
||||||
const etikett = '<span class="zl-etikett"><b>' + zlText(zlEtikettZeit(a)) + "</b>" + zlText(a.name) + lauf + "</span>";
|
const kappe = e.kappe ? ' style="max-width:' + Math.round(e.kappe) + "px" + (e.versatz ? ";margin-left:" + Math.round(e.versatz) + "px" : "") + '"' : "";
|
||||||
|
const etikett = '<span class="zl-etikett' + (e.kappe ? " gekappt" : "") + '"' + kappe + "><b>"
|
||||||
|
+ zlText(zlEtikettZeit(a)) + "</b>" + zlText(a.name) + lauf + "</span>";
|
||||||
|
|
||||||
if (a.art === "fenster") {
|
if (a.art === "fenster") {
|
||||||
// Läufe und die früheste Marke als Punkte auf dem Balken.
|
// Läufe und die früheste Marke als Punkte auf dem Balken.
|
||||||
@@ -334,7 +349,7 @@ function zlEintrag(e, d, prozent) {
|
|||||||
const m = zlMinuteAus(t);
|
const m = zlMinuteAus(t);
|
||||||
marken += '<span class="zl-marke zl-marke-innen gelaufen" style="left:' + ((m - a.von) / Math.max(1, a.bis - a.von) * 100).toFixed(2) + '%"></span>';
|
marken += '<span class="zl-marke zl-marke-innen gelaufen" style="left:' + ((m - a.von) / Math.max(1, a.bis - a.von) * 100).toFixed(2) + '%"></span>';
|
||||||
});
|
});
|
||||||
return '<div class="zl-ding zl-fenster ' + zustand + (e.nachLinks ? " links" : "") + '" data-id="' + a.id + '"'
|
return '<div class="zl-ding zl-fenster ' + zustand + '" data-id="' + a.id + '"'
|
||||||
+ (a.kette ? ' data-kette="' + a.kette + '"' : "") + ' title="' + titel + '"'
|
+ (a.kette ? ' data-kette="' + a.kette + '"' : "") + ' title="' + titel + '"'
|
||||||
+ ' style="top:' + oben + "px;left:" + prozent(a.von) + ";width:" + prozent(Math.max(10, a.bis - a.von)) + '">'
|
+ ' style="top:' + oben + "px;left:" + prozent(a.von) + ";width:" + prozent(Math.max(10, a.bis - a.von)) + '">'
|
||||||
+ '<span class="zl-balken">' + marken + "</span>" + etikett + "</div>";
|
+ '<span class="zl-balken">' + marken + "</span>" + etikett + "</div>";
|
||||||
@@ -365,29 +380,47 @@ function zlKettenZeichnen(ziel) {
|
|||||||
svg.setAttribute("width", basis.width);
|
svg.setAttribute("width", basis.width);
|
||||||
svg.setAttribute("height", basis.height);
|
svg.setAttribute("height", basis.height);
|
||||||
/*
|
/*
|
||||||
* Ankerpunkt eines Eintrags: beim Punkt die Marke, beim Fenster die
|
* Die Linie verlässt den Auslöser lotrecht nach unten und biegt mit einer
|
||||||
* Laufmarke, sonst der Balkenanfang. Die Linie beginnt am Auslöser rechts
|
* kleinen Rundung von links in den Nachfolger ein.
|
||||||
* vom Anker und endet am Nachfolger links davon - so kommt sie an und
|
*
|
||||||
* läuft nicht quer durch den Kreis.
|
* Start: beim Punkt unter der Marke; beim Fenster unter der Laufmarke,
|
||||||
|
* sonst unter dem Balkenanfang. Ziel: beim Punkt links an der Marke, beim
|
||||||
|
* Fenster am Balkenanfang. Liegt der Nachfolger links vom Auslöser (etwa
|
||||||
|
* weil er früher beginnen darf), kommt die Linie von oben an.
|
||||||
*/
|
*/
|
||||||
const anker = el => {
|
const rect = el => {
|
||||||
|
const r = el.getBoundingClientRect();
|
||||||
|
return { l: r.left - basis.left, r: r.right - basis.left, t: r.top - basis.top, b: r.bottom - basis.top };
|
||||||
|
};
|
||||||
|
const start = el => {
|
||||||
const marke = el.querySelector(".zl-marke-innen.gelaufen") || el.querySelector(".zl-marke:not(.zl-marke-innen)");
|
const marke = el.querySelector(".zl-marke-innen.gelaufen") || el.querySelector(".zl-marke:not(.zl-marke-innen)");
|
||||||
const r = (marke || el.querySelector(".zl-balken") || el).getBoundingClientRect();
|
if (marke) { const m = rect(marke); return { x: (m.l + m.r) / 2, y: m.b }; }
|
||||||
return marke
|
const b = rect(el.querySelector(".zl-balken") || el), ding = rect(el);
|
||||||
? { x: r.left + r.width / 2 - basis.left, y: r.top + r.height / 2 - basis.top, r: r.width / 2 }
|
return { x: b.l + 6, y: ding.b - 2 };
|
||||||
: { x: r.left - basis.left, y: r.top + r.height / 2 - basis.top, r: 0 };
|
};
|
||||||
|
const ankunft = el => {
|
||||||
|
const marke = el.querySelector(".zl-marke:not(.zl-marke-innen)");
|
||||||
|
const m = rect(marke || el.querySelector(".zl-balken") || el);
|
||||||
|
return { x: m.l, y: (m.t + m.b) / 2, oben: m.t, mitte: (m.l + m.r) / 2 };
|
||||||
};
|
};
|
||||||
let pfade = "";
|
let pfade = "";
|
||||||
raster.querySelectorAll(".zl-ding[data-kette]").forEach(kind => {
|
raster.querySelectorAll(".zl-ding[data-kette]").forEach(kind => {
|
||||||
const vater = raster.querySelector('.zl-ding[data-id="' + kind.dataset.kette + '"]');
|
const vater = raster.querySelector('.zl-ding[data-id="' + kind.dataset.kette + '"]');
|
||||||
if (!vater) return;
|
if (!vater) return;
|
||||||
const v = anker(vater), k = anker(kind);
|
const s = start(vater), z = ankunft(kind);
|
||||||
const x1 = v.x + (v.r ? v.r * 0.7 : 0), y1 = v.y + (v.r ? v.r * 0.7 : 0);
|
const x1 = Math.round(s.x) + 0.5, y1 = Math.round(s.y);
|
||||||
const x2 = k.x - (k.r ? k.r + 1 : 0), y2 = k.y;
|
let d, x2, y2;
|
||||||
// Erst senkrecht nach unten, dann waagerecht hinein: so trifft der Bogen
|
if (z.x - x1 >= 10) {
|
||||||
// den Nachfolger von links, auch wenn der fast senkrecht darunter liegt.
|
// lotrecht hinunter, Rundung, waagerecht hinein
|
||||||
const d = "M" + x1 + " " + y1 + " C" + x1 + " " + (y1 + (y2 - y1) * 0.8) + " "
|
x2 = Math.round(z.x) - 1; y2 = Math.round(z.y);
|
||||||
+ (x2 - Math.max(14, (x2 - x1) * 0.5)) + " " + y2 + " " + x2 + " " + y2;
|
const rund = Math.min(10, (y2 - y1) / 2, (x2 - x1) / 2);
|
||||||
|
d = "M" + x1 + " " + y1 + " V" + (y2 - rund) + " Q" + x1 + " " + y2 + " " + (x1 + rund) + " " + y2 + " H" + x2;
|
||||||
|
} else {
|
||||||
|
// Nachfolger liegt links oder genau darunter: von oben anfahren
|
||||||
|
x2 = Math.round(z.mitte) + 0.5; y2 = Math.round(z.oben) - 1;
|
||||||
|
const mitte = y1 + (y2 - y1) / 2;
|
||||||
|
d = "M" + x1 + " " + y1 + " V" + mitte + " H" + x2 + " V" + y2;
|
||||||
|
}
|
||||||
const paar = ' data-von="' + kind.dataset.kette + '" data-nach="' + kind.dataset.id + '"';
|
const paar = ' data-von="' + kind.dataset.kette + '" data-nach="' + kind.dataset.id + '"';
|
||||||
pfade += '<path class="zl-kette-grund" d="' + d + '"/>'
|
pfade += '<path class="zl-kette-grund" d="' + d + '"/>'
|
||||||
+ '<path class="zl-kette"' + paar + ' d="' + d + '"/>'
|
+ '<path class="zl-kette"' + paar + ' d="' + d + '"/>'
|
||||||
|
|||||||
Reference in New Issue
Block a user