Browse Source

- Add vertical range slider (20m-200m) to adjust RADAR_Y_MAX dynamically.

- Implement robust fallback and safety logic to prevent division-by-zero or invalid state crashes.
   - Update scale calculations and drawing utilities to use dynamic boundaries from appState.
   - Refine radar-info-overlay to match plot width and center text content for better alignment.
   - Add double-click reset functionality to the range slider to revert to default constants.
   - Fix hover detection bug in God Mode during scroll-zoom interactions.
   - Ensure Regions of Interest (ROI) scale proportionally with the dynamic plot range.
refactor/sync-centralize
RUSHIL AMBARISH KADU 3 months ago
parent
commit
e7c72160ed
  1. 13
      steps/index.html
  2. 4
      steps/src/dom.js
  3. 15
      steps/src/drawUtils.js
  4. 57
      steps/src/p5/radarSketch.js
  5. 12
      steps/src/state.js

13
steps/index.html

@ -394,12 +394,21 @@
<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">
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 relative">
<p id="canvas-placeholder" class="text-gray-500 dark:text-gray-400 text-lg">Load JSON data to start
visualization</p>
<!-- Range Slider (Vertical) -->
<div class="absolute bottom-8 left-2 flex flex-col items-center gap-2 z-20 group">
<span id="range-value-display" class="bg-black bg-opacity-60 text-white text-[10px] px-1.5 py-0.5 rounded font-mono">80m</span>
<input type="range" id="range-slider" min="40" max="200" value="80" step="10"
class="h-32 cursor-pointer accent-blue-600"
style="writing-mode: bt-lr; -webkit-appearance: slider-vertical; width: 8px;" />
<span class="text-[10px] font-bold text-gray-400 uppercase tracking-tighter" style="writing-mode: vertical-lr; transform: rotate(180deg);">Range</span>
</div>
</div>
<div id="radar-info-overlay"
class="absolute top-[-35px] left-2 z-10 bg-black bg-opacity-60 text-white font-mono text-xs p-2 rounded-md hidden">
class="absolute top-[-35px] left-0 right-0 z-10 bg-black bg-opacity-60 text-white font-mono text-xs p-2 rounded-md hidden">
</div>
<div class="absolute bottom left-1/2 -translate-x-1/2 flex items-center justify-center gap-4">
<div id="ego-speed-display"

4
steps/src/dom.js

