From 257b5e5099307e647271fb7306354b1cc669dc71 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 22 Aug 2026 12:03:29 +0200 Subject: [PATCH] Lehreransicht "Aktuell": Mini-Balken unter den Zahlen (Farmer-Spalten) Kleine Balkengrafik unter jedem Zahlenwert: bounded Metriken (Jahr/Trefferquote/ Sorten absolut zur Skala) + offene Werte (Konto/Laender/Felder/Versuche/CO2) relativ zum groessten Wert der Spalte ueber alle Schueler:innen -> auf einen Blick "wer liegt vorn". Konto signiert (rot bei minus), CO2/Krankheiten invers (rot = mehr). Helfer _liveMiniBar/_liveBarColor, colMax pro Spalte. Co-Authored-By: Claude Opus 4.8 --- App/teacher.html | 60 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/App/teacher.html b/App/teacher.html index bace8a3..1bd093b 100644 --- a/App/teacher.html +++ b/App/teacher.html @@ -634,25 +634,39 @@ function _liveBar(val, min, max, goodWhen) { + ''; } +// Farbwahl nach „gut wenn" (aus _liveBar extrahiert) — für die Mini-Balken. +function _liveBarColor(pct, goodWhen) { + pct = Math.max(0, Math.min(100, pct||0)); + if (goodWhen === 'low') return pct <= 33 ? '#5a8a5e' : pct <= 66 ? '#c9913a' : '#c07a6b'; + if (goodWhen === 'mid') return '#9a9a9a'; + return pct >= 60 ? '#5a8a5e' : pct >= 30 ? '#c9913a' : '#c07a6b'; +} +// Mini-Balken UNTER der Zahl (Cockpit „Aktuell"). pct 0–100. +function _liveMiniBar(pct, color) { + pct = Math.max(0, Math.min(100, pct||0)); + return '
' + + '
'; +} + var LIVE_PRIMARY_FIELDS = { farmer: [ - {k:'year', label:'Jahr', fmt:function(v){ return (v||0) + ' / 10'; }}, + {k:'year', label:'Jahr', bar:{kind:'abs',max:10,good:'mid'}, fmt:function(v){ return (v||0) + ' / 10'; }}, {k:'market_de', label:'Markt', align:'left', fmt:function(v){ return v ? '🌍 '+esc(v) : ''; }}, - {k:'cash', label:'Konto', fmt:function(v){ + {k:'cash', label:'Konto', bar:{kind:'rel',good:'signed'}, fmt:function(v){ if (v == null) return ''; var color = v < 0 ? '#c0392b' : '#5a8a5e'; return ''+Number(v).toLocaleString('de-AT')+' €'; }}, - {k:'hit_rate', label:'Trefferquote', fmt:function(v){ return _liveBar(v, 0, 100, 'high'); }}, - {k:'crops_used', label:'Sorten', fmt:function(v){ return (v||0) + ' / 10'; }}, - {k:'countries', label:'Länder', fmt:function(v){ return (v!=null? v : 0); }}, - {k:'fields', label:'Felder', fmt:function(v){ return (v!=null? v : 0); }}, - {k:'attempts', label:'Versuche',fmt:function(v){ return (v!=null? v : 0); }}, - {k:'co2_kg', label:'CO₂', unit:'kg', fmt:function(v){ + {k:'hit_rate', label:'Trefferquote', unit:'%', bar:{kind:'abs',max:100,good:'high'}, fmt:function(v){ return (v!=null? v : 0); }}, + {k:'crops_used', label:'Sorten', bar:{kind:'abs',max:10,good:'high'}, fmt:function(v){ return (v||0) + ' / 10'; }}, + {k:'countries', label:'Länder', bar:{kind:'rel',good:'high'}, fmt:function(v){ return (v!=null? v : 0); }}, + {k:'fields', label:'Felder', bar:{kind:'rel',good:'mid'}, fmt:function(v){ return (v!=null? v : 0); }}, + {k:'attempts', label:'Versuche',bar:{kind:'rel',good:'mid'}, fmt:function(v){ return (v!=null? v : 0); }}, + {k:'co2_kg', label:'CO₂', unit:'kg', bar:{kind:'rel',good:'low'}, fmt:function(v){ if (v == null) return ''; return ''+Number(Math.round(v)).toLocaleString('de-AT')+''; }}, - {k:'diseases', label:'Krankheiten', align:'center', fmt:function(v){ + {k:'diseases', label:'Krankheiten', align:'center', bar:{kind:'abs',max:5,good:'low'}, fmt:function(v){ if (v == null) return ''; var color = (v > 0) ? '#c07a6b' : '#8a8a8a'; return ''+v+''; @@ -1419,6 +1433,16 @@ async function renderLive() { html += ''; html += ''; + // Spalten-Maxima für relative Mini-Balken (über alle Zeilen dieser Sim). + var colMax = {}; + fields.forEach(function(f) { + if (f.bar && f.bar.kind === 'rel') { + var mx = 0; + grp.rows.forEach(function(r) { var val = (r.state||{})[f.k]; if (typeof val === 'number' && !isNaN(val)) mx = Math.max(mx, Math.abs(val)); }); + colMax[f.k] = mx; + } + }); + grp.rows.forEach(function(ls) { var avatarHtml = (typeof ls.emoji === 'string' && ls.emoji.indexOf('avatar:') === 0) ? '' @@ -1450,7 +1474,23 @@ async function renderLive() { html += '
'+missionStr+'
'+simStr+' ges.
'; fields.forEach(function(f) { var align = f.align || 'right'; - html += ''+_liveFmt(s[f.k], f.unit, f, ls)+''; + var cell = _liveFmt(s[f.k], f.unit, f, ls); + if (f.bar) { + var raw = s[f.k]; + if (typeof raw === 'number' && !isNaN(raw)) { + var pct = 0, bcol; + if (f.bar.kind === 'abs') { + pct = (raw / (f.bar.max || 100)) * 100; + bcol = _liveBarColor(pct, f.bar.good); + } else { + var mx = colMax[f.k] || 0; + pct = mx > 0 ? (Math.abs(raw) / mx) * 100 : 0; + bcol = (f.bar.good === 'signed') ? (raw < 0 ? '#c0392b' : '#5a8a5e') : _liveBarColor(pct, f.bar.good); + } + cell = '
'+cell+'
' + _liveMiniBar(pct, bcol); + } + } + html += ''+cell+''; }); html += ''+(paused ? '⏸ '+_fmtSince(lastSeen)+''