fix(viewports): The display of linked viewports during drag and drop has a race (#3286)
* fix: The display of linked viewports during drag and drop has a race * PR review comments * fix: Segmentation display two up * Removing console logs * Fix the blank viewport can have stuff added to it * Fix the null name on HP module * Fix the navigate to initial image * Fix the nth interleave loader * Fix the unit tests * PR comments - docs mostly * fix: Exception thrown on change displayset after double click
This commit is contained in:
1 parent
ca3b83b2b6
commit
5e42a42b5f
13 files changed
+215
-195
No files matched your search
@@ -10,7 +10,6 @@ import {
|
||||
utilities as csUtils,
|
||||
CONSTANTS,
|
||||
} from '@cornerstonejs/core';
|
||||
import { Services } from '@ohif/core';
|
||||
|
||||
import { setEnabledElement } from '../state';
|
||||
|
||||
@@ -23,9 +22,6 @@ import {
|
||||
import getSOPInstanceAttributes from '../utils/measurementServiceMappings/utils/getSOPInstanceAttributes';
|
||||
import { CinePlayer, useCine, useViewportGrid } from '@ohif/ui';
|
||||
|
||||
import { CornerstoneViewportService } from '../services/ViewportService/CornerstoneViewportService';
|
||||
import Presentation from '../types/Presentation';
|
||||
|
||||
const STACK = 'stack';
|
||||
|
||||
function areEqual(prevProps, nextProps) {
|
||||
@@ -407,7 +403,6 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
lutPresentation:
|
||||
lutPresentationStore[presentationIds?.lutPresentationId],
|
||||
};
|
||||
console.log('Using presentations', presentations);
|
||||
|
||||
cornerstoneViewportService.setViewportData(
|
||||
viewportIndex,
|
||||
|
||||
@@ -11,7 +11,7 @@ const mpr: Types.HangingProtocol.Protocol = {
|
||||
// Unknown number of priors referenced - so just match any study
|
||||
numberOfPriorsReferenced: 0,
|
||||
protocolMatchingRules: [],
|
||||
imageLoadStrategy: 'interleaveTopToBottom',
|
||||
imageLoadStrategy: 'nth',
|
||||
callbacks: {
|
||||
// Switches out of MPR mode when the layout change button is used
|
||||
onLayoutChange: [
|
||||
@@ -303,11 +303,11 @@ const mprAnd3DVolumeViewport = {
|
||||
function getHangingProtocolModule() {
|
||||
return [
|
||||
{
|
||||
id: 'mpr',
|
||||
name: 'mpr',
|
||||
protocol: mpr,
|
||||
},
|
||||
{
|
||||
id: mprAnd3DVolumeViewport.id,
|
||||
name: mprAnd3DVolumeViewport.id,
|
||||
protocol: mprAnd3DVolumeViewport,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -155,9 +155,14 @@ class CornerstoneViewportService extends PubSubService
|
||||
/**
|
||||
* Disables the viewport inside the renderingEngine, if no viewport is left
|
||||
* it destroys the renderingEngine.
|
||||
*
|
||||
* This is called when the element goes away entirely - with new viewportId's
|
||||
* 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
|
||||
*/
|
||||
public disableElement(viewportIndex: number) {
|
||||
public disableElement(viewportIndex: number): void {
|
||||
const viewportInfo = this.viewportsInfo.get(viewportIndex);
|
||||
if (!viewportInfo) {
|
||||
return;
|
||||
@@ -254,12 +259,6 @@ class CornerstoneViewportService extends PubSubService
|
||||
viewportInfo.setDisplaySetOptions(displaySetOptions);
|
||||
viewportInfo.setViewportData(viewportData);
|
||||
|
||||
this._broadcastEvent(this.EVENTS.VIEWPORT_DATA_CHANGED, {
|
||||
viewportData,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
});
|
||||
|
||||
const element = viewportInfo.getElement();
|
||||
const type = viewportInfo.getViewportType();
|
||||
const background = viewportInfo.getBackground();
|
||||
@@ -283,6 +282,15 @@ class CornerstoneViewportService extends PubSubService
|
||||
|
||||
const viewport = renderingEngine.getViewport(viewportId);
|
||||
this._setDisplaySets(viewport, viewportData, viewportInfo, presentations);
|
||||
|
||||
// The broadcast event here ensures that listeners have a valid, up to date
|
||||
// viewport to access. Doing it too early can result in exceptions or
|
||||
// invalid data.
|
||||
this._broadcastEvent(this.EVENTS.VIEWPORT_DATA_CHANGED, {
|
||||
viewportData,
|
||||
viewportIndex,
|
||||
viewportId,
|
||||
});
|
||||
}
|
||||
|
||||
public getCornerstoneViewport(
|
||||
@@ -386,11 +394,7 @@ class CornerstoneViewportService extends PubSubService
|
||||
}
|
||||
}
|
||||
|
||||
// There is a bug in CS3D that the setStack does not
|
||||
// navigate to the desired image.
|
||||
viewport.setStack(imageIds, 0).then(() => {
|
||||
// The scroll, however, works fine in CS3D
|
||||
viewport.scroll(initialImageIndexToUse);
|
||||
viewport.setStack(imageIds, initialImageIndexToUse).then(() => {
|
||||
viewport.setProperties(properties);
|
||||
const camera = presentations.positionPresentation?.camera;
|
||||
if (camera) viewport.setCamera(camera);
|
||||
@@ -621,6 +625,10 @@ class CornerstoneViewportService extends PubSubService
|
||||
|
||||
const viewportInfo = this.getViewportInfo(viewport.id);
|
||||
|
||||
if (!viewportInfo) {
|
||||
console.warn('Viewport info not defined for', viewport.id);
|
||||
}
|
||||
|
||||
const toolGroup = toolGroupService.getToolGroupForViewport(viewport.id);
|
||||
csToolsUtils.segmentation.triggerSegmentationRender(toolGroup.id);
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ const viewportIdVolumeInputArrayMap = new Map<string, unknown[]>();
|
||||
export default function interleaveNthLoader({
|
||||
data: { viewportId, volumeInputArray },
|
||||
displaySetsMatchDetails,
|
||||
viewportMatchDetails: matchDetails,
|
||||
}) {
|
||||
viewportIdVolumeInputArrayMap.set(viewportId, volumeInputArray);
|
||||
|
||||
@@ -29,6 +28,7 @@ export default function interleaveNthLoader({
|
||||
const volume = cache.getVolume(volumeId);
|
||||
|
||||
if (!volume) {
|
||||
console.log("interleaveNthLoader::No volume, can't load it");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,33 +39,6 @@ export default function interleaveNthLoader({
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The following is checking if all the viewports that were matched in the HP has been
|
||||
* successfully created their cornerstone viewport or not. Todo: This can be
|
||||
* improved by not checking it, and as soon as the matched DisplaySets have their
|
||||
* volume loaded, we start the loading, but that comes at the cost of viewports
|
||||
* not being created yet (e.g., in a 10 viewport ptCT fusion, when one ct viewport and one
|
||||
* pt viewport are created we have a guarantee that the volumes are created in the cache
|
||||
* but the rest of the viewports (fusion, mip etc.) are not created yet. So
|
||||
* we can't initiate setting the volumes for those viewports. One solution can be
|
||||
* to add an event when a viewport is created (not enabled element event) and then
|
||||
* listen to it and as the other viewports are created we can set the volumes for them
|
||||
* since volumes are already started loading.
|
||||
*/
|
||||
if (matchDetails.size !== viewportIdVolumeInputArrayMap.size) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if all the matched volumes are loaded
|
||||
for (const [_, details] of displaySetsMatchDetails.entries()) {
|
||||
const { SeriesInstanceUID } = details;
|
||||
|
||||
// HangingProtocol has matched, but don't have all the volumes created yet, so return
|
||||
if (!Array.from(volumeIdMapsToLoad.values()).includes(SeriesInstanceUID)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const volumeIds = Array.from(volumeIdMapsToLoad.keys()).slice();
|
||||
// get volumes from cache
|
||||
const volumes = volumeIds.map(volumeId => {
|
||||
|
||||
Reference in new issue
Block a user