Design
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user