All files / extensions/cornerstone/src/hooks useViewportHover.ts

91.42% Statements 32/35
75% Branches 6/8
88.88% Functions 8/9
91.17% Lines 31/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78                      342x 342x 342x   342x   342x 92x 92x   92x       92x 92x     92x 92x     92x 308x               92x 308x   308x 68x 68x         92x         92x 92x   92x   92x 27x 27x 27x       342x 92x 92x       342x    
import { useState, useEffect, useCallback, useMemo } from 'react';
import { useViewportGrid } from '@ohif/ui-next';
 
/**
 * Hook to track whether the mouse is hovering over a specific viewport
 * and whether the viewport is active
 *
 * @param viewportId - The ID of the viewport to track
 * @returns { isHovered, isActive } - Whether the viewport is hovered and active
 */
export function useViewportHover(viewportId: string): { isHovered: boolean; isActive: boolean } {
  const [isHovered, setIsHovered] = useState(false);
  const [viewportGrid] = useViewportGrid();
  const { activeViewportId } = viewportGrid;
 
  const isActive = activeViewportId === viewportId;
 
  const setupListeners = useCallback(() => {
    const viewportElement = document.querySelector(`[data-viewportId="${viewportId}"]`);
    const element = viewportElement?.closest('.viewport-wrapper') || viewportElement;
 
    Iif (!element) {
      return null;
    }
 
    let elementRect = (element as HTMLElement).getBoundingClientRect();
    let lastIsInside = false;
 
    // Update rectangle when window is resized
    const updateRect = () => {
      elementRect = (element as HTMLElement).getBoundingClientRect();
    };
 
    const isPointInViewport = (x, y) => {
      return (
        x >= elementRect.left &&
        x <= elementRect.right &&
        y >= elementRect.top &&
        y <= elementRect.bottom
      );
    };
 
    const handleMouseMove = event => {
      const isInside = isPointInViewport(event.clientX, event.clientY);
 
      if (isInside !== lastIsInside) {
        lastIsInside = isInside;
        setIsHovered(isInside);
      }
    };
 
    let resizeTimeout;
    const handleResize = () => {
      clearTimeout(resizeTimeout);
      resizeTimeout = setTimeout(updateRect, 10);
    };
 
    window.addEventListener('resize', handleResize);
    document.addEventListener('mousemove', handleMouseMove);
 
    updateRect();
 
    return () => {
      window.removeEventListener('resize', handleResize);
      document.removeEventListener('mousemove', handleMouseMove);
      clearTimeout(resizeTimeout);
    };
  }, [viewportId]);
 
  useEffect(() => {
    const cleanup = setupListeners();
    return cleanup;
  }, [setupListeners]);
 
  // Memoize the return value to prevent unnecessary re-renders
  return useMemo(() => ({ isHovered, isActive }), [isHovered, isActive]);
}