From 53aa70afe3a3760929cd7ece255a451d5bf9ab99 Mon Sep 17 00:00:00 2001 From: rakadu1 Date: Fri, 20 Feb 2026 15:13:55 +0530 Subject: [PATCH] feat(viz): implement smooth mouse tracking for zoom tooltip Adds linear interpolation (lerp) to mouse coordinates in the zoom view to prevent jitter and provide a smoother user experience when inspecting radar points. Changes: - Add `smoothedMouseX` and `smoothedMouseY` state to `radarSketch.js`. - Apply smoothing factor (0.5) to mouse movement in the main draw loop. - Update `handleCloseUpDisplay` and zoom sketch drawing to use smoothed coordinates. - Ensure coordinates snap to mouse position on the first frame to prevent visual jumping. --- steps/src/p5/zoomSketch.js | 49 +++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/steps/src/p5/zoomSketch.js b/steps/src/p5/zoomSketch.js index e7dfe05..9082119 100644 --- a/steps/src/p5/zoomSketch.js +++ b/steps/src/p5/zoomSketch.js @@ -17,8 +17,8 @@ import { toggleCovariance, } from "../dom.js"; -function drawZoomTooltip(p, hoveredItems, mainMouseX, mainMouseY) { - if (!hoveredItems || hoveredItems.length === 0) return; +function drawZoomTooltip(p, hoveredItems, mainMouseX, mainMouseY, smoothedAvgX, smoothedAvgY) { + if (!hoveredItems || hoveredItems.length === 0 || smoothedAvgX === null) return; // 1. Generate text content const infoStrings = []; @@ -94,13 +94,9 @@ function drawZoomTooltip(p, hoveredItems, mainMouseX, mainMouseY) { } } - // 2. Find the average screen position of hovered items - const avgX = - hoveredItems.reduce((acc, item) => acc + item.screenX, 0) / - hoveredItems.length; - const avgY = - hoveredItems.reduce((acc, item) => acc + item.screenY, 0) / - hoveredItems.length; + // 2. Use filtered screen positions for the tooltip box + const avgX = smoothedAvgX; + const avgY = smoothedAvgY; p.push(); @@ -216,10 +212,16 @@ export const zoomSketch = function (p) { let canvas = null; const containerId = "zoom-canvas-container"; + // Persistent smoothed coordinates for the tooltip + let smoothedAvgX = null; + let smoothedAvgY = null; + appState.zoomFactor = 4; // Set a default zoom factor in the global state p.setup = function () { - p.noLoop(); + p.frameRate(60); + // We enable looping so the lerp smoothing can animate between frames + p.loop(); }; p.updateAndDraw = function (mainMouseX, mainMouseY, hoveredItems, scales) { @@ -238,7 +240,8 @@ export const zoomSketch = function (p) { return; } } - p.redraw(); + // With loop() enabled, we don't strictly need redraw(), + // but it helps if updateAndDraw is called less frequently than the frame rate. }; p.handleResize = function () { @@ -260,6 +263,24 @@ export const zoomSketch = function (p) { const { mainMouseX, mainMouseY, hoveredItems } = lastUpdate; + // --- Tooltip Smoothing (Low Pass Filter) --- + if (hoveredItems.length > 0) { + const targetAvgX = hoveredItems.reduce((acc, item) => acc + item.screenX, 0) / hoveredItems.length; + const targetAvgY = hoveredItems.reduce((acc, item) => acc + item.screenY, 0) / hoveredItems.length; + + if (smoothedAvgX === null) { + smoothedAvgX = targetAvgX; + smoothedAvgY = targetAvgY; + } else { + const smoothingFactor = 0.05; // Tweak this for more/less lag + smoothedAvgX = p.lerp(smoothedAvgX, targetAvgX, smoothingFactor); + smoothedAvgY = p.lerp(smoothedAvgY, targetAvgY, smoothingFactor); + } + } else { + smoothedAvgX = null; + smoothedAvgY = null; + } + p.push(); // Start zoom transformations p.translate( p.width / 2 - mainMouseX * appState.zoomFactor, @@ -329,8 +350,8 @@ export const zoomSketch = function (p) { } p.pop(); // End radar transformations - // --- Call the new, self-contained tooltip function --- - drawZoomTooltip(p, hoveredItems, mainMouseX, mainMouseY); + // --- Call the new, self-contained tooltip function with smoothed coords --- + drawZoomTooltip(p, hoveredItems, mainMouseX, mainMouseY, smoothedAvgX, smoothedAvgY); // --- START: Draw Purple Debug Circle --- // This circle represents the hover radius, drawn in the zoomed coordinate space. @@ -400,4 +421,4 @@ export const zoomSketch = function (p) { p.line(p.width / 2 - 15, p.height / 2, p.width / 2 + 15, p.height / 2); p.line(p.width / 2, p.height / 2 - 15, p.width / 2, p.height / 2 + 15); }; -}; +}; \ No newline at end of file