x-axis justierung: lines 2

This commit is contained in:
chk
2026-06-10 18:49:26 +02:00
parent 145c14842a
commit fa91a36da9

View File

@@ -121,6 +121,21 @@
table.dtbl td:nth-child(2) { text-align: left; }
table.dtbl tr:hover td { background: #1a1f2b; }
.row-1cam td:first-child::before { content: ''; }
/* ── Viewer-Log ── */
#viewer-log {
flex-shrink: 0;
max-height: 64px;
overflow-y: auto;
border-top: 1px solid var(--border);
background: #090b0e;
padding: 2px 10px 3px;
font-size: 10px;
color: #4a5568;
line-height: 1.6;
}
#viewer-log .vl-ok { color: #4ade80; }
#viewer-log .vl-warn{ color: #fbbf24; }
#viewer-log .vl-err { color: #f87171; }
.cell-hi { color: #fbbf24; } /* amber: trianguliert */
.cell-lo { color: #dde3ec; } /* hell: nur 2D */
.cell-unk { color: #3b82f6; } /* blau: fremd */
@@ -171,6 +186,7 @@
</div>
<div id="table-wrap"></div>
<div id="viewer-log"></div>
<script type="module">
import * as THREE from 'three';
@@ -221,6 +237,18 @@ scene.add(gPaper, gMarkers, gMeasured, gCameras, gCompare, gCompareLines);
let _primaryFremdMarkers = []; // [{marker_id, position_mm, num_cameras}]
let _compareFremdMarkers = []; // [{marker_id, position_mm, num_cameras}]
// ── Viewer-interner Logger ────────────────────────────────────────────────────
function vlog(msg, kind = '') {
const el = document.getElementById('viewer-log');
if (!el) return;
const d = document.createElement('div');
d.className = kind ? `vl-${kind}` : '';
d.textContent = `${new Date().toLocaleTimeString('de-CH')} ${msg}`;
el.appendChild(d);
while (el.children.length > 40) el.removeChild(el.firstChild);
el.scrollTop = el.scrollHeight;
}
function clearGroup(g) {
while (g.children.length) {
const c = g.children[0];
@@ -609,15 +637,35 @@ function buildCompareLines() {
clearGroup(gCompareLines);
const compareActive = _compareFremdMarkers.length > 0;
setSceneOpacity(compareActive);
if (!compareActive || !_primaryFremdMarkers.length) return;
if (!compareActive) {
vlog(`Vergleich inaktiv Board-Marker voll sichtbar`);
return;
}
if (!_primaryFremdMarkers.length) {
vlog(`⚠ Basis hat 0 fremd-Marker keine Linien möglich`, 'warn');
return;
}
const primaryMap = new Map(_primaryFremdMarkers.map(m => [m.marker_id, m]));
const matchedIds = [];
const onlyCompare = []; // in compare aber nicht in primary
const onlyPrimary = [...primaryMap.keys()]; // werden unten gefiltert
for (const cm of _compareFremdMarkers) {
const pm = primaryMap.get(cm.marker_id);
if (!pm) continue;
if (!pm) { onlyCompare.push(cm.marker_id); continue; }
matchedIds.push(cm.marker_id);
// Linie: Basis-Position (blau) → Vergleichs-Position (orange)
gCompareLines.add(makeLine(r2vArr(pm.position_mm), r2vArr(cm.position_mm), 0xfb923c, 0.85));
}
const noMatch = onlyPrimary.filter(id => !matchedIds.includes(id));
const parts = [`${matchedIds.length} Linien`];
if (matchedIds.length) parts.push(`IDs: ${matchedIds.join(' ')}`);
if (onlyCompare.length) parts.push(`nur Vergleich: ${onlyCompare.join(' ')}`);
if (noMatch.length) parts.push(`nur Basis: ${noMatch.join(' ')}`);
vlog(parts.join(' | '), matchedIds.length ? 'ok' : 'warn');
}
// ── Daten laden ───────────────────────────────────────────────────────────────
@@ -645,6 +693,9 @@ async function loadData() {
// Fremd-Marker für Verbindungslinien merken (Marker, die nicht in Board-Link stehen)
const bIds = new Set((data.robot?.links?.Board?.markers ?? []).map(m => m.id));
_primaryFremdMarkers = (data.measuredMarkers?.markers ?? []).filter(m => !bIds.has(m.marker_id));
const measTotal = data.measuredMarkers?.markers?.length ?? 0;
vlog(`Basis: run=${data.runDir} gesamt=${measTotal} fremd=${_primaryFremdMarkers.length} boardIDs=${bIds.size}` +
(_primaryFremdMarkers.length ? ` (${_primaryFremdMarkers.map(m => m.marker_id).join(' ')})` : ''));
buildCompareLines();
const robotLabel = data.robotFile ? ` • Robot: ${data.robotFile}` : '';
statusEl.textContent = `Run: ${data.runDir}${robotLabel}${new Date().toLocaleTimeString('de-CH')}`;
@@ -662,10 +713,11 @@ async function loadCompareData() {
clearGroup(gCompare);
_compareFremdMarkers = [];
const selRun = document.getElementById('sel-run-compare')?.value ?? '';
if (!selRun) { buildCompareLines(); return; }
if (!selRun) { vlog('Vergleich: keiner gewählt'); buildCompareLines(); return; }
vlog(`Vergleich: lade ${selRun}`);
try {
const r = await fetch(`/api/board/latest?run=${encodeURIComponent(selRun)}`);
if (!r.ok) { buildCompareLines(); return; }
if (!r.ok) { vlog(`Vergleich: HTTP ${r.status}`, 'err'); buildCompareLines(); return; }
const data = await r.json();
const markers = data.measuredMarkers?.markers ?? [];
// Board-Marker-IDs aus Robot.json dieses Runs
@@ -676,7 +728,9 @@ async function loadCompareData() {
gCompare.add(makeSphere(r2vArr(m.position_mm), 0.006, 0xf97316)); // orange Kugel
}
}
} catch { /* kein 3b-Output für diesen Run */ }
vlog(`Vergleich: ${markers.length} gesamt fremd=${_compareFremdMarkers.length} boardIDs=${boardIds.size}` +
(_compareFremdMarkers.length ? ` (${_compareFremdMarkers.map(m => m.marker_id).join(' ')})` : ''));
} catch (err) { vlog(`Vergleich Fehler: ${err}`, 'err'); }
buildCompareLines(); // Linien + Transparenz aktualisieren
}
@@ -699,22 +753,35 @@ async function initRunSelectors() {
runs5.map(r => `<option value="${r}"${r === cur ? ' selected' : ''}>${r}</option>`).join('');
}
if (selC) {
// Default: zweiten neuesten Run vorwählen (falls vorhanden und noch kein Wert gesetzt)
const prevCompare = selC.value;
selC.innerHTML = '<option value=""> keiner </option>' +
runs10.map(r => `<option value="${r}">${r}</option>`).join('');
if (prevCompare) {
selC.value = prevCompare; // bisher gewählten behalten
} else if (runs10.length >= 2) {
selC.value = runs10[1]; // zweiter neuester als Default
}
}
} catch { /* offline oder noch keine Runs */ }
}
initRunSelectors().then(() => loadData());
document.getElementById('btnReload').addEventListener('click', () => {
initRunSelectors().then(() => { loadData(); loadCompareData(); });
/** Vollständige Initialisierung: Selektoren → Basis → Vergleich (sequenziell!) */
async function initAll() {
await initRunSelectors();
await loadData(); // setzt _primaryFremdMarkers
await loadCompareData(); // setzt _compareFremdMarkers + baut Linien
}
initAll();
document.getElementById('btnReload').addEventListener('click', initAll);
document.getElementById('sel-run-primary')?.addEventListener('change', async () => {
await loadData();
await loadCompareData();
});
document.getElementById('sel-run-primary')?.addEventListener('change', loadData);
document.getElementById('sel-run-compare')?.addEventListener('change', loadCompareData);
window.addEventListener('message', (e) => {
if (e.data?.type === 'reload') {
initRunSelectors().then(() => { loadData(); loadCompareData(); });
}
window.addEventListener('message', async (e) => {
if (e.data?.type === 'reload') await initAll();
});
// ── Resize & Render-Loop ──────────────────────────────────────────────────────