Browse Source

feat: Refactor visualizer and implement robust sync logic

Main:
This major update refactors the entire application from a single monolithic HTML file into a modern, modular JavaScript architecture for improved maintainability, performance, and future extensibility.

Alongside the refactoring, this commit introduces a completely overhauled synchronization engine and several quality-of-life improvements.

Key changes and new features include:

- **Modular Architecture**: The application is now split into distinct, decoupled modules for state management (`state.js`), DOM manipulation (`dom.js`), synchronization (`sync.js`), file parsing (`fileParsers.js`), and UI components (`p5/radarSketch.js`, `modal.js`, etc.).

- **Robust Synchronization Engine**:
    - The core playback loop in `sync.js` now correctly applies the manual time offset, ensuring accurate synchronization between the video and radar data during playback.
    - Fixed a bug where fast scrubbing with the timeline slider could leave a persistent drift while paused. The fix uses the video's `seeked` event for a reliable, event-driven UI update.

- **Enhanced User Experience**:
    - Added a new feature allowing users to press 'Enter' in the offset input box to instantly resync the video to the current radar frame, which significantly streamlines the manual calibration process.

- **Improved Debugging Tools**:
    - The advanced debug overlay's drift calculation is now "offset-aware," providing an accurate representation of the true synchronization status during both playback and seeking.
refactor/modularize
RUSHIL AMBARISH KADU 9 months ago
parent
commit
1d3131d7d2
  1. 25
      steps/Visualization_Start.bat
  2. 35
      steps/python_check.bat
  3. 7
      steps/src/dom.js
  4. 66
      steps/src/main.js
  5. 2
      steps/src/state.js
  6. 11
      steps/src/sync.js

25
steps/Visualization_Start.bat

@ -0,0 +1,25 @@
@echo off
title Radar and Video Visualizer - Server
color 0B
cls
echo.
echo ======================================================
echo Radar and Video Visualizer - Local Server
echo ======================================================
echo.
echo - This window is your local web server.
echo - Please KEEP THIS WINDOW OPEN while using the app.
echo - To stop the server, simply close this window.
echo.
echo ======================================================
echo.
echo Launching the application in your default browser...
start http://127.0.0.1:8000/index.html
echo Server is now running on http://127.0.0.1:8000
echo Press CTRL+C at any time to stop the server.
:: Run the server command directly. We know 'python' works from our test.
python -m http.server 8000

35
steps/python_check.bat

@ -0,0 +1,35 @@
@echo off
title Python Installation Diagnostic
echo =================================================================
echo This script will test your Python installation.
echo The window will PAUSE at the end. Please copy the output.
echo =================================================================
echo.
echo --- 1. Testing for the 'python' command... ---
python --version
echo.
echo --- 2. Testing for the 'python3' command... ---
python3 --version
echo.
echo --- 3. Testing for the 'py' command... ---
py --version
echo.
echo =================================================================
echo DIAGNOSTIC FINISHED. Please analyze the results above.
echo =================================================================
echo.
echo If you see a version number (e.g., Python 3.12.4) next to
echo one or more of the commands, that is the command we need to use.
echo.
echo If you see "'python' is not recognized..." for ALL of them,
echo it means Python was installed without being added to the system PATH.
echo.
echo Please copy ALL the text from this window and send it to me.
echo.
pause

7
steps/src/dom.js

