UI verbessern 2

This commit is contained in:
chk
2026-06-14 18:38:33 +02:00
parent c23fbf75f2
commit fc4d2b3c84
4 changed files with 98 additions and 22 deletions

View File

@@ -890,14 +890,20 @@ function computeAndShowYAxis() {
// ── Daten laden ───────────────────────────────────────────────────────────────
/** Haupt-Run laden. Im Homing-Mode: immer neuester Homing-Run, kein Dropdown. */
async function loadData() {
/**
* Haupt-Run laden.
* Im Homing-Mode: lädt spezifischen Run per runDir-Parameter (kein Dropdown).
* @param {string|null} specificRunDir Timestamp des Runs (nur im Homing-Mode genutzt)
*/
async function loadData(specificRunDir = null) {
const statusEl = document.getElementById('status');
statusEl.textContent = 'Laden …';
let url;
if (IS_HOMING) {
url = '/api/board/latest?from=homing';
url = specificRunDir
? `/api/board/latest?from=homing&run=${encodeURIComponent(specificRunDir)}`
: '/api/board/latest?from=homing';
} else {
const selRun = document.getElementById('sel-run-primary')?.value ?? '';
url = selRun
@@ -1071,7 +1077,11 @@ async function initAll() {
await loadPositionC(); // setzt _positionCFremdMarkers + berechnet Y-Achse
}
if (IS_HOMING) {
document.getElementById('status').textContent = '→ Homing-Run starten …';
} else {
initAll();
}
document.getElementById('btnReload').addEventListener('click', initAll);
document.getElementById('sel-run-primary')?.addEventListener('change', async () => {
await loadData();
@@ -1084,6 +1094,9 @@ document.getElementById('sel-run-compare')?.addEventListener('change', async ()
document.getElementById('sel-run-c')?.addEventListener('change', loadPositionC);
window.addEventListener('message', async (e) => {
if (e.data?.type === 'reload') await initAll();
if (e.data?.type === 'load-homing-run' && IS_HOMING) {
await loadData(e.data.runDir);
}
if (e.data?.type === 'homing-state' && IS_HOMING) {
_homingAngles = e.data.state;
if (_currentRobot) buildSkeletonFK(_currentRobot, _homingAngles);

View File

@@ -378,13 +378,15 @@ function showHomingResult(state) {
}
async function loadHomingImages(runDir) {
const display = document.getElementById('snapshot-info-picture');
if (!display || !runDir) return;
if (!runDir) return;
try {
const res = await fetch(`/api/homing/run-data?run=${encodeURIComponent(runDir)}`);
if (!res.ok) return;
const data = await res.json();
// ── Debug-Bilder ──────────────────────────────────────────────────────────
const display = document.getElementById('snapshot-info-picture');
if (display) {
const debugImages = (data.images ?? []).filter(img => /debug/i.test(img.filename));
let html = '<div style="display:flex;flex-direction:column;gap:12px;margin-top:8px">';
for (const img of debugImages) {
@@ -399,9 +401,64 @@ async function loadHomingImages(runDir) {
}
html += '</div>';
display.innerHTML = html;
}
// ── Marker-CSV-Tabelle ────────────────────────────────────────────────────
if (data.csvContent) renderHomingCsv(data.csvContent, runDir);
} catch { /* nicht kritisch */ }
}
function renderHomingCsv(csvContent, runDir) {
const table = document.getElementById('snapshot-table');
const infoEl = document.getElementById('snapshot-info');
if (!table) return;
const lines = csvContent.trim().split(/\r?\n/).filter(Boolean);
if (lines.length < 2) return;
const headers = lines[0].split(',').map(h => h.trim());
const rows = lines.slice(1).map(line => {
const cells = line.split(',');
const obj = {};
headers.forEach((h, i) => {
const raw = (cells[i] ?? '').trim();
const num = Number(raw);
obj[h] = raw !== '' && Number.isFinite(num) ? num : raw;
});
return obj;
});
if (infoEl) infoEl.textContent = `aruco_marker_poses.csv · ${runDir} · ${rows.length} Marker`;
table.innerHTML = '';
const thead = document.createElement('thead');
const headerRow = document.createElement('tr');
headers.forEach(h => {
const th = document.createElement('th');
th.textContent = h;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
table.appendChild(thead);
const tbody = document.createElement('tbody');
rows.forEach(row => {
const tr = document.createElement('tr');
headers.forEach(h => {
const td = document.createElement('td');
let v = row[h];
if (typeof v === 'number') {
v = /^(marker_id|id|num_cameras|seen_by)$/.test(h) ? Math.round(v) : v.toFixed(1);
}
td.textContent = v ?? '';
tr.appendChild(td);
});
tbody.appendChild(tr);
});
table.appendChild(tbody);
}
async function runHoming() {
// UI zurücksetzen
clearTextarea('log');
@@ -487,7 +544,7 @@ async function runHoming() {
if (evt.runDir) await loadHomingImages(evt.runDir);
const frame = document.getElementById('board-viewer-frame');
if (frame?.contentWindow) {
frame.contentWindow.postMessage({ type: 'reload' }, '*');
frame.contentWindow.postMessage({ type: 'load-homing-run', runDir: evt.runDir }, '*');
if (evt.state) {
frame.contentWindow.postMessage({ type: 'homing-state', state: evt.state }, '*');
}

View File

@@ -89,7 +89,7 @@
<iframe
id="board-viewer-frame"
src="/boardViewer.html?mode=homing"
style="width:100%;height:600px;border:1px solid #334155;border-radius:6px;background:#0d0f13;display:block;margin-top:12px"
style="width:100%;height:1200px;border:1px solid #334155;border-radius:6px;background:#0d0f13;display:block;margin-top:12px"
title="Board-Viewer"
></iframe>
</div>

View File

@@ -839,7 +839,13 @@ app.get('/api/homing/run-data', async (req, res) => {
} catch {}
}
return res.json({ runDir: runName, images, finalState });
// aruco_marker_poses.csv für Snapshot-CSV-Tabelle
let csvContent = null;
try {
csvContent = await fsPromises.readFile(path.join(runDir, 'aruco_marker_poses.csv'), 'utf8');
} catch {}
return res.json({ runDir: runName, images, finalState, csvContent });
} catch (err) {
return res.status(500).json({ error: String(err) });
}