feat(grid): remove viewportIndex and only rely on viewportId (#3591)
Co-authored-by: Bill Wallace <wayfarer3130@gmail.com>
This commit is contained in:
1 parent
5dafac7c92
commit
4c6ff873e8
83 files changed
+1309
-1123
No files matched your search
@@ -121,7 +121,7 @@ const getSopClassHandlerModule = (/* ... */) => {
|
||||
|
||||
const getToolbarModule = () => {};
|
||||
|
||||
// displaySet, viewportIndex, dataSource
|
||||
// displaySet, dataSource
|
||||
const getViewportModule = () => {
|
||||
const wrappedViewport = props => {
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
async function _hydrateRTDisplaySet({
|
||||
rtDisplaySet,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
servicesManager,
|
||||
}) {
|
||||
const {
|
||||
@@ -27,7 +27,7 @@ async function _hydrateRTDisplaySet({
|
||||
const { viewports } = viewportGridService.getState();
|
||||
|
||||
const updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
displaySetInstanceUID
|
||||
);
|
||||
|
||||
@@ -39,8 +39,8 @@ async function _hydrateRTDisplaySet({
|
||||
// is being displayed, if so we need to update the viewport to use volume viewport
|
||||
// (if already is not using it) since Cornerstone3D currently only supports
|
||||
// volume viewport for segmentation
|
||||
viewports.forEach((viewport, index) => {
|
||||
if (index === viewportIndex) {
|
||||
viewports.forEach(viewport => {
|
||||
if (viewport.viewportId === viewportId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -51,9 +51,16 @@ async function _hydrateRTDisplaySet({
|
||||
|
||||
if (shouldDisplaySeg) {
|
||||
updatedViewports.push({
|
||||
viewportIndex: index,
|
||||
viewportId: viewport.viewportId,
|
||||
displaySetInstanceUIDs: viewport.displaySetInstanceUIDs,
|
||||
viewportOptions: {
|
||||
// Note: This is a hack to get the grid to re-render the OHIFCornerstoneViewport component
|
||||
// Used for segmentation hydration right now, since the logic to decide whether
|
||||
// a viewport needs to render a segmentation lives inside the CornerstoneViewportService
|
||||
// so we need to re-render (force update via change of the needsRerendering) so that React
|
||||
// does the diffing and decides we should render this again (although the id and element has not changed)
|
||||
// so that the CornerstoneViewportService can decide whether to render the segmentation or not.
|
||||
needsRerendering: true,
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
|
||||
@@ -10,17 +10,14 @@ const RESPONSE = {
|
||||
function promptHydrateRT({
|
||||
servicesManager,
|
||||
rtDisplaySet,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
toolGroupId = 'default',
|
||||
preHydrateCallbacks,
|
||||
}) {
|
||||
const { uiViewportDialogService } = servicesManager.services;
|
||||
|
||||
return new Promise(async function(resolve, reject) {
|
||||
const promptResult = await _askHydrate(
|
||||
uiViewportDialogService,
|
||||
viewportIndex
|
||||
);
|
||||
const promptResult = await _askHydrate(uiViewportDialogService, viewportId);
|
||||
|
||||
if (promptResult === RESPONSE.HYDRATE_SEG) {
|
||||
preHydrateCallbacks?.forEach(callback => {
|
||||
@@ -29,7 +26,7 @@ function promptHydrateRT({
|
||||
|
||||
const isHydrated = await hydrateRTDisplaySet({
|
||||
rtDisplaySet,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
toolGroupId,
|
||||
servicesManager,
|
||||
});
|
||||
@@ -39,7 +36,7 @@ function promptHydrateRT({
|
||||
});
|
||||
}
|
||||
|
||||
function _askHydrate(uiViewportDialogService, viewportIndex) {
|
||||
function _askHydrate(uiViewportDialogService, viewportId) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const message = 'Do you want to open this Segmentation?';
|
||||
const actions = [
|
||||
@@ -60,7 +57,7 @@ function _askHydrate(uiViewportDialogService, viewportIndex) {
|
||||
};
|
||||
|
||||
uiViewportDialogService.show({
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
type: 'info',
|
||||
message,
|
||||
actions,
|
||||
|
||||
@@ -21,7 +21,6 @@ function OHIFCornerstoneRTViewport(props) {
|
||||
children,
|
||||
displaySets,
|
||||
viewportOptions,
|
||||
viewportIndex,
|
||||
viewportLabel,
|
||||
servicesManager,
|
||||
extensionManager,
|
||||
@@ -36,7 +35,9 @@ function OHIFCornerstoneRTViewport(props) {
|
||||
customizationService,
|
||||
} = servicesManager.services;
|
||||
|
||||
const toolGroupId = `${RT_TOOLGROUP_BASE_NAME}-${viewportIndex}`;
|
||||
const viewportId = viewportOptions.viewportId;
|
||||
|
||||
const toolGroupId = `${RT_TOOLGROUP_BASE_NAME}-${viewportId}`;
|
||||
|
||||
// RT viewport will always have a single display set
|
||||
if (displaySets.length > 1) {
|
||||
@@ -67,7 +68,7 @@ function OHIFCornerstoneRTViewport(props) {
|
||||
// refs
|
||||
const referencedDisplaySetRef = useRef(null);
|
||||
|
||||
const { viewports, activeViewportIndex } = viewportGrid;
|
||||
const { viewports, activeViewportId } = viewportGrid;
|
||||
|
||||
const referencedDisplaySet = rtDisplaySet.getReferenceDisplaySet();
|
||||
const referencedDisplaySetMetadata = _getReferencedDisplaySetMetadata(
|
||||
@@ -93,9 +94,9 @@ function OHIFCornerstoneRTViewport(props) {
|
||||
};
|
||||
|
||||
const storePresentationState = useCallback(() => {
|
||||
viewportGrid?.viewports.forEach(({ viewportIndex }) => {
|
||||
viewportGrid?.viewports.forEach(({ viewportId }) => {
|
||||
commandsManager.runCommand('storePresentation', {
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
});
|
||||
});
|
||||
}, [viewportGrid]);
|
||||
@@ -124,7 +125,7 @@ function OHIFCornerstoneRTViewport(props) {
|
||||
onElementDisabled={onElementDisabled}
|
||||
></Component>
|
||||
);
|
||||
}, [viewportIndex, rtDisplaySet, toolGroupId]);
|
||||
}, [viewportId, rtDisplaySet, toolGroupId]);
|
||||
|
||||
const onSegmentChange = useCallback(
|
||||
direction => {
|
||||
@@ -162,7 +163,7 @@ function OHIFCornerstoneRTViewport(props) {
|
||||
|
||||
promptHydrateRT({
|
||||
servicesManager,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
rtDisplaySet,
|
||||
preHydrateCallbacks: [storePresentationState],
|
||||
}).then(isHydrated => {
|
||||
@@ -170,7 +171,7 @@ function OHIFCornerstoneRTViewport(props) {
|
||||
setIsHydrated(true);
|
||||
}
|
||||
});
|
||||
}, [servicesManager, viewportIndex, rtDisplaySet, rtIsLoading]);
|
||||
}, [servicesManager, viewportId, rtDisplaySet, rtIsLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
const { unsubscribe } = segmentationService.subscribe(
|
||||
@@ -222,12 +223,12 @@ function OHIFCornerstoneRTViewport(props) {
|
||||
const onDisplaySetsRemovedSubscription = displaySetService.subscribe(
|
||||
displaySetService.EVENTS.DISPLAY_SETS_REMOVED,
|
||||
({ displaySetInstanceUIDs }) => {
|
||||
const activeViewport = viewports[activeViewportIndex];
|
||||
const activeViewport = viewports.get(activeViewportId);
|
||||
if (
|
||||
displaySetInstanceUIDs.includes(activeViewport.displaySetInstanceUID)
|
||||
) {
|
||||
viewportGridService.setDisplaySetsForViewport({
|
||||
viewportIndex: activeViewportIndex,
|
||||
viewportId: activeViewportId,
|
||||
displaySetInstanceUIDs: [],
|
||||
});
|
||||
}
|
||||
@@ -292,7 +293,7 @@ function OHIFCornerstoneRTViewport(props) {
|
||||
return (
|
||||
child &&
|
||||
React.cloneElement(child, {
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
key: index,
|
||||
})
|
||||
);
|
||||
@@ -322,7 +323,7 @@ function OHIFCornerstoneRTViewport(props) {
|
||||
storePresentationState();
|
||||
const isHydrated = await _hydrateRTDisplaySet({
|
||||
rtDisplaySet,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
servicesManager,
|
||||
});
|
||||
|
||||
@@ -384,7 +385,7 @@ function OHIFCornerstoneRTViewport(props) {
|
||||
|
||||
OHIFCornerstoneRTViewport.propTypes = {
|
||||
displaySets: PropTypes.arrayOf(PropTypes.object),
|
||||
viewportIndex: PropTypes.number.isRequired,
|
||||
viewportId: PropTypes.string.isRequired,
|
||||
dataSource: PropTypes.object,
|
||||
children: PropTypes.node,
|
||||
customProps: PropTypes.object,
|
||||
|
||||
@@ -271,7 +271,6 @@ PanelSegmentation.propTypes = {
|
||||
commandsManager: PropTypes.shape({
|
||||
runCommand: PropTypes.func.isRequired,
|
||||
}),
|
||||
appConfig: PropTypes.object.isRequired,
|
||||
servicesManager: PropTypes.shape({
|
||||
services: PropTypes.shape({
|
||||
segmentationService: PropTypes.shape({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
async function _hydrateSEGDisplaySet({
|
||||
segDisplaySet,
|
||||
viewportIndex,
|
||||
viewportId: targetViewportId,
|
||||
servicesManager,
|
||||
}) {
|
||||
const {
|
||||
@@ -27,7 +27,7 @@ async function _hydrateSEGDisplaySet({
|
||||
const { viewports } = viewportGridService.getState();
|
||||
|
||||
const updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
|
||||
viewportIndex,
|
||||
targetViewportId,
|
||||
displaySetInstanceUID
|
||||
);
|
||||
|
||||
@@ -37,8 +37,8 @@ async function _hydrateSEGDisplaySet({
|
||||
// is being displayed, if so we need to update the viewport to use volume viewport
|
||||
// (if already is not using it) since Cornerstone3D currently only supports
|
||||
// volume viewport for segmentation
|
||||
viewports.forEach((viewport, index) => {
|
||||
if (index === viewportIndex) {
|
||||
viewports.forEach((viewport, viewportId) => {
|
||||
if (targetViewportId === viewportId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,9 +49,16 @@ async function _hydrateSEGDisplaySet({
|
||||
|
||||
if (shouldDisplaySeg) {
|
||||
updatedViewports.push({
|
||||
viewportIndex: index,
|
||||
viewportId,
|
||||
displaySetInstanceUIDs: viewport.displaySetInstanceUIDs,
|
||||
viewportOptions: {
|
||||
// Note: This is a hack to get the grid to re-render the OHIFCornerstoneViewport component
|
||||
// Used for segmentation hydration right now, since the logic to decide whether
|
||||
// a viewport needs to render a segmentation lives inside the CornerstoneViewportService
|
||||
// so we need to re-render (force update via change of the needsRerendering) so that React
|
||||
// does the diffing and decides we should render this again (although the id and element has not changed)
|
||||
// so that the CornerstoneViewportService can decide whether to render the segmentation or not.
|
||||
needsRerendering: true,
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
|
||||
@@ -10,16 +10,13 @@ const RESPONSE = {
|
||||
function promptHydrateSEG({
|
||||
servicesManager,
|
||||
segDisplaySet,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
preHydrateCallbacks,
|
||||
}) {
|
||||
const { uiViewportDialogService } = servicesManager.services;
|
||||
|
||||
return new Promise(async function(resolve, reject) {
|
||||
const promptResult = await _askHydrate(
|
||||
uiViewportDialogService,
|
||||
viewportIndex
|
||||
);
|
||||
const promptResult = await _askHydrate(uiViewportDialogService, viewportId);
|
||||
|
||||
if (promptResult === RESPONSE.HYDRATE_SEG) {
|
||||
preHydrateCallbacks?.forEach(callback => {
|
||||
@@ -28,7 +25,7 @@ function promptHydrateSEG({
|
||||
|
||||
const isHydrated = await hydrateSEGDisplaySet({
|
||||
segDisplaySet,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
servicesManager,
|
||||
});
|
||||
|
||||
@@ -37,7 +34,7 @@ function promptHydrateSEG({
|
||||
});
|
||||
}
|
||||
|
||||
function _askHydrate(uiViewportDialogService, viewportIndex) {
|
||||
function _askHydrate(uiViewportDialogService, viewportId) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const message = 'Do you want to open this Segmentation?';
|
||||
const actions = [
|
||||
@@ -58,7 +55,7 @@ function _askHydrate(uiViewportDialogService, viewportIndex) {
|
||||
};
|
||||
|
||||
uiViewportDialogService.show({
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
type: 'info',
|
||||
message,
|
||||
actions,
|
||||
|
||||
@@ -20,7 +20,6 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
children,
|
||||
displaySets,
|
||||
viewportOptions,
|
||||
viewportIndex,
|
||||
viewportLabel,
|
||||
servicesManager,
|
||||
extensionManager,
|
||||
@@ -28,6 +27,7 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
} = props;
|
||||
|
||||
const { t } = useTranslation('SEGViewport');
|
||||
const viewportId = viewportOptions.viewportId;
|
||||
|
||||
const {
|
||||
displaySetService,
|
||||
@@ -37,7 +37,7 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
customizationService,
|
||||
} = servicesManager.services;
|
||||
|
||||
const toolGroupId = `${SEG_TOOLGROUP_BASE_NAME}-${viewportIndex}`;
|
||||
const toolGroupId = `${SEG_TOOLGROUP_BASE_NAME}-${viewportId}`;
|
||||
|
||||
// SEG viewport will always have a single display set
|
||||
if (displaySets.length > 1) {
|
||||
@@ -67,7 +67,7 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
// refs
|
||||
const referencedDisplaySetRef = useRef(null);
|
||||
|
||||
const { viewports, activeViewportIndex } = viewportGrid;
|
||||
const { viewports, activeViewportId } = viewportGrid;
|
||||
|
||||
const referencedDisplaySet = segDisplaySet.getReferenceDisplaySet();
|
||||
const referencedDisplaySetMetadata = _getReferencedDisplaySetMetadata(
|
||||
@@ -94,9 +94,9 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
};
|
||||
|
||||
const storePresentationState = useCallback(() => {
|
||||
viewportGrid?.viewports.forEach(({ viewportIndex }) => {
|
||||
viewportGrid?.viewports.forEach(({ viewportId }) => {
|
||||
commandsManager.runCommand('storePresentation', {
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
});
|
||||
});
|
||||
}, [viewportGrid]);
|
||||
@@ -126,7 +126,7 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
// initialImageIndex={initialImageIndex}
|
||||
></Component>
|
||||
);
|
||||
}, [viewportIndex, segDisplaySet, toolGroupId]);
|
||||
}, [viewportId, segDisplaySet, toolGroupId]);
|
||||
|
||||
const onSegmentChange = useCallback(
|
||||
direction => {
|
||||
@@ -165,7 +165,7 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
|
||||
promptHydrateSEG({
|
||||
servicesManager,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
segDisplaySet,
|
||||
preHydrateCallbacks: [storePresentationState],
|
||||
}).then(isHydrated => {
|
||||
@@ -173,7 +173,7 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
setIsHydrated(true);
|
||||
}
|
||||
});
|
||||
}, [servicesManager, viewportIndex, segDisplaySet, segIsLoading]);
|
||||
}, [servicesManager, viewportId, segDisplaySet, segIsLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
const { unsubscribe } = segmentationService.subscribe(
|
||||
@@ -225,12 +225,12 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
const onDisplaySetsRemovedSubscription = displaySetService.subscribe(
|
||||
displaySetService.EVENTS.DISPLAY_SETS_REMOVED,
|
||||
({ displaySetInstanceUIDs }) => {
|
||||
const activeViewport = viewports[activeViewportIndex];
|
||||
const activeViewport = viewports.get(activeViewportId);
|
||||
if (
|
||||
displaySetInstanceUIDs.includes(activeViewport.displaySetInstanceUID)
|
||||
) {
|
||||
viewportGridService.setDisplaySetsForViewport({
|
||||
viewportIndex: activeViewportIndex,
|
||||
viewportId: activeViewportId,
|
||||
displaySetInstanceUIDs: [],
|
||||
});
|
||||
}
|
||||
@@ -296,7 +296,7 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
return (
|
||||
child &&
|
||||
React.cloneElement(child, {
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
key: index,
|
||||
})
|
||||
);
|
||||
@@ -325,7 +325,7 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
storePresentationState();
|
||||
const isHydrated = await hydrateSEGDisplaySet({
|
||||
segDisplaySet,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
servicesManager,
|
||||
});
|
||||
|
||||
@@ -388,7 +388,7 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
|
||||
OHIFCornerstoneSEGViewport.propTypes = {
|
||||
displaySets: PropTypes.arrayOf(PropTypes.object),
|
||||
viewportIndex: PropTypes.number.isRequired,
|
||||
viewportId: PropTypes.string.isRequired,
|
||||
dataSource: PropTypes.object,
|
||||
children: PropTypes.node,
|
||||
customProps: PropTypes.object,
|
||||
|
||||
@@ -21,7 +21,6 @@ function OHIFCornerstoneSRViewport(props) {
|
||||
children,
|
||||
dataSource,
|
||||
displaySets,
|
||||
viewportIndex,
|
||||
viewportLabel,
|
||||
viewportOptions,
|
||||
servicesManager,
|
||||
@@ -36,6 +35,8 @@ function OHIFCornerstoneSRViewport(props) {
|
||||
measurementService,
|
||||
} = servicesManager.services;
|
||||
|
||||
const viewportId = viewportOptions.viewportId;
|
||||
|
||||
// SR viewport will always have a single display set
|
||||
if (displaySets.length > 1) {
|
||||
throw new Error('SR viewport should only have a single display set');
|
||||
@@ -54,7 +55,7 @@ function OHIFCornerstoneSRViewport(props) {
|
||||
setReferencedDisplaySetMetadata,
|
||||
] = useState(null);
|
||||
const [element, setElement] = useState(null);
|
||||
const { viewports, activeViewportIndex } = viewportGrid;
|
||||
const { viewports, activeViewportId } = viewportGrid;
|
||||
|
||||
// Optional hook into tracking extension, if present.
|
||||
let trackedMeasurements;
|
||||
@@ -88,7 +89,7 @@ function OHIFCornerstoneSRViewport(props) {
|
||||
if (displaySets.length) {
|
||||
viewportGridService.setDisplaySetsForViewports([
|
||||
{
|
||||
viewportIndex: activeViewportIndex,
|
||||
viewportId: activeViewportId,
|
||||
displaySetInstanceUIDs: [displaySets[0].displaySetInstanceUID],
|
||||
},
|
||||
]);
|
||||
@@ -163,12 +164,8 @@ function OHIFCornerstoneSRViewport(props) {
|
||||
// imageIdIndex will handle it by updating the viewport, but if they
|
||||
// are the same we just need to use measurementService to jump to the
|
||||
// new measurement
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(
|
||||
viewportIndex
|
||||
);
|
||||
|
||||
const csViewport = cornerstoneViewportService.getCornerstoneViewport(
|
||||
viewportInfo.getViewportId()
|
||||
viewportId
|
||||
);
|
||||
|
||||
const imageIds = csViewport.getImageIds();
|
||||
@@ -183,7 +180,7 @@ function OHIFCornerstoneSRViewport(props) {
|
||||
}
|
||||
});
|
||||
},
|
||||
[dataSource, srDisplaySet, activeImageDisplaySetData, viewportIndex]
|
||||
[dataSource, srDisplaySet, activeImageDisplaySetData, viewportId]
|
||||
);
|
||||
|
||||
const getCornerstoneViewport = useCallback(() => {
|
||||
@@ -231,7 +228,7 @@ function OHIFCornerstoneSRViewport(props) {
|
||||
isJumpToMeasurementDisabled={true}
|
||||
></Component>
|
||||
);
|
||||
}, [activeImageDisplaySetData, viewportIndex, measurementSelected]);
|
||||
}, [activeImageDisplaySetData, viewportId, measurementSelected]);
|
||||
|
||||
const onMeasurementChange = useCallback(
|
||||
direction => {
|
||||
@@ -269,12 +266,12 @@ function OHIFCornerstoneSRViewport(props) {
|
||||
const onDisplaySetsRemovedSubscription = displaySetService.subscribe(
|
||||
displaySetService.EVENTS.DISPLAY_SETS_REMOVED,
|
||||
({ displaySetInstanceUIDs }) => {
|
||||
const activeViewport = viewports[activeViewportIndex];
|
||||
const activeViewport = viewports[activeViewportId];
|
||||
if (
|
||||
displaySetInstanceUIDs.includes(activeViewport.displaySetInstanceUID)
|
||||
) {
|
||||
viewportGridService.setDisplaySetsForViewport({
|
||||
viewportIndex: activeViewportIndex,
|
||||
viewportId: activeViewportId,
|
||||
displaySetInstanceUIDs: [],
|
||||
});
|
||||
}
|
||||
@@ -341,7 +338,7 @@ function OHIFCornerstoneSRViewport(props) {
|
||||
return (
|
||||
child &&
|
||||
React.cloneElement(child, {
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
key: index,
|
||||
})
|
||||
);
|
||||
@@ -373,7 +370,7 @@ function OHIFCornerstoneSRViewport(props) {
|
||||
getStatusComponent={() =>
|
||||
_getStatusComponent({
|
||||
srDisplaySet,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
isTracked: false,
|
||||
isRehydratable: srDisplaySet.isRehydratable,
|
||||
isLocked,
|
||||
@@ -413,7 +410,7 @@ function OHIFCornerstoneSRViewport(props) {
|
||||
|
||||
OHIFCornerstoneSRViewport.propTypes = {
|
||||
displaySets: PropTypes.arrayOf(PropTypes.object),
|
||||
viewportIndex: PropTypes.number.isRequired,
|
||||
viewportId: PropTypes.string.isRequired,
|
||||
dataSource: PropTypes.object,
|
||||
children: PropTypes.node,
|
||||
viewportLabel: PropTypes.string,
|
||||
@@ -462,7 +459,7 @@ async function _getViewportReferencedDisplaySetData(
|
||||
|
||||
function _getStatusComponent({
|
||||
srDisplaySet,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
isRehydratable,
|
||||
isLocked,
|
||||
sendTrackedMeasurementsEvent,
|
||||
@@ -470,7 +467,7 @@ function _getStatusComponent({
|
||||
const handleMouseUp = () => {
|
||||
sendTrackedMeasurementsEvent('HYDRATE_SR', {
|
||||
displaySetInstanceUID: srDisplaySet.displaySetInstanceUID,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -63,6 +63,10 @@ function areEqual(prevProps, nextProps) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nextProps.viewportOptions.needsRerendering) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const prevDisplaySets = prevProps.displaySets;
|
||||
const nextDisplaySets = nextProps.displaySets;
|
||||
|
||||
@@ -107,7 +111,6 @@ function areEqual(prevProps, nextProps) {
|
||||
// Then we don't need to worry about the re-renders if the props change.
|
||||
const OHIFCornerstoneViewport = React.memo(props => {
|
||||
const {
|
||||
viewportIndex,
|
||||
displaySets,
|
||||
dataSource,
|
||||
viewportOptions,
|
||||
@@ -123,6 +126,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
initialImageIndex,
|
||||
} = props;
|
||||
|
||||
const viewportId = viewportOptions.viewportId;
|
||||
const [scrollbarHeight, setScrollbarHeight] = useState('100px');
|
||||
const [enabledVPElement, setEnabledVPElement] = useState(null);
|
||||
const elementRef = useRef();
|
||||
@@ -154,27 +158,24 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
}
|
||||
}, [elementRef]);
|
||||
|
||||
const cleanUpServices = useCallback(() => {
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(
|
||||
viewportIndex
|
||||
);
|
||||
const cleanUpServices = useCallback(
|
||||
viewportInfo => {
|
||||
const renderingEngineId = viewportInfo.getRenderingEngineId();
|
||||
const syncGroups = viewportInfo.getSyncGroups();
|
||||
|
||||
if (!viewportInfo) {
|
||||
return;
|
||||
}
|
||||
toolGroupService.removeViewportFromToolGroup(
|
||||
viewportId,
|
||||
renderingEngineId
|
||||
);
|
||||
|
||||
const viewportId = viewportInfo.getViewportId();
|
||||
const renderingEngineId = viewportInfo.getRenderingEngineId();
|
||||
const syncGroups = viewportInfo.getSyncGroups();
|
||||
|
||||
toolGroupService.removeViewportFromToolGroup(viewportId, renderingEngineId);
|
||||
|
||||
syncGroupService.removeViewportFromSyncGroup(
|
||||
viewportId,
|
||||
renderingEngineId,
|
||||
syncGroups
|
||||
);
|
||||
}, [viewportIndex, viewportOptions.viewportId]);
|
||||
syncGroupService.removeViewportFromSyncGroup(
|
||||
viewportId,
|
||||
renderingEngineId,
|
||||
syncGroups
|
||||
);
|
||||
},
|
||||
[viewportId]
|
||||
);
|
||||
|
||||
const elementEnabledHandler = useCallback(
|
||||
evt => {
|
||||
@@ -187,9 +188,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfo(
|
||||
viewportId
|
||||
);
|
||||
const viewportIndex = viewportInfo.getViewportIndex();
|
||||
|
||||
setEnabledElement(viewportIndex, element);
|
||||
setEnabledElement(viewportId, element);
|
||||
setEnabledVPElement(element);
|
||||
|
||||
const renderingEngineId = viewportInfo.getRenderingEngineId();
|
||||
@@ -212,16 +211,12 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
onElementEnabled(evt);
|
||||
}
|
||||
},
|
||||
[viewportIndex, onElementEnabled, toolGroupService]
|
||||
[viewportId, onElementEnabled, toolGroupService]
|
||||
);
|
||||
|
||||
// disable the element upon unmounting
|
||||
useEffect(() => {
|
||||
cornerstoneViewportService.enableViewport(
|
||||
viewportIndex,
|
||||
viewportOptions,
|
||||
elementRef.current
|
||||
);
|
||||
cornerstoneViewportService.enableViewport(viewportId, elementRef.current);
|
||||
|
||||
eventTarget.addEventListener(
|
||||
Enums.Events.ELEMENT_ENABLED,
|
||||
@@ -231,17 +226,16 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
setImageScrollBarHeight();
|
||||
|
||||
return () => {
|
||||
commandsManager.runCommand('storePresentation', {
|
||||
viewportIndex,
|
||||
});
|
||||
|
||||
cleanUpServices();
|
||||
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(
|
||||
viewportIndex
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfo(
|
||||
viewportId
|
||||
);
|
||||
|
||||
cornerstoneViewportService.disableElement(viewportIndex);
|
||||
if (!viewportInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
cleanUpServices(viewportInfo);
|
||||
cornerstoneViewportService.storePresentation({ viewportId });
|
||||
|
||||
if (onElementDisabled) {
|
||||
onElementDisabled(viewportInfo);
|
||||
@@ -273,8 +267,8 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(
|
||||
viewportIndex
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfo(
|
||||
viewportId
|
||||
);
|
||||
|
||||
if (viewportInfo.hasDisplaySet(invalidatedDisplaySetInstanceUID)) {
|
||||
@@ -288,7 +282,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
|
||||
const keepCamera = true;
|
||||
cornerstoneViewportService.updateViewport(
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
newViewportData,
|
||||
keepCamera
|
||||
);
|
||||
@@ -298,7 +292,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, [viewportIndex]);
|
||||
}, [viewportId]);
|
||||
|
||||
useEffect(() => {
|
||||
// handle the default viewportType to be stack
|
||||
@@ -329,15 +323,25 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
lutPresentationStore[presentationIds?.lutPresentationId],
|
||||
};
|
||||
let measurement;
|
||||
if (cacheJumpToMeasurementEvent?.viewportIndex === viewportIndex) {
|
||||
if (cacheJumpToMeasurementEvent?.viewportId === viewportId) {
|
||||
measurement = cacheJumpToMeasurementEvent.measurement;
|
||||
// Delete the position presentation so that viewport navigates direct
|
||||
presentations.positionPresentation = null;
|
||||
cacheJumpToMeasurementEvent = null;
|
||||
}
|
||||
|
||||
// Note: This is a hack to get the grid to re-render the OHIFCornerstoneViewport component
|
||||
// Used for segmentation hydration right now, since the logic to decide whether
|
||||
// a viewport needs to render a segmentation lives inside the CornerstoneViewportService
|
||||
// so we need to re-render (force update via change of the needsRerendering) so that React
|
||||
// does the diffing and decides we should render this again (although the id and element has not changed)
|
||||
// so that the CornerstoneViewportService can decide whether to render the segmentation or not. Not that we reached here we can turn it off.
|
||||
if (viewportOptions.needsRerendering) {
|
||||
viewportOptions.needsRerendering = false;
|
||||
}
|
||||
|
||||
cornerstoneViewportService.setViewportData(
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
viewportData,
|
||||
viewportOptions,
|
||||
displaySetOptions,
|
||||
@@ -370,7 +374,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
measurementService,
|
||||
displaySetService,
|
||||
elementRef,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
displaySets,
|
||||
viewportGridService,
|
||||
cornerstoneViewportService
|
||||
@@ -380,7 +384,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
measurementService,
|
||||
displaySetService,
|
||||
elementRef,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
displaySets,
|
||||
viewportGridService,
|
||||
cornerstoneViewportService
|
||||
@@ -389,7 +393,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
return () => {
|
||||
unsubscribeFromJumpToMeasurementEvents();
|
||||
};
|
||||
}, [displaySets, elementRef, viewportIndex]);
|
||||
}, [displaySets, elementRef, viewportId]);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
@@ -408,7 +412,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
ref={elementRef}
|
||||
></div>
|
||||
<CornerstoneOverlays
|
||||
viewportIndex={viewportIndex}
|
||||
viewportId={viewportId}
|
||||
toolBarService={toolbarService}
|
||||
element={elementRef.current}
|
||||
scrollbarHeight={scrollbarHeight}
|
||||
@@ -416,12 +420,12 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
/>
|
||||
<CinePlayer
|
||||
enabledVPElement={enabledVPElement}
|
||||
viewportIndex={viewportIndex}
|
||||
viewportId={viewportId}
|
||||
servicesManager={servicesManager}
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute w-full">
|
||||
{viewportDialogState.viewportIndex === viewportIndex && (
|
||||
{viewportDialogState.viewportId === viewportId && (
|
||||
<Notification
|
||||
id="viewport-notification"
|
||||
message={viewportDialogState.message}
|
||||
@@ -440,37 +444,34 @@ function _subscribeToJumpToMeasurementEvents(
|
||||
measurementService,
|
||||
displaySetService,
|
||||
elementRef,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
displaySets,
|
||||
viewportGridService,
|
||||
cornerstoneViewportService
|
||||
) {
|
||||
const displaysUIDs = displaySets.map(
|
||||
displaySet => displaySet.displaySetInstanceUID
|
||||
);
|
||||
const { unsubscribe } = measurementService.subscribe(
|
||||
MeasurementService.EVENTS.JUMP_TO_MEASUREMENT_VIEWPORT,
|
||||
props => {
|
||||
cacheJumpToMeasurementEvent = props;
|
||||
const { viewportIndex: jumpIndex, measurement, isConsumed } = props;
|
||||
const { viewportId: jumpId, measurement, isConsumed } = props;
|
||||
if (!measurement || isConsumed) {
|
||||
return;
|
||||
}
|
||||
if (cacheJumpToMeasurementEvent.cornerstoneViewport === undefined) {
|
||||
// Decide on which viewport should handle this
|
||||
cacheJumpToMeasurementEvent.cornerstoneViewport = cornerstoneViewportService.getViewportIndexToJump(
|
||||
jumpIndex,
|
||||
cacheJumpToMeasurementEvent.cornerstoneViewport = cornerstoneViewportService.getViewportIdToJump(
|
||||
jumpId,
|
||||
measurement.displaySetInstanceUID,
|
||||
{ referencedImageId: measurement.referencedImageId }
|
||||
);
|
||||
}
|
||||
if (cacheJumpToMeasurementEvent.cornerstoneViewport !== viewportIndex) {
|
||||
if (cacheJumpToMeasurementEvent.cornerstoneViewport !== viewportId) {
|
||||
return;
|
||||
}
|
||||
_jumpToMeasurement(
|
||||
measurement,
|
||||
elementRef,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
measurementService,
|
||||
displaySetService,
|
||||
viewportGridService,
|
||||
@@ -487,7 +488,7 @@ function _checkForCachedJumpToMeasurementEvents(
|
||||
measurementService,
|
||||
displaySetService,
|
||||
elementRef,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
displaySets,
|
||||
viewportGridService,
|
||||
cornerstoneViewportService
|
||||
@@ -513,7 +514,7 @@ function _checkForCachedJumpToMeasurementEvents(
|
||||
_jumpToMeasurement(
|
||||
measurement,
|
||||
elementRef,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
measurementService,
|
||||
displaySetService,
|
||||
viewportGridService,
|
||||
@@ -526,7 +527,7 @@ function _checkForCachedJumpToMeasurementEvents(
|
||||
function _jumpToMeasurement(
|
||||
measurement,
|
||||
targetElementRef,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
measurementService,
|
||||
displaySetService,
|
||||
viewportGridService,
|
||||
@@ -548,13 +549,10 @@ function _jumpToMeasurement(
|
||||
// to set it properly
|
||||
// setCornerstoneMeasurementActive(measurement);
|
||||
|
||||
viewportGridService.setActiveViewportIndex(viewportIndex);
|
||||
viewportGridService.setActiveViewportId(viewportId);
|
||||
|
||||
const enabledElement = getEnabledElement(targetElement);
|
||||
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(
|
||||
viewportIndex
|
||||
);
|
||||
if (enabledElement) {
|
||||
// See how the jumpToSlice() of Cornerstone3D deals with imageIdx param.
|
||||
const viewport = enabledElement.viewport as
|
||||
@@ -621,7 +619,6 @@ OHIFCornerstoneViewport.defaultProps = {
|
||||
};
|
||||
|
||||
OHIFCornerstoneViewport.propTypes = {
|
||||
viewportIndex: PropTypes.number.isRequired,
|
||||
displaySets: PropTypes.array.isRequired,
|
||||
dataSource: PropTypes.object.isRequired,
|
||||
viewportOptions: PropTypes.object,
|
||||
|
||||
@@ -6,7 +6,7 @@ import ViewportOrientationMarkers from './ViewportOrientationMarkers';
|
||||
import ViewportImageSliceLoadingIndicator from './ViewportImageSliceLoadingIndicator';
|
||||
|
||||
function CornerstoneOverlays(props) {
|
||||
const { viewportIndex, element, scrollbarHeight, servicesManager } = props;
|
||||
const { viewportId, element, scrollbarHeight, servicesManager } = props;
|
||||
const { cornerstoneViewportService } = servicesManager.services;
|
||||
const [imageSliceData, setImageSliceData] = useState({
|
||||
imageIndex: 0,
|
||||
@@ -18,7 +18,7 @@ function CornerstoneOverlays(props) {
|
||||
const { unsubscribe } = cornerstoneViewportService.subscribe(
|
||||
cornerstoneViewportService.EVENTS.VIEWPORT_DATA_CHANGED,
|
||||
props => {
|
||||
if (props.viewportIndex !== viewportIndex) {
|
||||
if (props.viewportId !== viewportId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,16 +29,14 @@ function CornerstoneOverlays(props) {
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, [viewportIndex]);
|
||||
}, [viewportId]);
|
||||
|
||||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (viewportData) {
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(
|
||||
viewportIndex
|
||||
);
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
|
||||
|
||||
if (viewportInfo?.viewportOptions?.customViewportProps?.hideOverlays) {
|
||||
return null;
|
||||
@@ -48,7 +46,7 @@ function CornerstoneOverlays(props) {
|
||||
return (
|
||||
<div className="noselect">
|
||||
<ViewportImageScrollbar
|
||||
viewportIndex={viewportIndex}
|
||||
viewportId={viewportId}
|
||||
viewportData={viewportData}
|
||||
element={element}
|
||||
imageSliceData={imageSliceData}
|
||||
@@ -60,7 +58,7 @@ function CornerstoneOverlays(props) {
|
||||
<CustomizableViewportOverlay
|
||||
imageSliceData={imageSliceData}
|
||||
viewportData={viewportData}
|
||||
viewportIndex={viewportIndex}
|
||||
viewportId={viewportId}
|
||||
servicesManager={servicesManager}
|
||||
element={element}
|
||||
/>
|
||||
@@ -75,7 +73,7 @@ function CornerstoneOverlays(props) {
|
||||
element={element}
|
||||
viewportData={viewportData}
|
||||
servicesManager={servicesManager}
|
||||
viewportIndex={viewportIndex}
|
||||
viewportId={viewportId}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -21,7 +21,6 @@ interface OverlayItemProps {
|
||||
element: any;
|
||||
viewportData: any;
|
||||
imageSliceData: ImageSliceData;
|
||||
viewportIndex: number | null;
|
||||
servicesManager: ServicesManager;
|
||||
instance: InstanceMetadata;
|
||||
customization: any;
|
||||
@@ -114,7 +113,7 @@ function CustomizableViewportOverlay({
|
||||
element,
|
||||
viewportData,
|
||||
imageSliceData,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
servicesManager,
|
||||
}) {
|
||||
const {
|
||||
@@ -152,13 +151,13 @@ function CustomizableViewportOverlay({
|
||||
if (viewportData != null) {
|
||||
return _getInstanceNumber(
|
||||
viewportData,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
imageIndex,
|
||||
cornerstoneViewportService
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}, [viewportData, viewportIndex, imageIndex, cornerstoneViewportService]);
|
||||
}, [viewportData, viewportId, imageIndex, cornerstoneViewportService]);
|
||||
|
||||
/**
|
||||
* Initial toolbar state
|
||||
@@ -192,7 +191,7 @@ function CustomizableViewportOverlay({
|
||||
return () => {
|
||||
element.removeEventListener(Enums.Events.VOI_MODIFIED, updateVOI);
|
||||
};
|
||||
}, [viewportIndex, viewportData, voi, element]);
|
||||
}, [viewportId, viewportData, voi, element]);
|
||||
|
||||
/**
|
||||
* Updating the scale when the viewport changes its zoom
|
||||
@@ -205,8 +204,8 @@ function CustomizableViewportOverlay({
|
||||
previousCamera.parallelScale !== camera.parallelScale ||
|
||||
previousCamera.scale !== camera.scale
|
||||
) {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewportByIndex(
|
||||
viewportIndex
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(
|
||||
viewportId
|
||||
);
|
||||
|
||||
if (!viewport) {
|
||||
@@ -237,7 +236,7 @@ function CustomizableViewportOverlay({
|
||||
return () => {
|
||||
element.removeEventListener(Enums.Events.CAMERA_MODIFIED, updateScale);
|
||||
};
|
||||
}, [viewportIndex, viewportData, cornerstoneViewportService, element]);
|
||||
}, [viewportId, viewportData, cornerstoneViewportService, element]);
|
||||
|
||||
/**
|
||||
* Updating the active tools when the toolbar changes
|
||||
@@ -262,7 +261,7 @@ function CustomizableViewportOverlay({
|
||||
element,
|
||||
viewportData,
|
||||
imageSliceData,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
servicesManager,
|
||||
customization: item,
|
||||
formatters: {
|
||||
@@ -296,7 +295,7 @@ function CustomizableViewportOverlay({
|
||||
element,
|
||||
viewportData,
|
||||
imageSliceData,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
servicesManager,
|
||||
customizationService,
|
||||
instance,
|
||||
@@ -390,7 +389,7 @@ function _getViewportInstance(viewportData, imageIndex) {
|
||||
|
||||
function _getInstanceNumber(
|
||||
viewportData,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
imageIndex,
|
||||
cornerstoneViewportService
|
||||
) {
|
||||
@@ -406,7 +405,7 @@ function _getInstanceNumber(
|
||||
instanceNumber = _getInstanceNumberFromVolume(
|
||||
viewportData,
|
||||
imageIndex,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
cornerstoneViewportService
|
||||
);
|
||||
}
|
||||
@@ -438,8 +437,7 @@ function _getInstanceNumberFromStack(viewportData, imageIndex) {
|
||||
// Here we check if viewport is in the acquisition direction and if so, we get the instanceNumber
|
||||
function _getInstanceNumberFromVolume(
|
||||
viewportData,
|
||||
imageIndex,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
cornerstoneViewportService
|
||||
) {
|
||||
const volumes = viewportData.volumes;
|
||||
@@ -452,8 +450,8 @@ function _getInstanceNumberFromVolume(
|
||||
const volume = volumes[0];
|
||||
const { direction, imageIds } = volume;
|
||||
|
||||
const cornerstoneViewport = cornerstoneViewportService.getCornerstoneViewportByIndex(
|
||||
viewportIndex
|
||||
const cornerstoneViewport = cornerstoneViewportService.getCornerstoneViewport(
|
||||
viewportId
|
||||
);
|
||||
|
||||
if (!cornerstoneViewport) {
|
||||
@@ -486,7 +484,7 @@ function _getInstanceNumberFromVolume(
|
||||
CustomizableViewportOverlay.propTypes = {
|
||||
viewportData: PropTypes.object,
|
||||
imageIndex: PropTypes.number,
|
||||
viewportIndex: PropTypes.number,
|
||||
viewportId: PropTypes.string,
|
||||
};
|
||||
|
||||
export default CustomizableViewportOverlay;
|
||||
@@ -7,7 +7,7 @@ import { ServicesManger } from '@ohif/core';
|
||||
|
||||
function CornerstoneImageScrollbar({
|
||||
viewportData,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
element,
|
||||
imageSliceData,
|
||||
setImageSliceData,
|
||||
@@ -19,12 +19,7 @@ function CornerstoneImageScrollbar({
|
||||
cornerstoneViewportService,
|
||||
} = (servicesManager as ServicesManger).services;
|
||||
|
||||
const onImageScrollbarChange = (imageIndex, viewportIndex) => {
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(
|
||||
viewportIndex
|
||||
);
|
||||
|
||||
const viewportId = viewportInfo.getViewportId();
|
||||
const onImageScrollbarChange = (imageIndex, viewportId) => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(
|
||||
viewportId
|
||||
);
|
||||
@@ -34,7 +29,7 @@ function CornerstoneImageScrollbar({
|
||||
if (isCineEnabled) {
|
||||
// on image scrollbar change, stop the CINE if it is playing
|
||||
cineService.stopClip(element);
|
||||
cineService.setCine({ id: viewportIndex, isPlaying: false });
|
||||
cineService.setCine({ id: viewportId, isPlaying: false });
|
||||
}
|
||||
|
||||
csToolsUtils.jumpToSlice(viewport.element, {
|
||||
@@ -48,8 +43,8 @@ function CornerstoneImageScrollbar({
|
||||
return;
|
||||
}
|
||||
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewportByIndex(
|
||||
viewportIndex
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(
|
||||
viewportId
|
||||
);
|
||||
|
||||
if (!viewport) {
|
||||
@@ -79,7 +74,7 @@ function CornerstoneImageScrollbar({
|
||||
const { imageIndex, numberOfSlices } = sliceData;
|
||||
setImageSliceData({ imageIndex, numberOfSlices });
|
||||
}
|
||||
}, [viewportIndex, viewportData]);
|
||||
}, [viewportId, viewportData]);
|
||||
|
||||
useEffect(() => {
|
||||
if (viewportData?.viewportType !== Enums.ViewportType.STACK) {
|
||||
@@ -131,7 +126,7 @@ function CornerstoneImageScrollbar({
|
||||
|
||||
return (
|
||||
<ImageScrollbar
|
||||
onChange={evt => onImageScrollbarChange(evt, viewportIndex)}
|
||||
onChange={evt => onImageScrollbarChange(evt, viewportId)}
|
||||
max={
|
||||
imageSliceData.numberOfSlices ? imageSliceData.numberOfSlices - 1 : 0
|
||||
}
|
||||
@@ -143,7 +138,7 @@ function CornerstoneImageScrollbar({
|
||||
|
||||
CornerstoneImageScrollbar.propTypes = {
|
||||
viewportData: PropTypes.object,
|
||||
viewportIndex: PropTypes.number.isRequired,
|
||||
viewportId: PropTypes.string.isRequired,
|
||||
element: PropTypes.instanceOf(Element),
|
||||
scrollbarHeight: PropTypes.string,
|
||||
imageSliceData: PropTypes.object.isRequired,
|
||||
|
||||
@@ -22,7 +22,7 @@ function ViewportOrientationMarkers({
|
||||
element,
|
||||
viewportData,
|
||||
imageSliceData,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
servicesManager,
|
||||
orientationMarkers = ['top', 'left'],
|
||||
}) {
|
||||
@@ -114,9 +114,7 @@ function ViewportOrientationMarkers({
|
||||
flipHorizontal
|
||||
);
|
||||
|
||||
const ohifViewport = cornerstoneViewportService.getViewportInfoByIndex(
|
||||
viewportIndex
|
||||
);
|
||||
const ohifViewport = cornerstoneViewportService.getViewportInfo(viewportId);
|
||||
|
||||
if (!ohifViewport) {
|
||||
console.log('ViewportOrientationMarkers::No viewport');
|
||||
|
||||
@@ -11,7 +11,7 @@ function CornerstoneViewportOverlay({
|
||||
element,
|
||||
viewportData,
|
||||
imageSliceData,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
servicesManager,
|
||||
}) {
|
||||
const {
|
||||
@@ -73,7 +73,7 @@ function CornerstoneViewportOverlay({
|
||||
return () => {
|
||||
element.removeEventListener(Enums.Events.VOI_MODIFIED, updateVOI);
|
||||
};
|
||||
}, [viewportIndex, viewportData, voi, element]);
|
||||
}, [viewportId, viewportData, voi, element]);
|
||||
|
||||
/**
|
||||
* Updating the scale when the viewport changes its zoom
|
||||
@@ -86,8 +86,8 @@ function CornerstoneViewportOverlay({
|
||||
previousCamera.parallelScale !== camera.parallelScale ||
|
||||
previousCamera.scale !== camera.scale
|
||||
) {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewportByIndex(
|
||||
viewportIndex
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(
|
||||
viewportId
|
||||
);
|
||||
|
||||
if (!viewport) {
|
||||
@@ -118,7 +118,7 @@ function CornerstoneViewportOverlay({
|
||||
return () => {
|
||||
element.removeEventListener(Enums.Events.CAMERA_MODIFIED, updateScale);
|
||||
};
|
||||
}, [viewportIndex, viewportData]);
|
||||
}, [viewportId, viewportData]);
|
||||
|
||||
const getTopLeftContent = useCallback(() => {
|
||||
const { windowWidth, windowCenter } = voi;
|
||||
@@ -168,7 +168,7 @@ function CornerstoneViewportOverlay({
|
||||
instanceNumber = _getInstanceNumberFromVolume(
|
||||
viewportData,
|
||||
imageIndex,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
cornerstoneViewportService
|
||||
);
|
||||
}
|
||||
@@ -183,15 +183,13 @@ function CornerstoneViewportOverlay({
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}, [imageSliceData, viewportData, viewportIndex]);
|
||||
}, [imageSliceData, viewportData, viewportId]);
|
||||
|
||||
if (!viewportData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const ohifViewport = cornerstoneViewportService.getViewportInfoByIndex(
|
||||
viewportIndex
|
||||
);
|
||||
const ohifViewport = cornerstoneViewportService.getViewportInfo(viewportId);
|
||||
|
||||
if (!ohifViewport) {
|
||||
return null;
|
||||
@@ -240,7 +238,7 @@ function _getInstanceNumberFromStack(viewportData, imageIndex) {
|
||||
function _getInstanceNumberFromVolume(
|
||||
viewportData,
|
||||
imageIndex,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
cornerstoneViewportService
|
||||
) {
|
||||
const volumes = viewportData.volumes;
|
||||
@@ -253,8 +251,8 @@ function _getInstanceNumberFromVolume(
|
||||
const volume = volumes[0];
|
||||
const { direction, imageIds } = volume;
|
||||
|
||||
const cornerstoneViewport = cornerstoneViewportService.getCornerstoneViewportByIndex(
|
||||
viewportIndex
|
||||
const cornerstoneViewport = cornerstoneViewportService.getCornerstoneViewport(
|
||||
viewportId
|
||||
);
|
||||
|
||||
if (!cornerstoneViewport) {
|
||||
@@ -287,7 +285,7 @@ function _getInstanceNumberFromVolume(
|
||||
CornerstoneViewportOverlay.propTypes = {
|
||||
viewportData: PropTypes.object,
|
||||
imageIndex: PropTypes.number,
|
||||
viewportIndex: PropTypes.number,
|
||||
viewportId: PropTypes.string,
|
||||
servicesManager: PropTypes.instanceOf(ServicesManager),
|
||||
};
|
||||
|
||||
|
||||
@@ -239,8 +239,7 @@ function commandsModule({
|
||||
return;
|
||||
}
|
||||
|
||||
const viewportIndex = viewportInfo.getViewportIndex();
|
||||
viewportGridService.setActiveViewportIndex(viewportIndex);
|
||||
viewportGridService.setActiveViewportId(viewportId);
|
||||
},
|
||||
arrowTextCallback: ({ callback, data }) => {
|
||||
callInputDialog(uiDialogService, data, callback);
|
||||
@@ -310,9 +309,11 @@ function commandsModule({
|
||||
}
|
||||
}
|
||||
|
||||
const { viewports } = viewportGridService.getState() || {
|
||||
viewports: [],
|
||||
};
|
||||
const { viewports } = viewportGridService.getState();
|
||||
|
||||
if (!viewports.size) {
|
||||
return;
|
||||
}
|
||||
|
||||
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
|
||||
const toolGroupViewportIds = toolGroup?.getViewportIds?.();
|
||||
@@ -322,15 +323,11 @@ function commandsModule({
|
||||
return;
|
||||
}
|
||||
|
||||
const filteredViewports = viewports.filter(viewport => {
|
||||
if (!viewport.viewportOptions) {
|
||||
return false;
|
||||
const filteredViewports = Array.from(viewports.values()).filter(
|
||||
viewport => {
|
||||
return toolGroupViewportIds.includes(viewport.viewportId);
|
||||
}
|
||||
|
||||
return toolGroupViewportIds.includes(
|
||||
viewport.viewportOptions.viewportId
|
||||
);
|
||||
});
|
||||
);
|
||||
|
||||
if (!filteredViewports.length) {
|
||||
return;
|
||||
@@ -368,12 +365,10 @@ function commandsModule({
|
||||
});
|
||||
},
|
||||
showDownloadViewportModal: () => {
|
||||
const { activeViewportIndex } = viewportGridService.getState();
|
||||
const { activeViewportId } = viewportGridService.getState();
|
||||
|
||||
if (
|
||||
!cornerstoneViewportService.getCornerstoneViewportByIndex(
|
||||
activeViewportIndex
|
||||
)
|
||||
!cornerstoneViewportService.getCornerstoneViewport(activeViewportId)
|
||||
) {
|
||||
// Cannot download a non-cornerstone viewport (image).
|
||||
uiNotificationService.show({
|
||||
@@ -391,7 +386,7 @@ function commandsModule({
|
||||
content: CornerstoneViewportDownloadForm,
|
||||
title: 'Download High Quality Image',
|
||||
contentProps: {
|
||||
activeViewportIndex,
|
||||
activeViewportId,
|
||||
onClose: uiModalService.hide,
|
||||
cornerstoneViewportService,
|
||||
},
|
||||
@@ -554,13 +549,13 @@ function commandsModule({
|
||||
cstUtils.scroll(viewport, options);
|
||||
},
|
||||
setViewportColormap: ({
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
displaySetInstanceUID,
|
||||
colormap,
|
||||
immediate = false,
|
||||
}) => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewportByIndex(
|
||||
viewportIndex
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(
|
||||
viewportId
|
||||
);
|
||||
|
||||
const actorEntries = viewport.getActors();
|
||||
@@ -577,17 +572,17 @@ function commandsModule({
|
||||
viewport.render();
|
||||
}
|
||||
},
|
||||
incrementActiveViewport: () => {
|
||||
const { activeViewportIndex, viewports } = viewportGridService.getState();
|
||||
const nextViewportIndex = (activeViewportIndex + 1) % viewports.length;
|
||||
viewportGridService.setActiveViewportIndex(nextViewportIndex);
|
||||
},
|
||||
decrementActiveViewport: () => {
|
||||
const { activeViewportIndex, viewports } = viewportGridService.getState();
|
||||
changeActiveViewport: ({ direction = 1 }) => {
|
||||
const { activeViewportId, viewports } = viewportGridService.getState();
|
||||
const viewportIds = Array.from(viewports.keys());
|
||||
const currentIndex = viewportIds.indexOf(activeViewportId);
|
||||
const nextViewportIndex =
|
||||
(activeViewportIndex - 1 + viewports.length) % viewports.length;
|
||||
viewportGridService.setActiveViewportIndex(nextViewportIndex);
|
||||
(currentIndex + direction + viewportIds.length) % viewportIds.length;
|
||||
viewportGridService.setActiveViewportId(
|
||||
viewportIds[nextViewportIndex] as string
|
||||
);
|
||||
},
|
||||
|
||||
toggleStackImageSync: ({ toggledState }) => {
|
||||
toggleStackImageSync({
|
||||
getEnabledElement,
|
||||
@@ -596,9 +591,9 @@ function commandsModule({
|
||||
});
|
||||
},
|
||||
toggleReferenceLines: ({ toggledState }) => {
|
||||
const { activeViewportIndex } = viewportGridService.getState();
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(
|
||||
activeViewportIndex
|
||||
const { activeViewportId } = viewportGridService.getState();
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfo(
|
||||
activeViewportId
|
||||
);
|
||||
|
||||
const viewportId = viewportInfo.getViewportId();
|
||||
@@ -617,34 +612,8 @@ function commandsModule({
|
||||
);
|
||||
toolGroup.setToolEnabled(ReferenceLinesTool.toolName);
|
||||
},
|
||||
storePresentation: ({ viewportIndex }) => {
|
||||
const presentation = cornerstoneViewportService.getPresentation(
|
||||
viewportIndex
|
||||
);
|
||||
if (!presentation || !presentation.presentationIds) {
|
||||
return;
|
||||
}
|
||||
const {
|
||||
lutPresentationStore,
|
||||
positionPresentationStore,
|
||||
} = stateSyncService.getState();
|
||||
const { presentationIds } = presentation;
|
||||
const { lutPresentationId, positionPresentationId } =
|
||||
presentationIds || {};
|
||||
const storeState = {};
|
||||
if (lutPresentationId) {
|
||||
storeState.lutPresentationStore = {
|
||||
...lutPresentationStore,
|
||||
[lutPresentationId]: presentation,
|
||||
};
|
||||
}
|
||||
if (positionPresentationId) {
|
||||
storeState.positionPresentationStore = {
|
||||
...positionPresentationStore,
|
||||
[positionPresentationId]: presentation,
|
||||
};
|
||||
}
|
||||
stateSyncService.store(storeState);
|
||||
storePresentation: ({ viewportId }) => {
|
||||
cornerstoneViewportService.storePresentation({ viewportId });
|
||||
},
|
||||
};
|
||||
|
||||
@@ -701,10 +670,11 @@ function commandsModule({
|
||||
options: { rotation: -90 },
|
||||
},
|
||||
incrementActiveViewport: {
|
||||
commandFn: actions.incrementActiveViewport,
|
||||
commandFn: actions.changeActiveViewport,
|
||||
},
|
||||
decrementActiveViewport: {
|
||||
commandFn: actions.decrementActiveViewport,
|
||||
commandFn: actions.changeActiveViewport,
|
||||
options: { direction: -1 },
|
||||
},
|
||||
flipViewportHorizontal: {
|
||||
commandFn: actions.flipViewportHorizontal,
|
||||
|
||||
@@ -2,14 +2,10 @@ import React, { useEffect } from 'react';
|
||||
import { CinePlayer, useCine, useViewportGrid } from '@ohif/ui';
|
||||
import { Enums, eventTarget } from '@cornerstonejs/core';
|
||||
|
||||
function WrappedCinePlayer({
|
||||
enabledVPElement,
|
||||
viewportIndex,
|
||||
servicesManager,
|
||||
}) {
|
||||
function WrappedCinePlayer({ enabledVPElement, viewportId, servicesManager }) {
|
||||
const { toolbarService, customizationService } = servicesManager.services;
|
||||
const [{ isCineEnabled, cines }, cineService] = useCine();
|
||||
const [{ activeViewportIndex }] = useViewportGrid();
|
||||
const [{ activeViewportId }] = useViewportGrid();
|
||||
|
||||
const { component: CinePlayerComponent = CinePlayer } =
|
||||
customizationService.get('cinePlayer') ?? {};
|
||||
@@ -30,11 +26,11 @@ function WrappedCinePlayer({
|
||||
};
|
||||
|
||||
const cineHandler = () => {
|
||||
if (!cines || !cines[viewportIndex] || !enabledVPElement) {
|
||||
if (!cines || !cines[viewportId] || !enabledVPElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cine = cines[viewportIndex];
|
||||
const cine = cines[viewportId];
|
||||
const isPlaying = cine.isPlaying || false;
|
||||
const frameRate = cine.frameRate || 24;
|
||||
|
||||
@@ -56,7 +52,7 @@ function WrappedCinePlayer({
|
||||
);
|
||||
|
||||
return () => {
|
||||
cineService.setCine({ id: viewportIndex, isPlaying: false });
|
||||
cineService.setCine({ id: viewportId, isPlaying: false });
|
||||
eventTarget.removeEventListener(
|
||||
Enums.Events.STACK_VIEWPORT_NEW_STACK,
|
||||
cineHandler
|
||||
@@ -65,20 +61,20 @@ function WrappedCinePlayer({
|
||||
}, [enabledVPElement]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!cines || !cines[viewportIndex] || !enabledVPElement) {
|
||||
if (!cines || !cines[viewportId] || !enabledVPElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
cineHandler();
|
||||
|
||||
return () => {
|
||||
if (enabledVPElement && cines?.[viewportIndex]?.isPlaying) {
|
||||
if (enabledVPElement && cines?.[viewportId]?.isPlaying) {
|
||||
cineService.stopClip(enabledVPElement);
|
||||
}
|
||||
};
|
||||
}, [cines, viewportIndex, cineService, enabledVPElement, cineHandler]);
|
||||
}, [cines, viewportId, cineService, enabledVPElement, cineHandler]);
|
||||
|
||||
const cine = cines[viewportIndex];
|
||||
const cine = cines[viewportId];
|
||||
const isPlaying = (cine && cine.isPlaying) || false;
|
||||
|
||||
return (
|
||||
@@ -89,13 +85,13 @@ function WrappedCinePlayer({
|
||||
onClose={handleCineClose}
|
||||
onPlayPauseChange={isPlaying =>
|
||||
cineService.setCine({
|
||||
id: activeViewportIndex,
|
||||
id: activeViewportId,
|
||||
isPlaying,
|
||||
})
|
||||
}
|
||||
onFrameRateChange={frameRate =>
|
||||
cineService.setCine({
|
||||
id: activeViewportIndex,
|
||||
id: activeViewportId,
|
||||
frameRate,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ const mpr: Types.HangingProtocol.Protocol = {
|
||||
viewports: [
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'mpr-axial',
|
||||
toolGroupId: 'mpr',
|
||||
viewportType: 'volume',
|
||||
orientation: 'axial',
|
||||
@@ -111,6 +112,7 @@ const mpr: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'mpr-sagittal',
|
||||
toolGroupId: 'mpr',
|
||||
viewportType: 'volume',
|
||||
orientation: 'sagittal',
|
||||
@@ -134,6 +136,7 @@ const mpr: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'mpr-coronal',
|
||||
toolGroupId: 'mpr',
|
||||
viewportType: 'volume',
|
||||
orientation: 'coronal',
|
||||
|
||||
@@ -282,9 +282,8 @@ export default async function init({
|
||||
);
|
||||
|
||||
viewportGridService.subscribe(
|
||||
viewportGridService.EVENTS.ACTIVE_VIEWPORT_INDEX_CHANGED,
|
||||
({ viewportIndex, viewportId }) => {
|
||||
viewportId = viewportId || `viewport-${viewportIndex}`;
|
||||
viewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED,
|
||||
({ viewportId }) => {
|
||||
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);
|
||||
|
||||
if (!toolGroup || !toolGroup._toolInstances?.['ReferenceLines']) {
|
||||
|
||||
@@ -63,7 +63,6 @@ function initContextMenu({
|
||||
customizationService.get('cornerstoneViewportClickCommands') ||
|
||||
DEFAULT_CONTEXT_MENU_CLICKS;
|
||||
const toRun = customizations[name];
|
||||
console.log('initContextMenu::cornerstoneViewportHandleEvent', name, toRun);
|
||||
const options = {
|
||||
nearbyToolData: findNearbyToolData(commandsManager, evt),
|
||||
event: evt,
|
||||
@@ -82,9 +81,8 @@ function initContextMenu({
|
||||
if (!viewportInfo) {
|
||||
return;
|
||||
}
|
||||
const viewportIndex = viewportInfo.getViewportIndex();
|
||||
// TODO check update upstream
|
||||
setEnabledElement(viewportIndex, element);
|
||||
setEnabledElement(viewportId, element);
|
||||
|
||||
element.addEventListener(
|
||||
cs3DToolsEvents.MOUSE_CLICK,
|
||||
|
||||
+97
-171
@@ -9,8 +9,6 @@ import {
|
||||
VolumeViewport,
|
||||
VolumeViewport3D,
|
||||
cache,
|
||||
utilities,
|
||||
CONSTANTS,
|
||||
Enums as csEnums,
|
||||
} from '@cornerstonejs/core';
|
||||
|
||||
@@ -55,7 +53,6 @@ class CornerstoneViewportService extends PubSubService
|
||||
};
|
||||
|
||||
renderingEngine: Types.IRenderingEngine | null;
|
||||
viewportsInfo: Map<number, ViewportInfo> = new Map();
|
||||
viewportsById: Map<string, ViewportInfo> = new Map();
|
||||
viewportGridResizeObserver: ResizeObserver | null;
|
||||
viewportsDisplaySets: Map<string, string[]> = new Map();
|
||||
@@ -75,45 +72,17 @@ class CornerstoneViewportService extends PubSubService
|
||||
|
||||
/**
|
||||
* Adds the HTML element to the viewportService
|
||||
* @param {*} viewportIndex
|
||||
* @param {*} viewportId
|
||||
* @param {*} elementRef
|
||||
*/
|
||||
public enableViewport(
|
||||
viewportIndex: number,
|
||||
viewportOptions: PublicViewportOptions,
|
||||
elementRef: HTMLDivElement
|
||||
): void {
|
||||
// Use the provided viewportId
|
||||
// Not providing a viewportId is frowned upon because it does weird things
|
||||
// on moving them around, but it does mostly work.
|
||||
if (!viewportOptions.viewportId) {
|
||||
console.warn('Should provide viewport id externally', viewportOptions);
|
||||
viewportOptions.viewportId =
|
||||
this.getViewportId(viewportIndex) || `viewport-${viewportIndex}`;
|
||||
}
|
||||
const { viewportId } = viewportOptions;
|
||||
const viewportInfo = new ViewportInfo(viewportIndex, viewportId);
|
||||
if (!viewportInfo.viewportId) {
|
||||
throw new Error('Should have viewport ID afterwards');
|
||||
}
|
||||
|
||||
public enableViewport(viewportId: string, elementRef: HTMLDivElement): void {
|
||||
const viewportInfo = new ViewportInfo(viewportId);
|
||||
viewportInfo.setElement(elementRef);
|
||||
this.viewportsInfo.set(viewportIndex, viewportInfo);
|
||||
this.viewportsById.set(viewportId, viewportInfo);
|
||||
}
|
||||
|
||||
public getViewportIds(): string[] {
|
||||
const viewportIds = [];
|
||||
|
||||
this.viewportsInfo.forEach(viewportInfo => {
|
||||
viewportIds.push(viewportInfo.getViewportId());
|
||||
});
|
||||
|
||||
return viewportIds;
|
||||
}
|
||||
|
||||
public getViewportId(viewportIndex: number): string {
|
||||
return this.viewportsInfo[viewportIndex]?.viewportId;
|
||||
return Array.from(this.viewportsById.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,21 +140,14 @@ class CornerstoneViewportService extends PubSubService
|
||||
* created for every new viewport, this will be called whenever the set of
|
||||
* viewports is changed, but NOT when the viewport position changes only.
|
||||
*
|
||||
* @param viewportIndex
|
||||
* @param viewportId - The viewportId to disable
|
||||
*/
|
||||
public disableElement(viewportIndex: number): void {
|
||||
const viewportInfo = this.viewportsInfo.get(viewportIndex);
|
||||
if (!viewportInfo) {
|
||||
return;
|
||||
}
|
||||
public disableElement(viewportId: string): void {
|
||||
this.renderingEngine?.disableElement(viewportId);
|
||||
|
||||
const viewportId = viewportInfo.getViewportId();
|
||||
|
||||
this.renderingEngine && this.renderingEngine.disableElement(viewportId);
|
||||
|
||||
this.viewportsInfo.get(viewportIndex).destroy();
|
||||
this.viewportsInfo.delete(viewportIndex);
|
||||
// clean up
|
||||
this.viewportsById.delete(viewportId);
|
||||
this.viewportsDisplaySets.delete(viewportId);
|
||||
}
|
||||
|
||||
public setPresentations(viewport, presentations?: Presentations): void {
|
||||
@@ -199,14 +161,14 @@ class CornerstoneViewportService extends PubSubService
|
||||
}
|
||||
}
|
||||
|
||||
public getPresentation(viewportIndex: number): Presentation {
|
||||
const viewportInfo = this.viewportsInfo.get(viewportIndex);
|
||||
public getPresentation(viewportId: string): Presentation {
|
||||
const viewportInfo = this.viewportsById.get(viewportId);
|
||||
if (!viewportInfo) {
|
||||
return;
|
||||
}
|
||||
const { viewportType, presentationIds } = viewportInfo.getViewportOptions();
|
||||
|
||||
const csViewport = this.getCornerstoneViewportByIndex(viewportIndex);
|
||||
const csViewport = this.getCornerstoneViewport(viewportId);
|
||||
if (!csViewport) {
|
||||
return;
|
||||
}
|
||||
@@ -228,55 +190,80 @@ class CornerstoneViewportService extends PubSubService
|
||||
};
|
||||
}
|
||||
|
||||
public storePresentation({ viewportId }) {
|
||||
const stateSyncService = this.servicesManager.services.stateSyncService;
|
||||
let presentation;
|
||||
try {
|
||||
presentation = this.getPresentation(viewportId);
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
|
||||
if (!presentation || !presentation.presentationIds) {
|
||||
return;
|
||||
}
|
||||
const {
|
||||
lutPresentationStore,
|
||||
positionPresentationStore,
|
||||
} = stateSyncService.getState();
|
||||
const { presentationIds } = presentation;
|
||||
const { lutPresentationId, positionPresentationId } = presentationIds || {};
|
||||
const storeState = {};
|
||||
if (lutPresentationId) {
|
||||
storeState.lutPresentationStore = {
|
||||
...lutPresentationStore,
|
||||
[lutPresentationId]: presentation,
|
||||
};
|
||||
}
|
||||
if (positionPresentationId) {
|
||||
storeState.positionPresentationStore = {
|
||||
...positionPresentationStore,
|
||||
[positionPresentationId]: presentation,
|
||||
};
|
||||
}
|
||||
stateSyncService.store(storeState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the renderingEngine to enable the element for the given viewport index
|
||||
* and sets the displaySet data to the viewport
|
||||
* @param {*} viewportIndex
|
||||
* @param {*} displaySet
|
||||
* @param {*} dataSource
|
||||
* @returns
|
||||
* Sets the viewport data for a viewport.
|
||||
* @param viewportId - The ID of the viewport to set the data for.
|
||||
* @param viewportData - The viewport data to set.
|
||||
* @param publicViewportOptions - The public viewport options.
|
||||
* @param publicDisplaySetOptions - The public display set options.
|
||||
* @param presentations - The presentations to set.
|
||||
*/
|
||||
public setViewportData(
|
||||
viewportIndex: number,
|
||||
viewportId: string,
|
||||
viewportData: StackViewportData | VolumeViewportData,
|
||||
publicViewportOptions: PublicViewportOptions,
|
||||
publicDisplaySetOptions: DisplaySetOptions[],
|
||||
presentations?: Presentations
|
||||
): void {
|
||||
const renderingEngine = this.getRenderingEngine();
|
||||
const viewportId =
|
||||
publicViewportOptions.viewportId || this.getViewportId(viewportIndex);
|
||||
if (!viewportId) {
|
||||
throw new Error('Must define viewportId externally');
|
||||
}
|
||||
|
||||
// This is the old viewportInfo, which may have old options but we might be
|
||||
// using its viewport (same viewportId as the new viewportInfo)
|
||||
const viewportInfo = this.viewportsById.get(viewportId);
|
||||
|
||||
// We should store the presentation for the current viewport since we can't only
|
||||
// rely to store it WHEN the viewport is disabled since we might keep around the
|
||||
// same viewport/element and just change the viewportData for it (drag and drop etc.)
|
||||
// the disableElement storePresentation handle would not be called in this case
|
||||
// and we would lose the presentation.
|
||||
this.storePresentation({ viewportId: viewportInfo.getViewportId() });
|
||||
|
||||
if (!viewportInfo) {
|
||||
throw new Error('Viewport info not defined');
|
||||
throw new Error('element is not enabled for the given viewportId');
|
||||
}
|
||||
|
||||
// If the viewport has moved index, then record the new index
|
||||
if (viewportInfo.viewportIndex !== viewportIndex) {
|
||||
this.viewportsInfo.delete(viewportInfo.viewportIndex);
|
||||
this.viewportsInfo.set(viewportIndex, viewportInfo);
|
||||
viewportInfo.viewportIndex = viewportIndex;
|
||||
}
|
||||
|
||||
viewportInfo.setRenderingEngineId(renderingEngine.id);
|
||||
|
||||
const {
|
||||
viewportOptions,
|
||||
displaySetOptions,
|
||||
} = this._getViewportAndDisplaySetOptions(
|
||||
publicViewportOptions,
|
||||
publicDisplaySetOptions,
|
||||
viewportInfo
|
||||
// override the viewportOptions and displaySetOptions with the public ones
|
||||
// since those are the newly set ones, we set them here so that it handles defaults
|
||||
const displaySetOptions = viewportInfo.setPublicDisplaySetOptions(
|
||||
publicDisplaySetOptions
|
||||
);
|
||||
const viewportOptions = viewportInfo.setPublicViewportOptions(
|
||||
publicViewportOptions
|
||||
);
|
||||
|
||||
viewportInfo.setViewportOptions(viewportOptions);
|
||||
viewportInfo.setDisplaySetOptions(displaySetOptions);
|
||||
viewportInfo.setViewportData(viewportData);
|
||||
|
||||
const element = viewportInfo.getElement();
|
||||
const type = viewportInfo.getViewportType();
|
||||
@@ -293,12 +280,26 @@ class CornerstoneViewportService extends PubSubService
|
||||
},
|
||||
};
|
||||
|
||||
// Rendering Engine Id set should happen before enabling the element
|
||||
// since there are callbacks that depend on the renderingEngine id
|
||||
// Todo: however, this is a limitation which means that we can't change
|
||||
// the rendering engine id for a given viewport which might be a super edge
|
||||
// case
|
||||
viewportInfo.setRenderingEngineId(renderingEngine.id);
|
||||
|
||||
// Todo: this is not optimal at all, we are re-enabling the already enabled
|
||||
// element which is not what we want. But enabledElement as part of the
|
||||
// renderingEngine is designed to be used like this. This will trigger
|
||||
// ENABLED_ELEMENT again and again, which will run onEnableElement callbacks
|
||||
renderingEngine.enableElement(viewportInput);
|
||||
|
||||
viewportInfo.setViewportOptions(viewportOptions);
|
||||
viewportInfo.setDisplaySetOptions(displaySetOptions);
|
||||
viewportInfo.setViewportData(viewportData);
|
||||
viewportInfo.setViewportId(viewportId);
|
||||
|
||||
this.viewportsById.set(viewportId, viewportInfo);
|
||||
|
||||
const viewport = renderingEngine.getViewport(viewportId);
|
||||
this._setDisplaySets(viewport, viewportData, viewportInfo, presentations);
|
||||
|
||||
@@ -307,7 +308,6 @@ class CornerstoneViewportService extends PubSubService
|
||||
// invalid data.
|
||||
this._broadcastEvent(this.EVENTS.VIEWPORT_DATA_CHANGED, {
|
||||
viewportData,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
});
|
||||
}
|
||||
@@ -330,43 +330,8 @@ class CornerstoneViewportService extends PubSubService
|
||||
return viewport;
|
||||
}
|
||||
|
||||
public getCornerstoneViewportByIndex(
|
||||
viewportIndex: number
|
||||
): Types.IStackViewport | Types.IVolumeViewport | null {
|
||||
const viewportInfo = this.getViewportInfoByIndex(viewportIndex);
|
||||
|
||||
if (
|
||||
!viewportInfo ||
|
||||
!this.renderingEngine ||
|
||||
this.renderingEngine.hasBeenDestroyed
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const viewport = this.renderingEngine.getViewport(
|
||||
viewportInfo.getViewportId()
|
||||
);
|
||||
|
||||
return viewport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the viewportIndex for the provided viewportId
|
||||
* @param {string} viewportId - the viewportId
|
||||
* @returns {number} - the viewportIndex
|
||||
*/
|
||||
public getViewportInfoByIndex(viewportIndex: number): ViewportInfo {
|
||||
return this.viewportsInfo.get(viewportIndex);
|
||||
}
|
||||
|
||||
public getViewportInfo(viewportId: string): ViewportInfo {
|
||||
// @ts-ignore
|
||||
for (const [index, viewport] of this.viewportsInfo.entries()) {
|
||||
if (viewport.getViewportId() === viewportId) {
|
||||
return viewport;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return this.viewportsById.get(viewportId);
|
||||
}
|
||||
|
||||
_setStackViewport(
|
||||
@@ -414,7 +379,7 @@ class CornerstoneViewportService extends PubSubService
|
||||
}
|
||||
|
||||
viewport.setStack(imageIds, initialImageIndexToUse).then(() => {
|
||||
viewport.setProperties(properties);
|
||||
viewport.setProperties({ ...properties });
|
||||
const camera = presentations.positionPresentation?.camera;
|
||||
if (camera) {
|
||||
viewport.setCamera(camera);
|
||||
@@ -541,10 +506,7 @@ class CornerstoneViewportService extends PubSubService
|
||||
|
||||
this.viewportsDisplaySets.set(viewport.id, displaySetInstanceUIDs);
|
||||
|
||||
if (
|
||||
hangingProtocolService.hasCustomImageLoadStrategy() &&
|
||||
!hangingProtocolService.customImageLoadPerformed
|
||||
) {
|
||||
if (hangingProtocolService.getShouldPerformCustomImageLoad()) {
|
||||
// delegate the volume loading to the hanging protocol service if it has a custom image load strategy
|
||||
return hangingProtocolService.runImageLoadStrategy({
|
||||
viewportId: viewport.id,
|
||||
@@ -744,14 +706,8 @@ class CornerstoneViewportService extends PubSubService
|
||||
|
||||
// Todo: keepCamera is an interim solution until we have a better solution for
|
||||
// keeping the camera position when the viewport data is changed
|
||||
public updateViewport(
|
||||
viewportIndex: number,
|
||||
viewportData,
|
||||
keepCamera = false
|
||||
) {
|
||||
const viewportInfo = this.getViewportInfoByIndex(viewportIndex);
|
||||
|
||||
const viewportId = viewportInfo.getViewportId();
|
||||
public updateViewport(viewportId: string, viewportData, keepCamera = false) {
|
||||
const viewportInfo = this.getViewportInfo(viewportId);
|
||||
const viewport = this.getCornerstoneViewport(viewportId);
|
||||
const viewportCamera = viewport.getCamera();
|
||||
|
||||
@@ -841,36 +797,6 @@ class CornerstoneViewportService extends PubSubService
|
||||
}
|
||||
}
|
||||
|
||||
_getViewportAndDisplaySetOptions(
|
||||
publicViewportOptions: PublicViewportOptions,
|
||||
publicDisplaySetOptions: DisplaySetOptions[],
|
||||
viewportInfo: ViewportInfo
|
||||
): {
|
||||
viewportOptions: ViewportOptions;
|
||||
displaySetOptions: DisplaySetOptions[];
|
||||
} {
|
||||
const viewportIndex = viewportInfo.getViewportIndex();
|
||||
|
||||
// Creating a temporary viewportInfo to handle defaults
|
||||
const newViewportInfo = new ViewportInfo(
|
||||
viewportIndex,
|
||||
viewportInfo.getViewportId()
|
||||
);
|
||||
|
||||
// To handle setting the default values if missing for the viewportOptions and
|
||||
// displaySetOptions
|
||||
newViewportInfo.setPublicViewportOptions(publicViewportOptions);
|
||||
newViewportInfo.setPublicDisplaySetOptions(publicDisplaySetOptions);
|
||||
|
||||
const newViewportOptions = newViewportInfo.getViewportOptions();
|
||||
const newDisplaySetOptions = newViewportInfo.getDisplaySetOptions();
|
||||
|
||||
return {
|
||||
viewportOptions: newViewportOptions,
|
||||
displaySetOptions: newDisplaySetOptions,
|
||||
};
|
||||
}
|
||||
|
||||
_getFrameOfReferenceUID(displaySetInstanceUID) {
|
||||
const { displaySetService } = this.servicesManager.services;
|
||||
const displaySet = displaySetService.getDisplaySetByUID(
|
||||
@@ -907,25 +833,25 @@ class CornerstoneViewportService extends PubSubService
|
||||
*
|
||||
* @param measurement
|
||||
* The measurement that is desired to view.
|
||||
* @param activeViewportIndex - the index that was active at the time the jump
|
||||
* @param activeViewportId - the index that was active at the time the jump
|
||||
* was initiated.
|
||||
* @return the viewportIndex to display the given measurement
|
||||
* @return the viewportId that the measurement should be displayed in.
|
||||
*/
|
||||
public getViewportIndexToJump(
|
||||
activeViewportIndex: number,
|
||||
public getViewportIdToJump(
|
||||
activeViewportId: string,
|
||||
displaySetInstanceUID: string,
|
||||
cameraProps: unknown
|
||||
): number {
|
||||
const viewportInfo = this.viewportsInfo.get(activeViewportIndex);
|
||||
): string {
|
||||
const viewportInfo = this.getViewportInfo(activeViewportId);
|
||||
const { referencedImageId } = cameraProps;
|
||||
if (viewportInfo?.contains(displaySetInstanceUID, referencedImageId)) {
|
||||
return activeViewportIndex;
|
||||
return activeViewportId;
|
||||
}
|
||||
|
||||
return (
|
||||
[...this.viewportsById.values()].find(viewportInfo =>
|
||||
viewportInfo.contains(displaySetInstanceUID, referencedImageId)
|
||||
)?.viewportIndex ?? -1
|
||||
)?.viewportId ?? null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ export interface IViewportService {
|
||||
viewportGridResizeObserver: unknown;
|
||||
viewportsInfo: unknown;
|
||||
sceneVolumeInputs: unknown;
|
||||
viewportIndexUIDMap: unknown;
|
||||
viewportDivElements: unknown;
|
||||
ViewportPropertiesMap: unknown;
|
||||
volumeUIDs: unknown;
|
||||
@@ -28,14 +27,9 @@ export interface IViewportService {
|
||||
_broadcastEvent: unknown;
|
||||
/**
|
||||
* Adds the HTML element to the viewportService
|
||||
* @param {*} viewportIndex
|
||||
* @param {*} elementRef
|
||||
*/
|
||||
enableViewport(
|
||||
viewportIndex: number,
|
||||
viewportOptions: ViewportOptions,
|
||||
elementRef: HTMLDivElement
|
||||
): void;
|
||||
enableViewport(viewportId: string, elementRef: HTMLDivElement): void;
|
||||
/**
|
||||
* It retrieves the renderingEngine if it does exist, or creates one otherwise
|
||||
* @returns {RenderingEngine} rendering engine
|
||||
@@ -54,19 +48,17 @@ export interface IViewportService {
|
||||
/**
|
||||
* Disables the viewport inside the renderingEngine, if no viewport is left
|
||||
* it destroys the renderingEngine.
|
||||
* @param viewportIndex
|
||||
* @param viewportId
|
||||
*/
|
||||
disableElement(viewportIndex: number): void;
|
||||
disableElement(viewportId: string): void;
|
||||
/**
|
||||
* Uses the renderingEngine to enable the element for the given viewport index
|
||||
* and sets the displaySet data to the viewport
|
||||
* @param {*} viewportIndex
|
||||
* @param {*} displaySet
|
||||
* @param {*} dataSource
|
||||
* @returns
|
||||
*/
|
||||
setViewportData(
|
||||
viewportIndex: number,
|
||||
viewportData: StackData | VolumeData,
|
||||
publicViewportOptions: PublicViewportOptions,
|
||||
publicDisplaySetOptions: DisplaySetOptions[]
|
||||
|
||||
@@ -106,15 +106,13 @@ const dataContains = (
|
||||
|
||||
class ViewportInfo {
|
||||
private viewportId = '';
|
||||
private viewportIndex: number;
|
||||
private element: HTMLDivElement;
|
||||
private viewportOptions: ViewportOptions;
|
||||
private displaySetOptions: Array<DisplaySetOptions>;
|
||||
private viewportData: StackViewportData | VolumeViewportData;
|
||||
private renderingEngineId: string;
|
||||
|
||||
constructor(viewportIndex: number, viewportId: string) {
|
||||
this.viewportIndex = viewportIndex;
|
||||
constructor(viewportId: string) {
|
||||
this.viewportId = viewportId;
|
||||
this.setPublicViewportOptions({});
|
||||
this.setPublicDisplaySetOptions([{}]);
|
||||
@@ -155,9 +153,6 @@ class ViewportInfo {
|
||||
public setViewportId(viewportId: string): void {
|
||||
this.viewportId = viewportId;
|
||||
}
|
||||
public setViewportIndex(viewportIndex: number): void {
|
||||
this.viewportIndex = viewportIndex;
|
||||
}
|
||||
|
||||
public setElement(element: HTMLDivElement): void {
|
||||
this.element = element;
|
||||
@@ -173,9 +168,6 @@ class ViewportInfo {
|
||||
return this.viewportData;
|
||||
}
|
||||
|
||||
public getViewportIndex(): number {
|
||||
return this.viewportIndex;
|
||||
}
|
||||
|
||||
public getElement(): HTMLDivElement {
|
||||
return this.element;
|
||||
@@ -187,13 +179,15 @@ class ViewportInfo {
|
||||
|
||||
public setPublicDisplaySetOptions(
|
||||
publicDisplaySetOptions: PublicDisplaySetOptions[] | DisplaySetSelector[]
|
||||
): void {
|
||||
): Array<DisplaySetOptions> {
|
||||
// map the displaySetOptions and check if they are undefined then set them to default values
|
||||
const displaySetOptions = this.mapDisplaySetOptions(
|
||||
publicDisplaySetOptions
|
||||
);
|
||||
|
||||
this.setDisplaySetOptions(displaySetOptions);
|
||||
|
||||
return this.displaySetOptions
|
||||
}
|
||||
|
||||
public hasDisplaySet(displaySetInstanceUID: string): boolean {
|
||||
@@ -217,7 +211,7 @@ class ViewportInfo {
|
||||
|
||||
public setPublicViewportOptions(
|
||||
viewportOptionsEntry: PublicViewportOptions
|
||||
): void {
|
||||
): ViewportOptions {
|
||||
let viewportType = viewportOptionsEntry.viewportType;
|
||||
const {
|
||||
toolGroupId = DEFAULT_TOOLGROUP_ID,
|
||||
@@ -250,6 +244,8 @@ class ViewportInfo {
|
||||
toolGroupId,
|
||||
presentationIds,
|
||||
});
|
||||
|
||||
return this.viewportOptions;
|
||||
}
|
||||
|
||||
public setViewportOptions(viewportOptions: ViewportOptions): void {
|
||||
|
||||
@@ -10,13 +10,13 @@ const state = {
|
||||
* @return void
|
||||
*/
|
||||
const setEnabledElement = (
|
||||
viewportIndex: number,
|
||||
viewportId: string,
|
||||
element: HTMLElement,
|
||||
context?: string
|
||||
): void => {
|
||||
const targetContext = context || state.DEFAULT_CONTEXT;
|
||||
|
||||
state.enabledElements[viewportIndex] = {
|
||||
state.enabledElements[viewportId] = {
|
||||
element,
|
||||
context: targetContext,
|
||||
};
|
||||
@@ -27,8 +27,8 @@ const setEnabledElement = (
|
||||
*
|
||||
* @return {HTMLElement} Active viewport element.
|
||||
*/
|
||||
const getEnabledElement = viewportIndex => {
|
||||
return state.enabledElements[viewportIndex];
|
||||
const getEnabledElement = viewportId => {
|
||||
return state.enabledElements[viewportId];
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
|
||||
@@ -20,10 +20,10 @@ const VIEWPORT_ID = 'cornerstone-viewport-download-form';
|
||||
|
||||
const CornerstoneViewportDownloadForm = ({
|
||||
onClose,
|
||||
activeViewportIndex,
|
||||
activeViewportId: activeViewportIdProp,
|
||||
cornerstoneViewportService,
|
||||
}) => {
|
||||
const enabledElement = OHIFgetEnabledElement(activeViewportIndex);
|
||||
const enabledElement = OHIFgetEnabledElement(activeViewportIdProp);
|
||||
const activeViewportElement = enabledElement?.element;
|
||||
const activeViewportEnabledElement = getEnabledElement(activeViewportElement);
|
||||
|
||||
@@ -268,7 +268,7 @@ const CornerstoneViewportDownloadForm = ({
|
||||
|
||||
CornerstoneViewportDownloadForm.propTypes = {
|
||||
onClose: PropTypes.func,
|
||||
activeViewportIndex: PropTypes.number.isRequired,
|
||||
activeViewportId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default CornerstoneViewportDownloadForm;
|
||||
@@ -6,8 +6,8 @@ import { getEnabledElement as OHIFgetEnabledElement } from '../state';
|
||||
export default function getActiveViewportEnabledElement(
|
||||
viewportGridService
|
||||
): IEnabledElement {
|
||||
const { activeViewportIndex } = viewportGridService.getState();
|
||||
const { element } = OHIFgetEnabledElement(activeViewportIndex) || {};
|
||||
const { activeViewportId } = viewportGridService.getState();
|
||||
const { element } = OHIFgetEnabledElement(activeViewportId) || {};
|
||||
const enabledElement = getEnabledElement(element);
|
||||
return enabledElement;
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import calculateViewportRegistrations from './calculateViewportRegistrations';
|
||||
|
||||
// [ {
|
||||
// synchronizerId: string,
|
||||
// viewports: [ { viewportId: number, renderingEngineId: string, index: number } , ...]
|
||||
// viewports: [ { viewportId: string, renderingEngineId: string, index: number } , ...]
|
||||
// ]}
|
||||
let STACK_IMAGE_SYNC_GROUPS_INFO = [];
|
||||
|
||||
@@ -37,32 +37,25 @@ export default function toggleStackImageSync({
|
||||
STACK_IMAGE_SYNC_GROUPS_INFO = [];
|
||||
|
||||
// create synchronization groups and add viewports
|
||||
let { viewports } = viewportGridService.getState();
|
||||
const { viewports } = viewportGridService.getState();
|
||||
|
||||
// filter empty viewports
|
||||
viewports = viewports.filter(
|
||||
viewport =>
|
||||
viewport.displaySetInstanceUIDs && viewport.displaySetInstanceUIDs.length
|
||||
);
|
||||
const viewportsArray = Array.from(viewports.values())
|
||||
.filter(viewport => viewport.displaySetInstanceUIDs?.length)
|
||||
// filter reconstructable viewports
|
||||
.filter(viewport => {
|
||||
const { displaySetInstanceUIDs } = viewport;
|
||||
|
||||
// filter reconstructable viewports
|
||||
viewports = viewports.filter(viewport => {
|
||||
const { displaySetInstanceUIDs } = viewport;
|
||||
for (const displaySetInstanceUID of displaySetInstanceUIDs) {
|
||||
const displaySet = displaySetService.getDisplaySetByUID(
|
||||
displaySetInstanceUID
|
||||
);
|
||||
|
||||
for (const displaySetInstanceUID of displaySetInstanceUIDs) {
|
||||
const displaySet = displaySetService.getDisplaySetByUID(
|
||||
displaySetInstanceUID
|
||||
);
|
||||
|
||||
if (displaySet && displaySet.isReconstructable) {
|
||||
return true;
|
||||
return !!displaySet?.isReconstructable;
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
const viewportsByOrientation = viewports.reduce((acc, viewport) => {
|
||||
const viewportsByOrientation = viewportsArray.reduce((acc, viewport) => {
|
||||
const { viewportId, viewportType } = viewport.viewportOptions;
|
||||
|
||||
if (viewportType !== 'stack') {
|
||||
@@ -71,9 +64,8 @@ export default function toggleStackImageSync({
|
||||
}
|
||||
|
||||
const { element } = cornerstoneViewportService.getViewportInfo(viewportId);
|
||||
const { viewport: csViewport, renderingEngineId } = getEnabledElement(
|
||||
element
|
||||
);
|
||||
const { viewport: csViewport, renderingEngineId } =
|
||||
getEnabledElement(element);
|
||||
const { viewPlaneNormal } = csViewport.getCamera();
|
||||
|
||||
// Should we round here? I guess so, but not sure how much precision we need
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function PanelMeasurementTable({
|
||||
extensionManager,
|
||||
}): React.FunctionComponent {
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
const { activeViewportIndex, viewports } = viewportGrid;
|
||||
const { activeViewportId, viewports } = viewportGrid;
|
||||
const {
|
||||
measurementService,
|
||||
uiDialogService,
|
||||
@@ -80,7 +80,7 @@ export default function PanelMeasurementTable({
|
||||
|
||||
async function createReport(): Promise<any> {
|
||||
// filter measurements that are added to the active study
|
||||
const activeViewport = viewports[activeViewportIndex];
|
||||
const activeViewport = viewports.get(activeViewportId);
|
||||
const measurements = measurementService.getMeasurements();
|
||||
const displaySet = displaySetService.getDisplaySetByUID(
|
||||
activeViewport.displaySetInstanceUIDs[0]
|
||||
@@ -133,7 +133,7 @@ export default function PanelMeasurementTable({
|
||||
}
|
||||
|
||||
const jumpToImage = ({ uid, isActive }) => {
|
||||
measurementService.jumpToMeasurement(viewportGrid.activeViewportIndex, uid);
|
||||
measurementService.jumpToMeasurement(viewportGrid.activeViewportId, uid);
|
||||
|
||||
onMeasurementItemClickHandler({ uid, isActive });
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ function PanelStudyBrowser({
|
||||
// Tabs --> Studies --> DisplaySets --> Thumbnails
|
||||
const { StudyInstanceUIDs } = useImageViewer();
|
||||
const [
|
||||
{ activeViewportIndex, viewports },
|
||||
{ activeViewportId, viewports },
|
||||
viewportGridService,
|
||||
] = useViewportGrid();
|
||||
const [activeTabName, setActiveTabName] = useState('primary');
|
||||
@@ -43,10 +43,10 @@ function PanelStudyBrowser({
|
||||
|
||||
const onDoubleClickThumbnailHandler = displaySetInstanceUID => {
|
||||
let updatedViewports = [];
|
||||
const viewportIndex = activeViewportIndex;
|
||||
const viewportId = activeViewportId;
|
||||
try {
|
||||
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
displaySetInstanceUID
|
||||
);
|
||||
} catch (error) {
|
||||
@@ -262,8 +262,8 @@ function PanelStudyBrowser({
|
||||
}
|
||||
}
|
||||
|
||||
const activeDisplaySetInstanceUIDs =
|
||||
viewports[activeViewportIndex]?.displaySetInstanceUIDs;
|
||||
const activeDisplaySetInstanceUIDs = viewports.get(activeViewportId)
|
||||
?.displaySetInstanceUIDs;
|
||||
|
||||
return (
|
||||
<StudyBrowser
|
||||
|
||||
@@ -261,17 +261,17 @@ const commandsModule = ({
|
||||
];
|
||||
stateSyncService.store(stateSyncReduce);
|
||||
// This is a default action applied
|
||||
actions.toggleHpTools(hangingProtocolService.getActiveProtocol());
|
||||
const { protocol } = hangingProtocolService.getActiveProtocol();
|
||||
actions.toggleHpTools(protocol);
|
||||
// Send the notification about updating the state
|
||||
if (protocolId !== hpInfo.protocolId) {
|
||||
const { protocol } = hangingProtocolService.getActiveProtocol();
|
||||
// The old protocol callbacks are used for turning off things
|
||||
// like crosshairs when moving to the new HP
|
||||
commandsManager.run(oldProtocol.callbacks?.onProtocolExit);
|
||||
// The new protocol callback is used for things like
|
||||
// activating modes etc.
|
||||
commandsManager.run(protocol.callbacks?.onProtocolEnter);
|
||||
}
|
||||
commandsManager.run(protocol.callbacks?.onProtocolEnter);
|
||||
return true;
|
||||
} catch (e) {
|
||||
actions.toggleHpTools(hangingProtocolService.getActiveProtocol());
|
||||
@@ -394,12 +394,12 @@ const commandsModule = ({
|
||||
|
||||
toggleOneUp() {
|
||||
const viewportGridState = viewportGridService.getState();
|
||||
const { activeViewportIndex, viewports, layout } = viewportGridState;
|
||||
const { activeViewportId, viewports, layout } = viewportGridState;
|
||||
const {
|
||||
displaySetInstanceUIDs,
|
||||
displaySetOptions,
|
||||
viewportOptions,
|
||||
} = viewports[activeViewportIndex];
|
||||
} = viewports.get(activeViewportId);
|
||||
|
||||
if (layout.numCols === 1 && layout.numRows === 1) {
|
||||
// The viewer is in one-up. Check if there is a state to restore/toggle back to.
|
||||
@@ -410,20 +410,16 @@ const commandsModule = ({
|
||||
}
|
||||
// There is a state to toggle back to. The viewport that was
|
||||
// originally toggled to one up was the former active viewport.
|
||||
const viewportIndexToUpdate =
|
||||
toggleOneUpViewportGridStore.activeViewportIndex;
|
||||
const viewportIdToUpdate =
|
||||
toggleOneUpViewportGridStore.activeViewportId;
|
||||
|
||||
// Determine which viewports need to be updated. This is particularly
|
||||
// important when MPR is toggled to one up and a different reconstructable
|
||||
// is swapped in. Note that currently HangingProtocolService.getViewportsRequireUpdate
|
||||
// does not support viewport with multiple display sets.
|
||||
const updatedViewports =
|
||||
const updatedViewportsViaHP =
|
||||
displaySetInstanceUIDs.length > 1
|
||||
? []
|
||||
: displaySetInstanceUIDs
|
||||
.map(displaySetInstanceUID =>
|
||||
hangingProtocolService.getViewportsRequireUpdate(
|
||||
viewportIndexToUpdate,
|
||||
viewportIdToUpdate,
|
||||
displaySetInstanceUID
|
||||
)
|
||||
)
|
||||
@@ -432,14 +428,37 @@ const commandsModule = ({
|
||||
// This findOrCreateViewport returns either one of the updatedViewports
|
||||
// returned from the HP service OR if there is not one from the HP service then
|
||||
// simply returns what was in the previous state.
|
||||
const findOrCreateViewport = (viewportIndex: number) => {
|
||||
const viewport = updatedViewports.find(
|
||||
viewport => viewport.viewportIndex === viewportIndex
|
||||
);
|
||||
const findOrCreateViewport = (position: number) => {
|
||||
// get the viewportId in the current state (since we are in the one-up layout)
|
||||
const currentOneUpViewport = Array.from(viewports.values())[0];
|
||||
|
||||
return viewport
|
||||
? { viewportOptions, displaySetOptions, ...viewport }
|
||||
: toggleOneUpViewportGridStore.viewports[viewportIndex];
|
||||
// we should restore the previous layout but take into the account the fact that
|
||||
// the current one up viewport might have a new displaySet dragged and dropped on it
|
||||
// so we should prioritize the current one in the old grid store layout viewports
|
||||
|
||||
const newViewports = Array.from(
|
||||
toggleOneUpViewportGridStore.viewports.values()
|
||||
).map(viewport => {
|
||||
if (viewport.viewportId === currentOneUpViewport.viewportId) {
|
||||
return {
|
||||
...currentOneUpViewport,
|
||||
};
|
||||
}
|
||||
|
||||
return viewport;
|
||||
});
|
||||
|
||||
// However, we also need to take into account that the current one up viewport
|
||||
// might have been part of a bigger hanging protocol layout, so going back
|
||||
// from one up we should apply those viewports as well.
|
||||
return updatedViewportsViaHP.length > 1 &&
|
||||
updatedViewportsViaHP[position]
|
||||
? {
|
||||
viewportOptions,
|
||||
displaySetOptions,
|
||||
...updatedViewportsViaHP[position],
|
||||
}
|
||||
: newViewports[position];
|
||||
};
|
||||
|
||||
const layoutOptions = viewportGridService.getLayoutOptionsFromState(
|
||||
@@ -450,7 +469,7 @@ const commandsModule = ({
|
||||
viewportGridService.setLayout({
|
||||
numRows: toggleOneUpViewportGridStore.layout.numRows,
|
||||
numCols: toggleOneUpViewportGridStore.layout.numCols,
|
||||
activeViewportIndex: viewportIndexToUpdate,
|
||||
activeViewportId: viewportIdToUpdate,
|
||||
layoutOptions,
|
||||
findOrCreateViewport,
|
||||
});
|
||||
@@ -520,8 +539,8 @@ const commandsModule = ({
|
||||
},
|
||||
|
||||
openDICOMTagViewer() {
|
||||
const { activeViewportIndex, viewports } = viewportGridService.getState();
|
||||
const activeViewportSpecificData = viewports[activeViewportIndex];
|
||||
const { activeViewportId, viewports } = viewportGridService.getState();
|
||||
const activeViewportSpecificData = viewports.get(activeViewportId);
|
||||
const { displaySetInstanceUIDs } = activeViewportSpecificData;
|
||||
|
||||
const displaySets = displaySetService.activeDisplaySets;
|
||||
@@ -552,17 +571,9 @@ const commandsModule = ({
|
||||
},
|
||||
|
||||
scrollActiveThumbnailIntoView: () => {
|
||||
const { activeViewportIndex, viewports } = viewportGridService.getState();
|
||||
const { activeViewportId, viewports } = viewportGridService.getState();
|
||||
|
||||
if (
|
||||
!viewports ||
|
||||
activeViewportIndex < 0 ||
|
||||
activeViewportIndex > viewports.length - 1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const activeViewport = viewports[activeViewportIndex];
|
||||
const activeViewport = viewports.get(activeViewportId);
|
||||
const activeDisplaySetInstanceUID =
|
||||
activeViewport.displaySetInstanceUIDs[0];
|
||||
|
||||
@@ -615,9 +626,9 @@ const commandsModule = ({
|
||||
|
||||
currentDisplaySets.sort(dsSortFn);
|
||||
|
||||
const { activeViewportIndex, viewports } = viewportGridService.getState();
|
||||
const { activeViewportId, viewports } = viewportGridService.getState();
|
||||
|
||||
const { displaySetInstanceUIDs } = viewports[activeViewportIndex];
|
||||
const { displaySetInstanceUIDs } = viewports.get(activeViewportId);
|
||||
|
||||
const activeDisplaySetIndex = currentDisplaySets.findIndex(displaySet =>
|
||||
displaySetInstanceUIDs.includes(displaySet.displaySetInstanceUID)
|
||||
@@ -656,7 +667,7 @@ const commandsModule = ({
|
||||
|
||||
try {
|
||||
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
|
||||
activeViewportIndex,
|
||||
activeViewportId,
|
||||
displaySetInstanceUID
|
||||
);
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { StateSyncService, Types } from '@ohif/core';
|
||||
import { StateSyncService } from '@ohif/core';
|
||||
|
||||
/**
|
||||
* This find or create viewport is paired with the reduce results from
|
||||
@@ -7,7 +7,7 @@ import { StateSyncService, Types } from '@ohif/core';
|
||||
* then one can be re-used from the display set if it isn't going to be displayed.
|
||||
* @param hangingProtocolService - bound parameter supplied before using this
|
||||
* @param viewportsByPosition - bound parameter supplied before using this
|
||||
* @param viewportIndex - the index to retrieve
|
||||
* @param position - the position in the grid to retrieve
|
||||
* @param positionId - the current position on screen to retrieve
|
||||
* @param options - the set of options used, so that subsequent calls can
|
||||
* store state that is reset by the setLayout.
|
||||
@@ -17,7 +17,7 @@ import { StateSyncService, Types } from '@ohif/core';
|
||||
export const findOrCreateViewport = (
|
||||
hangingProtocolService,
|
||||
viewportsByPosition,
|
||||
viewportIndex: number,
|
||||
position: number,
|
||||
positionId: string,
|
||||
options: Record<string, unknown>
|
||||
) => {
|
||||
@@ -74,24 +74,19 @@ const findViewportsByPosition = (
|
||||
const viewportsByPosition = { ...syncState.viewportsByPosition };
|
||||
const initialInDisplay = [];
|
||||
|
||||
for (const viewport of viewports) {
|
||||
viewports.forEach(viewport => {
|
||||
if (viewport.positionId) {
|
||||
const storedViewport = {
|
||||
...viewport,
|
||||
viewportOptions: { ...viewport.viewportOptions },
|
||||
};
|
||||
viewportsByPosition[viewport.positionId] = storedViewport;
|
||||
// The cache doesn't store the viewport options - it is only useful
|
||||
// for remembering the type of viewport and UIDs
|
||||
delete storedViewport.viewportId;
|
||||
delete storedViewport.viewportOptions.viewportId;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (let row = 0; row < numRows; row++) {
|
||||
for (let col = 0; col < numCols; col++) {
|
||||
const pos = col + row * numCols;
|
||||
const positionId = viewports?.[pos]?.positionId || `${col}-${row}`;
|
||||
const positionId = `${col}-${row}`;
|
||||
const viewport = viewportsByPosition[positionId];
|
||||
if (viewport?.displaySetInstanceUIDs) {
|
||||
initialInDisplay.push(...viewport.displaySetInstanceUIDs);
|
||||
|
||||
@@ -73,6 +73,7 @@ const defaultProtocol = {
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportType: 'stack',
|
||||
viewportId: 'default',
|
||||
toolGroupId: 'default',
|
||||
// This will specify the initial image options index if it matches in the URL
|
||||
// and will otherwise not specify anything.
|
||||
|
||||
@@ -19,22 +19,24 @@ const reuseCachedLayout = (
|
||||
hangingProtocolService: HangingProtocolService,
|
||||
syncService: StateSyncService
|
||||
): ReturnType => {
|
||||
const { activeViewportIndex, viewports, layout } = state;
|
||||
const { activeViewportId } = state;
|
||||
const { protocol } = hangingProtocolService.getActiveProtocol();
|
||||
const hpInfo = hangingProtocolService.getState();
|
||||
const { protocolId, stageIndex, activeStudyUID } = hpInfo;
|
||||
const { protocol } = hangingProtocolService.getActiveProtocol();
|
||||
|
||||
const syncState = syncService.getState();
|
||||
const viewportGridStore = { ...syncState.viewportGridStore };
|
||||
const displaySetSelectorMap = { ...syncState.displaySetSelectorMap };
|
||||
|
||||
const stage = protocol.stages[stageIndex];
|
||||
const storeId = `${activeStudyUID}:${protocolId}:${stageIndex}`;
|
||||
const syncState = syncService.getState();
|
||||
const cacheId = `${activeStudyUID}:${protocolId}`;
|
||||
const viewportGridStore = { ...syncState.viewportGridStore };
|
||||
const hangingProtocolStageIndexMap = {
|
||||
...syncState.hangingProtocolStageIndexMap,
|
||||
};
|
||||
const displaySetSelectorMap = { ...syncState.displaySetSelectorMap };
|
||||
const { rows, columns } = stage.viewportStructure.properties;
|
||||
const custom =
|
||||
stage.viewports.length !== state.viewports.length ||
|
||||
stage.viewports.length !== state.viewports.size ||
|
||||
state.layout.numRows !== rows ||
|
||||
state.layout.numCols !== columns;
|
||||
|
||||
@@ -44,18 +46,17 @@ const reuseCachedLayout = (
|
||||
viewportGridStore[storeId] = { ...state };
|
||||
}
|
||||
|
||||
for (let idx = 0; idx < state.viewports.length; idx++) {
|
||||
const viewport = state.viewports[idx];
|
||||
state.viewports.forEach((viewport, viewportId) => {
|
||||
const { displaySetOptions, displaySetInstanceUIDs } = viewport;
|
||||
if (!displaySetOptions) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < displaySetOptions.length; i++) {
|
||||
const displaySetUID = displaySetInstanceUIDs[i];
|
||||
if (!displaySetUID) {
|
||||
continue;
|
||||
}
|
||||
if (idx === activeViewportIndex && i === 0) {
|
||||
if (viewportId === activeViewportId && i === 0) {
|
||||
displaySetSelectorMap[
|
||||
`${activeStudyUID}:activeDisplaySet:0`
|
||||
] = displaySetUID;
|
||||
@@ -67,7 +68,7 @@ const reuseCachedLayout = (
|
||||
] = displaySetUID;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
hangingProtocolStageIndexMap,
|
||||
|
||||
@@ -49,12 +49,12 @@ class DicomMicroscopyViewport extends Component {
|
||||
|
||||
static propTypes = {
|
||||
viewportData: PropTypes.object,
|
||||
activeViewportIndex: PropTypes.number,
|
||||
activeViewportId: PropTypes.string,
|
||||
setViewportActive: PropTypes.func,
|
||||
|
||||
// props from OHIF Viewport Grid
|
||||
displaySets: PropTypes.array,
|
||||
viewportIndex: PropTypes.number,
|
||||
viewportId: PropTypes.string,
|
||||
viewportLabel: PropTypes.string,
|
||||
dataSource: PropTypes.object,
|
||||
viewportOptions: PropTypes.object,
|
||||
@@ -230,7 +230,7 @@ class DicomMicroscopyViewport extends Component {
|
||||
|
||||
this.managedViewer = this.microscopyService.addViewer(
|
||||
this.viewer,
|
||||
this.props.viewportIndex,
|
||||
this.props.viewportId,
|
||||
container,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID
|
||||
@@ -259,8 +259,10 @@ class DicomMicroscopyViewport extends Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { displaySets, viewportIndex } = this.props;
|
||||
const displaySet = displaySets[viewportIndex];
|
||||
const { displaySets, viewportOptions } = this.props;
|
||||
const { viewportId } = viewportOptions;
|
||||
// Todo-rename: this is always getting the 0
|
||||
const displaySet = displaySets[0];
|
||||
this.installOpenLayersRenderer(this.container.current, displaySet).then(
|
||||
() => {
|
||||
this.setState({ isLoaded: true });
|
||||
@@ -295,14 +297,10 @@ class DicomMicroscopyViewport extends Component {
|
||||
}
|
||||
|
||||
setViewportActiveHandler = () => {
|
||||
const {
|
||||
setViewportActive,
|
||||
viewportIndex,
|
||||
activeViewportIndex,
|
||||
} = this.props;
|
||||
const { setViewportActive, viewportId, activeViewportId } = this.props;
|
||||
|
||||
if (viewportIndex !== activeViewportIndex) {
|
||||
setViewportActive(viewportIndex);
|
||||
if (viewportId !== activeViewportId) {
|
||||
setViewportActive(viewportId);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ const formatLength = (length, unit) => {
|
||||
|
||||
interface IMicroscopyPanelProps extends WithTranslation {
|
||||
viewports: PropTypes.array;
|
||||
activeViewportIndex: PropTypes.number;
|
||||
activeViewportId: PropTypes.string;
|
||||
|
||||
//
|
||||
onSaveComplete?: PropTypes.func; // callback when successfully saved annotations
|
||||
@@ -83,7 +83,7 @@ function MicroscopyPanel(props: IMicroscopyPanelProps) {
|
||||
const { uiDialogService, displaySetService } = servicesManager.services;
|
||||
|
||||
useEffect(() => {
|
||||
const viewport = props.viewports[props.activeViewportIndex];
|
||||
const viewport = props.viewports[props.activeViewportId];
|
||||
if (viewport.displaySetInstanceUIDs[0]) {
|
||||
const displaySet = displaySetService.getDisplaySetByUID(
|
||||
viewport.displaySetInstanceUIDs[0]
|
||||
@@ -92,7 +92,7 @@ function MicroscopyPanel(props: IMicroscopyPanelProps) {
|
||||
setStudyInstanceUID(displaySet.StudyInstanceUID);
|
||||
}
|
||||
}
|
||||
}, [props.viewports, props.activeViewportIndex]);
|
||||
}, [props.viewports, props.activeViewportId]);
|
||||
|
||||
useEffect(() => {
|
||||
const onAnnotationUpdated = () => {
|
||||
@@ -265,7 +265,7 @@ function MicroscopyPanel(props: IMicroscopyPanelProps) {
|
||||
*/
|
||||
const onDeleteCurrentSRHandler = async () => {
|
||||
try {
|
||||
const activeViewport = props.viewports[props.activeViewportIndex];
|
||||
const activeViewport = props.viewports[props.activeViewportId];
|
||||
const { StudyInstanceUID } = activeViewport;
|
||||
|
||||
// TODO: studies?
|
||||
@@ -307,7 +307,7 @@ function MicroscopyPanel(props: IMicroscopyPanelProps) {
|
||||
const onMeasurementItemClickHandler = ({ uid }: { uid: string }) => {
|
||||
const roiAnnotation = microscopyService.getAnnotation(uid);
|
||||
microscopyService.selectAnnotation(roiAnnotation);
|
||||
microscopyService.focusAnnotation(roiAnnotation, props.activeViewportIndex);
|
||||
microscopyService.focusAnnotation(roiAnnotation, props.activeViewportId);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -122,19 +122,6 @@ export default function getCommandsModule({
|
||||
]);
|
||||
}
|
||||
},
|
||||
|
||||
incrementActiveViewport: () => {
|
||||
const { activeViewportIndex, viewports } = viewportGridService.getState();
|
||||
const nextViewportIndex = (activeViewportIndex + 1) % viewports.length;
|
||||
viewportGridService.setActiveViewportIndex(nextViewportIndex);
|
||||
},
|
||||
decrementActiveViewport: () => {
|
||||
const { activeViewportIndex, viewports } = viewportGridService.getState();
|
||||
const nextViewportIndex =
|
||||
(activeViewportIndex - 1 + viewports.length) % viewports.length;
|
||||
viewportGridService.setActiveViewportIndex(nextViewportIndex);
|
||||
},
|
||||
|
||||
toggleOverlays: () => {
|
||||
// overlay
|
||||
const overlays = document.getElementsByClassName(
|
||||
@@ -149,8 +136,8 @@ export default function getCommandsModule({
|
||||
}
|
||||
|
||||
// overview
|
||||
const { activeViewportIndex, viewports } = viewportGridService.getState();
|
||||
microscopyService.toggleOverviewMap(activeViewportIndex);
|
||||
const { activeViewportId, viewports } = viewportGridService.getState();
|
||||
microscopyService.toggleOverviewMap(activeViewportId);
|
||||
},
|
||||
toggleAnnotations: () => {
|
||||
microscopyService.toggleROIsVisibility();
|
||||
@@ -173,14 +160,6 @@ export default function getCommandsModule({
|
||||
storeContexts: [] as any[],
|
||||
options: {},
|
||||
},
|
||||
incrementActiveViewport: {
|
||||
commandFn: actions.incrementActiveViewport,
|
||||
storeContexts: [] as any[],
|
||||
},
|
||||
decrementActiveViewport: {
|
||||
commandFn: actions.decrementActiveViewport,
|
||||
storeContexts: [] as any[],
|
||||
},
|
||||
toggleOverlays: {
|
||||
commandFn: actions.toggleOverlays,
|
||||
storeContexts: [] as any[],
|
||||
|
||||
@@ -18,15 +18,12 @@ export default function getPanelModule({
|
||||
extensionManager: ExtensionManager;
|
||||
}) {
|
||||
const wrappedMeasurementPanel = () => {
|
||||
const [
|
||||
{ activeViewportIndex, viewports },
|
||||
viewportGridService,
|
||||
] = useViewportGrid();
|
||||
const [{ activeViewportId, viewports }] = useViewportGrid();
|
||||
|
||||
return (
|
||||
<MicroscopyPanel
|
||||
viewports={viewports}
|
||||
activeViewportIndex={activeViewportIndex}
|
||||
activeViewportId={activeViewportId}
|
||||
onSaveComplete={() => {}}
|
||||
onRejectComplete={() => {}}
|
||||
commandsManager={commandsManager}
|
||||
|
||||
@@ -52,7 +52,7 @@ export default {
|
||||
*
|
||||
* @param props {*}
|
||||
* @param props.displaySets
|
||||
* @param props.viewportIndex
|
||||
* @param props.viewportId
|
||||
* @param props.viewportLabel
|
||||
* @param props.dataSource
|
||||
* @param props.viewportOptions
|
||||
@@ -63,16 +63,16 @@ export default {
|
||||
const { viewportOptions } = props;
|
||||
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
const { viewports, activeViewportIndex } = viewportGrid;
|
||||
const { activeViewportId } = viewportGrid;
|
||||
|
||||
return (
|
||||
<MicroscopyViewport
|
||||
servicesManager={servicesManager}
|
||||
extensionManager={extensionManager}
|
||||
commandsManager={commandsManager}
|
||||
activeViewportIndex={activeViewportIndex}
|
||||
setViewportActive={(viewportIndex: number) => {
|
||||
viewportGridService.setActiveViewportIndex(viewportIndex);
|
||||
activeViewportId={activeViewportId}
|
||||
setViewportActive={(viewportId: string) => {
|
||||
viewportGridService.setActiveViewportId(viewportId);
|
||||
}}
|
||||
viewportData={viewportOptions}
|
||||
{...props}
|
||||
|
||||
@@ -286,31 +286,31 @@ export default class MicroscopyService extends PubSubService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a managed viewer instance for the given thrid-party API's viewer.
|
||||
* Creates a managed viewer instance for the given third-party API's viewer.
|
||||
* Restores existing annotations for the given study/series.
|
||||
* Adds event subscriptions for the viewer being added.
|
||||
* Focuses the selected annotation when the viewer is being loaded into the
|
||||
* active viewport.
|
||||
*
|
||||
* @param {Object} viewer Third-party viewer API's object to be managed
|
||||
* @param {Number} viewportIndex The index of the viewport to load the viewer
|
||||
* @param {HTMLElement} container The DOM element where it will be renderd
|
||||
* @param {String} studyInstanceUID The study UID of the loaded image
|
||||
* @param {String} seriesInstanceUID The series UID of the loaded image
|
||||
* @param {Array} displaySets All displaySets related to the same StudyInstanceUID
|
||||
* @param viewer - Third-party viewer API's object to be managed
|
||||
* @param viewportId - The viewport Id where the viewer will be loaded
|
||||
* @param container - The DOM element where it will be rendered
|
||||
* @param studyInstanceUID - The study UID of the loaded image
|
||||
* @param seriesInstanceUID - The series UID of the loaded image
|
||||
* @param displaySets - All displaySets related to the same StudyInstanceUID
|
||||
*
|
||||
* @returns {ViewerManager} managed viewer
|
||||
*/
|
||||
addViewer(
|
||||
viewer,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
container,
|
||||
studyInstanceUID,
|
||||
seriesInstanceUID
|
||||
) {
|
||||
const managedViewer = new ViewerManager(
|
||||
viewer,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
container,
|
||||
studyInstanceUID,
|
||||
seriesInstanceUID
|
||||
@@ -325,7 +325,7 @@ export default class MicroscopyService extends PubSubService {
|
||||
|
||||
if (this.pendingFocus) {
|
||||
this.pendingFocus = false;
|
||||
this.focusAnnotation(this.selectedAnnotation, viewportIndex);
|
||||
this.focusAnnotation(this.selectedAnnotation, viewportId);
|
||||
}
|
||||
|
||||
return managedViewer;
|
||||
@@ -502,13 +502,13 @@ export default class MicroscopyService extends PubSubService {
|
||||
/**
|
||||
* Toggles overview map
|
||||
*
|
||||
* @param viewportIndex The active viewport index
|
||||
* @param viewportId The active viewport index
|
||||
* @returns {void}
|
||||
*/
|
||||
toggleOverviewMap(viewportIndex) {
|
||||
toggleOverviewMap(viewportId) {
|
||||
const managedViewers = Array.from(this.managedViewers);
|
||||
const managedViewer = managedViewers.find(
|
||||
mv => mv.viewportIndex === viewportIndex
|
||||
mv => mv.viewportId === viewportId
|
||||
);
|
||||
if (managedViewer) {
|
||||
managedViewer.toggleOverviewMap();
|
||||
@@ -550,10 +550,10 @@ export default class MicroscopyService extends PubSubService {
|
||||
* the managed viewer instance is created.
|
||||
*
|
||||
* @param {RoiAnnotation} roiAnnotation RoiAnnotation instance to be focused
|
||||
* @param {Number} viewportIndex Index of the viewport to focus
|
||||
* @param {string} viewportId Index of the viewport to focus
|
||||
*/
|
||||
focusAnnotation(roiAnnotation, viewportIndex) {
|
||||
const filter = mv => mv.viewportIndex === viewportIndex;
|
||||
focusAnnotation(roiAnnotation, viewportId) {
|
||||
const filter = mv => mv.viewportId === viewportId;
|
||||
const managedViewer = Array.from(this.managedViewers).find(filter);
|
||||
if (managedViewer) {
|
||||
managedViewer.setViewStateByExtent(roiAnnotation);
|
||||
|
||||
@@ -48,14 +48,14 @@ const EVENTS = {
|
||||
class ViewerManager extends PubSubService {
|
||||
constructor(
|
||||
viewer,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
container,
|
||||
studyInstanceUID,
|
||||
seriesInstanceUID
|
||||
) {
|
||||
super(EVENTS);
|
||||
this.viewer = viewer;
|
||||
this.viewportIndex = viewportIndex;
|
||||
this.viewportId = viewportId;
|
||||
this.container = container;
|
||||
this.studyInstanceUID = studyInstanceUID;
|
||||
this.seriesInstanceUID = seriesInstanceUID;
|
||||
|
||||
+11
-13
@@ -33,7 +33,7 @@ function TrackedMeasurementsContextProvider(
|
||||
const [appConfig] = useAppConfig();
|
||||
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
const { activeViewportIndex, viewports } = viewportGrid;
|
||||
const { activeViewportId, viewports } = viewportGrid;
|
||||
const { measurementService, displaySetService } = servicesManager.services;
|
||||
|
||||
const machineOptions = Object.assign({}, defaultOptions);
|
||||
@@ -49,7 +49,7 @@ function TrackedMeasurementsContextProvider(
|
||||
|
||||
console.log(
|
||||
'jumping to measurement reset viewport',
|
||||
viewportGrid.activeViewportIndex,
|
||||
viewportGrid.activeViewportId,
|
||||
trackedMeasurements[0]
|
||||
);
|
||||
|
||||
@@ -84,7 +84,7 @@ function TrackedMeasurementsContextProvider(
|
||||
}
|
||||
|
||||
viewportGridService.setDisplaySetsForViewport({
|
||||
viewportIndex: viewportGrid.activeViewportIndex,
|
||||
viewportId: viewportGrid.activeViewportId,
|
||||
displaySetInstanceUIDs: [referencedDisplaySetUID],
|
||||
viewportOptions: {
|
||||
initialImageOptions: {
|
||||
@@ -99,7 +99,7 @@ function TrackedMeasurementsContextProvider(
|
||||
evt.data.createdDisplaySetInstanceUIDs[0].displaySetInstanceUID;
|
||||
|
||||
viewportGridService.setDisplaySetsForViewport({
|
||||
viewportIndex: evt.data.viewportIndex,
|
||||
viewportId: evt.data.viewportId,
|
||||
displaySetInstanceUIDs: [StructuredReportDisplaySetInstanceUID],
|
||||
});
|
||||
}
|
||||
@@ -172,16 +172,14 @@ function TrackedMeasurementsContextProvider(
|
||||
machineOptions
|
||||
);
|
||||
|
||||
const [
|
||||
trackedMeasurements,
|
||||
sendTrackedMeasurementsEvent,
|
||||
trackedMeasurementsService,
|
||||
] = useMachine(measurementTrackingMachine);
|
||||
const [trackedMeasurements, sendTrackedMeasurementsEvent] = useMachine(
|
||||
measurementTrackingMachine
|
||||
);
|
||||
|
||||
// ~~ Listen for changes to ViewportGrid for potential SRs hung in panes when idle
|
||||
useEffect(() => {
|
||||
if (viewports.length > 0) {
|
||||
const activeViewport = viewports[activeViewportIndex];
|
||||
if (viewports.size > 0) {
|
||||
const activeViewport = viewports.get(activeViewportId);
|
||||
|
||||
if (!activeViewport || !activeViewport?.displaySetInstanceUIDs?.length) {
|
||||
return;
|
||||
@@ -229,12 +227,12 @@ function TrackedMeasurementsContextProvider(
|
||||
sendTrackedMeasurementsEvent('PROMPT_HYDRATE_SR', {
|
||||
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||
SeriesInstanceUID: displaySet.SeriesInstanceUID,
|
||||
viewportIndex: activeViewportIndex,
|
||||
viewportId: activeViewportId,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [
|
||||
activeViewportIndex,
|
||||
activeViewportId,
|
||||
sendTrackedMeasurementsEvent,
|
||||
servicesManager.services,
|
||||
viewports,
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ function hydrateStructuredReport(
|
||||
evt
|
||||
) {
|
||||
const { displaySetService } = servicesManager.services;
|
||||
const { viewportIndex, displaySetInstanceUID } = evt;
|
||||
const { viewportId, displaySetInstanceUID } = evt;
|
||||
const srDisplaySet = displaySetService.getDisplaySetByUID(
|
||||
displaySetInstanceUID
|
||||
);
|
||||
@@ -23,7 +23,7 @@ function hydrateStructuredReport(
|
||||
resolve({
|
||||
displaySetInstanceUID: evt.displaySetInstanceUID,
|
||||
srSeriesInstanceUID: srDisplaySet.SeriesInstanceUID,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUIDs,
|
||||
});
|
||||
|
||||
+5
-5
@@ -10,24 +10,24 @@ const RESPONSE = {
|
||||
|
||||
function promptBeginTracking({ servicesManager, extensionManager }, ctx, evt) {
|
||||
const { uiViewportDialogService } = servicesManager.services;
|
||||
const { viewportIndex, StudyInstanceUID, SeriesInstanceUID } = evt;
|
||||
const { viewportId, StudyInstanceUID, SeriesInstanceUID } = evt;
|
||||
|
||||
return new Promise(async function(resolve, reject) {
|
||||
let promptResult = await _askTrackMeasurements(
|
||||
uiViewportDialogService,
|
||||
viewportIndex
|
||||
viewportId
|
||||
);
|
||||
|
||||
resolve({
|
||||
userResponse: promptResult,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function _askTrackMeasurements(uiViewportDialogService, viewportIndex) {
|
||||
function _askTrackMeasurements(uiViewportDialogService, viewportId) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const message = 'Track measurements for this series?';
|
||||
const actions = [
|
||||
@@ -56,7 +56,7 @@ function _askTrackMeasurements(uiViewportDialogService, viewportIndex) {
|
||||
};
|
||||
|
||||
uiViewportDialogService.show({
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
id: 'measurement-tracking-prompt-begin-tracking',
|
||||
type: 'info',
|
||||
message,
|
||||
|
||||
+7
-7
@@ -20,15 +20,15 @@ function promptHydrateStructuredReport(
|
||||
uiViewportDialogService,
|
||||
displaySetService,
|
||||
} = servicesManager.services;
|
||||
const { viewportIndex, displaySetInstanceUID } = evt;
|
||||
const { viewportId, displaySetInstanceUID } = evt;
|
||||
const srDisplaySet = displaySetService.getDisplaySetByUID(
|
||||
displaySetInstanceUID
|
||||
);
|
||||
|
||||
return new Promise(async function (resolve, reject) {
|
||||
return new Promise(async function(resolve, reject) {
|
||||
const promptResult = await _askTrackMeasurements(
|
||||
uiViewportDialogService,
|
||||
viewportIndex
|
||||
viewportId
|
||||
);
|
||||
|
||||
// Need to do action here... So we can set state...
|
||||
@@ -49,15 +49,15 @@ function promptHydrateStructuredReport(
|
||||
userResponse: promptResult,
|
||||
displaySetInstanceUID: evt.displaySetInstanceUID,
|
||||
srSeriesInstanceUID: srDisplaySet.SeriesInstanceUID,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUIDs,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function _askTrackMeasurements(uiViewportDialogService, viewportIndex) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
function _askTrackMeasurements(uiViewportDialogService, viewportId) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const message =
|
||||
'Do you want to continue tracking measurements for this study?';
|
||||
const actions = [
|
||||
@@ -78,7 +78,7 @@ function _askTrackMeasurements(uiViewportDialogService, viewportIndex) {
|
||||
};
|
||||
|
||||
uiViewportDialogService.show({
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
type: 'info',
|
||||
message,
|
||||
actions,
|
||||
|
||||
+3
-5
@@ -13,10 +13,8 @@ function promptSaveReport(
|
||||
measurementService,
|
||||
displaySetService,
|
||||
} = servicesManager.services;
|
||||
const viewportIndex =
|
||||
evt.viewportIndex === undefined
|
||||
? evt.data.viewportIndex
|
||||
: evt.viewportIndex;
|
||||
const viewportId =
|
||||
evt.viewportId === undefined ? evt.data.viewportId : evt.viewportId;
|
||||
const isBackupSave =
|
||||
evt.isBackupSave === undefined ? evt.data.isBackupSave : evt.isBackupSave;
|
||||
const StudyInstanceUID = evt?.data?.StudyInstanceUID;
|
||||
@@ -66,7 +64,7 @@ function promptSaveReport(
|
||||
createdDisplaySetInstanceUIDs: displaySetInstanceUIDs,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
isBackupSave,
|
||||
});
|
||||
});
|
||||
|
||||
+8
-8
@@ -11,17 +11,17 @@ const RESPONSE = {
|
||||
|
||||
function promptTrackNewSeries({ servicesManager, extensionManager }, ctx, evt) {
|
||||
const { UIViewportDialogService } = servicesManager.services;
|
||||
const { viewportIndex, StudyInstanceUID, SeriesInstanceUID } = evt;
|
||||
const { viewportId, StudyInstanceUID, SeriesInstanceUID } = evt;
|
||||
|
||||
return new Promise(async function(resolve, reject) {
|
||||
let promptResult = await _askShouldAddMeasurements(
|
||||
UIViewportDialogService,
|
||||
viewportIndex
|
||||
viewportId
|
||||
);
|
||||
|
||||
if (promptResult === RESPONSE.CREATE_REPORT) {
|
||||
promptResult = ctx.isDirty
|
||||
? await _askSaveDiscardOrCancel(UIViewportDialogService, viewportIndex)
|
||||
? await _askSaveDiscardOrCancel(UIViewportDialogService, viewportId)
|
||||
: RESPONSE.SET_STUDY_AND_SERIES;
|
||||
}
|
||||
|
||||
@@ -29,13 +29,13 @@ function promptTrackNewSeries({ servicesManager, extensionManager }, ctx, evt) {
|
||||
userResponse: promptResult,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
isBackupSave: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function _askShouldAddMeasurements(uiViewportDialogService, viewportIndex) {
|
||||
function _askShouldAddMeasurements(uiViewportDialogService, viewportId) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const message =
|
||||
'Do you want to add this measurement to the existing report?';
|
||||
@@ -62,7 +62,7 @@ function _askShouldAddMeasurements(uiViewportDialogService, viewportIndex) {
|
||||
};
|
||||
|
||||
uiViewportDialogService.show({
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
type: 'info',
|
||||
message,
|
||||
actions,
|
||||
@@ -75,7 +75,7 @@ function _askShouldAddMeasurements(uiViewportDialogService, viewportIndex) {
|
||||
});
|
||||
}
|
||||
|
||||
function _askSaveDiscardOrCancel(UIViewportDialogService, viewportIndex) {
|
||||
function _askSaveDiscardOrCancel(UIViewportDialogService, viewportId) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const message =
|
||||
'You have existing tracked measurements. What would you like to do with your existing tracked measurements?';
|
||||
@@ -98,7 +98,7 @@ function _askSaveDiscardOrCancel(UIViewportDialogService, viewportIndex) {
|
||||
};
|
||||
|
||||
UIViewportDialogService.show({
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
type: 'warning',
|
||||
message,
|
||||
actions,
|
||||
|
||||
+8
-8
@@ -9,17 +9,17 @@ const RESPONSE = {
|
||||
|
||||
function promptTrackNewStudy({ servicesManager, extensionManager }, ctx, evt) {
|
||||
const { UIViewportDialogService } = servicesManager.services;
|
||||
const { viewportIndex, StudyInstanceUID, SeriesInstanceUID } = evt;
|
||||
const { viewportId, StudyInstanceUID, SeriesInstanceUID } = evt;
|
||||
|
||||
return new Promise(async function(resolve, reject) {
|
||||
let promptResult = await _askTrackMeasurements(
|
||||
UIViewportDialogService,
|
||||
viewportIndex
|
||||
viewportId
|
||||
);
|
||||
|
||||
if (promptResult === RESPONSE.SET_STUDY_AND_SERIES) {
|
||||
promptResult = ctx.isDirty
|
||||
? await _askSaveDiscardOrCancel(UIViewportDialogService, viewportIndex)
|
||||
? await _askSaveDiscardOrCancel(UIViewportDialogService, viewportId)
|
||||
: RESPONSE.SET_STUDY_AND_SERIES;
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ function promptTrackNewStudy({ servicesManager, extensionManager }, ctx, evt) {
|
||||
userResponse: promptResult,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
isBackupSave: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function _askTrackMeasurements(UIViewportDialogService, viewportIndex) {
|
||||
function _askTrackMeasurements(UIViewportDialogService, viewportId) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const message = 'Track measurements for this series?';
|
||||
const actions = [
|
||||
@@ -55,7 +55,7 @@ function _askTrackMeasurements(UIViewportDialogService, viewportIndex) {
|
||||
};
|
||||
|
||||
UIViewportDialogService.show({
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
type: 'info',
|
||||
message,
|
||||
actions,
|
||||
@@ -68,7 +68,7 @@ function _askTrackMeasurements(UIViewportDialogService, viewportIndex) {
|
||||
});
|
||||
}
|
||||
|
||||
function _askSaveDiscardOrCancel(UIViewportDialogService, viewportIndex) {
|
||||
function _askSaveDiscardOrCancel(UIViewportDialogService, viewportId) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const message =
|
||||
'Measurements cannot span across multiple studies. Do you want to save your tracked measurements?';
|
||||
@@ -91,7 +91,7 @@ function _askSaveDiscardOrCancel(UIViewportDialogService, viewportIndex) {
|
||||
};
|
||||
|
||||
UIViewportDialogService.show({
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
type: 'warning',
|
||||
message,
|
||||
actions,
|
||||
|
||||
@@ -25,7 +25,7 @@ const DISPLAY_STUDY_SUMMARY_INITIAL_VALUE = {
|
||||
};
|
||||
|
||||
function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
const [viewportGrid] = useViewportGrid();
|
||||
const [measurementChangeTimestamp, setMeasurementsUpdated] = useState(
|
||||
Date.now().toString()
|
||||
);
|
||||
@@ -157,7 +157,7 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
||||
}
|
||||
|
||||
const jumpToImage = ({ uid, isActive }) => {
|
||||
measurementService.jumpToMeasurement(viewportGrid.activeViewportIndex, uid);
|
||||
measurementService.jumpToMeasurement(viewportGrid.activeViewportId, uid);
|
||||
|
||||
onMeasurementItemClickHandler({ uid, isActive });
|
||||
};
|
||||
@@ -280,7 +280,7 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
||||
onExportClick={exportReport}
|
||||
onCreateReportClick={() => {
|
||||
sendTrackedMeasurementsEvent('SAVE_REPORT', {
|
||||
viewportIndex: viewportGrid.activeViewportIndex,
|
||||
viewportId: viewportGrid.activeViewportId,
|
||||
isBackupSave: true,
|
||||
});
|
||||
}}
|
||||
|
||||
+18
-19
@@ -40,7 +40,7 @@ function PanelStudyBrowserTracking({
|
||||
// Tabs --> Studies --> DisplaySets --> Thumbnails
|
||||
const { StudyInstanceUIDs } = useImageViewer();
|
||||
const [
|
||||
{ activeViewportIndex, viewports },
|
||||
{ activeViewportId, viewports },
|
||||
viewportGridService,
|
||||
] = useViewportGrid();
|
||||
const [
|
||||
@@ -58,10 +58,10 @@ function PanelStudyBrowserTracking({
|
||||
|
||||
const onDoubleClickThumbnailHandler = displaySetInstanceUID => {
|
||||
let updatedViewports = [];
|
||||
const viewportIndex = activeViewportIndex;
|
||||
const viewportId = activeViewportId;
|
||||
try {
|
||||
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
displaySetInstanceUID
|
||||
);
|
||||
} catch (error) {
|
||||
@@ -78,8 +78,8 @@ function PanelStudyBrowserTracking({
|
||||
viewportGridService.setDisplaySetsForViewports(updatedViewports);
|
||||
};
|
||||
|
||||
const activeViewportDisplaySetInstanceUIDs =
|
||||
viewports[activeViewportIndex]?.displaySetInstanceUIDs;
|
||||
const activeViewportDisplaySetInstanceUIDs = viewports.get(activeViewportId)
|
||||
?.displaySetInstanceUIDs;
|
||||
|
||||
const { trackedSeries } = trackedMeasurements.context;
|
||||
|
||||
@@ -447,20 +447,19 @@ function _mapDisplaySets(
|
||||
const imageSrc = thumbnailImageSrcMap[ds.displaySetInstanceUID];
|
||||
const componentType = _getComponentType(ds);
|
||||
const numPanes = viewportGridService.getNumViewportPanes();
|
||||
const viewportIdentificator =
|
||||
numPanes === 1
|
||||
? []
|
||||
: viewports.reduce((acc, viewportData, index) => {
|
||||
if (
|
||||
index < numPanes &&
|
||||
viewportData?.displaySetInstanceUIDs?.includes(
|
||||
ds.displaySetInstanceUID
|
||||
)
|
||||
) {
|
||||
acc.push(viewportData.viewportLabel);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
const viewportIdentificator = [];
|
||||
|
||||
if (numPanes !== 1) {
|
||||
viewports.forEach(viewportData => {
|
||||
if (
|
||||
viewportData?.displaySetInstanceUIDs?.includes(
|
||||
ds.displaySetInstanceUID
|
||||
)
|
||||
) {
|
||||
viewportIdentificator.push(viewportData.viewportLabel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const array =
|
||||
componentType === 'thumbnailTracked'
|
||||
|
||||
@@ -15,11 +15,10 @@ const { formatDate } = utils;
|
||||
function TrackedCornerstoneViewport(props) {
|
||||
const {
|
||||
displaySets,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
viewportLabel,
|
||||
servicesManager,
|
||||
extensionManager,
|
||||
viewportOptions,
|
||||
} = props;
|
||||
|
||||
const { t } = useTranslation('Common');
|
||||
@@ -43,7 +42,6 @@ function TrackedCornerstoneViewport(props) {
|
||||
const [viewportElem, setViewportElem] = useState(null);
|
||||
|
||||
const { trackedSeries } = trackedMeasurements.context;
|
||||
const viewportId = viewportOptions.viewportId;
|
||||
|
||||
const {
|
||||
SeriesDate,
|
||||
@@ -64,8 +62,8 @@ function TrackedCornerstoneViewport(props) {
|
||||
} = displaySet.images[0];
|
||||
|
||||
const updateIsTracked = useCallback(() => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewportByIndex(
|
||||
viewportIndex
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(
|
||||
viewportId
|
||||
);
|
||||
|
||||
if (viewport instanceof BaseVolumeViewport) {
|
||||
@@ -84,7 +82,7 @@ function TrackedCornerstoneViewport(props) {
|
||||
if (trackedSeries.includes(SeriesInstanceUID) !== isTracked) {
|
||||
setIsTracked(!isTracked);
|
||||
}
|
||||
}, [isTracked, trackedMeasurements, viewportIndex, SeriesInstanceUID]);
|
||||
}, [isTracked, trackedMeasurements, viewportId, SeriesInstanceUID]);
|
||||
|
||||
const onElementEnabled = useCallback(
|
||||
evt => {
|
||||
@@ -113,7 +111,7 @@ function TrackedCornerstoneViewport(props) {
|
||||
const { unsubscribe } = cornerstoneViewportService.subscribe(
|
||||
cornerstoneViewportService.EVENTS.VIEWPORT_DATA_CHANGED,
|
||||
props => {
|
||||
if (props.viewportIndex !== viewportIndex) {
|
||||
if (props.viewportId !== viewportId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -124,7 +122,7 @@ function TrackedCornerstoneViewport(props) {
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, [updateIsTracked, viewportIndex]);
|
||||
}, [updateIsTracked, viewportId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isTracked) {
|
||||
@@ -169,12 +167,12 @@ function TrackedCornerstoneViewport(props) {
|
||||
[added, addedRaw].forEach(evt => {
|
||||
subscriptions.push(
|
||||
measurementService.subscribe(evt, ({ source, measurement }) => {
|
||||
const { activeViewportIndex } = viewportGridService.getState();
|
||||
const { activeViewportId } = viewportGridService.getState();
|
||||
|
||||
// Each TrackedCornerstoneViewport receives the MeasurementService's events.
|
||||
// Only send the tracked measurements event for the active viewport to avoid
|
||||
// sending it more than once.
|
||||
if (viewportIndex === activeViewportIndex) {
|
||||
if (viewportId === activeViewportId) {
|
||||
const {
|
||||
referenceStudyUID: StudyInstanceUID,
|
||||
referenceSeriesUID: SeriesInstanceUID,
|
||||
@@ -182,7 +180,7 @@ function TrackedCornerstoneViewport(props) {
|
||||
|
||||
sendTrackedMeasurementsEvent('SET_DIRTY', { SeriesInstanceUID });
|
||||
sendTrackedMeasurementsEvent('TRACK_SERIES', {
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
});
|
||||
@@ -199,7 +197,7 @@ function TrackedCornerstoneViewport(props) {
|
||||
}, [
|
||||
measurementService,
|
||||
sendTrackedMeasurementsEvent,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
viewportGridService,
|
||||
]);
|
||||
|
||||
@@ -217,10 +215,7 @@ function TrackedCornerstoneViewport(props) {
|
||||
|
||||
setTrackedMeasurementUID(newTrackedMeasurementUID);
|
||||
|
||||
measurementService.jumpToMeasurement(
|
||||
viewportIndex,
|
||||
newTrackedMeasurementUID
|
||||
);
|
||||
measurementService.jumpToMeasurement(viewportId, newTrackedMeasurementUID);
|
||||
}
|
||||
|
||||
const getCornerstoneViewport = () => {
|
||||
@@ -280,7 +275,7 @@ function TrackedCornerstoneViewport(props) {
|
||||
|
||||
TrackedCornerstoneViewport.propTypes = {
|
||||
displaySets: PropTypes.arrayOf(PropTypes.object.isRequired).isRequired,
|
||||
viewportIndex: PropTypes.number.isRequired,
|
||||
viewportId: PropTypes.string.isRequired,
|
||||
dataSource: PropTypes.object,
|
||||
children: PropTypes.node,
|
||||
customProps: PropTypes.object,
|
||||
@@ -299,10 +294,10 @@ function _getNextMeasurementUID(
|
||||
const { measurementService, viewportGridService } = servicesManager.services;
|
||||
const measurements = measurementService.getMeasurements();
|
||||
|
||||
const { activeViewportIndex, viewports } = viewportGridService.getState();
|
||||
const { activeViewportId, viewports } = viewportGridService.getState();
|
||||
const {
|
||||
displaySetInstanceUIDs: activeViewportDisplaySetInstanceUIDs,
|
||||
} = viewports[activeViewportIndex];
|
||||
} = viewports.get(activeViewportId);
|
||||
|
||||
const { trackedSeries } = trackedMeasurements.context;
|
||||
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
import { Types } from '@ohif/core';
|
||||
|
||||
const viewport0a = {
|
||||
viewportOptions: {
|
||||
viewportId: 'viewportA',
|
||||
toolGroupId: 'default',
|
||||
allowUnmatchedView: true,
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
id: 'defaultDisplaySetId',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const viewport1b = {
|
||||
viewportOptions: {
|
||||
viewportId: 'viewportB',
|
||||
toolGroupId: 'default',
|
||||
allowUnmatchedView: true,
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
matchedDisplaySetsIndex: 1,
|
||||
id: 'defaultDisplaySetId',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const viewport2c = {
|
||||
viewportOptions: {
|
||||
viewportId: 'viewportC',
|
||||
toolGroupId: 'default',
|
||||
allowUnmatchedView: true,
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
matchedDisplaySetsIndex: 2,
|
||||
id: 'defaultDisplaySetId',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const viewport3d = {
|
||||
viewportOptions: {
|
||||
viewportId: 'viewportD',
|
||||
toolGroupId: 'default',
|
||||
allowUnmatchedView: true,
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
matchedDisplaySetsIndex: 3,
|
||||
id: 'defaultDisplaySetId',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const viewport4e = {
|
||||
viewportOptions: {
|
||||
viewportId: 'viewportE',
|
||||
toolGroupId: 'default',
|
||||
allowUnmatchedView: true,
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
matchedDisplaySetsIndex: 4,
|
||||
id: 'defaultDisplaySetId',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const viewport5f = {
|
||||
viewportOptions: {
|
||||
viewportId: 'viewportF',
|
||||
toolGroupId: 'default',
|
||||
allowUnmatchedView: true,
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
matchedDisplaySetsIndex: 5,
|
||||
id: 'defaultDisplaySetId',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const viewport3a = {
|
||||
viewportOptions: {
|
||||
viewportId: 'viewportA',
|
||||
toolGroupId: 'default',
|
||||
allowUnmatchedView: true,
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
matchedDisplaySetsIndex: 3,
|
||||
id: 'defaultDisplaySetId',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const viewport2b = {
|
||||
viewportOptions: {
|
||||
viewportId: 'viewportB',
|
||||
toolGroupId: 'default',
|
||||
allowUnmatchedView: true,
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
matchedDisplaySetsIndex: 2,
|
||||
id: 'defaultDisplaySetId',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const viewport1c = {
|
||||
viewportOptions: {
|
||||
viewportId: 'viewportC',
|
||||
toolGroupId: 'default',
|
||||
allowUnmatchedView: true,
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
matchedDisplaySetsIndex: 1,
|
||||
id: 'defaultDisplaySetId',
|
||||
},
|
||||
],
|
||||
};
|
||||
const viewport0d = {
|
||||
viewportOptions: {
|
||||
viewportId: 'viewportD',
|
||||
toolGroupId: 'default',
|
||||
allowUnmatchedView: true,
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
matchedDisplaySetsIndex: 0,
|
||||
id: 'defaultDisplaySetId',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const viewportStructure = {
|
||||
layoutType: 'grid',
|
||||
properties: {
|
||||
rows: 2,
|
||||
columns: 2,
|
||||
},
|
||||
};
|
||||
|
||||
const viewportStructure32 = {
|
||||
layoutType: 'grid',
|
||||
properties: {
|
||||
rows: 2,
|
||||
columns: 3,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* This hanging protocol is a test hanging protocol used to apply various
|
||||
* layouts in different positions for display, re-using earlier names in
|
||||
* various orders.
|
||||
*/
|
||||
const hpTestSwitch: Types.HangingProtocol.Protocol = {
|
||||
hasUpdatedPriorsInformation: false,
|
||||
id: '@ohif/mnTestSwitch',
|
||||
description: 'Has various hanging protocol grid layouts',
|
||||
name: 'Test Switch',
|
||||
protocolMatchingRules: [
|
||||
{
|
||||
id: 'OneOrMoreSeries',
|
||||
weight: 25,
|
||||
attribute: 'numberOfDisplaySetsWithImages',
|
||||
constraint: {
|
||||
greaterThan: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
toolGroupIds: ['default'],
|
||||
displaySetSelectors: {
|
||||
defaultDisplaySetId: {
|
||||
seriesMatchingRules: [
|
||||
{
|
||||
attribute: 'numImageFrames',
|
||||
constraint: {
|
||||
greaterThan: { value: 0 },
|
||||
},
|
||||
},
|
||||
// This display set will select the specified items by preference
|
||||
// It has no affect if nothing is specified in the URL.
|
||||
{
|
||||
attribute: 'isDisplaySetFromUrl',
|
||||
weight: 10,
|
||||
constraint: {
|
||||
equals: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
defaultViewport: {
|
||||
viewportOptions: {
|
||||
viewportType: 'stack',
|
||||
toolGroupId: 'default',
|
||||
allowUnmatchedView: true,
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
id: 'defaultDisplaySetId',
|
||||
matchedDisplaySetsIndex: -1,
|
||||
},
|
||||
],
|
||||
},
|
||||
stages: [
|
||||
{
|
||||
name: '2x2 0a1b2c3d',
|
||||
viewportStructure,
|
||||
viewports: [viewport0a, viewport1b, viewport2c, viewport3d],
|
||||
},
|
||||
{
|
||||
name: '3x2 0a1b4e2c3d5f',
|
||||
viewportStructure: viewportStructure32,
|
||||
// Note the following structure simply preserves the viewportId for
|
||||
// a given screen position
|
||||
viewports: [
|
||||
viewport0a,
|
||||
viewport1b,
|
||||
viewport4e,
|
||||
viewport2c,
|
||||
viewport3d,
|
||||
viewport5f,
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '2x2 1c0d3a2b',
|
||||
viewportStructure,
|
||||
viewports: [viewport1c, viewport0d, viewport3a, viewport2b],
|
||||
},
|
||||
{
|
||||
name: '2x2 3a2b1c0d',
|
||||
viewportStructure,
|
||||
viewports: [viewport3a, viewport2b, viewport1c, viewport0d],
|
||||
},
|
||||
],
|
||||
numberOfPriorsReferenced: -1,
|
||||
};
|
||||
|
||||
export default hpTestSwitch;
|
||||
@@ -2,6 +2,8 @@ import { Types } from '@ohif/core';
|
||||
|
||||
import { id } from './id';
|
||||
|
||||
import hpTestSwitch from './hpTestSwitch';
|
||||
|
||||
import getCustomizationModule from './getCustomizationModule';
|
||||
// import {setViewportZoomPan, storeViewportZoomPan } from './custom-viewport/setViewportZoomPan';
|
||||
import sameAs from './custom-attribute/sameAs';
|
||||
@@ -47,6 +49,16 @@ const testExtension: Types.Extensions.Extension = {
|
||||
|
||||
/** Registers some customizations */
|
||||
getCustomizationModule,
|
||||
|
||||
getHangingProtocolModule: () => {
|
||||
return [
|
||||
// Create a MxN hanging protocol available by default
|
||||
{
|
||||
name: hpTestSwitch.id,
|
||||
protocol: hpTestSwitch,
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
export default testExtension;
|
||||
@@ -36,8 +36,8 @@ const commandsModule = ({
|
||||
const { getEnabledElement } = utilityModule.exports;
|
||||
|
||||
function _getActiveViewportsEnabledElement() {
|
||||
const { activeViewportIndex } = viewportGridService.getState();
|
||||
const { element } = getEnabledElement(activeViewportIndex) || {};
|
||||
const { activeViewportId } = viewportGridService.getState();
|
||||
const { element } = getEnabledElement(activeViewportId) || {};
|
||||
const enabledElement = cs.getEnabledElement(element);
|
||||
return enabledElement;
|
||||
}
|
||||
@@ -45,8 +45,8 @@ const commandsModule = ({
|
||||
function _getMatchedViewportsToolGroupIds() {
|
||||
const { viewportMatchDetails } = hangingProtocolService.getMatchDetails();
|
||||
const toolGroupIds = [];
|
||||
viewportMatchDetails.forEach((value, key) => {
|
||||
const { viewportOptions } = value;
|
||||
viewportMatchDetails.forEach(viewport => {
|
||||
const { viewportOptions } = viewport;
|
||||
const { toolGroupId } = viewportOptions;
|
||||
if (toolGroupIds.indexOf(toolGroupId) === -1) {
|
||||
toolGroupIds.push(toolGroupId);
|
||||
@@ -64,7 +64,7 @@ const commandsModule = ({
|
||||
// corrected PT vs the non-attenuation correct PT)
|
||||
|
||||
let ptDisplaySet = null;
|
||||
for (const [viewportIndex, viewportDetails] of viewportMatchDetails) {
|
||||
for (const [viewportId, viewportDetails] of viewportMatchDetails) {
|
||||
const { displaySetsInfo } = viewportDetails;
|
||||
const displaySets = displaySetsInfo.map(({ displaySetInstanceUID }) =>
|
||||
displaySetService.getDisplaySetByUID(displaySetInstanceUID)
|
||||
@@ -137,7 +137,6 @@ const commandsModule = ({
|
||||
|
||||
// Add Segmentation to all toolGroupIds in the viewer
|
||||
const toolGroupIds = _getMatchedViewportsToolGroupIds();
|
||||
|
||||
const representationType = LABELMAP;
|
||||
|
||||
for (const toolGroupId of toolGroupIds) {
|
||||
@@ -545,13 +544,8 @@ const commandsModule = ({
|
||||
|
||||
let viewports = [];
|
||||
fusionViewportIds.forEach(viewportId => {
|
||||
const viewportInfo = cornerstoneViewportService.getViewportInfo(
|
||||
viewportId
|
||||
);
|
||||
|
||||
const viewportIndex = viewportInfo.getViewportIndex();
|
||||
commandsManager.runCommand('setViewportColormap', {
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
displaySetInstanceUID: ptDisplaySet.displaySetInstanceUID,
|
||||
colormap: {
|
||||
name: colormap,
|
||||
|
||||
@@ -114,6 +114,9 @@ const ptAXIAL = {
|
||||
id: 'ptFusionWLSync',
|
||||
source: true,
|
||||
target: false,
|
||||
options: {
|
||||
syncInvertState: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -155,6 +158,9 @@ const ptSAGITTAL = {
|
||||
id: 'ptFusionWLSync',
|
||||
source: true,
|
||||
target: false,
|
||||
options: {
|
||||
syncInvertState: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -196,6 +202,9 @@ const ptCORONAL = {
|
||||
id: 'ptFusionWLSync',
|
||||
source: true,
|
||||
target: false,
|
||||
options: {
|
||||
syncInvertState: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -246,6 +255,9 @@ const fusionAXIAL = {
|
||||
id: 'ptFusionWLSync',
|
||||
source: false,
|
||||
target: true,
|
||||
options: {
|
||||
syncInvertState: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -306,6 +318,9 @@ const fusionSAGITTAL = {
|
||||
id: 'ptFusionWLSync',
|
||||
source: false,
|
||||
target: true,
|
||||
options: {
|
||||
syncInvertState: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -366,6 +381,9 @@ const fusionCORONAL = {
|
||||
id: 'ptFusionWLSync',
|
||||
source: false,
|
||||
target: true,
|
||||
options: {
|
||||
syncInvertState: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -411,6 +429,9 @@ const mipSAGITTAL = {
|
||||
id: 'ptFusionWLSync',
|
||||
source: true,
|
||||
target: false,
|
||||
options: {
|
||||
syncInvertState: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
|
||||
Reference in new issue
Block a user