Browse Source

feat(explorer): implement vertical ADAS property view and optimize workspace layout

This commit introduces a specialized visualization for ADAS radar data and significantly
improves the Data Explorer's responsiveness at small window dimensions.

Key Changes:
- ADAS Visualization: Replaced the horizontal AG Grid for the ADAS tab with a custom
  Vertical Property View. This uses a card-based layout with clean Key-Value tables,
  optimizing for high-column counts and narrow panels.
- Layout Optimizations:
  - Reduced minimum window dimensions for the Data Explorer from 400x300 to 250x200.
  - Implemented horizontal scrolling for the tab navigation row to prevent UI breakage
    at narrow widths.
  - Added 'flex-shrink-0' guards to the panel header and tabs to ensure they remain
    visible and stable during vertical resizing.
- UI Refinement: Cleaned up the ADAS view by removing redundant property IDs from
  headers and centering all data within a structured 2-column grid.
- Documentation:
  - Updated the /intel folder (readme.md, context.md, GEMINI.md) to reflect new features.
  - Added "Rationale" comments to source code (index.html, dataExplorer.js) to document
    architectural decisions and prevent future UI regressions.

Fixes: #ADAS-Explorer-Overhaul
refactor/sync-centralize
RUSHIL AMBARISH KADU 4 weeks ago
parent
commit
bc17f57b81
  1. 28
      steps/index.html
  2. 5
      steps/intel/GEMINI.md
  3. 11
      steps/intel/context.md
  4. 2
      steps/intel/readme.md
  5. 74
      steps/src/dataExplorer.js
  6. 873540
      track_history_playback.json

28
steps/index.html

@ -620,33 +620,30 @@
<!-- END: Floating Zoom Panel -->
<div id="data-explorer-panel"
/* flex-col is critical for the header/tabs/content stack */
class="hidden fixed bottom-24 right-4 bg-white dark:bg-gray-800 shadow-2xl rounded-lg z-30 flex flex-col w-full max-w-2xl h-1/2 border dark:border-gray-600">
<!-- START: Add Draggable Header and Resizer Handles -->
<!-- Draggable Header: flex-shrink-0 prevents it from being squashed during vertical resize -->
<div id="data-explorer-header"
class="flex items-center justify-between p-2 border-b dark:border-gray-700 cursor-move">
class="flex items-center justify-between p-2 border-b dark:border-gray-700 cursor-move flex-shrink-0">
<h2 class="text-lg font-bold ml-2">Data Explorer</h2>
<button id="close-explorer-btn"
class="text-gray-500 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700 rounded-lg p-1.5">&times;</button>
</div>
<div class="resizer resizer-t"></div>
<div class="resizer resizer-r"></div>
<div class="resizer resizer-b"></div>
<div class="resizer resizer-l"></div>
<div class="resizer resizer-tl"></div>
<div class="resizer resizer-tr"></div>
<div class="resizer resizer-br"></div>
<div class="resizer resizer-bl"></div>
<!-- END: Add Draggable Header and Resizer Handles -->
<div class="flex border-b dark:border-gray-700">
<button id="tab-btn-tree" class="px-4 py-2 text-sm font-medium border-b-2 border-blue-500">Tree View</button>
<button id="tab-btn-grid" class="px-4 py-2 text-sm font-medium text-gray-500 dark:text-gray-400">Grid
<!-- Scrollable Tab Row: overflow-x-auto allows navigation at narrow widths. flex-shrink-0 is required to keep it visible. -->
<div class="flex border-b dark:border-gray-700 overflow-x-auto overflow-y-hidden whitespace-nowrap flex-shrink-0">
<button id="tab-btn-tree" class="px-4 py-2 text-sm font-medium border-b-2 border-blue-500 flex-shrink-0">Tree View</button>
<button id="tab-btn-grid" class="px-4 py-2 text-sm font-medium text-gray-500 dark:text-gray-400 flex-shrink-0">Grid
View</button>
<button id="tab-btn-track-grid" class="px-4 py-2 text-sm font-medium text-gray-500 dark:text-gray-400">Track
<button id="tab-btn-track-grid" class="px-4 py-2 text-sm font-medium text-gray-500 dark:text-gray-400 flex-shrink-0">Track
Grid</button>
<button id="tab-btn-plot" class="px-4 py-2 text-sm font-medium text-gray-500 dark:text-gray-400">Plot
<button id="tab-btn-adas" class="px-4 py-2 text-sm font-medium text-gray-500 dark:text-gray-400 flex-shrink-0">ADAS
Data</button>
<button id="tab-btn-plot" class="px-4 py-2 text-sm font-medium text-gray-500 dark:text-gray-400 flex-shrink-0">Plot
View</button>
</div>
@ -658,6 +655,9 @@
<div id="tab-panel-track-grid" class="hidden h-full p-2">
<div id="track-data-grid" class="ag-theme-alpine-dark h-full w-full"></div>
</div>
<div id="tab-panel-adas" class="hidden h-full p-2 overflow-y-auto">
<div id="adas-vertical-view" class="space-y-4"></div>
</div>
<div id="tab-panel-plot" class="hidden p-2">
<canvas id="data-chart"></canvas>
</div>

