fix(microscopy): Prevent measurement clearing on viewport resize (#5796)
Wrap DicomMicroscopyViewport with React.memo and custom areEqual to prevent unnecessary re-renders that trigger clearAnnotations(). --------- Co-authored-by: Joe Boccanfuso <joe.boccanfuso@radicalimaging.com>
This commit is contained in:
parent
7cdc54c86d
commit
baef707e46
@ -7,21 +7,27 @@ import getDicomWebClient from './utils/dicomWebClient';
|
|||||||
import dcmjs from 'dcmjs';
|
import dcmjs from 'dcmjs';
|
||||||
import { useSystem } from '@ohif/core';
|
import { useSystem } from '@ohif/core';
|
||||||
|
|
||||||
function DicomMicroscopyViewport({
|
// This component is wrapped with React.memo and uses a custom areEqual comparison
|
||||||
|
// function to prevent unnecessary re-renders when props are semantically identical
|
||||||
|
// (e.g. `displaySets` reference changes, but the content is the same).
|
||||||
|
// Note: If this component starts depending on additional props,
|
||||||
|
// update `areEqual` accordingly.
|
||||||
|
const DicomMicroscopyViewport = React.memo(
|
||||||
|
({
|
||||||
activeViewportId,
|
activeViewportId,
|
||||||
setViewportActive,
|
setViewportActive,
|
||||||
displaySets,
|
displaySets,
|
||||||
viewportId,
|
viewportId,
|
||||||
dataSource,
|
dataSource,
|
||||||
resizeRef,
|
resizeRef,
|
||||||
}: {
|
}: {
|
||||||
activeViewportId: string;
|
activeViewportId: string;
|
||||||
setViewportActive: Function;
|
setViewportActive: Function;
|
||||||
displaySets: any[];
|
displaySets: any[];
|
||||||
viewportId: string;
|
viewportId: string;
|
||||||
dataSource: any;
|
dataSource: any;
|
||||||
resizeRef: any;
|
resizeRef: any;
|
||||||
}) {
|
}) => {
|
||||||
const { servicesManager, extensionManager } = useSystem();
|
const { servicesManager, extensionManager } = useSystem();
|
||||||
const [isLoaded, setIsLoaded] = useState(false);
|
const [isLoaded, setIsLoaded] = useState(false);
|
||||||
const [viewer, setViewer] = useState(null);
|
const [viewer, setViewer] = useState(null);
|
||||||
@ -181,24 +187,27 @@ function DicomMicroscopyViewport({
|
|||||||
await loadViewer(smDisplaySet.others);
|
await loadViewer(smDisplaySet.others);
|
||||||
|
|
||||||
if (displaySet.isOverlayDisplaySet && !displaySet.isLoaded && !displaySet.isLoading) {
|
if (displaySet.isOverlayDisplaySet && !displaySet.isLoaded && !displaySet.isLoading) {
|
||||||
displaySet.load(smDisplaySet);
|
const referencedDisplaySet = displaySet.getSourceDisplaySet();
|
||||||
|
displaySet.load(referencedDisplaySet);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[dataSource, extensionManager, microscopyService, servicesManager, viewportId]
|
[dataSource, extensionManager, microscopyService, servicesManager, viewportId]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!viewer) {
|
||||||
const displaySet = displaySets[0];
|
const displaySet = displaySets[0];
|
||||||
installOpenLayersRenderer(container.current, displaySet).then(() => {
|
installOpenLayersRenderer(container.current, displaySet).then(() => {
|
||||||
setIsLoaded(true);
|
setIsLoaded(true);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (viewer) {
|
if (viewer) {
|
||||||
microscopyService.removeViewer(viewer);
|
microscopyService.removeViewer(viewer);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, []);
|
}, [viewer]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const displaySet = displaySets[0];
|
const displaySet = displaySets[0];
|
||||||
@ -253,6 +262,69 @@ function DicomMicroscopyViewport({
|
|||||||
{isLoaded ? null : <LoadingIndicatorProgress className={'h-full w-full bg-black'} />}
|
{isLoaded ? null : <LoadingIndicatorProgress className={'h-full w-full bg-black'} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
areEqual
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if the props are the same
|
||||||
|
function areEqual(prevProps, nextProps) {
|
||||||
|
if (prevProps.setViewportActive !== nextProps.setViewportActive) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevProps.resizeRef !== nextProps.resizeRef) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevProps.viewportId !== nextProps.viewportId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevProps.activeViewportId !== nextProps.activeViewportId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevProps.dataSource !== nextProps.dataSource) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prevDisplaySets = prevProps.displaySets;
|
||||||
|
const nextDisplaySets = nextProps.displaySets;
|
||||||
|
|
||||||
|
if (prevDisplaySets.length !== nextDisplaySets.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the displaySets are the same
|
||||||
|
for (let i = 0; i < prevDisplaySets.length; i++) {
|
||||||
|
const prevDisplaySet = prevDisplaySets[i];
|
||||||
|
|
||||||
|
const foundDisplaySet = nextDisplaySets.find(
|
||||||
|
nextDisplaySet =>
|
||||||
|
nextDisplaySet.displaySetInstanceUID === prevDisplaySet.displaySetInstanceUID
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!foundDisplaySet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Check if the displaySet's images are the same
|
||||||
|
if (foundDisplaySet.images?.length !== prevDisplaySet.images?.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the displaySet's imageIds are the same
|
||||||
|
if (foundDisplaySet.images?.length) {
|
||||||
|
for (let j = 0; j < foundDisplaySet.images.length; j++) {
|
||||||
|
if (foundDisplaySet.images[j].imageId !== prevDisplaySet.images[j].imageId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DicomMicroscopyViewport.displayName = 'DicomMicroscopyViewport';
|
||||||
|
|
||||||
export default DicomMicroscopyViewport;
|
export default DicomMicroscopyViewport;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { id } from './id';
|
import { id } from './id';
|
||||||
import React, { Suspense, useMemo } from 'react';
|
import React, { Suspense, useCallback, useMemo } from 'react';
|
||||||
import getPanelModule from './getPanelModule';
|
import getPanelModule from './getPanelModule';
|
||||||
import getCommandsModule from './getCommandsModule';
|
import getCommandsModule from './getCommandsModule';
|
||||||
import getCustomizationModule from './getCustomizationModule';
|
import getCustomizationModule from './getCustomizationModule';
|
||||||
@ -81,13 +81,18 @@ const extension: Types.Extensions.Extension = {
|
|||||||
handleWidth: true,
|
handleWidth: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const setViewportActive = useCallback(
|
||||||
|
(viewportId: string) => {
|
||||||
|
viewportGridService.setActiveViewportId(viewportId);
|
||||||
|
},
|
||||||
|
[viewportGridService]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MicroscopyViewport
|
<MicroscopyViewport
|
||||||
key={displaySetsKey}
|
key={displaySetsKey}
|
||||||
activeViewportId={activeViewportId}
|
activeViewportId={activeViewportId}
|
||||||
setViewportActive={(viewportId: string) => {
|
setViewportActive={setViewportActive}
|
||||||
viewportGridService.setActiveViewportId(viewportId);
|
|
||||||
}}
|
|
||||||
viewportData={viewportOptions}
|
viewportData={viewportOptions}
|
||||||
resizeRef={resizeRef}
|
resizeRef={resizeRef}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user