fix(state synchronization): SEG and RT viewports should keep their before hydration voi (#3560)

This commit is contained in:
Alireza authored and GitHub committed 2023-08-09 08:08:23 -04:00
1 parent 4f037ae55e
commit 8adf663248
12 files changed
+140 -43

No files matched your search

@@ -36,12 +36,14 @@ const extension: Types.Extensions.Extension = {
getViewportModule({
servicesManager,
extensionManager,
commandsManager,
}: Types.Extensions.ExtensionParams) {
const ExtendedOHIFCornerstoneRTViewport = props => {
return (
<OHIFCornerstoneRTViewport
servicesManager={servicesManager}
extensionManager={extensionManager}
commandsManager={commandsManager}
{...props}
/>
);
@@ -12,6 +12,7 @@ function promptHydrateRT({
rtDisplaySet,
viewportIndex,
toolGroupId = 'default',
preHydrateCallbacks,
}) {
const { uiViewportDialogService } = servicesManager.services;
@@ -22,6 +23,10 @@ function promptHydrateRT({
);
if (promptResult === RESPONSE.HYDRATE_SEG) {
preHydrateCallbacks?.forEach(callback => {
callback();
});
const isHydrated = await hydrateRTDisplaySet({
rtDisplaySet,
viewportIndex,
@@ -25,6 +25,7 @@ function OHIFCornerstoneRTViewport(props) {
viewportLabel,
servicesManager,
extensionManager,
commandsManager,
} = props;
const {
@@ -91,6 +92,14 @@ function OHIFCornerstoneRTViewport(props) {
setElement(null);
};
const storePresentationState = useCallback(() => {
viewportGrid?.viewports.forEach(({ viewportIndex }) => {
commandsManager.runCommand('storePresentation', {
viewportIndex,
});
});
}, [viewportGrid]);
const getCornerstoneViewport = useCallback(() => {
const { component: Component } = extensionManager.getModuleEntry(
'@ohif/extension-cornerstone.viewportModule.cornerstone'
@@ -155,6 +164,7 @@ function OHIFCornerstoneRTViewport(props) {
servicesManager,
viewportIndex,
rtDisplaySet,
preHydrateCallbacks: [storePresentationState],
}).then(isHydrated => {
if (isHydrated) {
setIsHydrated(true);
@@ -303,6 +313,13 @@ function OHIFCornerstoneRTViewport(props) {
} = referencedDisplaySetRef.current.metadata;
const onStatusClick = async () => {
// Before hydrating a RT and make it added to all viewports in the grid
// that share the same frameOfReferenceUID, we need to store the viewport grid
// presentation state, so that we can restore it after hydrating the RT. This is
// required if the user has changed the viewport (other viewport than RT viewport)
// presentation state (w/l and invert) and then opens the RT. If we don't store
// the presentation state, the viewport will be reset to the default presentation
storePresentationState();
const isHydrated = await _hydrateRTDisplaySet({
rtDisplaySet,
viewportIndex,
@@ -69,6 +69,7 @@ const extension = {
<OHIFCornerstoneSEGViewport
servicesManager={servicesManager}
extensionManager={extensionManager}
commandsManager={commandsManager}
{...props}
/>
);
@@ -88,4 +89,4 @@ const extension = {
getHangingProtocolModule,
};
export default extension;
export default extension;
@@ -7,7 +7,12 @@ const RESPONSE = {
HYDRATE_SEG: 5,
};
function promptHydrateSEG({ servicesManager, segDisplaySet, viewportIndex }) {
function promptHydrateSEG({
servicesManager,
segDisplaySet,
viewportIndex,
preHydrateCallbacks,
}) {
const { uiViewportDialogService } = servicesManager.services;
return new Promise(async function(resolve, reject) {
@@ -17,6 +22,10 @@ function promptHydrateSEG({ servicesManager, segDisplaySet, viewportIndex }) {
);
if (promptResult === RESPONSE.HYDRATE_SEG) {
preHydrateCallbacks?.forEach(callback => {
callback();
});
const isHydrated = await hydrateSEGDisplaySet({
segDisplaySet,
viewportIndex,
@@ -24,6 +24,7 @@ function OHIFCornerstoneSEGViewport(props) {
viewportLabel,
servicesManager,
extensionManager,
commandsManager,
} = props;
const { t } = useTranslation('SEGViewport');
@@ -48,7 +49,6 @@ function OHIFCornerstoneSEGViewport(props) {
const [viewportGrid, viewportGridService] = useViewportGrid();
// States
const [isToolGroupCreated, setToolGroupCreated] = useState(false);
const [selectedSegment, setSelectedSegment] = useState(1);
// Hydration means that the SEG is opened and segments are loaded into the
@@ -93,6 +93,14 @@ function OHIFCornerstoneSEGViewport(props) {
setElement(null);
};
const storePresentationState = useCallback(() => {
viewportGrid?.viewports.forEach(({ viewportIndex }) => {
commandsManager.runCommand('storePresentation', {
viewportIndex,
});
});
}, [viewportGrid]);
const getCornerstoneViewport = useCallback(() => {
const { component: Component } = extensionManager.getModuleEntry(
'@ohif/extension-cornerstone.viewportModule.cornerstone'
@@ -159,6 +167,7 @@ function OHIFCornerstoneSEGViewport(props) {
servicesManager,
viewportIndex,
segDisplaySet,
preHydrateCallbacks: [storePresentationState],
}).then(isHydrated => {
if (isHydrated) {
setIsHydrated(true);
@@ -248,8 +257,6 @@ function OHIFCornerstoneSEGViewport(props) {
toolGroupId
);
setToolGroupCreated(true);
return () => {
// remove the segmentation representations if seg displayset changed
segmentationService.removeSegmentationRepresentationFromToolGroup(
@@ -309,6 +316,13 @@ function OHIFCornerstoneSEGViewport(props) {
} = referencedDisplaySetRef.current.metadata;
const onStatusClick = async () => {
// Before hydrating a SEG and make it added to all viewports in the grid
// that share the same frameOfReferenceUID, we need to store the viewport grid
// presentation state, so that we can restore it after hydrating the SEG. This is
// required if the user has changed the viewport (other viewport than SEG viewport)
// presentation state (w/l and invert) and then opens the SEG. If we don't store
// the presentation state, the viewport will be reset to the default presentation
storePresentationState();
const isHydrated = await hydrateSEGDisplaySet({
segDisplaySet,
viewportIndex,
@@ -112,6 +112,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
viewportOptions,
displaySetOptions,
servicesManager,
commandsManager,
onElementEnabled,
onElementDisabled,
isJumpToMeasurementDisabled,
@@ -152,33 +153,6 @@ const OHIFCornerstoneViewport = React.memo(props => {
}
}, [elementRef]);
const storePresentation = () => {
const currentPresentation = cornerstoneViewportService.getPresentation(
viewportIndex
);
if (!currentPresentation || !currentPresentation.presentationIds) return;
const {
lutPresentationStore,
positionPresentationStore,
} = stateSyncService.getState();
const { presentationIds } = currentPresentation;
const { lutPresentationId, positionPresentationId } = presentationIds || {};
const storeState = {};
if (lutPresentationId) {
storeState.lutPresentationStore = {
...lutPresentationStore,
[lutPresentationId]: currentPresentation,
};
}
if (positionPresentationId) {
storeState.positionPresentationStore = {
...positionPresentationStore,
[positionPresentationId]: currentPresentation,
};
}
stateSyncService.store(storeState);
};
const cleanUpServices = useCallback(() => {
const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(
viewportIndex
@@ -256,7 +230,9 @@ const OHIFCornerstoneViewport = React.memo(props => {
setImageScrollBarHeight();
return () => {
storePresentation();
commandsManager.runCommand('storePresentation', {
viewportIndex,
});
cleanUpServices();
@@ -407,8 +383,6 @@ const OHIFCornerstoneViewport = React.memo(props => {
};
}, [displaySets, elementRef, viewportIndex]);
console.debug('OHIFCornerstoneViewport rendering');
return (
<React.Fragment>
<div className="viewport-wrapper">
@@ -28,6 +28,7 @@ function commandsModule({
toolGroupService,
cineService,
toolbarService,
stateSyncService,
uiDialogService,
cornerstoneViewportService,
uiNotificationService,
@@ -616,6 +617,35 @@ 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);
},
};
const definitions = {
@@ -740,6 +770,11 @@ function commandsModule({
toggleReferenceLines: {
commandFn: actions.toggleReferenceLines,
},
storePresentation: {
commandFn: actions.storePresentation,
storeContexts: [],
options: {},
},
};
return {