[OHIF-173] - Jump between measurements (#1863)
* jump between measurements. * Apply suggestions from code review Co-authored-by: Danny Brown <danny.ri.brown@gmail.com>
This commit is contained in:
parent
11fbe4cf01
commit
5ee4598bbe
@ -14,17 +14,17 @@ const OHIFCornerstoneViewport = props => {
|
|||||||
|
|
||||||
function getViewportModule({ servicesManager }) {
|
function getViewportModule({ servicesManager }) {
|
||||||
const ExtendedOHIFCornerstoneSRViewport = props => {
|
const ExtendedOHIFCornerstoneSRViewport = props => {
|
||||||
const { ToolBarService } = servicesManager.services;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OHIFCornerstoneViewport
|
<OHIFCornerstoneViewport servicesManager={servicesManager} {...props} />
|
||||||
ToolBarService={ToolBarService}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return [{ name: 'cornerstone-tracked', component: ExtendedOHIFCornerstoneSRViewport }];
|
return [
|
||||||
|
{
|
||||||
|
name: 'cornerstone-tracked',
|
||||||
|
component: ExtendedOHIFCornerstoneSRViewport,
|
||||||
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default getViewportModule;
|
export default getViewportModule;
|
||||||
|
|||||||
@ -44,8 +44,9 @@ function TrackedCornerstoneViewport({
|
|||||||
dataSource,
|
dataSource,
|
||||||
displaySet,
|
displaySet,
|
||||||
viewportIndex,
|
viewportIndex,
|
||||||
ToolBarService,
|
servicesManager,
|
||||||
}) {
|
}) {
|
||||||
|
const { ToolBarService, DisplaySetService } = servicesManager.services;
|
||||||
const [trackedMeasurements] = useTrackedMeasurements();
|
const [trackedMeasurements] = useTrackedMeasurements();
|
||||||
const [
|
const [
|
||||||
{ activeViewportIndex, viewports },
|
{ activeViewportIndex, viewports },
|
||||||
@ -55,7 +56,10 @@ function TrackedCornerstoneViewport({
|
|||||||
const [viewportDialogState, viewportDialogApi] = useViewportDialog();
|
const [viewportDialogState, viewportDialogApi] = useViewportDialog();
|
||||||
const [viewportData, setViewportData] = useState(null);
|
const [viewportData, setViewportData] = useState(null);
|
||||||
const [element, setElement] = useState(null);
|
const [element, setElement] = useState(null);
|
||||||
|
|
||||||
const [isTracked, setIsTracked] = useState(false);
|
const [isTracked, setIsTracked] = useState(false);
|
||||||
|
const [trackedMeasurementId, setTrackedMeasurementId] = useState(null);
|
||||||
|
|
||||||
// TODO: Still needed? Better way than import `OHIF` and destructure?
|
// TODO: Still needed? Better way than import `OHIF` and destructure?
|
||||||
// Why is this managed by `core`?
|
// Why is this managed by `core`?
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -246,14 +250,56 @@ function TrackedCornerstoneViewport({
|
|||||||
? _viewportLabels[firstViewportIndexWithMatchingDisplaySetUid]
|
? _viewportLabels[firstViewportIndexWithMatchingDisplaySetUid]
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
|
function switchMeasurement(direction) {
|
||||||
|
if (!element) {
|
||||||
|
// Element not yet enabled.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newTrackedMeasurementId = _getNextMeasurementId(
|
||||||
|
direction,
|
||||||
|
servicesManager,
|
||||||
|
trackedMeasurementId,
|
||||||
|
trackedMeasurements
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!newTrackedMeasurementId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTrackedMeasurementId(newTrackedMeasurementId);
|
||||||
|
|
||||||
|
const { MeasurementService } = servicesManager.services;
|
||||||
|
const measurements = MeasurementService.getMeasurements();
|
||||||
|
const measurement = measurements.find(
|
||||||
|
m => m.id === newTrackedMeasurementId
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
displaySetInstanceUID,
|
||||||
|
imageIndex,
|
||||||
|
} = _getViewportDataFromTrackedMeasurementId(
|
||||||
|
measurement,
|
||||||
|
DisplaySetService
|
||||||
|
);
|
||||||
|
|
||||||
|
viewportGridService.setDisplaysetForViewport({
|
||||||
|
viewportIndex,
|
||||||
|
displaySetInstanceUID,
|
||||||
|
imageIndex,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const showNavArrows = isTracked && viewportIndex === activeViewportIndex;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ViewportActionBar
|
<ViewportActionBar
|
||||||
onSeriesChange={direction => alert(`Series ${direction}`)}
|
onSeriesChange={direction => switchMeasurement(direction)}
|
||||||
showNavArrows={viewportIndex === activeViewportIndex}
|
showNavArrows={showNavArrows}
|
||||||
studyData={{
|
studyData={{
|
||||||
label,
|
label,
|
||||||
isTracked: trackedSeries.includes(SeriesInstanceUID),
|
isTracked,
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
studyDate: formatDate(SeriesDate), // TODO: This is series date. Is that ok?
|
studyDate: formatDate(SeriesDate), // TODO: This is series date. Is that ok?
|
||||||
currentSeries: SeriesNumber,
|
currentSeries: SeriesNumber,
|
||||||
@ -270,8 +316,8 @@ function TrackedCornerstoneViewport({
|
|||||||
spacing:
|
spacing:
|
||||||
PixelSpacing && PixelSpacing.length
|
PixelSpacing && PixelSpacing.length
|
||||||
? `${PixelSpacing[0].toFixed(2)}mm x ${PixelSpacing[1].toFixed(
|
? `${PixelSpacing[0].toFixed(2)}mm x ${PixelSpacing[1].toFixed(
|
||||||
2
|
2
|
||||||
)}mm`
|
)}mm`
|
||||||
: '',
|
: '',
|
||||||
scanner: ManufacturerModelName || '',
|
scanner: ManufacturerModelName || '',
|
||||||
},
|
},
|
||||||
@ -379,4 +425,79 @@ async function _getViewportData(dataSource, displaySet) {
|
|||||||
return viewportData;
|
return viewportData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _getNextMeasurementId(
|
||||||
|
direction,
|
||||||
|
servicesManager,
|
||||||
|
trackedMeasurementId,
|
||||||
|
trackedMeasurements
|
||||||
|
) {
|
||||||
|
const { MeasurementService } = servicesManager.services;
|
||||||
|
const measurements = MeasurementService.getMeasurements();
|
||||||
|
|
||||||
|
const { trackedSeries } = trackedMeasurements.context;
|
||||||
|
|
||||||
|
// Get the potentially trackable measurements for this series,
|
||||||
|
// The measurements to jump between are the same
|
||||||
|
// regardless if this series is tracked or not.
|
||||||
|
|
||||||
|
const filteredMeasurements = measurements.filter(m =>
|
||||||
|
trackedSeries.includes(m.referenceSeriesUID)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!filteredMeasurements.length) {
|
||||||
|
// No measurements on this series.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const measurementCount = filteredMeasurements.length;
|
||||||
|
|
||||||
|
const ids = filteredMeasurements.map(fm => fm.id);
|
||||||
|
let measurementIndex = ids.findIndex(id => id === trackedMeasurementId);
|
||||||
|
|
||||||
|
if (measurementIndex === -1) {
|
||||||
|
// Not tracking a measurement, or previous measurement now deleted, revert to 0.
|
||||||
|
measurementIndex = 0;
|
||||||
|
} else {
|
||||||
|
if (direction === 'left') {
|
||||||
|
measurementIndex--;
|
||||||
|
|
||||||
|
if (measurementIndex < 0) {
|
||||||
|
measurementIndex = measurementCount - 1;
|
||||||
|
}
|
||||||
|
} else if (direction === 'right') {
|
||||||
|
measurementIndex++;
|
||||||
|
|
||||||
|
if (measurementIndex === measurementCount) {
|
||||||
|
measurementIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const newTrackedMeasurementId = ids[measurementIndex];
|
||||||
|
|
||||||
|
return newTrackedMeasurementId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getViewportDataFromTrackedMeasurementId(
|
||||||
|
measurement,
|
||||||
|
DisplaySetService
|
||||||
|
) {
|
||||||
|
const { referenceSeriesUID: SeriesInstanceUID, SOPInstanceUID } = measurement;
|
||||||
|
|
||||||
|
const activeDisplaySets = DisplaySetService.getActiveDisplaySets();
|
||||||
|
|
||||||
|
const displaySet = activeDisplaySets.find(
|
||||||
|
ds => ds.SeriesInstanceUID === SeriesInstanceUID
|
||||||
|
);
|
||||||
|
|
||||||
|
const imageIndex = displaySet.images.findIndex(
|
||||||
|
image => image.SOPInstanceUID === SOPInstanceUID
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
imageIndex,
|
||||||
|
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default TrackedCornerstoneViewport;
|
export default TrackedCornerstoneViewport;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user