Browse Source

Debug Overlays fixed.

refactor/modularize
RUSHIL AMBARISH KADU 9 months ago
parent
commit
4d0e7fe5cd
  1. 311
      steps/index.html
  2. 118
      steps/src/dom.js
  3. 71
      steps/src/main.js
  4. 2
      steps/src/sync.js

311
steps/index.html

@ -1,5 +1,4 @@
<!DOCTYPE html> <!DOCTYPE html>
<!-- DARK MODE: The 'dark' class will be toggled here by JavaScript -->
<html lang="en"> <html lang="en">
<head> <head>
@ -7,16 +6,14 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Radar and Video Visualizer - Timestamp Synchronized</title> <title>Radar and Video Visualizer - Timestamp Synchronized</title>
<link rel="icon" type="image/png" sizes="32x32" href="favicon.png" /> <link rel="icon" type="image/png" sizes="32x32" href="favicon.png" />
<script src="https://cdn.tailwindcss.com"></script> <!--CSS link-->
<script src="https://unpkg.com/oboe@2.1.5/dist/oboe-browser.min.js"></script><!--Oboe link-->
<!-- DARK MODE: Step 1 - Configure Tailwind to use the 'class' strategy for dark mode -->
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/oboe@2.1.5/dist/oboe-browser.min.js"></script>
<script> <script>
tailwind.config = { tailwind.config = {
darkMode: "class", darkMode: "class",
}; };
</script> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.js"></script> <!--P5 link-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link <link
@ -31,12 +28,7 @@
font-family: "Roboto Mono", monospace; font-family: "Roboto Mono", monospace;
} }
.p5Canvas {
border-radius: 0.5rem;
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1),
0 2px 4px -2px rgb(0 0 0 / 0.1);
}
.p5Canvas,
video { video {
border-radius: 0.5rem; border-radius: 0.5rem;
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1),
@ -67,22 +59,11 @@
0 -2px 4px -2px rgb(0 0 0 / 0.1); 0 -2px 4px -2px rgb(0 0 0 / 0.1);
} }
#modal-overlay {
transition: opacity 0.2s ease-in-out;
}
#modal-content {
transition: transform 0.2s ease-in-out;
}
/* ... (your existing styles) ... */
#modal-overlay,
#modal-content { #modal-content {
transition: transform 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
} }
/* ADD THIS NEW CSS RULE */
#progress-bar { #progress-bar {
transition: width 0.1s linear; transition: width 0.1s linear;
} }
@ -90,16 +71,18 @@
</head> </head>
<body class="bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-gray-200 flex flex-col min-h-screen"> <body class="bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-gray-200 flex flex-col min-h-screen">
<header class="bg-white dark:bg-gray-800 shadow-md p-4 z-10 relative">
<header class="bg-white dark:bg-gray-800 shadow-md p-4 z-20 relative">
<h1 class="text-2xl font-bold text-gray-900 dark:text-white"> <h1 class="text-2xl font-bold text-gray-900 dark:text-white">
Radar and Video Synchronizer Radar and Video Synchronizer
</h1> </h1>
<p class="text-sm text-gray-600 dark:text-gray-400"> <p class="text-sm text-gray-600 dark:text-gray-400">
High-precision, timestamp-synchronized playback. High-precision, timestamp-synchronized playback.
</p> </p>
<!-- DARK MODE: Step 2 - Add the toggle button -->
<div class="absolute top-4 right-4">
<div class="absolute top-4 right-4 flex items-center gap-2">
<button id="fullscreen-btn" type="button"
class="text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 font-medium rounded-lg text-xs px-4 py-2 transition-colors">
FULLSCREEN ( F11 )
</button>
<button id="theme-toggle" type="button" <button id="theme-toggle" type="button"
class="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5"> class="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5">
<svg id="theme-toggle-dark-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20"> <svg id="theme-toggle-dark-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
@ -114,160 +97,146 @@
</div> </div>
</header> </header>
<main class="flex-grow container mx-auto p-4 flex flex-col lg:flex-row gap-6">
<div class="lg:w-1/2 flex flex-col gap-4">
<div class="relative">
<div id="canvas-container"
class="w-full h-[60vh] bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg shadow-inner flex items-center justify-center">
<p id="canvas-placeholder" class="text-gray-500 dark:text-gray-400 text-lg">
Load JSON data to start visualization
</p>
</div>
<!-- START: Add the new Radar Info Overlay here -->
<div id="radar-info-overlay"
class="absolute top-1 left-2 z-10 bg-black bg-opacity-60 text-white font-mono text-xs p-2 rounded-md hidden">
<!-- Content will be added by JavaScript -->
</div>
<!-- END: Add the new Radar Info Overlay here -->
<div class="absolute bottom-2 left-1/2 -translate-x-1/2 flex items-center justify-center gap-4">
<div id="ego-speed-display"
class="bg-black bg-opacity-60 text-white text-sm px-3 py-1.5 rounded-md hidden font-mono"></div>
<div id="can-speed-display"
class="bg-black bg-opacity-60 text-white text-sm px-3 py-1.5 rounded-md hidden font-mono"></div>
</div>
<!-- Sidebar (Initially hidden) -->
<aside id="collapsible-menu"
class="fixed top-0 left-0 h-full bg-white dark:bg-gray-800 shadow-xl z-30 transform -translate-x-full transition-transform duration-300 ease-in-out w-full max-w-sm flex flex-col">
<div class="flex items-center justify-between p-4 border-b dark:border-gray-700">
<h2 class="text-xl font-bold">Display Settings</h2>
<button id="close-menu-btn"
class="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg p-2">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div> </div>
<div id="feature-toggles"
class="p-3 bg-gray-50 dark:bg-gray-800 rounded-lg border dark:border-gray-700 flex flex-col items-center gap-4 hidden">
<div class="flex flex-wrap justify-center gap-x-6 gap-y-2">
<!-- Scrollable Content Area -->
<div class="flex-grow p-4 overflow-y-auto">
<div id="feature-toggles" class="flex flex-col items-start gap-4">
<!-- Checkboxes -->
<div class="flex flex-col items-start gap-3 w-full">
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-snr-color" <label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-snr-color"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" />
Color by SNR</label>
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" /> Color by SNR (S)</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-cluster-color" <label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-cluster-color"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" />
Color by Cluster</label>
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" /> Color by Cluster</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-inlier-color" <label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-inlier-color"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" />
Color by Inlier</label>
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" /> Color by Inlier</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" <label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox"
id="toggle-stationary-color" class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" /> id="toggle-stationary-color" class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" />
Color by Stationary</label> Color by Stationary</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-velocity" <label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-velocity"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" checked />
Show Object Details</label>
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" checked /> Show Object Details
(D)</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-tracks" <label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-tracks"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" checked />
Show Tracks</label>
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" checked /> Show Tracks (T)</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-ego-speed" <label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-ego-speed"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" checked />
Show Ego Speed</label>
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" checked /> Show Ego Speed</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-frame-norm" <label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-frame-norm"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" />
Per-Frame SNR</label>
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" /> Per-Frame SNR</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-debug-overlay" <label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-debug-overlay"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" />
Show Debug Info</label>
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" /> Show Debug Info</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" <label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox"
id="toggle-debug2-overlay" class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" />
Show Advanced Debug</label>
id="toggle-debug2-overlay" class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" /> Show
Advanced Debug (A)</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-close-up" <label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-close-up"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" />
CLOSE-UP</label>
<label class="flex items-center gap-2 text-sm cursor-pointer">
<input type="checkbox" id="toggle-predicted-pos"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" />
Show Predicted Position</label>
<label class="flex items-center gap-2 text-sm cursor-pointer">
<input type="checkbox" id="toggle-covariance"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" />
Show Covariance</label>
</div>
<!-- START: Add This Entire New Block for Custom TTC Controls -->
<div class="border-t border-gray-200 dark:border-gray-700 w-full mt-4 pt-4">
<div class="text-sm font-medium mb-2 text-center">Track Coloring Mode</div>
<div class="flex justify-center items-center gap-6 mb-3">
<label class="flex items-center gap-2 text-sm cursor-pointer">
<input type="radio" name="ttc-mode" id="ttc-mode-default" class="form-radio h-4 w-4 text-blue-600"
checked>
Default TTC
</label>
<label class="flex items-center gap-2 text-sm cursor-pointer">
<input type="radio" name="ttc-mode" id="ttc-mode-custom" class="form-radio h-4 w-4 text-blue-600">
Custom TTC
</label>
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" /> CLOSE-UP (C)</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-predicted-pos"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" /> Show Predicted Position
(P)</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-covariance"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" /> Show Covariance</label>
</div> </div>
<!-- This container will be shown/hidden by JavaScript -->
<div id="custom-ttc-panel"
class="hidden flex-col md:flex-row flex-wrap justify-center items-center gap-x-6 gap-y-3">
<!-- Critical Risk -->
<div class="flex items-center gap-2">
<input type="color" id="ttc-color-critical" value="#ff0000" class="w-8 h-8 rounded-md">
<label for="ttc-time-critical" class="text-sm">Critical if TTC &lt;=</label>
<input type="number" id="ttc-time-critical" value="1" step="0.1"
class="w-20 p-2 border border-gray-300 dark:bg-gray-600 dark:border-gray-500 rounded-lg text-sm">
<span class="text-sm">s</span>
</div>
<!-- High Risk -->
<div class="flex items-center gap-2">
<input type="color" id="ttc-color-high" value="#ffa500" class="w-8 h-8 rounded-md">
<label for="ttc-time-high" class="text-sm">High if TTC &lt;=</label>
<input type="number" id="ttc-time-high" value="2" step="0.1"
class="w-20 p-2 border border-gray-300 dark:bg-gray-600 dark:border-gray-500 rounded-lg text-sm">
<span class="text-sm">s</span>
</div>
<!-- Medium Risk -->
<div class="flex items-center gap-2">
<input type="color" id="ttc-color-medium" value="#FFC300" class="w-8 h-8 rounded-md">
<label for="ttc-time-medium" class="text-sm">Medium if TTC &lt;=</label>
<input type="number" id="ttc-time-medium" value="3" step="0.1"
class="w-20 p-2 border border-gray-300 dark:bg-gray-600 dark:border-gray-500 rounded-lg text-sm">
<span class="text-sm">s</span>
</div>
<div class="flex items-center gap-2">
<input type="color" id="ttc-color-low" value="#00ff00" class="w-8 h-8 rounded-md">
<label class="text-sm">Low Risk (everything else)</label>
<!-- SNR Controls -->
<div class="border-t border-gray-200 dark:border-gray-700 w-full mt-4 pt-4 flex flex-col gap-3">
<h3 class="text-sm font-medium text-center">Global SNR Range</h3>
<div class="flex items-center gap-2"><label for="snr-min-input" class="text-sm font-medium w-16">Min
SNR:</label><input type="number" id="snr-min-input" step="0.1"
class="w-full p-2 border border-gray-300 dark:bg-gray-600 dark:border-gray-500 dark:text-white rounded-lg text-sm" />
</div> </div>
<div class="flex items-center gap-2"><label for="snr-max-input" class="text-sm font-medium w-16">Max
SNR:</label><input type="number" id="snr-max-input" step="0.1"
class="w-full p-2 border border-gray-300 dark:bg-gray-600 dark:border-gray-500 dark:text-white rounded-lg text-sm" />
</div> </div>
<button id="apply-snr-btn"
class="bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700 transition-colors text-sm font-medium">Apply
Manual SNR</button>
</div> </div>
<!-- END: Add This Entire New Block -->
<div class="flex items-center gap-4 hidden">
<div class="flex items-center gap-2">
<label for="snr-min-input" class="text-sm font-medium">Min SNR:</label><input type="number"
id="snr-min-input" step="0.1"
class="w-20 p-2 border border-gray-300 dark:bg-gray-600 dark:border-gray-500 dark:text-white rounded-lg text-sm" />
<!-- TTC Controls -->
<div class="border-t border-gray-200 dark:border-gray-700 w-full mt-4 pt-4">
<div class="text-sm font-medium mb-2 text-center">Track Coloring Mode</div>
<div class="flex justify-center items-center gap-6 mb-3">
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="radio" name="ttc-mode"
id="ttc-mode-default" class="form-radio h-4 w-4 text-blue-600" checked> Default TTC </label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="radio" name="ttc-mode"
id="ttc-mode-custom" class="form-radio h-4 w-4 text-blue-600"> Custom TTC </label>
</div>
<div id="custom-ttc-panel" class="hidden flex flex-col gap-3">
<div class="flex items-center gap-2"><input type="color" id="ttc-color-critical" value="#ff0000"
class="w-8 h-8 rounded-md"><label for="ttc-time-critical" class="text-sm">Critical &lt;=</label><input
type="number" id="ttc-time-critical" value="1" step="0.1"
class="w-20 p-2 border border-gray-300 dark:bg-gray-600 dark:border-gray-500 rounded-lg text-sm"><span
class="text-sm">s</span></div>
<div class="flex items-center gap-2"><input type="color" id="ttc-color-high" value="#ffa500"
class="w-8 h-8 rounded-md"><label for="ttc-time-high" class="text-sm">High &lt;=</label><input
type="number" id="ttc-time-high" value="2" step="0.1"
class="w-20 p-2 border border-gray-300 dark:bg-gray-600 dark:border-gray-500 rounded-lg text-sm"><span
class="text-sm">s</span></div>
<div class="flex items-center gap-2"><input type="color" id="ttc-color-medium" value="#FFC300"
class="w-8 h-8 rounded-md"><label for="ttc-time-medium" class="text-sm">Medium &lt;=</label><input
type="number" id="ttc-time-medium" value="3" step="0.1"
class="w-20 p-2 border border-gray-300 dark:bg-gray-600 dark:border-gray-500 rounded-lg text-sm"><span
class="text-sm">s</span></div>
<div class="flex items-center gap-2"><input type="color" id="ttc-color-low" value="#00ff00"
class="w-8 h-8 rounded-md"><label class="text-sm">Low Risk (else)</label></div>
</div>
</div>
</div>
</div>
</aside>
<!-- Open Menu Button -->
<button id="toggle-menu-btn"
class="fixed top-20 left-3 z-20 bg-white dark:bg-gray-700 p-2 rounded-md shadow-lg hover:bg-gray-100 dark:hover:bg-gray-600 transition-all">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
</button>
<!-- Main Content -->
<main class="flex-grow container mx-auto p-4 pt-8 flex flex-col lg:flex-row gap-6">
<div class="lg:w-1/2 flex flex-col gap-4">
<div class="relative">
<div id="canvas-container"
class="w-full h-[75vh] bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg shadow-inner flex items-center justify-center">
<p id="canvas-placeholder" class="text-gray-500 dark:text-gray-400 text-lg">Load JSON data to start
visualization</p>
</div> </div>
<div class="flex items-center gap-2">
<label for="snr-max-input" class="text-sm font-medium">Max SNR:</label><input type="number"
id="snr-max-input" step="0.1"
class="w-20 p-2 border border-gray-300 dark:bg-gray-600 dark:border-gray-500 dark:text-white rounded-lg text-sm" />
<div id="radar-info-overlay"
class="absolute top-1 left-2 z-10 bg-black bg-opacity-60 text-white font-mono text-xs p-2 rounded-md hidden">
</div> </div>
<button id="apply-snr-btn"
class="bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700 transition-colors text-sm font-medium">
Apply
</button>
<div class="absolute bottom-2 left-1/2 -translate-x-1/2 flex items-center justify-center gap-4">
<div id="ego-speed-display"
class="bg-black bg-opacity-60 text-white text-sm px-3 py-1.5 rounded-md hidden font-mono"></div>
<div id="can-speed-display"
class="bg-black bg-opacity-60 text-white text-sm px-3 py-1.5 rounded-md hidden font-mono"></div>
</div> </div>
</div> </div>
</div> </div>
<div class="lg:w-1/2 flex flex-col gap-4"> <div class="lg:w-1/2 flex flex-col gap-4">
<div class="w-full h-[45vh] bg-black rounded-lg shadow-inner flex items-center justify-center relative">
<div class="w-full h-[50vh] bg-black rounded-lg shadow-inner flex items-center justify-center relative">
<video id="video-player" class="w-full h-full object-contain hidden" muted playsinline></video> <video id="video-player" class="w-full h-full object-contain hidden" muted playsinline></video>
<p id="video-placeholder" class="text-gray-500 dark:text-gray-400 text-lg">
Load a video file
</p>
<!-- START: Add the new Video Info Overlay here -->
<p id="video-placeholder" class="text-gray-500 dark:text-gray-400 text-lg">Load a video file</p>
<div id="video-info-overlay" <div id="video-info-overlay"
class="absolute top-1 left-2 z-10 bg-black bg-opacity-60 text-white font-mono text-xs p-2 rounded-md hidden"> class="absolute top-1 left-2 z-10 bg-black bg-opacity-60 text-white font-mono text-xs p-2 rounded-md hidden">
<!-- Content will be added by JavaScript -->
</div> </div>
<!-- END: Add the new Video Info Overlay here -->
<div id="debug-overlay" <div id="debug-overlay"
class="absolute top-0 left-0 bg-black bg-opacity-60 text-white p-2 font-mono text-xs hidden w-full"></div> class="absolute top-0 left-0 bg-black bg-opacity-60 text-white p-2 font-mono text-xs hidden w-full"></div>
</div> </div>
<div id="speed-graph-container" <div id="speed-graph-container"
class="w-full h-[27vh] bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg shadow-inner flex items-center justify-center"> class="w-full h-[27vh] bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg shadow-inner flex items-center justify-center">
<p id="speed-graph-placeholder" class="text-gray-500 dark:text-gray-400 text-lg">
Load JSON to see speed graph
<p id="speed-graph-placeholder" class="text-gray-500 dark:text-gray-400 text-lg">Load JSON to see speed graph
</p> </p>
</div> </div>
</div> </div>
@ -277,25 +246,21 @@
<div class="mb-4"> <div class="mb-4">
<div id="timeline-tooltip" <div id="timeline-tooltip"
class="absolute hidden bg-gray-900 dark:bg-gray-700 text-white text-xs rounded py-1 px-2 pointer-events-none text-center" class="absolute hidden bg-gray-900 dark:bg-gray-700 text-white text-xs rounded py-1 px-2 pointer-events-none text-center"
style="transform: translate(-50%, -125%);">
</div>
style="transform: translate(-50%, -125%);"></div>
<input type="range" id="timeline-slider" min="0" max="0" value="0" <input type="range" id="timeline-slider" min="0" max="0" value="0"
class="w-full h-2 bg-gray-300 dark:bg-gray-600 rounded-lg appearance-none cursor-pointer" /> class="w-full h-2 bg-gray-300 dark:bg-gray-600 rounded-lg appearance-none cursor-pointer" />
</div> </div>
<div class="flex flex-wrap items-center justify-center md:justify-between gap-4"> <div class="flex flex-wrap items-center justify-center md:justify-between gap-4">
<div class="flex items-center gap-4 justify-center"> <div class="flex items-center gap-4 justify-center">
<button id="load-json-btn" <button id="load-json-btn"
class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors text-sm font-medium">
Load JSON
</button>
class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors text-sm font-medium">Load
JSON</button>
<button id="load-video-btn" <button id="load-video-btn"
class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition-colors text-sm font-medium">
Load Video
</button>
class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition-colors text-sm font-medium">Load
Video</button>
<button id="clear-cache-btn" <button id="clear-cache-btn"
class="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 transition-colors text-sm font-medium">
Clear Cache
</button>
class="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 transition-colors text-sm font-medium">Clear
Cache</button>
<button id="save-session-btn" <button id="save-session-btn"
class="bg-purple-600 text-white px-4 py-2 rounded-lg hover:bg-purple-700 transition-colors text-sm font-medium">Save class="bg-purple-600 text-white px-4 py-2 rounded-lg hover:bg-purple-700 transition-colors text-sm font-medium">Save
Session</button> Session</button>
@ -303,9 +268,8 @@
class="bg-teal-600 text-white px-4 py-2 rounded-lg hover:bg-teal-700 transition-colors text-sm font-medium">Load class="bg-teal-600 text-white px-4 py-2 rounded-lg hover:bg-teal-700 transition-colors text-sm font-medium">Load
Session</button> Session</button>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<label for="offset-input" class="text-sm font-medium">
Offset (ms):<br /><small>(+ve values if radar<br />
lags behind video)</small></label>
<label for="offset-input" class="text-sm font-medium">Offset (ms):<br /><small>(+ve if radar
lags)</small></label>
<input type="number" id="offset-input" value="0" <input type="number" id="offset-input" value="0"
class="w-20 p-2 border border-gray-300 dark:bg-gray-600 dark:border-gray-500 dark:text-white rounded-lg text-sm" /> class="w-20 p-2 border border-gray-300 dark:bg-gray-600 dark:border-gray-500 dark:text-white rounded-lg text-sm" />
<span id="auto-offset-indicator" class="text-green-600 font-semibold text-sm hidden">(auto)</span> <span id="auto-offset-indicator" class="text-green-600 font-semibold text-sm hidden">(auto)</span>
@ -313,13 +277,9 @@
</div> </div>
<div class="flex items-center justify-center gap-4"> <div class="flex items-center justify-center gap-4">
<button id="play-pause-btn" <button id="play-pause-btn"
class="px-5 py-2 rounded-lg bg-gray-200 dark:bg-gray-600 dark:hover:bg-gray-500 hover:bg-gray-300 font-semibold w-20">
Play
</button>
class="px-5 py-2 rounded-lg bg-gray-200 dark:bg-gray-600 dark:hover:bg-gray-500 hover:bg-gray-300 font-semibold w-20">Play</button>
<button id="stop-btn" <button id="stop-btn"
class="px-5 py-2 rounded-lg bg-gray-200 dark:bg-gray-600 dark:hover:bg-gray-500 hover:bg-gray-300 font-semibold">
Stop
</button>
class="px-5 py-2 rounded-lg bg-gray-200 dark:bg-gray-600 dark:hover:bg-gray-500 hover:bg-gray-300 font-semibold">Stop</button>
<div class="text-center"> <div class="text-center">
<span id="frame-counter" class="font-mono text-lg">Frame: 0 / 0</span> <span id="frame-counter" class="font-mono text-lg">Frame: 0 / 0</span>
</div> </div>
@ -343,18 +303,15 @@
style="width: 0%"></div> style="width: 0%"></div>
</div> </div>
<span id="modal-progress-text" class="text-sm text-gray-500 dark:text-gray-400 mt-1 block text-center"></span> <span id="modal-progress-text" class="text-sm text-gray-500 dark:text-gray-400 mt-1 block text-center"></span>
<div id="modal-buttons" class="flex justify-end gap-4">
</div>
<div id="modal-buttons" class="flex justify-end gap-4">
<div class="flex justify-end gap-4 mt-4">
<button id="modal-cancel-btn" <button id="modal-cancel-btn"
class="px-4 py-2 rounded-lg bg-gray-200 dark:bg-gray-600 dark:hover:bg-gray-500 hover:bg-gray-300 font-semibold">
Cancel</button><button id="modal-ok-btn"
class="px-4 py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700 font-semibold">
OK
</button>
class="px-4 py-2 rounded-lg bg-gray-200 dark:bg-gray-600 dark:hover:bg-gray-500 hover:bg-gray-300 font-semibold">Cancel</button>
<button id="modal-ok-btn"
class="px-4 py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700 font-semibold">OK</button>
</div> </div>
</div> </div>
</div> </div>
<input type="file" id="json-file-input" class="hidden" accept=".json" /> <input type="file" id="json-file-input" class="hidden" accept=".json" />
<input type="file" id="video-file-input" class="hidden" accept="video/*" /> <input type="file" id="video-file-input" class="hidden" accept="video/*" />
<input type="file" id="session-file-input" class="hidden" accept=".json" /> <input type="file" id="session-file-input" class="hidden" accept=".json" />