5
steps/intel/GEMINI.md

@ -12,7 +12,7 @@ This project is a modular ES6 JavaScript application refactored from a monolithi
- **Storage**: **IndexedDB** for persistent file caching; **localStorage** for user workspace state and layout persistence.
- **Layout Engine**: [GridStack.js](https://gridstackjs.com/) for the modular, resizable dashboard interface.
- **Styling**: Tailwind CSS for a premium, dark-mode-first UI.
- **Data Exploration**: [AG Grid](https://www.ag-grid.com/) and [Chart.js](https://www.chartjs.org/) for forensic data inspection.
- **Data Exploration**: [AG Grid](https://www.ag-grid.com/), **Custom Vertical Property View**, and [Chart.js](https://www.chartjs.org/) for forensic data inspection.
### Architecture
- **State Management**: Centralized in `src/state.js` via the `appState` object.
@ -40,7 +40,8 @@ Since this is a static project using ES6 modules directly in the browser:
## Key Directories and Files
- `src/`: Main source code directory.
- `p5/`: p5.js sketches for Radar, Speed Graph, and Standalone "GOD MODE" Zoom.
- `ui.js`: Unified UI/Workspace engine with layout memory.
- `dataExplorer.js`: Logic for the Data Explorer panel (AG Grid, Vertical Property View, Chart.js).
- `ui.js`: Unified UI/Workspace engine with layout memory and resizable panel logic.
- `sync.js`: High-precision synchronization logic.
- `parser.worker.js`: Off-thread streaming JSON parser.
- `vendor/`: Local copies of 3rd party libraries ensuring offline functionality.

11
steps/intel/context.md

@ -11,7 +11,10 @@ Context Document: Radar and Video Synchronizer Application
- **Data Handling**:
- **Web Workers** (`parser.worker.js`) with the `Clarinet.js` streaming library to parse large JSON files off the main thread, preventing UI freezes.
- `Oboe.js` is included in vendor files but `Clarinet.js` is the active parser.
- **Data Exploration**: `AG-Grid` for tabular data view and `Chart.js` for plotting data from the grid.
- **Data Exploration**:
- `AG-Grid` for tabular Point Cloud and Track data.
- **Vertical Property View** (`dataExplorer.js`) for high-density ADAS data.
- `Chart.js` for plotting data from the grids.
- **Persistence**: `IndexedDB` for caching large files (JSON, Video) and `localStorage` for user settings (UI state, theme, file references).
### 2. Project Architecture & File Structure
@ -49,7 +52,11 @@ The application uses a modular ES6 structure. All source code resides in the `/s
- **`/src/db.js`**: **The Caching Layer**. Manages all interactions with `IndexedDB` to save and load file blobs and their metadata, enabling fast session reloads.
- **`/src/dataExplorer.js`**: **The Inspector**. Manages the "Data Explorer" panel. It uses AG-Grid to display data in a table and Chart.js to plot selected columns. It includes `throttledUpdateExplorer` to efficiently update the view during playback.
- **`/src/dataExplorer.js`**: **The Inspector**. Manages the "Data Explorer" panel.
- **Standard Grids**: Uses AG-Grid for Point Cloud and Track data.
- **ADAS View**: Implements a custom Vertical Property View for readable ADAS inspection.
- **Visualization**: Chart.js for plotting selected numeric columns.
- **Optimizations**: `throttledUpdateExplorer` for performance; scrollable tabs and 250x200 minimum dimensions for compact layouts.
- **`/src/ui.js`**: **The UI Engine**. Manages all advanced interface interactions.
- `makeDraggableAndResizable()`: A unified utility that transforms any DOM element into a floating window with persistent memory.

2
steps/intel/readme.md

@ -58,7 +58,9 @@ The application leverages **p5.js** for rendering, **Web Workers** for backgroun
### `dataExplorer.js` (Data Inspector)
- **Deep Inspection**: Provides Tree View, AG-Grid View, and Chart.js Plotting for raw numerical frame data.
- **ADAS Property View [NEW]**: A specialized Vertical Property View for ADAS data, optimized for high readability of many columns in narrow panels.
- **Persistent Memory [NEW]**: Remembers its last position, size, and display state across page reloads.
- **Layout Optimization [NEW]**: Support for compact "sidecar" mode with reduced minimum dimensions (250x200) and scrollable navigation tabs.
### `keyboard.js` (Shortcuts)
- **Centralized Handler**: Manages all keyboard interactions (Space, 1-4, S, T, D, G, P, etc.).

74
steps/src/dataExplorer.js

@ -19,11 +19,13 @@ const tabs = {
tree: { btn: document.getElementById('tab-btn-tree'), panel: document.getElementById('tab-panel-tree') },
grid: { btn: document.getElementById('tab-btn-grid'), panel: document.getElementById('tab-panel-grid') },
trackGrid: { btn: document.getElementById('tab-btn-track-grid'), panel: document.getElementById('tab-panel-track-grid') },
adas: { btn: document.getElementById('tab-btn-adas'), panel: document.getElementById('tab-panel-adas') },
plot: { btn: document.getElementById('tab-btn-plot'), panel: document.getElementById('tab-panel-plot') },
};
const gridDiv = document.getElementById('data-grid');
const trackGridDiv = document.getElementById('track-data-grid');
const adasContainer = document.getElementById('adas-vertical-view');
const chartCanvas = document.getElementById('data-chart');
// --- Module-Local State ---
@ -170,6 +172,7 @@ function updateExplorer() {
displayInGrid(frame.pointCloud, `${appState.currentFrame + 1}`);
// --- END: Auto-update Point Cloud Grid ---
displayTracksInGrid(tracksForCurrentFrame);
displayAdasData(frame.adas);
}
@ -249,6 +252,74 @@ function displayTracksInGrid(trackData) {
trackGridApi.setGridOption('rowData', trackData);
}
/**
* Renders ADAS data as a vertical property list (cards).
* Rationale: ADAS objects have many properties but few entries per frame.
* A vertical layout is much more readable than a wide horizontal grid.
*/
function displayAdasData(adasData) {
if (!adasContainer) return;
adasContainer.innerHTML = '';
if (!Array.isArray(adasData) || adasData.length === 0) {
const emptyMsg = document.createElement('div');
emptyMsg.className = 'text-gray-500 text-center p-4';
emptyMsg.textContent = 'No ADAS data for this frame';
adasContainer.appendChild(emptyMsg);
return;
}
tabs.adas.btn.textContent = `ADAS Data: Frame ${appState.currentFrame + 1}`;
adasData.forEach((item, index) => {
const card = document.createElement('div');
card.className = 'bg-gray-50 dark:bg-gray-700/50 rounded-lg border border-gray-200 dark:border-gray-600 overflow-hidden';
const table = document.createElement('div');
table.className = 'grid grid-cols-[1fr_auto] gap-px bg-gray-200 dark:bg-gray-600';
// Add Table Headers
const keyHeader = document.createElement('div');
keyHeader.className = 'bg-gray-100 dark:bg-gray-700 px-2 py-1 text-[10px] font-bold uppercase text-gray-400 border-b border-gray-200 dark:border-gray-600';
keyHeader.textContent = 'Key';
const valHeader = document.createElement('div');
valHeader.className = 'bg-gray-100 dark:bg-gray-700 px-2 py-1 text-[10px] font-bold uppercase text-gray-400 border-b border-gray-200 dark:border-gray-600 text-right min-w-[80px]';
valHeader.textContent = 'Value';
table.appendChild(keyHeader);
table.appendChild(valHeader);
Object.entries(item).forEach(([key, value]) => {
const keyEl = document.createElement('div');
keyEl.className = 'bg-white dark:bg-gray-800 px-2 py-1 text-[11px] font-medium text-gray-500 dark:text-gray-400 truncate';
keyEl.textContent = key;
const valEl = document.createElement('div');
valEl.className = 'bg-white dark:bg-gray-800 px-2 py-1 text-[11px] font-mono text-gray-900 dark:text-gray-100 text-right';
// Apply formatting
if (typeof value === 'number') {
if (Number.isInteger(value)) {
valEl.textContent = value;
} else if (key === 'snr') {
valEl.textContent = value.toFixed(2);
} else {
valEl.textContent = value.toFixed(4);
}
} else if (Array.isArray(value)) {
valEl.textContent = `[${value.map(v => typeof v === 'number' ? v.toFixed(3) : v).join(', ')}]`;
} else {
valEl.textContent = value;
}
table.appendChild(keyEl);
table.appendChild(valEl);
});
card.appendChild(table);
adasContainer.appendChild(card);
});
}
// --- START: New Robust Update Logic ---
let throttleTimer = null;
@ -298,7 +369,8 @@ export function initializeDataExplorer() {
// --- START: Make panel interactive ---
initializePanelPosition(panel);
makeDraggableAndResizable(panel, document.getElementById('data-explorer-header'));
// Rationale for 250x200: Allows for a very compact "sidecar" view when using the ADAS Property View.
makeDraggableAndResizable(panel, document.getElementById('data-explorer-header'), 250, 200);
// --- END: Make panel interactive ---
// --- Wire up all event listeners ---

873540
track_history_playback.json
File diff suppressed because it is too large
View File

Loading…
Cancel
Save