@ -214,10 +214,15 @@ export function updateDebugOverlay(currentMediaTime) {
appState.vizData &&
appState.vizData.radarFrames[appState.currentFrame]
) {
// --- START: Corrected Debug Logic ---
const currentRadarFrame =
appState.vizData.radarFrames[appState.currentFrame];
const targetRadarTimeMs = currentRadarFrame.timestampMs;
const driftMs = currentMediaTime * 1000 - targetRadarTimeMs;
const offsetMs = parseFloat(offsetInput.value) || 0; // Read the current offset
// Make the drift calculation "offset-aware"
const driftMs = currentMediaTime * 1000 + offsetMs - targetRadarTimeMs;
// --- END: Corrected Debug Logic ---
// Style the drift value to be green if sync is good, and red if it's off.
const driftColor = Math.abs(driftMs) > 40 ? "#FF6347" : "#98FB98"; // Tomato red or Pale green

66
steps/src/main.js

@ -402,6 +402,22 @@ document.addEventListener("keydown", (event) => {
}
});
// In src/main.js, add this new event listener
videoPlayer.addEventListener("seeked", () => {
// This event fires every time a seek operation completes.
// We only act if our flag has been set.
if (appState.needsPostSeekUpdate) {
console.log(
"Video has finished seeking. Performing final debug overlay update."
);
// Now we can be sure videoPlayer.currentTime is accurate.
updateDebugOverlay(videoPlayer.currentTime);
// Reset the flag so this logic doesn't run on every seek
appState.needsPostSeekUpdate = false;
}
});
function calculateAndSetOffset() {
const jsonTimestampInfo = extractTimestampInfo(appState.jsonFilename);
const videoTimestampInfo = extractTimestampInfo(appState.videoFilename);
@ -541,3 +557,53 @@ document.addEventListener("DOMContentLoaded", () => {
});
});
});
// In src/main.js, add this new event listener
offsetInput.addEventListener("keydown", (event) => {
// Check if the key pressed was 'Enter'
if (event.key === "Enter") {
// Prevent the default browser action for the Enter key (like submitting a form)
event.preventDefault();
// Make sure visualization data is loaded before proceeding
if (!appState.vizData) return;
console.log(
`Enter pressed. Forcing resync with new offset: ${offsetInput.value}`
);
// If the video is playing, pause it to allow for precise frame tuning.
if (appState.isPlaying) {
playPauseBtn.click();
}
// Call updateFrame, forcing it to resync the video to the current radar frame
// using the new offset value from the input box.
updateFrame(appState.currentFrame, true);
}
});
// In src/main.js, REPLACE the 'change' event listener with this:
timelineSlider.addEventListener("change", () => {
if (!appState.vizData || appState.isPlaying) return;
const currentRadarFrame = appState.vizData.radarFrames[appState.currentFrame];
if (!currentRadarFrame) return;
const targetRadarTimeMs = currentRadarFrame.timestampMs;
const offsetMs = parseFloat(offsetInput.value) || 0;
const currentVideoTimeMs = videoPlayer.currentTime * 1000;
const driftMs = currentVideoTimeMs + offsetMs - targetRadarTimeMs;
if (Math.abs(driftMs) > 50) {
console.log(
`Setting flag for post-seek update. Initial drift: ${driftMs.toFixed(
0
)}ms`
);
// 1. Set the flag to true
appState.needsPostSeekUpdate = true;
// 2. Initiate the final seek operation
updateFrame(appState.currentFrame, true);
}
});

2
steps/src/state.js

@ -29,4 +29,6 @@ export const appState = {
mediaTimeStart: 0,
// Timestamp (from performance.now()) of the last synchronization check
lastSyncTime: 0,
// new flag for seek finished
needsPostSeekUpdate: false,
};

11
steps/src/sync.js

@ -29,14 +29,17 @@ export function animationLoop() {
// Check if visualization data and video start date are available
if (appState.vizData && appState.videoStartDate) {
// Get the offset from the input field, default to 0 if not a valid number
// --- START: Corrected Logic ---
const offsetMs = parseFloat(offsetInput.value) || 0;
// Calculate the target radar time in milliseconds
const targetRadarTimeMs = currentMediaTime * 1000;
// Find the index of the radar frame that corresponds to the target time
// The master clock represents the VIDEO's timeline.
// To find the corresponding RADAR time, we must add the offset.
const targetRadarTimeMs = currentMediaTime * 1000 + offsetMs;
const targetFrame = findRadarFrameIndexForTime(
targetRadarTimeMs,
appState.vizData
);
// --- END: Corrected Logic ---
if (targetFrame !== appState.currentFrame) {
// Update the displayed frame if it's different from the current one
updateFrame(targetFrame, false);
@ -45,7 +48,7 @@ export function animationLoop() {
// Periodically check for drift between master clock and video element
const now = performance.now();
if (now - appState.lastSyncTime > 500) {
if (now - appState.lastSyncTime > 150) {
const videoTime = videoPlayer.currentTime;
const drift = Math.abs(currentMediaTime - videoTime);
// Resync if drift is > 150ms

Loading…
Cancel
Save