From fc4d2b3c8421cce35cb6c15c8fc991a9d7cb8fd9 Mon Sep 17 00:00:00 2001
From: chk <79915315+ChKendel@users.noreply.github.com>
Date: Sun, 14 Jun 2026 18:38:33 +0200
Subject: [PATCH] UI verbessern 2
---
public/boardViewer.html | 21 ++++++++--
public/client.js | 89 +++++++++++++++++++++++++++++++++--------
public/index.html | 2 +-
server/server.js | 8 +++-
4 files changed, 98 insertions(+), 22 deletions(-)
diff --git a/public/boardViewer.html b/public/boardViewer.html
index 9e51b0a..a9f83d8 100644
--- a/public/boardViewer.html
+++ b/public/boardViewer.html
@@ -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
}
-initAll();
+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);
diff --git a/public/client.js b/public/client.js
index 1f4b467..b1221c4 100755
--- a/public/client.js
+++ b/public/client.js
@@ -378,30 +378,87 @@ 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();
- const debugImages = (data.images ?? []).filter(img => /debug/i.test(img.filename));
- let html = '
';
- for (const img of debugImages) {
- html += `
-
-
- ${img.filename}
-
- `;
+ // ── Debug-Bilder ──────────────────────────────────────────────────────────
+ const display = document.getElementById('snapshot-info-picture');
+ if (display) {
+ const debugImages = (data.images ?? []).filter(img => /debug/i.test(img.filename));
+ let html = '
';
+ for (const img of debugImages) {
+ html += `
+
+
+ ${img.filename}
+
+ `;
+ }
+ html += '
';
+ display.innerHTML = html;
}
- html += '
';
- 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 }, '*');
}
diff --git a/public/index.html b/public/index.html
index 5822f70..b0bc400 100755
--- a/public/index.html
+++ b/public/index.html
@@ -89,7 +89,7 @@
diff --git a/server/server.js b/server/server.js
index 8b8118f..745a7ce 100755
--- a/server/server.js
+++ b/server/server.js
@@ -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) });
}