@ -110,6 +110,8 @@ export const guideModalCloseBtn = document.getElementById("guide-modal-close-btn
export const codebaseBtn = document.getElementById("codebase-btn");
export const codebaseModal = document.getElementById("codebase-modal");
export const codebaseModalCloseBtn = document.getElementById("codebase-modal-close-btn");
export const rangeSlider = document.getElementById("range-slider");
export const rangeValueDisplay = document.getElementById("range-value-display");
@ -327,7 +329,7 @@ export function updatePersistentOverlays(currentMediaTime) {
// --- OPTIMIZATION: One-time DOM Setup & Caching ---
if (!overlayCache) {
radarInfoOverlay.innerHTML = `
<div id="radar-text-content" style="line-height: 1.5;">
<div id="radar-text-content" style="line-height: 1.5; text-align: center;">
Frame: <span id="ov-frame"></span>
| EGO State: <span id="ov-motion"></span>
| FPS: <b id="ov-fps"></b>

15
steps/src/drawUtils.js

@ -1,13 +1,10 @@
import {
RADAR_X_MAX,
RADAR_X_MIN,
RADAR_Y_MAX,
RADAR_Y_MIN,
MAX_TRAJECTORY_LENGTH,
ROI_TRACKS_Y_MIN,
ROI_TRACKS_Y_MAX,
ROI_CLOSE_Y_MIN,
ROI_CLOSE_Y_MAX,
} from "./constants.js";
import { appState } from "./state.js";
import {
@ -163,7 +160,7 @@ export function drawAxes(p, plotScales) {
// Draw horizontal grid lines.
p.stroke(axisColor);
p.strokeWeight(1);
for (let y = 5; y <= RADAR_Y_MAX; y += 5)
for (let y = 5; y <= appState.radarYMax; y += 5)
p.line(
RADAR_X_MIN * plotScales.plotScaleX,
y * plotScales.plotScaleY,
@ -182,7 +179,7 @@ export function drawAxes(p, plotScales) {
x * plotScales.plotScaleX,
RADAR_Y_MIN * plotScales.plotScaleY,
x * plotScales.plotScaleX,
RADAR_Y_MAX * plotScales.plotScaleY
appState.radarYMax * plotScales.plotScaleY
);
}
p.stroke(mainAxisColor);
@ -196,13 +193,13 @@ export function drawAxes(p, plotScales) {
0,
RADAR_Y_MIN * plotScales.plotScaleY,
0,
RADAR_Y_MAX * plotScales.plotScaleY
appState.radarYMax * plotScales.plotScaleY
);
// Draw Y-axis labels.
p.fill(textColor);
p.noStroke();
p.textSize(10);
for (let y = 5; y <= RADAR_Y_MAX; y += 5) {
for (let y = 5; y <= appState.radarYMax; y += 5) {
p.push();
p.translate(5, y * plotScales.plotScaleY);
// Flip text vertically to align with flipped Y-axis.
@ -1022,7 +1019,7 @@ export function drawRegionsOfInterest(p, frameData, plotScales) {
left * plotScales.plotScaleX,
ROI_TRACKS_Y_MIN * plotScales.plotScaleY,
right * plotScales.plotScaleX,
ROI_TRACKS_Y_MAX * plotScales.plotScaleY
appState.radarYMax * plotScales.plotScaleY
);
// --- Draw Close Region ---
@ -1031,7 +1028,7 @@ export function drawRegionsOfInterest(p, frameData, plotScales) {
left * plotScales.plotScaleX,
ROI_CLOSE_Y_MIN * plotScales.plotScaleY,
right * plotScales.plotScaleX,
ROI_CLOSE_Y_MAX * plotScales.plotScaleY
(appState.radarYMax * 0.25) * plotScales.plotScaleY
);
p.pop();

57
steps/src/p5/radarSketch.js

@ -2,7 +2,6 @@ import { appState } from "../state.js";
import { debugFlags } from "../debug.js";
import {
RADAR_X_MAX,
// Define radar plot boundaries
RADAR_X_MIN,
RADAR_Y_MAX,
RADAR_Y_MIN,
@ -17,6 +16,8 @@ import {
toggleVehicleDimensions,
toggleClusterColor,
toggleConfirmedOnly,
rangeSlider,
rangeValueDisplay,
} from "../dom.js";
import {
drawStaticRegionsToBuffer,
@ -60,6 +61,21 @@ export const radarSketch = function (p) {
};
// Function to calculate scaling factors for radar coordinates to canvas pixels
function calculatePlotScales() {
// --- START: Safety Fallback Logic ---
// Ensure we have valid numbers; if not, revert to constants from constants.js
const xMin = typeof appState.radarXMin === 'number' ? appState.radarXMin : RADAR_X_MIN;
const xMax = typeof appState.radarXMax === 'number' ? appState.radarXMax : RADAR_X_MAX;
const yMin = typeof appState.radarYMin === 'number' ? appState.radarYMin : RADAR_Y_MIN;
const yMax = typeof appState.radarYMax === 'number' ? appState.radarYMax : RADAR_Y_MAX;
const dx = xMax - xMin;
const dy = yMax - yMin;
// Final safety: Prevent division by zero if values are somehow identical or inverted
const safeDx = dx > 0 ? dx : 50; // Default width 50m
const safeDy = dy > 0 ? dy : 80; // Default height 80m
// --- END: Safety Fallback Logic ---
// Padding and offset values for the plot area
const hPad = 0.05,
vPad = 0.05,
@ -67,9 +83,10 @@ export const radarSketch = function (p) {
// Calculate available width and height for the plot
const aW = p.width * (1 - 2 * hPad);
const aH = p.height * (1 - bOff - vPad);
// Determine plot scales based on radar boundaries and available canvas space
plotScales.plotScaleX = aW / (RADAR_X_MAX - RADAR_X_MIN);
plotScales.plotScaleY = aH / (RADAR_Y_MAX - RADAR_Y_MIN);
plotScales.plotScaleX = aW / safeDx;
plotScales.plotScaleY = aH / safeDy;
}
p.setup = function () {
@ -106,7 +123,7 @@ export const radarSketch = function (p) {
appState.zoomSketchInstance &&
appState.zoomSketchInstance.updateAndDraw
) {
const hoveredItems = handleCloseUpDisplay(p, plotScales);
const hoveredItems = handleCloseUpDisplay(p, plotScales, p.mouseX, p.mouseY);
appState.zoomSketchInstance.updateAndDraw(
p.mouseX,
p.mouseY,
@ -134,6 +151,38 @@ export const radarSketch = function (p) {
// Reset FPS state to prevent stale values from previous sessions
appState.fps = 0;
// --- START: Radar Range Slider Logic ---
if (rangeSlider && rangeValueDisplay) {
// Initialize slider value from appState
rangeSlider.value = appState.radarYMax;
rangeValueDisplay.textContent = appState.radarYMax + "m";
// Add listener to handle slider changes
rangeSlider.addEventListener("input", () => {
const newMax = parseInt(rangeSlider.value);
appState.radarYMax = newMax;
rangeValueDisplay.textContent = newMax + "m";
// Recalculate scales and redraw static background
calculatePlotScales();
drawStaticRegionsToBuffer(p, staticBackgroundBuffer, plotScales);
// Redraw main sketch to reflect new scale immediately
p.redraw();
});
// Reset to default on double-click
rangeSlider.addEventListener("dblclick", () => {
appState.radarYMax = RADAR_Y_MAX;
rangeSlider.value = RADAR_Y_MAX;
rangeValueDisplay.textContent = RADAR_Y_MAX + "m";
calculatePlotScales();
drawStaticRegionsToBuffer(p, staticBackgroundBuffer, plotScales);
p.redraw();
});
}
// --- END: Radar Range Slider Logic ---
p.noLoop();
// Disable continuous looping, redraw will be called manually
};

12
steps/src/state.js

@ -1,3 +1,10 @@
import {
RADAR_X_MIN,
RADAR_X_MAX,
RADAR_Y_MIN,
RADAR_Y_MAX
} from "./constants.js";
export const appState = {
zoomHideDelayTimeout: null, // Timeout before the hide countdown begins
zoomCountdown: null, // Holds the number of seconds left before zoom hides
@ -60,4 +67,9 @@ export const appState = {
consecutiveResyncs: 0, // Counter for consecutive resyncs
isInLockdown: false, // Flag to prevent nested lockdown triggers
// --- Dynamic Radar Boundaries ---
radarXMin: RADAR_X_MIN,
radarXMax: RADAR_X_MAX,
radarYMin: RADAR_Y_MIN,
radarYMax: RADAR_Y_MAX,
};
Loading…
Cancel
Save