This commit is contained in:
chk
2026-06-10 11:20:10 +02:00
parent 3741ad9f6a
commit 9650dee02e
2 changed files with 261 additions and 14 deletions

View File

@@ -155,6 +155,31 @@
.status-badge.done { color: #34d399; background: #064e3b; }
.status-badge.wip { color: #60a5fa; }
/* ===== INFO GRID ===== */
.info-grid {
display: grid;
grid-template-columns: 160px 1fr;
gap: 6px 12px;
margin-top: 14px;
font-size: 13px;
}
.info-label {
color: var(--muted);
}
.info-value {
color: var(--text);
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
/* Buttons: aktiv vs. deaktiviert visuell unterscheiden */
.controls button:disabled {
opacity: 0.35;
cursor: not-allowed;
}
</style>
</head>
<body>
@@ -183,22 +208,33 @@
<div class="tab-panel active" id="tab-camera-npz">
<div class="sections">
<!-- Info-Box: Aktuelle Kalibrierung -->
<div class="section full">
<h2>Camera NPZ <span class="status-badge open">offen</span></h2>
<div class="placeholder-note">
Ziel: Intrinsische Kameraparameter (Kameramatrix, Verzerrungskoeffizienten) für jede
Kamera ermitteln und als <code>.npz</code>-Datei speichern.<br><br>
Geplante Aktionen: Fotos aufnehmen (verschiedene Posen) · Kalibrierung berechnen ·
Reprojektionsfehler anzeigen · Datei speichern.<br><br>
<em>Aktionen werden ergänzt sobald das Konzept feststeht.</em>
</div>
<div class="controls" style="margin-top: 14px;">
<button disabled>Fotos aufnehmen</button>
<button disabled>Kalibrierung berechnen</button>
<button disabled>NPZ speichern</button>
<h2>Aktuelle Kalibrierung</h2>
<div id="calib-info" class="info-grid">
<span class="info-label">Timestamp</span>
<span class="info-value" id="info-timestamp"></span>
<span class="info-label">Erstellt am</span>
<span class="info-value" id="info-created"></span>
<span class="info-label">Bilder / Kameras</span>
<span class="info-value" id="info-images"></span>
</div>
</div>
<!-- Aktionen -->
<div class="section full">
<h2>Aktionen</h2>
<div class="controls" style="margin-top: 14px;">
<button id="btn-new-calib">Neue Kalibrierung anlegen</button>
<button id="btn-foto-calib">Foto aufnehmen</button>
<button disabled title="Folgt später">Kalibrierung berechnen</button>
<button disabled title="Folgt später">NPZ speichern</button>
</div>
</div>
<!-- Ausgabe -->
<div class="section full">
<h2>Ausgabe / Log</h2>
<textarea id="log-camera" readonly placeholder="(Ausgabe erscheint hier)"></textarea>
@@ -304,7 +340,7 @@
</div><!-- /.calib-body -->
<script>
// Tab-Switching
// ── Tab-Switching ──────────────────────────────────────────────────────────
document.getElementById('tabSidebar').addEventListener('click', e => {
const btn = e.target.closest('.tab-btn');
if (!btn) return;
@@ -314,10 +350,83 @@
document.getElementById('tab-' + btn.dataset.tab).classList.add('active');
});
// Section collapse (gleiche Logik wie Hauptseite)
// ── Section collapse ───────────────────────────────────────────────────────
document.querySelectorAll('.section h2').forEach(h2 => {
h2.addEventListener('click', () => h2.closest('.section').classList.toggle('collapsed'));
});
// ── Camera NPZ ─────────────────────────────────────────────────────────────
const logCamera = document.getElementById('log-camera');
function logC(msg) {
const ts = new Date().toLocaleTimeString('de-CH');
logCamera.value += `[${ts}] ${msg}\n`;
logCamera.scrollTop = logCamera.scrollHeight;
}
function formatDate(isoString) {
if (!isoString) return '';
return new Date(isoString).toLocaleString('de-CH');
}
function updateCalibInfo(meta) {
if (!meta) {
document.getElementById('info-timestamp').textContent = '(keine Session vorhanden)';
document.getElementById('info-created').textContent = '';
document.getElementById('info-images').textContent = '';
return;
}
document.getElementById('info-timestamp').textContent = meta.timestamp ?? '';
document.getElementById('info-created').textContent = formatDate(meta.createdAt);
const imgTxt = meta.imageCount != null
? `${meta.imageCount} Bilder total. ${(meta.cameras ?? []).length} Kamera(s) verwendet.`
: '';
document.getElementById('info-images').textContent = imgTxt;
}
// Beim Laden aktuelle Session holen
async function loadCalibCurrent() {
try {
const r = await fetch('/api/calibration/current');
const d = await r.json();
updateCalibInfo(d.meta);
if (d.session) logC(`Session geladen: ${d.session}`);
else logC('Noch keine Kalibrierungs-Session vorhanden.');
} catch (err) {
logC(`Fehler beim Laden: ${err}`);
}
}
loadCalibCurrent();
// "Neue Kalibrierung anlegen"
document.getElementById('btn-new-calib').addEventListener('click', async () => {
logC('Neue Kalibrierung wird angelegt …');
try {
const r = await fetch('/api/calibration/new', { method: 'POST' });
const d = await r.json();
if (d.error) { logC(`Fehler: ${d.error}`); return; }
updateCalibInfo(d.meta);
if (d.warning) logC(`Warnung: ${d.warning}`);
else logC(`Session angelegt: ${d.session} | Fotos: ${(d.savedFiles ?? []).join(', ')}`);
} catch (err) {
logC(`Fehler: ${err}`);
}
});
// "Foto aufnehmen"
document.getElementById('btn-foto-calib').addEventListener('click', async () => {
logC('Fotos werden aufgenommen …');
try {
const r = await fetch('/api/calibration/foto', { method: 'POST' });
const d = await r.json();
if (d.error) { logC(`Fehler: ${d.error}`); return; }
updateCalibInfo(d.meta);
logC(`Gespeichert: ${(d.savedFiles ?? []).join(', ')}`);
} catch (err) {
logC(`Fehler: ${err}`);
}
});
</script>
</body>