2022-07-27 18:39:04 +02:00
|
|
|
import React, { useEffect, useCallback } from 'react';
|
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
|
import { ViewportGrid, ViewportPane, useViewportGrid } from '@ohif/ui';
|
2022-11-16 20:19:52 +01:00
|
|
|
import { utils } from '@ohif/core';
|
2022-07-27 18:39:04 +02:00
|
|
|
import EmptyViewport from './EmptyViewport';
|
|
|
|
|
import classNames from 'classnames';
|
|
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
const { isEqualWithin } = utils;
|
|
|
|
|
|
|
|
|
|
const ORIENTATION_MAP = {
|
|
|
|
|
axial: {
|
|
|
|
|
viewPlaneNormal: [0, 0, -1],
|
|
|
|
|
viewUp: [0, -1, 0],
|
|
|
|
|
},
|
|
|
|
|
sagittal: {
|
|
|
|
|
viewPlaneNormal: [1, 0, 0],
|
|
|
|
|
viewUp: [0, 0, 1],
|
|
|
|
|
},
|
|
|
|
|
coronal: {
|
|
|
|
|
viewPlaneNormal: [0, 1, 0],
|
|
|
|
|
viewUp: [0, 0, 1],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
function ViewerViewportGrid(props) {
|
|
|
|
|
const { servicesManager, viewportComponents, dataSource } = props;
|
|
|
|
|
const [viewportGrid, viewportGridService] = useViewportGrid();
|
|
|
|
|
|
|
|
|
|
const { numCols, numRows, activeViewportIndex, viewports } = viewportGrid;
|
|
|
|
|
|
|
|
|
|
// TODO -> Need some way of selecting which displaySets hit the viewports.
|
|
|
|
|
const {
|
2023-02-10 22:46:09 +01:00
|
|
|
displaySetService,
|
|
|
|
|
measurementService,
|
|
|
|
|
hangingProtocolService,
|
|
|
|
|
uiNotificationService,
|
2022-07-27 18:39:04 +02:00
|
|
|
} = servicesManager.services;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This callback runs only after displaySets have changed (created and added or modified)
|
|
|
|
|
*/
|
|
|
|
|
const updateDisplaySetsForViewports = useCallback(
|
|
|
|
|
availableDisplaySets => {
|
|
|
|
|
if (!availableDisplaySets.length) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-07 17:59:11 +02:00
|
|
|
const {
|
|
|
|
|
viewportMatchDetails,
|
2022-07-27 18:39:04 +02:00
|
|
|
hpAlreadyApplied,
|
2023-02-10 22:46:09 +01:00
|
|
|
} = hangingProtocolService.getMatchDetails();
|
2022-07-27 18:39:04 +02:00
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
if (!viewportMatchDetails.size) {
|
2022-07-27 18:39:04 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-14 16:01:39 +01:00
|
|
|
const gridDisplaySetUIDs = [];
|
|
|
|
|
const blankViewportIndices = [];
|
|
|
|
|
|
|
|
|
|
// Match each viewport individually.
|
|
|
|
|
const numViewports = viewportGridService.getNumViewportPanes();
|
|
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
for (
|
|
|
|
|
let viewportIndex = 0;
|
|
|
|
|
viewportIndex < numViewports;
|
|
|
|
|
viewportIndex++
|
|
|
|
|
) {
|
2023-02-14 16:01:39 +01:00
|
|
|
const viewportDisplaySetUIDs =
|
|
|
|
|
viewports[viewportIndex]?.displaySetInstanceUIDs ?? [];
|
|
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
if (hpAlreadyApplied.get(viewportIndex)) {
|
2023-02-14 16:01:39 +01:00
|
|
|
gridDisplaySetUIDs.push(...viewportDisplaySetUIDs);
|
2022-07-27 18:39:04 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if current viewport doesn't have a match
|
2022-11-16 20:19:52 +01:00
|
|
|
if (viewportMatchDetails.get(viewportIndex) === undefined) {
|
2023-02-14 16:01:39 +01:00
|
|
|
// if the current viewport is empty/blank
|
|
|
|
|
if (viewportDisplaySetUIDs.length === 0) {
|
|
|
|
|
blankViewportIndices.push(viewportIndex);
|
|
|
|
|
} else {
|
|
|
|
|
gridDisplaySetUIDs.push(...viewportDisplaySetUIDs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue;
|
2022-09-07 17:59:11 +02:00
|
|
|
}
|
2022-07-27 18:39:04 +02:00
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
const { displaySetsInfo, viewportOptions } = viewportMatchDetails.get(
|
|
|
|
|
viewportIndex
|
|
|
|
|
);
|
2022-07-27 18:39:04 +02:00
|
|
|
|
|
|
|
|
const displaySetUIDsToHang = [];
|
|
|
|
|
const displaySetUIDsToHangOptions = [];
|
2022-09-07 17:59:11 +02:00
|
|
|
displaySetsInfo.forEach(
|
|
|
|
|
({ displaySetInstanceUID, displaySetOptions }) => {
|
|
|
|
|
if (!displaySetInstanceUID) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
displaySetUIDsToHang.push(displaySetInstanceUID);
|
|
|
|
|
displaySetUIDsToHangOptions.push(displaySetOptions);
|
2022-07-27 18:39:04 +02:00
|
|
|
}
|
2022-09-07 17:59:11 +02:00
|
|
|
);
|
2022-07-27 18:39:04 +02:00
|
|
|
|
2023-02-14 16:01:39 +01:00
|
|
|
gridDisplaySetUIDs.push(...displaySetUIDsToHang);
|
|
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
viewportGridService.setDisplaySetsForViewport({
|
2022-11-16 20:19:52 +01:00
|
|
|
viewportIndex: viewportIndex,
|
2022-07-27 18:39:04 +02:00
|
|
|
displaySetInstanceUIDs: displaySetUIDsToHang,
|
|
|
|
|
viewportOptions,
|
|
|
|
|
displaySetOptions: displaySetUIDsToHangOptions,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// During setting displaySets for viewport, we need to update the hanging protocol
|
|
|
|
|
// but some viewports contain more than one display set (fusion), and their displaySet
|
|
|
|
|
// will not be available at the time of setting displaySets for viewport. So we need to
|
|
|
|
|
// update the hanging protocol after making sure all the matched display sets are available
|
|
|
|
|
// and set on the viewport
|
|
|
|
|
if (displaySetUIDsToHang.length === displaySetsInfo.length) {
|
2022-11-16 20:19:52 +01:00
|
|
|
// The following will set the viewportsDisplaySetsMatched state
|
|
|
|
|
|
|
|
|
|
const suppressEvent = true;
|
|
|
|
|
const applied = true;
|
2023-02-10 22:46:09 +01:00
|
|
|
hangingProtocolService.setHangingProtocolAppliedForViewport(
|
2022-11-16 20:19:52 +01:00
|
|
|
viewportIndex,
|
|
|
|
|
applied,
|
|
|
|
|
suppressEvent
|
|
|
|
|
);
|
2022-07-27 18:39:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-02-14 16:01:39 +01:00
|
|
|
|
|
|
|
|
blankViewportIndices.forEach((blankVPIndex: number) => {
|
|
|
|
|
// try to fill the empty viewport with a display set not already in the grid
|
|
|
|
|
const displaySetsNotInGrid = availableDisplaySets.filter(
|
|
|
|
|
displaySet =>
|
2023-02-14 20:17:13 +01:00
|
|
|
gridDisplaySetUIDs.indexOf(displaySet.displaySetInstanceUID) ===
|
|
|
|
|
-1 &&
|
|
|
|
|
['SEG', 'SR', 'RTSTRUCT'].indexOf(displaySet.Modality) === -1
|
2023-02-14 16:01:39 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (displaySetsNotInGrid.length > 0) {
|
|
|
|
|
const displaySetUIDToAdd =
|
|
|
|
|
displaySetsNotInGrid[0].displaySetInstanceUID;
|
|
|
|
|
gridDisplaySetUIDs.push(displaySetUIDToAdd);
|
|
|
|
|
|
|
|
|
|
viewportGridService.setDisplaySetsForViewport({
|
|
|
|
|
viewportIndex: blankVPIndex,
|
|
|
|
|
displaySetInstanceUIDs: [displaySetUIDToAdd],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2022-07-27 18:39:04 +02:00
|
|
|
},
|
|
|
|
|
[viewportGrid, numRows, numCols]
|
|
|
|
|
);
|
|
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
const _getUpdatedViewports = useCallback(
|
|
|
|
|
(viewportIndex, displaySetInstanceUID) => {
|
|
|
|
|
let updatedViewports = [];
|
|
|
|
|
try {
|
2023-02-10 22:46:09 +01:00
|
|
|
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
|
2022-11-16 20:19:52 +01:00
|
|
|
viewportIndex,
|
|
|
|
|
displaySetInstanceUID
|
|
|
|
|
);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.warn(error);
|
2023-02-10 22:46:09 +01:00
|
|
|
uiNotificationService.show({
|
2022-11-16 20:19:52 +01:00
|
|
|
title: 'Drag and Drop',
|
|
|
|
|
message:
|
|
|
|
|
'The selected display sets could not be added to the viewport due to a mismatch in the Hanging Protocol rules.',
|
|
|
|
|
type: 'info',
|
|
|
|
|
duration: 3000,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return updatedViewports;
|
|
|
|
|
},
|
2023-02-10 22:46:09 +01:00
|
|
|
[hangingProtocolService, uiNotificationService]
|
2022-11-16 20:19:52 +01:00
|
|
|
);
|
|
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
useEffect(() => {
|
2023-02-10 22:46:09 +01:00
|
|
|
const displaySets = displaySetService.getActiveDisplaySets();
|
2022-07-27 18:39:04 +02:00
|
|
|
updateDisplaySetsForViewports(displaySets);
|
|
|
|
|
}, [numRows, numCols]);
|
|
|
|
|
|
|
|
|
|
// Layout change based on hanging protocols
|
|
|
|
|
useEffect(() => {
|
2023-02-10 22:46:09 +01:00
|
|
|
const { unsubscribe } = hangingProtocolService.subscribe(
|
|
|
|
|
hangingProtocolService.EVENTS.NEW_LAYOUT,
|
2022-07-27 18:39:04 +02:00
|
|
|
({ layoutType, numRows, numCols, layoutOptions }) => {
|
|
|
|
|
viewportGridService.setLayout({
|
|
|
|
|
numRows,
|
|
|
|
|
numCols,
|
|
|
|
|
layoutType,
|
|
|
|
|
layoutOptions,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
unsubscribe();
|
|
|
|
|
};
|
2022-11-16 20:19:52 +01:00
|
|
|
}, []);
|
2022-07-27 18:39:04 +02:00
|
|
|
|
|
|
|
|
// Using Hanging protocol engine to match the displaySets
|
|
|
|
|
useEffect(() => {
|
2023-02-10 22:46:09 +01:00
|
|
|
const { unsubscribe } = hangingProtocolService.subscribe(
|
|
|
|
|
hangingProtocolService.EVENTS.PROTOCOL_CHANGED,
|
2022-09-07 17:59:11 +02:00
|
|
|
() => {
|
2023-02-10 22:46:09 +01:00
|
|
|
const displaySets = displaySetService.getActiveDisplaySets();
|
2022-09-07 17:59:11 +02:00
|
|
|
updateDisplaySetsForViewports(displaySets);
|
2022-07-27 18:39:04 +02:00
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
unsubscribe();
|
|
|
|
|
};
|
|
|
|
|
}, [viewports]);
|
|
|
|
|
|
2023-02-14 16:01:39 +01:00
|
|
|
useEffect(() => {
|
|
|
|
|
const { unsubscribe } = hangingProtocolService.subscribe(
|
|
|
|
|
hangingProtocolService.EVENTS.STAGE_CHANGE,
|
|
|
|
|
() => {
|
|
|
|
|
const displaySets = DisplaySetService.getActiveDisplaySets();
|
|
|
|
|
updateDisplaySetsForViewports(displaySets);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
unsubscribe();
|
|
|
|
|
};
|
|
|
|
|
}, [viewports]);
|
|
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
useEffect(() => {
|
2023-02-10 22:46:09 +01:00
|
|
|
const { unsubscribe } = measurementService.subscribe(
|
|
|
|
|
measurementService.EVENTS.JUMP_TO_MEASUREMENT,
|
2022-07-27 18:39:04 +02:00
|
|
|
({ viewportIndex, measurement }) => {
|
2022-11-16 20:19:52 +01:00
|
|
|
const {
|
|
|
|
|
displaySetInstanceUID: referencedDisplaySetInstanceUID,
|
|
|
|
|
metadata: { viewPlaneNormal },
|
|
|
|
|
} = measurement;
|
2022-07-27 18:39:04 +02:00
|
|
|
|
|
|
|
|
// if we already have the displaySet in one of the viewports
|
|
|
|
|
// Todo: handle fusion display sets?
|
|
|
|
|
for (const viewport of viewports) {
|
|
|
|
|
const isMatch = viewport.displaySetInstanceUIDs.includes(
|
|
|
|
|
referencedDisplaySetInstanceUID
|
|
|
|
|
);
|
|
|
|
|
if (isMatch) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 22:46:09 +01:00
|
|
|
const displaySet = displaySetService.getDisplaySetByUID(
|
2022-07-27 18:39:04 +02:00
|
|
|
referencedDisplaySetInstanceUID
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let imageIndex;
|
|
|
|
|
// jump straight to the initial image index if we can
|
|
|
|
|
if (displaySet.images && measurement.SOPInstanceUID) {
|
|
|
|
|
imageIndex = displaySet.images.findIndex(
|
|
|
|
|
image => image.SOPInstanceUID === measurement.SOPInstanceUID
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
const updatedViewports = _getUpdatedViewports(
|
2022-07-27 18:39:04 +02:00
|
|
|
viewportIndex,
|
2022-11-16 20:19:52 +01:00
|
|
|
referencedDisplaySetInstanceUID
|
|
|
|
|
);
|
2022-07-27 18:39:04 +02:00
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
if (!updatedViewports || !updatedViewports.length) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-07-27 18:39:04 +02:00
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
updatedViewports.forEach(vp => {
|
|
|
|
|
const { orientation, viewportType } = vp.viewportOptions;
|
|
|
|
|
let initialImageOptions;
|
2022-07-27 18:39:04 +02:00
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
// For initial imageIndex to hang be careful for the volume viewport
|
|
|
|
|
if (viewportType === 'stack') {
|
|
|
|
|
initialImageOptions = {
|
|
|
|
|
index: imageIndex,
|
|
|
|
|
};
|
|
|
|
|
} else if (viewportType === 'volume') {
|
|
|
|
|
// For the volume viewports, be careful to not jump in the viewports
|
|
|
|
|
// that are not in the same orientation.
|
|
|
|
|
// Todo: this doesn't work for viewports that have custom orientation
|
|
|
|
|
// vectors specified
|
|
|
|
|
if (
|
|
|
|
|
orientation &&
|
|
|
|
|
viewPlaneNormal &&
|
|
|
|
|
isEqualWithin(
|
|
|
|
|
ORIENTATION_MAP[orientation]?.viewPlaneNormal,
|
|
|
|
|
viewPlaneNormal
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
initialImageOptions = {
|
|
|
|
|
index: imageIndex,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-27 18:39:04 +02:00
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
vp.viewportOptions['initialImageOptions'] = initialImageOptions;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
viewportGridService.setDisplaySetsForViewports(updatedViewports);
|
2022-07-27 18:39:04 +02:00
|
|
|
}
|
|
|
|
|
);
|
2022-11-16 20:19:52 +01:00
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
return () => {
|
|
|
|
|
unsubscribe();
|
|
|
|
|
};
|
|
|
|
|
}, [viewports]);
|
|
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
/**
|
2022-07-27 18:39:04 +02:00
|
|
|
const onDoubleClick = viewportIndex => {
|
|
|
|
|
// TODO -> Disabled for now.
|
|
|
|
|
// onNewImage on a cornerstone viewport is firing setDisplaySetsForViewport.
|
|
|
|
|
// Which it really really shouldn't. We need a larger fix for jump to
|
|
|
|
|
// measurements and all cornerstone "imageIndex" state to fix this.
|
|
|
|
|
if (cachedLayout) {
|
|
|
|
|
viewportGridService.set({
|
|
|
|
|
numCols: cachedLayout.numCols,
|
|
|
|
|
numRows: cachedLayout.numRows,
|
|
|
|
|
activeViewportIndex: cachedLayout.activeViewportIndex,
|
|
|
|
|
viewports: cachedLayout.viewports,
|
|
|
|
|
cachedLayout: null,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const cachedViewports = viewports.map(viewport => {
|
|
|
|
|
return {
|
|
|
|
|
displaySetInstanceUID: viewport.displaySetInstanceUID,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
viewportGridService.set({
|
|
|
|
|
numCols: 1,
|
|
|
|
|
numRows: 1,
|
|
|
|
|
activeViewportIndex: 0,
|
|
|
|
|
viewports: [
|
|
|
|
|
{
|
|
|
|
|
displaySetInstanceUID: viewports[viewportIndex].displaySetInstanceUID,
|
|
|
|
|
imageIndex: undefined,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
cachedLayout: {
|
|
|
|
|
numCols,
|
|
|
|
|
numRows,
|
|
|
|
|
viewports: cachedViewports,
|
|
|
|
|
activeViewportIndex: viewportIndex,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const onDropHandler = (viewportIndex, { displaySetInstanceUID }) => {
|
2022-11-16 20:19:52 +01:00
|
|
|
const updatedViewports = _getUpdatedViewports(
|
2022-07-27 18:39:04 +02:00
|
|
|
viewportIndex,
|
2022-11-16 20:19:52 +01:00
|
|
|
displaySetInstanceUID
|
|
|
|
|
);
|
|
|
|
|
viewportGridService.setDisplaySetsForViewports(updatedViewports);
|
2022-07-27 18:39:04 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getViewportPanes = useCallback(() => {
|
|
|
|
|
const viewportPanes = [];
|
|
|
|
|
|
2023-02-14 16:01:39 +01:00
|
|
|
const numViewports = viewportGridService.getNumViewportPanes();
|
|
|
|
|
for (let i = 0; i < numViewports; i++) {
|
2022-07-27 18:39:04 +02:00
|
|
|
const viewportIndex = i;
|
|
|
|
|
const isActive = activeViewportIndex === viewportIndex;
|
|
|
|
|
const paneMetadata = viewports[i] || {};
|
|
|
|
|
const {
|
|
|
|
|
displaySetInstanceUIDs,
|
|
|
|
|
viewportOptions,
|
|
|
|
|
displaySetOptions, // array of options for each display set in the viewport
|
|
|
|
|
x: viewportX,
|
|
|
|
|
y: viewportY,
|
|
|
|
|
width: viewportWidth,
|
|
|
|
|
height: viewportHeight,
|
|
|
|
|
viewportLabel,
|
|
|
|
|
} = paneMetadata;
|
|
|
|
|
|
|
|
|
|
const displaySetInstanceUIDsToUse = displaySetInstanceUIDs || [];
|
|
|
|
|
|
|
|
|
|
// This is causing the viewport components re-render when the activeViewportIndex changes
|
|
|
|
|
const displaySets = displaySetInstanceUIDsToUse.map(
|
|
|
|
|
displaySetInstanceUID => {
|
|
|
|
|
return (
|
2023-02-10 22:46:09 +01:00
|
|
|
displaySetService.getDisplaySetByUID(displaySetInstanceUID) || {}
|
2022-07-27 18:39:04 +02:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const ViewportComponent = _getViewportComponent(
|
|
|
|
|
displaySets,
|
2022-11-16 20:19:52 +01:00
|
|
|
viewportComponents,
|
2023-02-10 22:46:09 +01:00
|
|
|
uiNotificationService
|
2022-07-27 18:39:04 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// look inside displaySets to see if they need reRendering
|
|
|
|
|
const displaySetsNeedsRerendering = displaySets.some(displaySet => {
|
|
|
|
|
return displaySet.needsRerendering;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const onInteractionHandler = event => {
|
|
|
|
|
if (isActive) return;
|
|
|
|
|
|
|
|
|
|
if (event) {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
event.stopPropagation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
viewportGridService.setActiveViewportIndex(viewportIndex);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// TEMP -> Double click disabled for now
|
|
|
|
|
// onDoubleClick={() => onDoubleClick(viewportIndex)}
|
|
|
|
|
|
|
|
|
|
viewportPanes[i] = (
|
|
|
|
|
<ViewportPane
|
|
|
|
|
key={viewportIndex}
|
|
|
|
|
acceptDropsFor="displayset"
|
|
|
|
|
onDrop={onDropHandler.bind(null, viewportIndex)}
|
|
|
|
|
onInteraction={onInteractionHandler}
|
|
|
|
|
customStyle={{
|
|
|
|
|
position: 'absolute',
|
|
|
|
|
top: viewportY * 100 + 0.2 + '%',
|
|
|
|
|
left: viewportX * 100 + 0.2 + '%',
|
|
|
|
|
width: viewportWidth * 100 - 0.3 + '%',
|
|
|
|
|
height: viewportHeight * 100 - 0.3 + '%',
|
|
|
|
|
}}
|
|
|
|
|
isActive={isActive}
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
className={classNames('h-full w-full flex flex-col', {
|
|
|
|
|
'pointer-events-none': !isActive,
|
|
|
|
|
})}
|
|
|
|
|
>
|
|
|
|
|
<ViewportComponent
|
|
|
|
|
displaySets={displaySets}
|
|
|
|
|
viewportIndex={viewportIndex}
|
2023-02-14 16:01:39 +01:00
|
|
|
viewportLabel={numViewports > 1 ? viewportLabel : ''}
|
2022-07-27 18:39:04 +02:00
|
|
|
dataSource={dataSource}
|
|
|
|
|
viewportOptions={viewportOptions}
|
|
|
|
|
displaySetOptions={displaySetOptions}
|
|
|
|
|
needsRerendering={displaySetsNeedsRerendering}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</ViewportPane>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return viewportPanes;
|
|
|
|
|
}, [viewports, activeViewportIndex, viewportComponents, dataSource]);
|
|
|
|
|
|
|
|
|
|
/**
|
2023-02-10 22:46:09 +01:00
|
|
|
* Loading indicator until numCols and numRows are gotten from the hangingProtocolService
|
2022-07-27 18:39:04 +02:00
|
|
|
*/
|
|
|
|
|
if (!numRows || !numCols) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<ViewportGrid numRows={numRows} numCols={numCols}>
|
|
|
|
|
{/* {ViewportPanes} */}
|
|
|
|
|
{getViewportPanes()}
|
|
|
|
|
</ViewportGrid>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ViewerViewportGrid.propTypes = {
|
|
|
|
|
viewportComponents: PropTypes.array.isRequired,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ViewerViewportGrid.defaultProps = {
|
|
|
|
|
viewportComponents: [],
|
|
|
|
|
};
|
|
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
function _getViewportComponent(
|
|
|
|
|
displaySets,
|
|
|
|
|
viewportComponents,
|
2023-02-10 22:46:09 +01:00
|
|
|
uiNotificationService
|
2022-11-16 20:19:52 +01:00
|
|
|
) {
|
2022-07-27 18:39:04 +02:00
|
|
|
if (!displaySets || !displaySets.length) {
|
|
|
|
|
return EmptyViewport;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Todo: Do we have a viewport that has two different SOPClassHandlerIds?
|
|
|
|
|
const SOPClassHandlerId = displaySets[0].SOPClassHandlerId;
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < viewportComponents.length; i++) {
|
2022-09-09 04:09:28 +02:00
|
|
|
if (!viewportComponents[i]) {
|
2022-09-07 17:59:11 +02:00
|
|
|
throw new Error('viewport components not defined');
|
2022-09-09 04:09:28 +02:00
|
|
|
}
|
2022-09-07 17:59:11 +02:00
|
|
|
if (!viewportComponents[i].displaySetsToDisplay) {
|
|
|
|
|
throw new Error('displaySetsToDisplay is null');
|
|
|
|
|
}
|
2022-07-27 18:39:04 +02:00
|
|
|
if (
|
|
|
|
|
viewportComponents[i].displaySetsToDisplay.includes(SOPClassHandlerId)
|
|
|
|
|
) {
|
|
|
|
|
const { component } = viewportComponents[i];
|
|
|
|
|
return component;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-16 20:19:52 +01:00
|
|
|
|
2022-12-09 16:58:01 +01:00
|
|
|
console.log("Can't show displaySet", SOPClassHandlerId, displaySets[0]);
|
2023-02-10 22:46:09 +01:00
|
|
|
uiNotificationService.show({
|
2022-11-16 20:19:52 +01:00
|
|
|
title: 'Viewport Not Supported Yet',
|
|
|
|
|
message: `Cannot display SOPClassId of ${displaySets[0].SOPClassUID} yet`,
|
|
|
|
|
type: 'error',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return EmptyViewport;
|
2022-07-27 18:39:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default ViewerViewportGrid;
|