From 21a04ac7fd6ac96084db5fb35ee36584e939efca Mon Sep 17 00:00:00 2001 From: Konsti Wohlwend Date: Mon, 13 Jul 2026 18:29:14 -0700 Subject: [PATCH] Coalesce Overview globe hover hit-testing to one per frame (#1758) --- .../projects/[projectId]/(overview)/globe.tsx | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/globe.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/globe.tsx index 6628ca964..cf3e6beaa 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/globe.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/globe.tsx @@ -533,6 +533,8 @@ function GlobeSectionInner({ countryData, totalUsers, activeUsersByCountry, sate selectedCountryRef.current = selectedCountry; const pendingCountryClearTimeoutRef = useRef | null>(null); + const pendingHoverHitTestRafRef = useRef(null); + const latestPointerPositionRef = useRef<{ clientX: number, clientY: number } | null>(null); const clearPendingCountryClear = () => { if (pendingCountryClearTimeoutRef.current != null) { clearTimeout(pendingCountryClearTimeoutRef.current); @@ -589,6 +591,14 @@ function GlobeSectionInner({ countryData, totalUsers, activeUsersByCountry, sate updateSelectedCountry(findCountryAt(globeCoords.lat, globeCoords.lng, countries.features)); }; + const cancelPendingHoverHitTest = () => { + if (pendingHoverHitTestRafRef.current != null) { + cancelAnimationFrame(pendingHoverHitTestRafRef.current); + pendingHoverHitTestRafRef.current = null; + } + latestPointerPositionRef.current = null; + }; + useEffect(() => { if (selectedCountry) { setPreviousSelectedCountry(selectedCountry); @@ -600,6 +610,10 @@ function GlobeSectionInner({ countryData, totalUsers, activeUsersByCountry, sate if (pendingCountryClearTimeoutRef.current != null) { clearTimeout(pendingCountryClearTimeoutRef.current); } + if (pendingHoverHitTestRafRef.current != null) { + cancelAnimationFrame(pendingHoverHitTestRafRef.current); + } + latestPointerPositionRef.current = null; }; }, []); @@ -1107,13 +1121,25 @@ function GlobeSectionInner({ countryData, totalUsers, activeUsersByCountry, sate }} onMouseMoveCapture={(e) => { resumeRender(); - updateSelectedCountryFromPointerPosition(e.clientX, e.clientY); + latestPointerPositionRef.current = { clientX: e.clientX, clientY: e.clientY }; + // Mousemove can fire many times between paints; coalesce the expensive + // globe raycast and country scan to one hit-test per animation frame. + if (pendingHoverHitTestRafRef.current == null) { + pendingHoverHitTestRafRef.current = requestAnimationFrame(() => { + pendingHoverHitTestRafRef.current = null; + const pointerPosition = latestPointerPositionRef.current; + if (pointerPosition != null) { + updateSelectedCountryFromPointerPosition(pointerPosition.clientX, pointerPosition.clientY); + } + }); + } if (tooltipRef.current) { tooltipRef.current.style.transform = `translate(${e.clientX}px, ${e.clientY}px)`; } }} onMouseLeave={() => { // Only clear when leaving the entire globe area + cancelPendingHoverHitTest(); updateSelectedCountry(null, { immediateClear: true }); if (globeRef.current) { //globeRef.current.controls().autoRotate = true;