diff --git a/steps/src/drawUtils.js b/steps/src/drawUtils.js index 10d189f..3ff0d6c 100644 --- a/steps/src/drawUtils.js +++ b/steps/src/drawUtils.js @@ -527,7 +527,10 @@ export function handleCloseUpDisplay(p, plotScales) { const frameData = appState.vizData.radarFrames[appState.currentFrame]; if (!frameData) return []; // Return empty array if no data const hoveredItems = []; - const radius = 10; + // --- START: Dynamic Radius Logic --- + // The hover radius is now inversely proportional to the zoom factor. + const radius = p.constrain(80 / appState.zoomFactor, 5, 25); + // --- END: Dynamic Radius Logic --- const localClusterColors = clusterColors(p); // <-- Get the color palette once // ... (Step 1a: Find hovered points - no changes here) ... @@ -585,38 +588,45 @@ export function handleCloseUpDisplay(p, plotScales) { // Find hovered track markers and predicted positions if (appState.vizData.tracks) { for (const track of appState.vizData.tracks) { - const log = track.historyLog.find( - (log) => log.frameIdx === appState.currentFrame + 1 + // --- FIX START: Fetch log for the CURRENT frame for the track marker --- + const currentLog = track.historyLog.find( + (log) => log.frameIdx === appState.currentFrame ); - if (log) { - if (log.correctedPosition && log.correctedPosition[0] !== null) { - const pos = log.correctedPosition; + // --- FIX END --- + + if (currentLog) { + if (currentLog.correctedPosition && currentLog.correctedPosition[0] !== null) { + const pos = currentLog.correctedPosition; const screenX = pos[0] * plotScales.plotScaleX + p.width / 2; const screenY = p.height * 0.95 - pos[1] * plotScales.plotScaleY; const d = p.dist(p.mouseX, p.mouseY, screenX, screenY); if (d < radius) { hoveredItems.push({ type: "track", - data: log, + data: currentLog, // Use the log for the current frame trackId: track.id, screenX, screenY, }); } } + } + + // For predicted position, we now also use the current frame's log. + if (currentLog) { if ( togglePredictedPos.checked && - log.predictedPosition && - log.predictedPosition[0] !== null + currentLog.predictedPosition && + currentLog.predictedPosition[0] !== null ) { - const pos = log.predictedPosition; + const pos = currentLog.predictedPosition; const screenX = pos[0] * plotScales.plotScaleX + p.width / 2; const screenY = p.height * 0.95 - pos[1] * plotScales.plotScaleY; const d = p.dist(p.mouseX, p.mouseY, screenX, screenY); if (d < radius) { hoveredItems.push({ type: "prediction", - data: log, + data: currentLog, trackId: track.id, screenX, screenY, diff --git a/steps/src/p5/radarSketch.js b/steps/src/p5/radarSketch.js index 0114e34..dcf22d4 100644 --- a/steps/src/p5/radarSketch.js +++ b/steps/src/p5/radarSketch.js @@ -225,6 +225,40 @@ export const radarSketch = function (p) { const zoomPanel = document.getElementById("zoom-panel"); if (appState.isCloseUpMode) { const hoveredItems = handleCloseUpDisplay(p, plotScales); + + // --- START: Draw Zoom Area Rectangle & Debug Circle --- + const zoomWindow = document.getElementById("zoom-canvas-container"); + if (zoomWindow) { + const zoomWindowWidth = zoomWindow.offsetWidth; + const zoomWindowHeight = zoomWindow.offsetHeight; + + // Calculate the dimensions of the source rectangle on the main canvas. + const sourceWidth = zoomWindowWidth / appState.zoomFactor; + const sourceHeight = zoomWindowHeight / appState.zoomFactor; + + p.push(); + p.noFill(); + p.stroke(255, 0, 0, 150); // Semi-transparent red, visible in both themes. + p.strokeWeight(1); // Reduced thickness. + p.drawingContext.setLineDash([5, 3]); // Dashed line. + p.rectMode(p.CENTER); + p.rect(p.mouseX, p.mouseY, sourceWidth, sourceHeight); + p.drawingContext.setLineDash([]); // Reset line dash + p.pop(); + } + + // Draw a temporary debug circle representing the hover radius. + // This formula must match the one in drawUtils.js for accurate visualization. + const hoverRadius = p.constrain(80 / appState.zoomFactor, 5, 25); + p.push(); + p.noFill(); + p.stroke(148, 0, 211, 150); // Deep purple, semi-transparent. + p.strokeWeight(1); + p.drawingContext.setLineDash([5,3]) + p.ellipse(p.mouseX, p.mouseY, hoverRadius * 2, hoverRadius * 2); + p.pop(); + // --- END: Draw Zoom Area Rectangle & Debug Circle --- + if (hoveredItems.length > 0) { clearTimeout(appState.zoomHoverTimeout); // Cancel the timer appState.zoomHoverTimeout = null; diff --git a/steps/src/p5/zoomSketch.js b/steps/src/p5/zoomSketch.js index 8fbe899..43fc1bd 100644 --- a/steps/src/p5/zoomSketch.js +++ b/steps/src/p5/zoomSketch.js @@ -275,7 +275,7 @@ export const zoomSketch = function (p) { if (togglePredictedPos.checked) { for (const track of appState.vizData.tracks) { const log = track.historyLog.find( - (log) => log.frameIdx === appState.currentFrame + 1 + (log) => log.frameIdx === appState.currentFrame ); if ( log && @@ -314,7 +314,7 @@ export const zoomSketch = function (p) { p.fill(textColor); p.noStroke(); p.textSize(16); - p.textAlign(p.LEFT - 2, p.TOP); + p.textAlign(p.LEFT, p.TOP); p.textStyle(p.BOLD); p.text(titleText, 10, 10); p.pop();