Add visualization_tool/js/charts.js
This commit is contained in:
parent
7dd2ee785a
commit
8dddf4fcf4
1 changed files with 123 additions and 0 deletions
123
visualization_tool/js/charts.js
Normal file
123
visualization_tool/js/charts.js
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
/**
|
||||||
|
* js/charts.js
|
||||||
|
* Visualisierung der Laufdaten in Matrix- und Zeitdiagrammen.
|
||||||
|
* Enthält Funktionen zur DOM-Aktualisierung von #delta-matrix und #timeline-chart.
|
||||||
|
* @module charts
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rendert eine 2×2-Matrix aus den gegebenen aggregierten Daten.
|
||||||
|
* Die Matrix zeigt pinned/unpinned (x) vs. Δt≥0/<0 (y).
|
||||||
|
* @param {Object} data - Aggregierte Daten in der Form:
|
||||||
|
* {
|
||||||
|
* pinned_pos: number,
|
||||||
|
* pinned_neg: number,
|
||||||
|
* unpinned_pos: number,
|
||||||
|
* unpinned_neg: number
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export function renderDeltaMatrix(data) {
|
||||||
|
const container = document.getElementById('delta-matrix');
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
container.innerHTML = '';
|
||||||
|
|
||||||
|
const matrixData = [
|
||||||
|
{ label: 'Pinned Δt≥0', value: data?.pinned_pos ?? 0 },
|
||||||
|
{ label: 'Pinned Δt<0', value: data?.pinned_neg ?? 0 },
|
||||||
|
{ label: 'Unpinned Δt≥0', value: data?.unpinned_pos ?? 0 },
|
||||||
|
{ label: 'Unpinned Δt<0', value: data?.unpinned_neg ?? 0 }
|
||||||
|
];
|
||||||
|
|
||||||
|
const matrixGrid = document.createElement('div');
|
||||||
|
matrixGrid.className = 'delta-matrix__grid';
|
||||||
|
matrixGrid.style.display = 'grid';
|
||||||
|
matrixGrid.style.gridTemplateColumns = 'repeat(2, 1fr)';
|
||||||
|
matrixGrid.style.gap = '1rem';
|
||||||
|
|
||||||
|
matrixData.forEach(cell => {
|
||||||
|
const cellDiv = document.createElement('div');
|
||||||
|
cellDiv.className = 'delta-matrix__cell';
|
||||||
|
cellDiv.setAttribute('role', 'region');
|
||||||
|
cellDiv.setAttribute('aria-label', cell.label);
|
||||||
|
|
||||||
|
const label = document.createElement('div');
|
||||||
|
label.className = 'delta-matrix__label';
|
||||||
|
label.textContent = cell.label;
|
||||||
|
|
||||||
|
const value = document.createElement('div');
|
||||||
|
value.className = 'delta-matrix__value';
|
||||||
|
value.textContent = cell.value.toFixed(2);
|
||||||
|
|
||||||
|
cellDiv.appendChild(label);
|
||||||
|
cellDiv.appendChild(value);
|
||||||
|
matrixGrid.appendChild(cellDiv);
|
||||||
|
});
|
||||||
|
|
||||||
|
container.appendChild(matrixGrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rendert den zeitlichen Verlauf der Δt-Werte als Liniendiagramm.
|
||||||
|
* Nutzt Canvas API (ohne externes Chart-Framework).
|
||||||
|
* @param {Array<{timestamp: string|number, delta_t: number}>} timeData - Zeitreihen-Daten.
|
||||||
|
*/
|
||||||
|
export function renderTimelineChart(timeData) {
|
||||||
|
const container = document.getElementById('timeline-chart');
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
container.innerHTML = '';
|
||||||
|
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = container.clientWidth || 600;
|
||||||
|
canvas.height = 300;
|
||||||
|
container.appendChild(canvas);
|
||||||
|
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
if (!ctx || !Array.isArray(timeData) || timeData.length === 0) {
|
||||||
|
ctx.fillStyle = '#666';
|
||||||
|
ctx.fillText('Keine Daten verfügbar', 20, 40);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxVal = Math.max(...timeData.map(d => d.delta_t));
|
||||||
|
const minVal = Math.min(...timeData.map(d => d.delta_t));
|
||||||
|
|
||||||
|
const normalize = v => (v - minVal) / (maxVal - minVal || 1);
|
||||||
|
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.strokeStyle = '#0077cc';
|
||||||
|
|
||||||
|
timeData.forEach((point, i) => {
|
||||||
|
const x = (i / (timeData.length - 1)) * (canvas.width - 40) + 20;
|
||||||
|
const y = canvas.height - (normalize(point.delta_t) * (canvas.height - 40) + 20);
|
||||||
|
if (i === 0) ctx.moveTo(x, y);
|
||||||
|
else ctx.lineTo(x, y);
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// Achsen zeichnen
|
||||||
|
ctx.strokeStyle = '#333';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(20, 10);
|
||||||
|
ctx.lineTo(20, canvas.height - 20);
|
||||||
|
ctx.lineTo(canvas.width - 20, canvas.height - 20);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// Beschriftungen
|
||||||
|
ctx.fillStyle = '#222';
|
||||||
|
ctx.font = '12px sans-serif';
|
||||||
|
ctx.fillText('Zeit', canvas.width / 2 - 20, canvas.height - 5);
|
||||||
|
ctx.save();
|
||||||
|
ctx.rotate(-Math.PI / 2);
|
||||||
|
ctx.fillText('Δt', -canvas.height / 2 - 10, 10);
|
||||||
|
ctx.restore();
|
||||||
|
|
||||||
|
// Accessibility-Hinweis
|
||||||
|
canvas.setAttribute('role', 'img');
|
||||||
|
canvas.setAttribute('aria-label', 'Liniendiagramm der Δt-Zeitverteilung');
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue