* chore(tests): Update multiple screenshot test images for various specs * feat(screenshot-reviewer): Add screenshot review tool and update package.json scripts * fix(DICOMSRDisplayTool): Improve actor presence check in viewport * chore(tests): Update multiple screenshot assets for various specs * chore(tests): Integrate waitForPaintToSettle and waitForViewportsRendered in multiple specs for improved rendering stability * chore(tests): Update screenshot assets for SEGHydration and SEGNoHydration specs * test: update progressive loading screenshots * jest 30 test fixes for compatibility with pnpm cs3d * Use correct setDisplaySets instead of setDataId * fix: Naming change for LegacyVolumeViewport3D * Update to allow tolerance for contour tests * update * fix * refactor: Replace instanceof checks with utility functions for viewport type validation * fix: Update createSegmentationForViewport to handle undefined displaySetInstanceUID gracefully * bun lock * fix: Install cs3d with pnpm instead of bun * Update node version for playwright * Update to v5.0.0 of cs3d * fix: Build dependency * audit * Change to a web await retry assert * Fix timing related test failures * fix: Freehand close --------- Co-authored-by: Bill Wallace <wayfarer3130@gmail.com>
133 lines
4.4 KiB
TypeScript
133 lines
4.4 KiB
TypeScript
import { useState, useEffect, useCallback } from 'react';
|
|
import { useSystem } from '@ohif/core/src';
|
|
import { useViewportDisplaySets } from './useViewportDisplaySets';
|
|
import { isVolumeViewportType } from '../utils/getLegacyViewportType';
|
|
|
|
/**
|
|
* Hook that provides measurement tracking information for a viewport
|
|
*
|
|
* @param options - The hook options
|
|
* @param options.viewportId - The ID of the viewport to track
|
|
* @returns An object containing the tracking state, related information, and tracked measurement UIDs
|
|
*/
|
|
export function useMeasurementTracking({ viewportId }: { viewportId: string }) {
|
|
const { servicesManager } = useSystem();
|
|
const { cornerstoneViewportService, trackedMeasurementsService, measurementService } =
|
|
servicesManager.services;
|
|
|
|
const { backgroundDisplaySet } = useViewportDisplaySets(viewportId);
|
|
|
|
// Tracking states
|
|
const [isTracked, setIsTracked] = useState(false);
|
|
const [isLocked, setIsLocked] = useState(false);
|
|
const [trackedMeasurementUIDs, setTrackedMeasurementUIDs] = useState<string[]>([]);
|
|
|
|
const updateTrackedMeasurements = useCallback(() => {
|
|
if (!measurementService || !backgroundDisplaySet?.SeriesInstanceUID || !isTracked) {
|
|
setTrackedMeasurementUIDs([]);
|
|
return;
|
|
}
|
|
|
|
const seriesInstanceUID = backgroundDisplaySet.SeriesInstanceUID;
|
|
|
|
const seriesMeasurements = measurementService.getMeasurements(
|
|
measurement => measurement.referenceSeriesUID === seriesInstanceUID
|
|
);
|
|
|
|
const uids = seriesMeasurements.map(measurement => measurement.uid);
|
|
setTrackedMeasurementUIDs(uids);
|
|
}, [measurementService, backgroundDisplaySet, isTracked]);
|
|
|
|
const updateIsTracked = useCallback(() => {
|
|
if (!trackedMeasurementsService || !backgroundDisplaySet?.SeriesInstanceUID) {
|
|
setIsTracked(false);
|
|
return;
|
|
}
|
|
|
|
const trackedSeries = trackedMeasurementsService.getTrackedSeries();
|
|
|
|
if (!trackedSeries?.length) {
|
|
setIsTracked(false);
|
|
return;
|
|
}
|
|
|
|
const viewport = cornerstoneViewportService?.getCornerstoneViewport(viewportId);
|
|
const SeriesInstanceUID = backgroundDisplaySet.SeriesInstanceUID;
|
|
|
|
if (isVolumeViewportType(viewport)) {
|
|
const currentImageId = viewport?.getCurrentImageId();
|
|
|
|
if (!currentImageId) {
|
|
setIsTracked(false);
|
|
return;
|
|
}
|
|
}
|
|
|
|
const seriesIsTracked = trackedSeries.includes(SeriesInstanceUID);
|
|
setIsTracked(seriesIsTracked);
|
|
}, [viewportId, backgroundDisplaySet, cornerstoneViewportService, trackedMeasurementsService]);
|
|
|
|
// Update tracked measurements whenever tracking state changes
|
|
useEffect(() => {
|
|
updateTrackedMeasurements();
|
|
}, [isTracked, updateTrackedMeasurements]);
|
|
|
|
useEffect(() => {
|
|
if (!trackedMeasurementsService) {
|
|
return;
|
|
}
|
|
|
|
setIsLocked(trackedMeasurementsService.isTrackingEnabled());
|
|
updateIsTracked();
|
|
|
|
const subscriptions = [
|
|
trackedMeasurementsService.subscribe(trackedMeasurementsService.EVENTS.TRACKING_ENABLED, () =>
|
|
setIsLocked(true)
|
|
),
|
|
trackedMeasurementsService.subscribe(
|
|
trackedMeasurementsService.EVENTS.TRACKING_DISABLED,
|
|
() => setIsLocked(false)
|
|
),
|
|
|
|
trackedMeasurementsService.subscribe(
|
|
trackedMeasurementsService.EVENTS.TRACKED_SERIES_CHANGED,
|
|
() => updateIsTracked()
|
|
),
|
|
trackedMeasurementsService.subscribe(trackedMeasurementsService.EVENTS.SERIES_ADDED, () =>
|
|
updateIsTracked()
|
|
),
|
|
trackedMeasurementsService.subscribe(trackedMeasurementsService.EVENTS.SERIES_REMOVED, () =>
|
|
updateIsTracked()
|
|
),
|
|
];
|
|
|
|
// Subscribe to measurement service events to update trackedMeasurementUIDs
|
|
if (measurementService) {
|
|
[
|
|
measurementService.EVENTS.MEASUREMENT_ADDED,
|
|
measurementService.EVENTS.RAW_MEASUREMENT_ADDED,
|
|
measurementService.EVENTS.MEASUREMENT_UPDATED,
|
|
measurementService.EVENTS.MEASUREMENT_REMOVED,
|
|
measurementService.EVENTS.MEASUREMENTS_CLEARED,
|
|
].forEach(eventType => {
|
|
subscriptions.push(
|
|
measurementService.subscribe(eventType, () => updateTrackedMeasurements())
|
|
);
|
|
});
|
|
}
|
|
|
|
return () => {
|
|
subscriptions.forEach(sub => sub.unsubscribe());
|
|
};
|
|
}, [trackedMeasurementsService, measurementService, updateIsTracked, updateTrackedMeasurements]);
|
|
|
|
return {
|
|
isTracked,
|
|
isLocked,
|
|
seriesInstanceUID: backgroundDisplaySet?.SeriesInstanceUID,
|
|
trackedMeasurementUIDs,
|
|
};
|
|
}
|
|
|
|
export default useMeasurementTracking;
|