diff --git a/steps/src/dom.js b/steps/src/dom.js index 72a4438..72cbf47 100644 --- a/steps/src/dom.js +++ b/steps/src/dom.js @@ -103,22 +103,37 @@ export const explorerBtn = document.getElementById("explorer-btn"); //----------------------Reset UI for New file Load----------------------// -// Resets the UI to make sure everything is clean before new files load. -export function resetUIForNewLoad() { - console.log("Resetting UI for new file load."); +// Resets the UI to make sure everything is clean before new files load. +// @param {boolean} isNewVideo - If true, the video player will be reset. If false, existing video is preserved. +export function resetUIForNewLoad(isNewVideo = true) { + console.log(`Resetting UI for new file load. New Video: ${isNewVideo}`); // Hide feature toggles featureToggles.classList.add("hidden"); - // Show placeholders - canvasPlaceholder.style.display = 'flex'; - videoPlaceholder.classList.remove('hidden'); + // Reset the FPS counter state to prevent incorrect calculations on reload + appState.fps = 0; + + // --- Conditional Video Reset --- + if (isNewVideo || !videoPlayer.src) { + // Reset video UI: Show placeholder, hide player, clear source + videoPlaceholder.classList.remove('hidden'); + videoPlayer.classList.add('hidden'); + videoPlayer.src = ''; // Clear the video source + videoInfoOverlay.classList.add('hidden'); + } else { + // Preserve video UI: Ensure player is visible, placeholder hidden + videoPlaceholder.classList.add('hidden'); + videoPlayer.classList.remove('hidden'); + // Do NOT clear videoPlayer.src + videoInfoOverlay.classList.remove('hidden'); + } - // Hide video player and overlays - videoPlayer.classList.add('hidden'); - videoPlayer.src = ''; // Clear the video source + // Show canvas placeholder (will be hidden later if data loads) + canvasPlaceholder.style.display = 'flex'; + + // Always hide radar overlay initially radarInfoOverlay.classList.add('hidden'); - videoInfoOverlay.classList.add('hidden'); // Remove the p5 sketches completely if (appState.p5_instance) { diff --git a/steps/src/fileLoader.js b/steps/src/fileLoader.js index a3bb0f3..1527f2a 100644 --- a/steps/src/fileLoader.js +++ b/steps/src/fileLoader.js @@ -30,6 +30,7 @@ import { speedSlider, updatePersistentOverlays, updateDebugOverlay, + resetUIForNewLoad, } from "./dom.js"; /** @@ -58,6 +59,11 @@ export function handleFiles(files, fromCache = false) { } async function processFilePipeline(jsonFile, videoFile, fromCache) { + // 0. Reset the UI to a clean state before processing anything. + // Pass 'true' if a new video is present, 'false' if we should try to keep the old one. + const isNewVideo = !!videoFile; + resetUIForNewLoad(isNewVideo); + // 1. Show the unified loading modal. showLoadingModal("Processing files..."); @@ -298,8 +304,9 @@ function finalizeSetup() { if (!appState.p5_instance) { appState.p5_instance = new p5(radarSketch); } else { - // If it existed, ensure it's looping/active - appState.p5_instance.loop(); + // If it existed, ensure it's up to date. + // CRITICAL: Do NOT call .loop(). The app uses a custom animationLoop in sync.js. + appState.p5_instance.redraw(); } if (!appState.zoomSketchInstance) { diff --git a/steps/src/p5/radarSketch.js b/steps/src/p5/radarSketch.js index 262d2d9..67a2eea 100644 --- a/steps/src/p5/radarSketch.js +++ b/steps/src/p5/radarSketch.js @@ -48,6 +48,7 @@ export const radarSketch = function (p) { // --- START: FPS Calculation Variables --- let lastFrameTime = 0; + let framesDrawn = 0; // --- END: FPS Calculation Variables --- // Helper function to allow other sketches to access the static background @@ -126,6 +127,10 @@ export const radarSketch = function (p) { p.drawTrackLegendToBuffer(); // Call the new function to draw the legend drawStaticRegionsToBuffer(p, staticBackgroundBuffer, plotScales); + + // Reset FPS state to prevent stale values from previous sessions + appState.fps = 0; + p.noLoop(); // Disable continuous looping, redraw will be called manually }; @@ -136,18 +141,28 @@ export const radarSketch = function (p) { } // --- START: FPS Calculation & Display --- + framesDrawn++; const currentTime = p.millis(); - if (lastFrameTime > 0) { + + // Skip FPS calculation during the first few frames to avoid initialization spikes. + // This prevents the "300+ FPS" bug caused by the race between auto-draw and first redraw. + if (framesDrawn < 10) { + lastFrameTime = currentTime; + } else { const delta = currentTime - lastFrameTime; if (delta > 0) { const currentFps = 1000 / delta; - // Use exponential moving average for smoothing - const smoothingFactor = 0.95; - appState.fps = - appState.fps * smoothingFactor + currentFps * (1 - smoothingFactor); + // On the first valid calculation, snap to the current FPS to avoid slow ramp-up. + // Otherwise, use exponential moving average for smoothing. + if (framesDrawn === 10 || appState.fps === 0) { + appState.fps = currentFps; + } else { + const smoothingFactor = 0.95; + appState.fps = appState.fps * smoothingFactor + currentFps * (1 - smoothingFactor); + } } + lastFrameTime = currentTime; } - lastFrameTime = currentTime; // --- END: FPS Calculation & Display --- // Set background color based on current theme (dark/light)