118
steps/src/dom.js

@ -24,25 +24,39 @@ export const speedSlider = document.getElementById("speed-slider");
export const speedDisplay = document.getElementById("speed-display"); export const speedDisplay = document.getElementById("speed-display");
export const featureToggles = document.getElementById("feature-toggles"); export const featureToggles = document.getElementById("feature-toggles");
export const toggleSnrColor = document.getElementById("toggle-snr-color"); export const toggleSnrColor = document.getElementById("toggle-snr-color");
export const toggleClusterColor = document.getElementById("toggle-cluster-color");
export const toggleClusterColor = document.getElementById(
"toggle-cluster-color"
);
export const toggleInlierColor = document.getElementById("toggle-inlier-color"); export const toggleInlierColor = document.getElementById("toggle-inlier-color");
export const toggleStationaryColor = document.getElementById("toggle-stationary-color");
export const toggleStationaryColor = document.getElementById(
"toggle-stationary-color"
);
export const toggleVelocity = document.getElementById("toggle-velocity"); export const toggleVelocity = document.getElementById("toggle-velocity");
export const toggleTracks = document.getElementById("toggle-tracks"); export const toggleTracks = document.getElementById("toggle-tracks");
export const toggleEgoSpeed = document.getElementById("toggle-ego-speed"); export const toggleEgoSpeed = document.getElementById("toggle-ego-speed");
export const toggleFrameNorm = document.getElementById("toggle-frame-norm"); export const toggleFrameNorm = document.getElementById("toggle-frame-norm");
export const toggleDebugOverlay = document.getElementById("toggle-debug-overlay");
export const toggleDebugOverlay = document.getElementById(
"toggle-debug-overlay"
);
export const egoSpeedDisplay = document.getElementById("ego-speed-display"); export const egoSpeedDisplay = document.getElementById("ego-speed-display");
export const canSpeedDisplay = document.getElementById("can-speed-display"); export const canSpeedDisplay = document.getElementById("can-speed-display");
export const debugOverlay = document.getElementById("debug-overlay"); export const debugOverlay = document.getElementById("debug-overlay");
export const toggleDebug2Overlay = document.getElementById("toggle-debug2-overlay");
export const toggleDebug2Overlay = document.getElementById(
"toggle-debug2-overlay"
);
export const snrMinInput = document.getElementById("snr-min-input"); export const snrMinInput = document.getElementById("snr-min-input");
export const snrMaxInput = document.getElementById("snr-max-input"); export const snrMaxInput = document.getElementById("snr-max-input");
export const applySnrBtn = document.getElementById("apply-snr-btn"); export const applySnrBtn = document.getElementById("apply-snr-btn");
export const autoOffsetIndicator = document.getElementById("auto-offset-indicator");
export const autoOffsetIndicator = document.getElementById(
"auto-offset-indicator"
);
export const clearCacheBtn = document.getElementById("clear-cache-btn"); export const clearCacheBtn = document.getElementById("clear-cache-btn");
export const speedGraphContainer = document.getElementById("speed-graph-container");
export const speedGraphPlaceholder = document.getElementById("speed-graph-placeholder");
export const speedGraphContainer = document.getElementById(
"speed-graph-container"
);
export const speedGraphPlaceholder = document.getElementById(
"speed-graph-placeholder"
);
export const modalContainer = document.getElementById("modal-container"); export const modalContainer = document.getElementById("modal-container");
export const modalOverlay = document.getElementById("modal-overlay"); export const modalOverlay = document.getElementById("modal-overlay");
export const modalContent = document.getElementById("modal-content"); export const modalContent = document.getElementById("modal-content");
@ -50,9 +64,13 @@ export const modalText = document.getElementById("modal-text");
export const modalOkBtn = document.getElementById("modal-ok-btn"); export const modalOkBtn = document.getElementById("modal-ok-btn");
export const modalCancelBtn = document.getElementById("modal-cancel-btn"); export const modalCancelBtn = document.getElementById("modal-cancel-btn");
export const toggleCloseUp = document.getElementById("toggle-close-up"); export const toggleCloseUp = document.getElementById("toggle-close-up");
export const togglePredictedPos = document.getElementById("toggle-predicted-pos");
export const togglePredictedPos = document.getElementById(
"toggle-predicted-pos"
);
export const toggleCovariance = document.getElementById("toggle-covariance"); export const toggleCovariance = document.getElementById("toggle-covariance");
export const modalProgressContainer = document.getElementById("modal-progress-container");
export const modalProgressContainer = document.getElementById(
"modal-progress-container"
);
export const modalProgressBar = document.getElementById("modal-progress-bar"); export const modalProgressBar = document.getElementById("modal-progress-bar");
export const modalProgressText = document.getElementById("modal-progress-text"); export const modalProgressText = document.getElementById("modal-progress-text");
export const timelineTooltip = document.getElementById("timeline-tooltip"); export const timelineTooltip = document.getElementById("timeline-tooltip");
@ -61,17 +79,27 @@ export const videoInfoOverlay = document.getElementById("video-info-overlay");
export const saveSessionBtn = document.getElementById("save-session-btn"); export const saveSessionBtn = document.getElementById("save-session-btn");
export const loadSessionBtn = document.getElementById("load-session-btn"); export const loadSessionBtn = document.getElementById("load-session-btn");
export const sessionFileInput = document.getElementById("session-file-input"); export const sessionFileInput = document.getElementById("session-file-input");
export const ttcModeDefault = document.getElementById('ttc-mode-default');
export const ttcModeCustom = document.getElementById('ttc-mode-custom');
export const customTtcPanel = document.getElementById('custom-ttc-panel');
export const ttcColorCritical = document.getElementById('ttc-color-critical');
export const ttcTimeCritical = document.getElementById('ttc-time-critical');
export const ttcColorHigh = document.getElementById('ttc-color-high');
export const ttcTimeHigh = document.getElementById('ttc-time-high');
export const ttcColorMedium = document.getElementById('ttc-color-medium');
export const ttcTimeMedium = document.getElementById('ttc-time-medium');
export const ttcColorLow = document.getElementById('ttc-color-low');
export const ttcModeDefault = document.getElementById("ttc-mode-default");
export const ttcModeCustom = document.getElementById("ttc-mode-custom");
export const customTtcPanel = document.getElementById("custom-ttc-panel");
export const ttcColorCritical = document.getElementById("ttc-color-critical");
export const ttcTimeCritical = document.getElementById("ttc-time-critical");
export const ttcColorHigh = document.getElementById("ttc-color-high");
export const ttcTimeHigh = document.getElementById("ttc-time-high");
export const ttcColorMedium = document.getElementById("ttc-color-medium");
export const ttcTimeMedium = document.getElementById("ttc-time-medium");
export const ttcColorLow = document.getElementById("ttc-color-low");
export const collapsibleMenu = document.getElementById("collapsible-menu");
export const toggleMenuBtn = document.getElementById("toggle-menu-btn");
export const fullscreenBtn = document.getElementById("fullscreen-btn");
export const mainContent = document.querySelector("main");
export const closeMenuBtn = document.getElementById("close-menu-btn");
export const fullscreenEnterIcon = document.getElementById(
"fullscreen-enter-icon"
);
export const fullscreenExitIcon = document.getElementById(
"fullscreen-exit-icon"
);
//----------------------UPDATE FRAME Function----------------------// //----------------------UPDATE FRAME Function----------------------//
// Updates the UI to reflect the current radar frame and synchronizes video playback. // Updates the UI to reflect the current radar frame and synchronizes video playback.
@ -253,26 +281,34 @@ export function updateDebugOverlay(currentMediaTime) {
debugOverlay.innerHTML = content.join("<br>"); // Update debug overlay content. debugOverlay.innerHTML = content.join("<br>"); // Update debug overlay content.
} }
export function updatePersistentOverlays(currentMediaTime) { export function updatePersistentOverlays(currentMediaTime) {
// If we don't have the necessary data, hide the overlays and exit. // If we don't have the necessary data, hide the overlays and exit.
const isDebug1Visible = toggleDebugOverlay.checked;
const isDebug2Visible = toggleDebug2Overlay.checked;
if (!appState.vizData || !appState.videoStartDate) { if (!appState.vizData || !appState.videoStartDate) {
radarInfoOverlay.classList.add('hidden');
videoInfoOverlay.classList.add('hidden');
radarInfoOverlay.classList.add("hidden");
videoInfoOverlay.classList.add("hidden");
return;
}
if (isDebug1Visible && isDebug2Visible) {
radarInfoOverlay.classList.add("hidden");
videoInfoOverlay.classList.add("hidden");
return; return;
} }
// Otherwise, make sure they are visible. // Otherwise, make sure they are visible.
radarInfoOverlay.classList.remove('hidden');
videoInfoOverlay.classList.remove('hidden');
radarInfoOverlay.classList.remove("hidden");
videoInfoOverlay.classList.remove("hidden");
// --- Update Radar Overlay --- // --- Update Radar Overlay ---
const currentRadarFrame = appState.vizData.radarFrames[appState.currentFrame]; const currentRadarFrame = appState.vizData.radarFrames[appState.currentFrame];
if (currentRadarFrame) { if (currentRadarFrame) {
const absRadarTime = new Date(appState.videoStartDate.getTime() + currentRadarFrame.timestampMs);
const absRadarTime = new Date(
appState.videoStartDate.getTime() + currentRadarFrame.timestampMs
);
const targetRadarTimeMs = currentRadarFrame.timestampMs; const targetRadarTimeMs = currentRadarFrame.timestampMs;
const offsetMs = parseFloat(offsetInput.value) || 0; const offsetMs = parseFloat(offsetInput.value) || 0;
const driftMs = (currentMediaTime * 1000 + offsetMs) - targetRadarTimeMs;
const driftMs = currentMediaTime * 1000 + offsetMs - targetRadarTimeMs;
const driftColor = Math.abs(driftMs) > 50 ? "#FF6347" : "#98FB98"; // Tomato red or Pale green const driftColor = Math.abs(driftMs) > 50 ? "#FF6347" : "#98FB98"; // Tomato red or Pale green
radarInfoOverlay.innerHTML = ` radarInfoOverlay.innerHTML = `
@ -283,7 +319,9 @@ export function updatePersistentOverlays(currentMediaTime) {
} }
// --- Update Video Overlay --- // --- Update Video Overlay ---
const absVideoTime = new Date(appState.videoStartDate.getTime() + (currentMediaTime * 1000));
const absVideoTime = new Date(
appState.videoStartDate.getTime() + currentMediaTime * 1000
);
const videoFrame = Math.floor(currentMediaTime * VIDEO_FPS); const videoFrame = Math.floor(currentMediaTime * VIDEO_FPS);
videoInfoOverlay.innerHTML = ` videoInfoOverlay.innerHTML = `
@ -292,11 +330,13 @@ export function updatePersistentOverlays(currentMediaTime) {
`; `;
} }
const customTtcInputs = [ const customTtcInputs = [
ttcColorCritical, ttcTimeCritical,
ttcColorHigh, ttcTimeHigh,
ttcColorMedium, ttcTimeMedium,
ttcColorCritical,
ttcTimeCritical,
ttcColorHigh,
ttcTimeHigh,
ttcColorMedium,
ttcTimeMedium,
]; ];
function updateCustomTtcScheme() { function updateCustomTtcScheme() {
@ -312,23 +352,23 @@ function updateCustomTtcScheme() {
} }
} }
ttcModeDefault.addEventListener('change', () => {
ttcModeDefault.addEventListener("change", () => {
if (ttcModeDefault.checked) { if (ttcModeDefault.checked) {
appState.useCustomTtcScheme = false; appState.useCustomTtcScheme = false;
customTtcPanel.classList.add('hidden');
customTtcPanel.classList.add("hidden");
if (appState.p5_instance) appState.p5_instance.redraw(); if (appState.p5_instance) appState.p5_instance.redraw();
} }
}); });
ttcModeCustom.addEventListener('change', () => {
ttcModeCustom.addEventListener("change", () => {
if (ttcModeCustom.checked) { if (ttcModeCustom.checked) {
appState.useCustomTtcScheme = true; appState.useCustomTtcScheme = true;
customTtcPanel.classList.remove('hidden');
customTtcPanel.classList.remove("hidden");
updateCustomTtcScheme(); // Apply current custom values immediately updateCustomTtcScheme(); // Apply current custom values immediately
} }
}); });
// Add listeners to all custom inputs to update the scheme on the fly // Add listeners to all custom inputs to update the scheme on the fly
customTtcInputs.forEach(input => {
input.addEventListener('input', updateCustomTtcScheme);
customTtcInputs.forEach((input) => {
input.addEventListener("input", updateCustomTtcScheme);
}); });

71
steps/src/main.js

@ -84,6 +84,13 @@ import {
togglePredictedPos, togglePredictedPos,
toggleCovariance, toggleCovariance,
updatePersistentOverlays, updatePersistentOverlays,
collapsibleMenu,
toggleMenuBtn,
fullscreenBtn,
mainContent,
closeMenuBtn,
fullscreenEnterIcon,
fullscreenExitIcon,
} from "./dom.js"; } from "./dom.js";
import { initializeTheme } from "./theme.js"; import { initializeTheme } from "./theme.js";
@ -343,6 +350,44 @@ sessionFileInput.addEventListener("change", (event) => {
// --- END: Add Session Management Logic --- // --- END: Add Session Management Logic ---
// --- Collapsible Menu Logic ---
function toggleMenu(show) {
if (show) {
collapsibleMenu.classList.remove("-translate-x-full");
mainContent.classList.add("lg:ml-96");
} else {
collapsibleMenu.classList.add("-translate-x-full");
mainContent.classList.remove("lg:ml-96");
}
}
// Open the menu
toggleMenuBtn.addEventListener("click", () => toggleMenu(true));
// Close the menu
closeMenuBtn.addEventListener("click", () => toggleMenu(false));
// --- Fullscreen Logic ---
fullscreenBtn.addEventListener("click", () => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
} else if (document.exitFullscreen) {
document.exitFullscreen();
}
});
// This listener updates the icon whenever fullscreen state changes,
// whether it's triggered by our button or the F11 key.
document.addEventListener("fullscreenchange", () => {
if (document.fullscreenElement) {
fullscreenEnterIcon.classList.add("hidden");
fullscreenExitIcon.classList.remove("hidden");
} else {
fullscreenEnterIcon.classList.remove("hidden");
fullscreenExitIcon.classList.add("hidden");
}
});
// In main.js, REPLACE your existing jsonFileInput event listener with this entire block: // In main.js, REPLACE your existing jsonFileInput event listener with this entire block:
jsonFileInput.addEventListener("change", (event) => { jsonFileInput.addEventListener("change", (event) => {
@ -703,7 +748,9 @@ document.addEventListener("keydown", (event) => {
// --- FIX APPLIED HERE --- // --- FIX APPLIED HERE ---
// We only want to block shortcuts if the user is actively typing in a text or number input. // We only want to block shortcuts if the user is actively typing in a text or number input.
// This allows shortcuts to work even when other elements, like the timeline slider, are focused. // This allows shortcuts to work even when other elements, like the timeline slider, are focused.
const isTextInputFocused = event.target.tagName === 'INPUT' && (event.target.type === 'text' || event.target.type === 'number');
const isTextInputFocused =
event.target.tagName === "INPUT" &&
(event.target.type === "text" || event.target.type === "number");
if (isTextInputFocused) { if (isTextInputFocused) {
return; return;
} }
@ -711,7 +758,22 @@ document.addEventListener("keydown", (event) => {
const key = event.key; const key = event.key;
// We can add any new shortcut keys to this array. // We can add any new shortcut keys to this array.
const recognizedKeys = ["ArrowRight", "ArrowLeft", " ", "1", "2", "3", "4", "t", "d", "c", "r", "p", "a", "s"];
const recognizedKeys = [
"ArrowRight",
"ArrowLeft",
" ",
"1",
"2",
"3",
"4",
"t",
"d",
"c",
"r",
"p",
"a",
"s",
];
if (!appState.vizData || !recognizedKeys.includes(key)) { if (!appState.vizData || !recognizedKeys.includes(key)) {
return; return;
@ -744,7 +806,7 @@ document.addEventListener("keydown", (event) => {
} }
// --- Number keys for color modes --- // --- Number keys for color modes ---
if (key >= '1' && key <= '4') {
if (key >= "1" && key <= "4") {
const colorToggles = [ const colorToggles = [
toggleSnrColor, toggleSnrColor,
toggleClusterColor, toggleClusterColor,
@ -778,6 +840,9 @@ document.addEventListener("keydown", (event) => {
toggleDebugOverlay.click(); toggleDebugOverlay.click();
toggleDebug2Overlay.click(); toggleDebug2Overlay.click();
} }
if (key === "m") {
toggleMenuBtn.click();
}
}); });
function calculateAndSetOffset() { function calculateAndSetOffset() {

2
steps/src/sync.js

@ -69,6 +69,8 @@ export function animationLoop() {
// Update debug overlay information // Update debug overlay information
updatePersistentOverlays(currentMediaTime); updatePersistentOverlays(currentMediaTime);
updateDebugOverlay(currentMediaTime);
// Redraw the speed graph if an instance exists // Redraw the speed graph if an instance exists
if (appState.speedGraphInstance) appState.speedGraphInstance.redraw(); if (appState.speedGraphInstance) appState.speedGraphInstance.redraw();

Loading…
Cancel
Save