x-axis justierung: lines 2
This commit is contained in:
@@ -121,6 +121,21 @@
|
|||||||
table.dtbl td:nth-child(2) { text-align: left; }
|
table.dtbl td:nth-child(2) { text-align: left; }
|
||||||
table.dtbl tr:hover td { background: #1a1f2b; }
|
table.dtbl tr:hover td { background: #1a1f2b; }
|
||||||
.row-1cam td:first-child::before { content: ''; }
|
.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-hi { color: #fbbf24; } /* amber: trianguliert */
|
||||||
.cell-lo { color: #dde3ec; } /* hell: nur 2D */
|
.cell-lo { color: #dde3ec; } /* hell: nur 2D */
|
||||||
.cell-unk { color: #3b82f6; } /* blau: fremd */
|
.cell-unk { color: #3b82f6; } /* blau: fremd */
|
||||||
@@ -171,6 +186,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="table-wrap"></div>
|
<div id="table-wrap"></div>
|
||||||
|
<div id="viewer-log"></div>
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import * as THREE from 'three';
|
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 _primaryFremdMarkers = []; // [{marker_id, position_mm, num_cameras}]
|
||||||
let _compareFremdMarkers = []; // [{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) {
|
function clearGroup(g) {
|
||||||
while (g.children.length) {
|
while (g.children.length) {
|
||||||
const c = g.children[0];
|
const c = g.children[0];
|
||||||
@@ -609,15 +637,35 @@ function buildCompareLines() {
|
|||||||
clearGroup(gCompareLines);
|
clearGroup(gCompareLines);
|
||||||
const compareActive = _compareFremdMarkers.length > 0;
|
const compareActive = _compareFremdMarkers.length > 0;
|
||||||
setSceneOpacity(compareActive);
|
setSceneOpacity(compareActive);
|
||||||
if (!compareActive || !_primaryFremdMarkers.length) return;
|
|
||||||
|
|
||||||
const primaryMap = new Map(_primaryFremdMarkers.map(m => [m.marker_id, m]));
|
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) {
|
for (const cm of _compareFremdMarkers) {
|
||||||
const pm = primaryMap.get(cm.marker_id);
|
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)
|
// Linie: Basis-Position (blau) → Vergleichs-Position (orange)
|
||||||
gCompareLines.add(makeLine(r2vArr(pm.position_mm), r2vArr(cm.position_mm), 0xfb923c, 0.85));
|
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 ───────────────────────────────────────────────────────────────
|
// ── Daten laden ───────────────────────────────────────────────────────────────
|
||||||
@@ -645,6 +693,9 @@ async function loadData() {
|
|||||||
// Fremd-Marker für Verbindungslinien merken (Marker, die nicht in Board-Link stehen)
|
// 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));
|
const bIds = new Set((data.robot?.links?.Board?.markers ?? []).map(m => m.id));
|
||||||
_primaryFremdMarkers = (data.measuredMarkers?.markers ?? []).filter(m => !bIds.has(m.marker_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();
|
buildCompareLines();
|
||||||
const robotLabel = data.robotFile ? ` • Robot: ${data.robotFile}` : '';
|
const robotLabel = data.robotFile ? ` • Robot: ${data.robotFile}` : '';
|
||||||
statusEl.textContent = `Run: ${data.runDir}${robotLabel} • ${new Date().toLocaleTimeString('de-CH')}`;
|
statusEl.textContent = `Run: ${data.runDir}${robotLabel} • ${new Date().toLocaleTimeString('de-CH')}`;
|
||||||
@@ -662,21 +713,24 @@ async function loadCompareData() {
|
|||||||
clearGroup(gCompare);
|
clearGroup(gCompare);
|
||||||
_compareFremdMarkers = [];
|
_compareFremdMarkers = [];
|
||||||
const selRun = document.getElementById('sel-run-compare')?.value ?? '';
|
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 {
|
try {
|
||||||
const r = await fetch(`/api/board/latest?run=${encodeURIComponent(selRun)}`);
|
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 data = await r.json();
|
||||||
const markers = data.measuredMarkers?.markers ?? [];
|
const markers = data.measuredMarkers?.markers ?? [];
|
||||||
// Board-Marker-IDs aus Robot.json dieses Runs
|
// Board-Marker-IDs aus Robot.json dieses Runs
|
||||||
const boardIds = new Set((data.robot?.links?.Board?.markers ?? []).map(m => m.id));
|
const boardIds = new Set((data.robot?.links?.Board?.markers ?? []).map(m => m.id));
|
||||||
for (const m of markers) {
|
for (const m of markers) {
|
||||||
if (!boardIds.has(m.marker_id)) {
|
if (!boardIds.has(m.marker_id)) {
|
||||||
_compareFremdMarkers.push(m); // für Linien
|
_compareFremdMarkers.push(m); // für Linien
|
||||||
gCompare.add(makeSphere(r2vArr(m.position_mm), 0.006, 0xf97316)); // orange Kugel
|
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
|
buildCompareLines(); // Linien + Transparenz aktualisieren
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,22 +753,35 @@ async function initRunSelectors() {
|
|||||||
runs5.map(r => `<option value="${r}"${r === cur ? ' selected' : ''}>${r}</option>`).join('');
|
runs5.map(r => `<option value="${r}"${r === cur ? ' selected' : ''}>${r}</option>`).join('');
|
||||||
}
|
}
|
||||||
if (selC) {
|
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>' +
|
selC.innerHTML = '<option value="">– keiner –</option>' +
|
||||||
runs10.map(r => `<option value="${r}">${r}</option>`).join('');
|
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 */ }
|
} catch { /* offline oder noch keine Runs */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
initRunSelectors().then(() => loadData());
|
/** Vollständige Initialisierung: Selektoren → Basis → Vergleich (sequenziell!) */
|
||||||
document.getElementById('btnReload').addEventListener('click', () => {
|
async function initAll() {
|
||||||
initRunSelectors().then(() => { loadData(); loadCompareData(); });
|
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);
|
document.getElementById('sel-run-compare')?.addEventListener('change', loadCompareData);
|
||||||
window.addEventListener('message', (e) => {
|
window.addEventListener('message', async (e) => {
|
||||||
if (e.data?.type === 'reload') {
|
if (e.data?.type === 'reload') await initAll();
|
||||||
initRunSelectors().then(() => { loadData(); loadCompareData(); });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Resize & Render-Loop ──────────────────────────────────────────────────────
|
// ── Resize & Render-Loop ──────────────────────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user