From 9a1ee0fae12200d3a22ee823c9386e7d14879ae9 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 23 Aug 2026 22:23:34 +0200 Subject: [PATCH] Tag-Zeitachse: gestauchte Skala - Nacht 00-06 und Abend 21-24 je 1 Block, Tag 06-21 stuendlich Regler UND Zeitachse/Balken nutzen dieselbe Stunde-Einheit-Abbildung (_hourToUnit/_unitToHour, 17 gleich breite Bloecke). Nacht-/Abend-Bloecke dunkel ohne interne Linien; Tag stuendlich beschriftet + Trennlinien. Auto-Default rundet auf Block-Grenzen. Marker an den Block-Grenzen. Co-Authored-By: Claude Opus 4.8 --- App/teacher.html | 88 ++++++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 33 deletions(-) diff --git a/App/teacher.html b/App/teacher.html index 81d635f..3acb8a6 100644 --- a/App/teacher.html +++ b/App/teacher.html @@ -2105,6 +2105,21 @@ function _vHM(ms){ var s = new Date(ms).toLocaleString('en-GB', {timeZone:'Europe/Vienna', hour:'2-digit', minute:'2-digit', hour12:false}); var p = s.split(':'); return { h: parseInt(p[0],10)||0, m: parseInt(p[1],10)||0 }; } +// Gestauchte Tages-Skala: Nacht 00–06 und Abend 21–24 je NUR EIN Block, dazwischen +// (06–21) stündlich. 17 Blöcke → „Einheiten" 0..17. Stunde ⇄ Einheit. +function _hourToUnit(h){ + h = Math.max(0, Math.min(24, h)); + if (h <= 6) return h/6; // 00–06 → Einheit 0..1 + if (h <= 21) return 1 + (h-6); // 06–21 → Einheit 1..16 (1 pro Stunde) + return 16 + (h-21)/3; // 21–24 → Einheit 16..17 +} +function _unitToHour(u){ + u = Math.max(0, Math.min(17, u)); + if (u <= 1) return u*6; // 0→00, 1→06 + if (u <= 16) return 6 + (u-1); // 1→06 … 16→21 + return 21 + (u-16)*3; // 16→21, 17→24 +} +var TS_STOPS = [0,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,24]; // Einheit-Index → Stunde function _tsInjectCss(){ if (document.getElementById('ts-css')) return; var s = document.createElement('style'); s.id = 'ts-css'; @@ -2128,21 +2143,22 @@ function _tsInjectCss(){ document.head.appendChild(s); } // Schieberegler-Interaktion (global, für inline-Handler). +// Regler arbeitet in EINHEITEN 0..17 (gestauchte Skala). from/to = Einheit-Index. function _tsClamp(){ var fe=document.getElementById('tsFrom'), te=document.getElementById('tsTo'); if(!fe||!te) return null; var f=+fe.value, t=+te.value; - if(f>=t){ if(f>=24){f=23;} t=Math.min(24,f+1); if(+te.valuef) fe.value=f; } + if(f>=t){ if(f>=17){f=16;} t=Math.min(17,f+1); if(+te.valuef) fe.value=f; } return {f:f,t:t}; } function _tsVisual(){ var v=_tsClamp(); if(!v) return; - var r=document.getElementById('tsRange'); if(r){ r.style.left=(v.f/24*100)+'%'; r.style.width=((v.t-v.f)/24*100)+'%'; } - var l=document.getElementById('tsLbl'); if(l) l.textContent=_pad2(v.f)+':00 – '+_pad2(v.t)+':00'; + var r=document.getElementById('tsRange'); if(r){ r.style.left=(v.f/17*100)+'%'; r.style.width=((v.t-v.f)/17*100)+'%'; } + var l=document.getElementById('tsLbl'); if(l) l.textContent=_pad2(_unitToHour(v.f))+':00 – '+_pad2(_unitToHour(v.t))+':00'; } function _tsCommit(){ var v=_tsClamp(); if(!v) return; - _liveWin.from=v.f; _liveWin.to=v.t; + _liveWin.from=v.f; _liveWin.to=v.t; // Einheiten renderLiveSummary(); } function _tsReset(){ _liveWin.from=null; _liveWin.to=null; renderLiveSummary(); } @@ -2239,15 +2255,25 @@ async function renderLiveSummary() { var _lo=_vHM(minMs), _hi=_vHM(maxMs); var autoFromH = Math.max(0, _lo.h); var autoToH = Math.min(24, _hi.h + ((_hi.m>0)?1:0)); - if (autoToH <= autoFromH) autoToH = Math.min(24, autoFromH+1); - // Effektives Fenster: Schieberegler-Auswahl (falls gesetzt) ODER Auto. - var fromH = (_liveWin.from!=null) ? _liveWin.from : autoFromH; - var toH = (_liveWin.to !=null) ? _liveWin.to : autoToH; - if (toH <= fromH) toH = Math.min(24, fromH+1); + // Auto-Grenzen als EINHEITEN der gestauchten Skala (auf Block-Grenzen gerundet). + var autoFromU = Math.floor(_hourToUnit(autoFromH)); + var autoToU = Math.ceil(_hourToUnit(autoToH)); + if (autoToU <= autoFromU) autoToU = Math.min(17, autoFromU+1); + // Effektives Fenster in Einheiten: Regler-Auswahl ODER Auto. + var fromU = (_liveWin.from!=null) ? _liveWin.from : autoFromU; + var toU = (_liveWin.to !=null) ? _liveWin.to : autoToU; + if (toU <= fromU) toU = Math.min(17, fromU+1); + var fromH = _unitToHour(fromU), toH = _unitToHour(toU); var winStart = dayBase + fromH*3600*1000; var winEnd = dayBase + toH*3600*1000; var winSpanMs = winEnd - winStart; - function _msToPct(ms) { return ((ms - winStart) / winSpanMs) * 100; } + // Position auf der GESTAUCHTEN Skala (Nacht/Abend gestaucht, Tag stündlich) — + // nicht linear in der Zeit. + function _msToPct(ms){ + var h = (ms - dayBase)/3600000; + if (toU === fromU) return 0; + return ((_hourToUnit(h) - fromU) / (toU - fromU)) * 100; + } function _fmtHM(ms) { return new Date(ms).toLocaleTimeString('de-AT', {timeZone:'Europe/Vienna', hour:'2-digit', minute:'2-digit'}); } @@ -2262,15 +2288,15 @@ async function renderLiveSummary() { // (erste bis letzte Aktivität). onchange committet + rendert neu, oninput nur Visual. _tsInjectCss(); var _isAuto = (_liveWin.from==null && _liveWin.to==null); - // Hintergrund: dunklere Nachtzeiten (00–01 und 20–24, um Mitternacht = ein Bereich) - // + 23 stündliche Trennlinien. - var _bg = '' - + ''; - // Stunden-Trennlinien NUR im Tag-Bereich (2–19); die Nacht-Bänder (00–01, 20–24) - // bleiben glatt dunkel (zusammengefasst, keine Linien). - for (var _d=2; _d<20; _d++){ _bg += ''; } - // Stündliche Beschriftung 0–24. - var _ticks=''; for (var _h=0;_h<=24;_h++){ _ticks += ''+_pad2(_h)+''; } + // Gestauchte Skala (17 gleich breite Blöcke): Nacht 00–06 = Block 0, Tag 06–21 + // stündlich = Blöcke 1–15, Abend 21–24 = Block 16. Dunklere Nacht-/Abend-Blöcke + // OHNE interne Linien; Stunden-Trennlinien nur im Tag. + var _u2p = function(u){ return (u/17*100); }; + var _bg = '' // 00–06 + + ''; // 21–24 + for (var _d=2; _d<16; _d++){ _bg += ''; } // Tag-Stundenlinien + // Beschriftung an jeder Block-Grenze: 00,06,07,…,21,24. + var _ticks=''; for (var _u=0;_u<=17;_u++){ _ticks += ''+_pad2(_unitToHour(_u))+''; } html += '
' + '
🕒 Zeitraum '+_pad2(fromH)+':00 – '+_pad2(toH)+':00' + (_isAuto ? 'Auto: erste – letzte Aktivität' @@ -2278,25 +2304,21 @@ async function renderLiveSummary() { + '
' + '
' + '
'+_bg+'
' - + '
' - + '' - + '' + + '
' + + '' + + '' + '
' + '
'+_ticks+'
' + '
'; - // Marker an sauberen Uhrzeiten INNERHALB des Fensters — Schrittweite passt sich - // der Spanne an (kurze Stunde = 15-min-Takt, langer Tag = Stunden-Takt), damit - // die Achse weder leer noch überladen wirkt. Erster Marker = erste saubere Zeit - // ab winStart (nicht winStart selbst, das liegt ja mitten im 15-min-Raster). - var stepMs = winSpanMs <= 2*3600*1000 ? 15*60*1000 - : winSpanMs <= 5*3600*1000 ? 30*60*1000 - : 60*60*1000; + // Marker an den Block-Grenzen der gestauchten Skala (Stopp-Stunden 0,6,7,…,21,24), + // soweit sie im gewählten Fenster liegen. So verdichtet sich nichts in den + // gestauchten Nacht-/Abend-Blöcken. var scaleMarks = []; - for (var t = Math.ceil(winStart / stepMs) * stepMs; t <= winEnd; t += stepMs) { - var d = new Date(t); - scaleMarks.push({ ms: t, label: _fmtHM(t), isHour: d.getMinutes() === 0 }); - } + TS_STOPS.forEach(function(hh){ + if (hh < fromH - 0.001 || hh > toH + 0.001) return; + scaleMarks.push({ ms: dayBase + hh*3600*1000, label: _pad2(hh)+':00', isHour: true }); + }); html += '
'; html += '
';