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:
Bill Wallace authored and GitHub committed 2023-03-31 11:58:48 -04:00
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);
+1 -28
View File
@@ -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 => {