All files / src/components/VirtualWalkthrough xr-gaze-dwell-state.ts

100% Statements 9/9
100% Branches 6/6
100% Functions 1/1
100% Lines 9/9

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                      1x             1x 5x 1x   4x 1x     3x 3x   3x    
export interface DwellState {
  targetIndex: number | null;
  elapsed: number;
}
 
export interface DwellUpdate {
  state: DwellState;
  progress: number;
  justOpened: boolean;
}
 
export const INITIAL_DWELL_STATE: DwellState = { targetIndex: null, elapsed: 0 };
 
/**
 * Advances gaze-dwell timing for one frame. `target` is the annotation index currently under the
 * gaze ray, or null. Dwell time accumulates while the same target is held and resets when it
 * changes or is lost. `justOpened` is true only on the frame the dwell first reaches `threshold`.
 */
export const advanceDwell = (prev: DwellState, target: number | null, dt: number, threshold: number): DwellUpdate => {
  if (target === null) {
    return { state: INITIAL_DWELL_STATE, progress: 0, justOpened: false };
  }
  if (target !== prev.targetIndex) {
    return { state: { targetIndex: target, elapsed: 0 }, progress: 0, justOpened: false };
  }
 
  const elapsed = Math.min(prev.elapsed + dt, threshold);
  const justOpened = prev.elapsed < threshold && elapsed >= threshold;
 
  return { state: { targetIndex: target, elapsed }, progress: elapsed / threshold, justOpened };
};