Phase E (substituted): Auswertungen-Drilldown-Modal (#59)
Sachsen-Adapter (#26/#38) ist Eigensystem mit ASP.NET-Webforms-Postbacks (__VIEWSTATE/__CALLBACKID, siehe bundeslaender.py:343-348) und braucht HAR-Aufnahme → Blocker für autonome Bearbeitung. Phase E entsprechend substituiert mit der Frontend-Erweiterung der Auswertungen. - Matrix-Zellen sind jetzt klickbar (`cell-with-data`-Klasse + hover-outline mit Blue-Border) - Klick öffnet ein Modal, das `/api/auswertungen/zeitreihe? bundesland=...&partei=...` aufruft und die Score-Entwicklung dieser (BL, Partei)-Kombination über alle bekannten WPs als Tabelle rendert - ESC-Taste oder Backdrop-Klick schließt das Modal - Schließt damit den Frontend-Loop für die in Phase C gebauten Backend-Endpoints (CLAUDE.md-Sync separat — die Datei liegt im Projekt-Root außerhalb des Webapp-Git-Repos.) Refs: #59 (Phase E substituted) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
26f13bd29d
commit
7cf073122f
@ -104,6 +104,59 @@
|
||||
border-radius: 4px;
|
||||
color: var(--color-lightgray);
|
||||
}
|
||||
table.matrix td.cell-with-data {
|
||||
cursor: pointer;
|
||||
}
|
||||
table.matrix td.cell-with-data:hover {
|
||||
outline: 2px solid var(--color-blue);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
.modal-backdrop {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
}
|
||||
.modal-backdrop.show { display: flex; }
|
||||
.modal {
|
||||
background: white;
|
||||
border-radius: 6px;
|
||||
padding: 1.5rem 2rem;
|
||||
min-width: 320px;
|
||||
max-width: 90vw;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.modal h2 {
|
||||
color: var(--color-blue);
|
||||
margin-bottom: 0.8rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
.modal table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
.modal table th, .modal table td {
|
||||
padding: 0.4rem 0.8rem;
|
||||
border-bottom: 1px solid var(--color-bg);
|
||||
text-align: left;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.modal table th { background: var(--color-bg); }
|
||||
.modal-close {
|
||||
float: right;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1.2rem;
|
||||
cursor: pointer;
|
||||
color: var(--color-lightgray);
|
||||
}
|
||||
.modal-close:hover { color: var(--color-darkgray); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -136,6 +189,15 @@
|
||||
<div class="meta" id="meta"></div>
|
||||
</main>
|
||||
|
||||
<!-- Drill-down modal: Zeitreihe für eine (BL, Partei)-Kombination -->
|
||||
<div class="modal-backdrop" id="modal-backdrop" onclick="closeModal(event)">
|
||||
<div class="modal" onclick="event.stopPropagation()">
|
||||
<button class="modal-close" onclick="closeModal()">×</button>
|
||||
<h2 id="modal-title">Zeitreihe</h2>
|
||||
<div id="modal-body">Lade …</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const wpFilter = document.getElementById('wp-filter');
|
||||
const reloadBtn = document.getElementById('reload');
|
||||
@ -174,7 +236,8 @@
|
||||
for (const partei of data.parteien) {
|
||||
const cell = (data.cells[bl] || {})[partei];
|
||||
if (cell) {
|
||||
html += `<td class="${scoreClass(cell.avg)}">${cell.avg.toFixed(1)}<br><small>n=${cell.n}</small></td>`;
|
||||
// Click → drill-down auf die Zeitreihe für diese Zelle
|
||||
html += `<td class="cell-with-data ${scoreClass(cell.avg)}" data-bl="${bl}" data-partei="${partei}" onclick="showZeitreihe(this.dataset.bl, this.dataset.partei)">${cell.avg.toFixed(1)}<br><small>n=${cell.n}</small></td>`;
|
||||
} else {
|
||||
html += '<td class="empty">—</td>';
|
||||
}
|
||||
@ -195,6 +258,45 @@
|
||||
window.location.href = '/api/auswertungen/export.csv';
|
||||
});
|
||||
|
||||
// Zeitreihen-Modal: zeigt die Score-Entwicklung einer (BL, Partei)-
|
||||
// Kombination über alle bekannten Wahlperioden hinweg.
|
||||
async function showZeitreihe(bundesland, partei) {
|
||||
const backdrop = document.getElementById('modal-backdrop');
|
||||
const title = document.getElementById('modal-title');
|
||||
const body = document.getElementById('modal-body');
|
||||
title.textContent = `${bundesland} × ${partei}`;
|
||||
body.innerHTML = '<p>Lade Zeitreihe …</p>';
|
||||
backdrop.classList.add('show');
|
||||
try {
|
||||
const r = await fetch(`/api/auswertungen/zeitreihe?bundesland=${encodeURIComponent(bundesland)}&partei=${encodeURIComponent(partei)}`);
|
||||
const z = await r.json();
|
||||
if (!z.wahlperioden || !z.wahlperioden.length) {
|
||||
body.innerHTML = '<p style="color:#888;">Keine Daten für diese Kombination.</p>';
|
||||
return;
|
||||
}
|
||||
let html = '<table><thead><tr><th>Wahlperiode</th><th>Anträge</th><th>Ø GWÖ-Score</th></tr></thead><tbody>';
|
||||
for (const row of z.wahlperioden) {
|
||||
html += `<tr><td>${row.wp}</td><td>${row.n}</td><td><strong>${row.avg.toFixed(2)}</strong></td></tr>`;
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
body.innerHTML = html;
|
||||
} catch (e) {
|
||||
body.innerHTML = `<p style="color:#d00;">Fehler: ${e}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
function closeModal(ev) {
|
||||
// Klick aufs Backdrop schließt; Klicks im Modal nicht
|
||||
if (!ev || ev.target.id === 'modal-backdrop') {
|
||||
document.getElementById('modal-backdrop').classList.remove('show');
|
||||
} else if (!ev.target) {
|
||||
document.getElementById('modal-backdrop').classList.remove('show');
|
||||
}
|
||||
}
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') document.getElementById('modal-backdrop').classList.remove('show');
|
||||
});
|
||||
|
||||
loadMatrix();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user