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                      2267x 2267x 2267x   2267x   2267x 596x 596x   596x       596x 596x     596x 596x     596x 3653x               596x 3653x   3653x 348x 348x         596x         596x 596x   596x   596x 185x 185x 185x       2267x 596x 596x       2267x    
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]);
}