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

92.5% Statements 37/40
77.77% Branches 14/18
90.9% Functions 10/11
92.3% Lines 36/39

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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105            159x   159x   159x       159x   159x   159x     159x           159x 159x       159x 82x 82x 82x           159x       159x                                 194x 194x 194x   194x 81x 107x 107x 159x   107x 107x 63x   44x       81x   81x   81x               81x 405x     81x 270x 54x       194x    
import { useState, useEffect } from 'react';
import debounce from 'lodash.debounce';
import { useSystem } from '@ohif/core';
import i18n from '@ohif/i18n';
 
function mapMeasurementToDisplay(measurement, displaySetService) {
  const { referenceSeriesUID } = measurement;
 
  const displaySets = displaySetService.getDisplaySetsForSeries(referenceSeriesUID);
 
  Iif (!displaySets[0]?.instances) {
    throw new Error('The tracked measurements panel should only be tracking "stack" displaySets.');
  }
 
  const { findingSites, finding, label: baseLabel, displayText: baseDisplayText } = measurement;
 
  const firstSite = findingSites?.[0];
  const label =
    baseLabel || finding?.text || firstSite?.text || i18n.t('MeasurementTable:empty');
 
  // Initialize displayText with the structure used in Length.ts and CobbAngle.ts
  const displayText = {
    primary: [],
    secondary: baseDisplayText?.secondary || [],
  };
 
  // Add baseDisplayText to primary if it exists
  if (baseDisplayText) {
    displayText.primary.push(...baseDisplayText.primary);
  }
 
  // Add finding sites to primary
  if (findingSites) {
    findingSites.forEach(site => {
      if (site?.text && site.text !== label) {
        displayText.primary.push(site.text);
      }
    });
  }
 
  // Add finding to primary if it's different from the label
  Iif (finding && finding.text && finding.text !== label) {
    displayText.primary.push(finding.text);
  }
 
  return {
    ...measurement,
    displayText,
    label,
  };
}
 
/**
 * A custom hook that provides mapped measurements based on the given services and filters.
 *
 * @param {Object} servicesManager - The services manager object.
 * @param {Object} options - The options for filtering and mapping measurements.
 * @param {Function} options.measurementFilter - Optional function to filter measurements.
 * @param {Object} options.valueTypes - The value types for mapping measurements.
 * @returns {Array} An array of mapped and filtered measurements.
 */
export function useMeasurements({ measurementFilter } = { measurementFilter: () => true }) {
  const { servicesManager } = useSystem();
  const { measurementService, displaySetService } = servicesManager.services;
  const [displayMeasurements, setDisplayMeasurements] = useState([]);
 
  useEffect(() => {
    const updateDisplayMeasurements = () => {
      const measurements = measurementService.getMeasurements(measurementFilter);
      const mappedMeasurements = measurements.map(m =>
        mapMeasurementToDisplay(m, displaySetService)
      );
      setDisplayMeasurements(prevMeasurements => {
        if (JSON.stringify(prevMeasurements) !== JSON.stringify(mappedMeasurements)) {
          return mappedMeasurements;
        }
        return prevMeasurements;
      });
    };
 
    const debouncedUpdate = debounce(updateDisplayMeasurements, 100);
 
    updateDisplayMeasurements();
 
    const events = [
      measurementService.EVENTS.MEASUREMENT_ADDED,
      measurementService.EVENTS.RAW_MEASUREMENT_ADDED,
      measurementService.EVENTS.MEASUREMENT_UPDATED,
      measurementService.EVENTS.MEASUREMENT_REMOVED,
      measurementService.EVENTS.MEASUREMENTS_CLEARED,
    ];
 
    const subscriptions = events.map(
      evt => measurementService.subscribe(evt, debouncedUpdate).unsubscribe
    );
 
    return () => {
      subscriptions.forEach(unsub => unsub());
      debouncedUpdate.cancel();
    };
  }, [measurementService, measurementFilter, displaySetService]);
 
  return displayMeasurements;
}