[OHIF 284] - JumpToMeasurement + prevent layout change on scroll Prevent layout change on scroll (#1889)
* No more setting on debounce, jumpToMeasurement service set up. * Fix bug causing a race condition sometimes if you click super fast. * Optimise rendering of Tracking viewport slightly. * element => targetElement * Remove complete TODO * Respond to reviewer comments. * Fix e2e workflow. * Fix regression that removed highlighting on jump to. * Make sure jump to works from panel as well as viewport. * Fix typo and remove debugger. Co-authored-by: Danny Brown <danny.ri.brown@gmail.com>
This commit is contained in:
parent
4985fbf5a6
commit
a4f286feee
@ -35,7 +35,7 @@
|
||||
"cornerstone-math": "^0.1.8",
|
||||
"cornerstone-tools": "4.18.1",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dcmjs": "0.16.0",
|
||||
"dcmjs": "0.16.1",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"hammerjs": "^2.0.8",
|
||||
"prop-types": "^15.6.2",
|
||||
|
||||
@ -83,8 +83,6 @@ const commandsModule = ({ servicesManager }) => {
|
||||
const enabledElement = _getActiveViewportsEnabledElement();
|
||||
|
||||
if (enabledElement) {
|
||||
debugger;
|
||||
|
||||
const cancelActiveManipulatorsForElement = cornerstoneTools.getModule(
|
||||
'manipulatorState'
|
||||
).setters.cancelActiveManipulatorsForElement;
|
||||
@ -284,32 +282,6 @@ const commandsModule = ({ servicesManager }) => {
|
||||
cornerstone.setViewport(enabledElement, viewport);
|
||||
}
|
||||
},
|
||||
jumpToImage: ({
|
||||
StudyInstanceUID,
|
||||
SOPInstanceUID,
|
||||
imageIndex,
|
||||
activeViewportIndex,
|
||||
}) => {
|
||||
const study = studyMetadataManager.get(StudyInstanceUID);
|
||||
|
||||
const displaySet = study.findDisplaySet(ds => {
|
||||
return (
|
||||
ds.images &&
|
||||
ds.images.find(i => i.getSOPInstanceUID() === SOPInstanceUID)
|
||||
);
|
||||
});
|
||||
|
||||
displaySet.SOPInstanceUID = SOPInstanceUID;
|
||||
displaySet.imageIndex = imageIndex;
|
||||
|
||||
window.store.dispatch(
|
||||
setViewportSpecificData(activeViewportIndex, displaySet)
|
||||
);
|
||||
|
||||
cornerstone.getEnabledElements().forEach(enabledElement => {
|
||||
cornerstone.updateImage(enabledElement.element);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const definitions = {
|
||||
|
||||
@ -18,7 +18,11 @@ import { setEnabledElement } from './state';
|
||||
* @param {Object|Array} configuration.csToolsConfig
|
||||
*/
|
||||
export default function init({ servicesManager, configuration }) {
|
||||
const { UIDialogService, MeasurementService } = servicesManager.services;
|
||||
const {
|
||||
UIDialogService,
|
||||
MeasurementService,
|
||||
DisplaySetService,
|
||||
} = servicesManager.services;
|
||||
|
||||
const callInputDialog = (data, event, callback) => {
|
||||
if (UIDialogService) {
|
||||
@ -137,7 +141,7 @@ export default function init({ servicesManager, configuration }) {
|
||||
);
|
||||
|
||||
/* Measurement Service */
|
||||
_connectToolsToMeasurementService(MeasurementService);
|
||||
_connectToolsToMeasurementService(MeasurementService, DisplaySetService);
|
||||
|
||||
/* Add extension tools configuration here. */
|
||||
const internalToolsConfig = {
|
||||
@ -220,21 +224,21 @@ export default function init({ servicesManager, configuration }) {
|
||||
csTools.setToolEnabled('Overlay', {});
|
||||
}
|
||||
|
||||
const _initMeasurementService = measurementService => {
|
||||
const _initMeasurementService = (MeasurementService, DisplaySetService) => {
|
||||
/* Initialization */
|
||||
const {
|
||||
Length,
|
||||
Bidirectional,
|
||||
EllipticalRoi,
|
||||
ArrowAnnotate,
|
||||
} = measurementServiceMappingsFactory(measurementService);
|
||||
const csToolsVer4MeasurementSource = measurementService.createSource(
|
||||
} = measurementServiceMappingsFactory(MeasurementService, DisplaySetService);
|
||||
const csToolsVer4MeasurementSource = MeasurementService.createSource(
|
||||
'CornerstoneTools',
|
||||
'4'
|
||||
);
|
||||
|
||||
/* Mappings */
|
||||
measurementService.addMapping(
|
||||
MeasurementService.addMapping(
|
||||
csToolsVer4MeasurementSource,
|
||||
'Length',
|
||||
Length.matchingCriteria,
|
||||
@ -242,7 +246,7 @@ const _initMeasurementService = measurementService => {
|
||||
Length.toMeasurement
|
||||
);
|
||||
|
||||
measurementService.addMapping(
|
||||
MeasurementService.addMapping(
|
||||
csToolsVer4MeasurementSource,
|
||||
'Bidirectional',
|
||||
Bidirectional.matchingCriteria,
|
||||
@ -250,7 +254,7 @@ const _initMeasurementService = measurementService => {
|
||||
Bidirectional.toMeasurement
|
||||
);
|
||||
|
||||
measurementService.addMapping(
|
||||
MeasurementService.addMapping(
|
||||
csToolsVer4MeasurementSource,
|
||||
'EllipticalRoi',
|
||||
EllipticalRoi.matchingCriteria,
|
||||
@ -258,7 +262,7 @@ const _initMeasurementService = measurementService => {
|
||||
EllipticalRoi.toMeasurement
|
||||
);
|
||||
|
||||
measurementService.addMapping(
|
||||
MeasurementService.addMapping(
|
||||
csToolsVer4MeasurementSource,
|
||||
'ArrowAnnotate',
|
||||
ArrowAnnotate.matchingCriteria,
|
||||
@ -269,12 +273,16 @@ const _initMeasurementService = measurementService => {
|
||||
return csToolsVer4MeasurementSource;
|
||||
};
|
||||
|
||||
const _connectToolsToMeasurementService = measurementService => {
|
||||
const _connectToolsToMeasurementService = (
|
||||
MeasurementService,
|
||||
DisplaySetService
|
||||
) => {
|
||||
const csToolsVer4MeasurementSource = _initMeasurementService(
|
||||
measurementService
|
||||
MeasurementService,
|
||||
DisplaySetService
|
||||
);
|
||||
_connectMeasurementServiceToTools(
|
||||
measurementService,
|
||||
MeasurementService,
|
||||
csToolsVer4MeasurementSource
|
||||
);
|
||||
const { addOrUpdate, remove } = csToolsVer4MeasurementSource;
|
||||
@ -330,9 +338,9 @@ const _connectToolsToMeasurementService = measurementService => {
|
||||
}
|
||||
}
|
||||
|
||||
const { MEASUREMENTS_CLEARED } = measurementService.EVENTS;
|
||||
const { MEASUREMENTS_CLEARED } = MeasurementService.EVENTS;
|
||||
|
||||
measurementService.subscribe(MEASUREMENTS_CLEARED, () => {
|
||||
MeasurementService.subscribe(MEASUREMENTS_CLEARED, () => {
|
||||
cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState(
|
||||
{}
|
||||
);
|
||||
@ -350,16 +358,16 @@ const _connectToolsToMeasurementService = measurementService => {
|
||||
};
|
||||
|
||||
const _connectMeasurementServiceToTools = (
|
||||
measurementService,
|
||||
MeasurementService,
|
||||
measurementSource
|
||||
) => {
|
||||
const {
|
||||
MEASUREMENTS_CLEARED,
|
||||
MEASUREMENT_REMOVED,
|
||||
} = measurementService.EVENTS;
|
||||
} = MeasurementService.EVENTS;
|
||||
const sourceId = measurementSource.id;
|
||||
|
||||
measurementService.subscribe(MEASUREMENTS_CLEARED, () => {
|
||||
MeasurementService.subscribe(MEASUREMENTS_CLEARED, () => {
|
||||
cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState({});
|
||||
cornerstone.getEnabledElements().forEach(enabledElement => {
|
||||
cornerstone.updateImage(enabledElement.element);
|
||||
@ -367,7 +375,7 @@ const _connectMeasurementServiceToTools = (
|
||||
});
|
||||
|
||||
/* TODO: Remove per measurement
|
||||
measurementService.subscribe(MEASUREMENT_REMOVED,
|
||||
MeasurementService.subscribe(MEASUREMENT_REMOVED,
|
||||
({ source, measurement }) => {
|
||||
if ([sourceId].includes(source.id)) {
|
||||
// const annotation = getAnnotation('Length', measurement.id);
|
||||
@ -380,9 +388,9 @@ const _connectMeasurementServiceToTools = (
|
||||
// const {
|
||||
// MEASUREMENT_ADDED,
|
||||
// MEASUREMENT_UPDATED,
|
||||
// } = measurementService.EVENTS;
|
||||
// } = MeasurementService.EVENTS;
|
||||
|
||||
// measurementService.subscribe(
|
||||
// MeasurementService.subscribe(
|
||||
// MEASUREMENT_ADDED,
|
||||
// ({ source, measurement }) => {
|
||||
// if (![sourceId].includes(source.id)) {
|
||||
@ -397,7 +405,7 @@ const _connectMeasurementServiceToTools = (
|
||||
// }
|
||||
// );
|
||||
|
||||
// measurementService.subscribe(
|
||||
// MeasurementService.subscribe(
|
||||
// MEASUREMENT_UPDATED,
|
||||
// ({ source, measurement }) => {
|
||||
// if (![sourceId].includes(source.id)) {
|
||||
|
||||
@ -6,7 +6,11 @@ const ArrowAnnotate = {
|
||||
toAnnotation: (measurement, definition) => {
|
||||
// TODO -> Implement when this is needed.
|
||||
},
|
||||
toMeasurement: (csToolsAnnotation, getValueTypeFromToolType) => {
|
||||
toMeasurement: (
|
||||
csToolsAnnotation,
|
||||
DisplaySetService,
|
||||
getValueTypeFromToolType
|
||||
) => {
|
||||
const { element, measurementData } = csToolsAnnotation;
|
||||
const tool =
|
||||
csToolsAnnotation.toolType ||
|
||||
@ -26,6 +30,11 @@ const ArrowAnnotate = {
|
||||
StudyInstanceUID,
|
||||
} = getSOPInstanceAttributes(element);
|
||||
|
||||
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
|
||||
SOPInstanceUID,
|
||||
SeriesInstanceUID
|
||||
);
|
||||
|
||||
const points = [];
|
||||
points.push(measurementData.handles);
|
||||
|
||||
@ -35,6 +44,7 @@ const ArrowAnnotate = {
|
||||
FrameOfReferenceUID,
|
||||
referenceSeriesUID: SeriesInstanceUID,
|
||||
referenceStudyUID: StudyInstanceUID,
|
||||
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||
label: measurementData.text,
|
||||
description: measurementData.description,
|
||||
unit: measurementData.unit,
|
||||
|
||||
@ -5,7 +5,11 @@ const Bidirectional = {
|
||||
toAnnotation: (measurement, definition) => {
|
||||
// TODO -> Implement when this is needed.
|
||||
},
|
||||
toMeasurement: (csToolsAnnotation, getValueTypeFromToolType) => {
|
||||
toMeasurement: (
|
||||
csToolsAnnotation,
|
||||
DisplaySetService,
|
||||
getValueTypeFromToolType
|
||||
) => {
|
||||
const { element, measurementData } = csToolsAnnotation;
|
||||
const tool =
|
||||
csToolsAnnotation.toolType ||
|
||||
@ -25,6 +29,11 @@ const Bidirectional = {
|
||||
StudyInstanceUID,
|
||||
} = getSOPInstanceAttributes(element);
|
||||
|
||||
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
|
||||
SOPInstanceUID,
|
||||
SeriesInstanceUID
|
||||
);
|
||||
|
||||
const { handles } = measurementData;
|
||||
|
||||
const longAxis = [handles.start, handles.end];
|
||||
@ -36,6 +45,7 @@ const Bidirectional = {
|
||||
FrameOfReferenceUID,
|
||||
referenceSeriesUID: SeriesInstanceUID,
|
||||
referenceStudyUID: StudyInstanceUID,
|
||||
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||
label: measurementData.text,
|
||||
description: measurementData.description,
|
||||
unit: measurementData.unit,
|
||||
|
||||
@ -5,7 +5,11 @@ const EllipticalRoi = {
|
||||
toAnnotation: (measurement, definition) => {
|
||||
// TODO -> Implement when this is needed.
|
||||
},
|
||||
toMeasurement: (csToolsAnnotation, getValueTypeFromToolType) => {
|
||||
toMeasurement: (
|
||||
csToolsAnnotation,
|
||||
DisplaySetService,
|
||||
getValueTypeFromToolType
|
||||
) => {
|
||||
const { element, measurementData } = csToolsAnnotation;
|
||||
const tool =
|
||||
csToolsAnnotation.toolType ||
|
||||
@ -25,6 +29,11 @@ const EllipticalRoi = {
|
||||
StudyInstanceUID,
|
||||
} = getSOPInstanceAttributes(element);
|
||||
|
||||
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
|
||||
SOPInstanceUID,
|
||||
SeriesInstanceUID
|
||||
);
|
||||
|
||||
const { start, end } = measurementData.handles;
|
||||
|
||||
const halfXLength = Math.abs(start.x - end.x) / 2;
|
||||
@ -58,6 +67,7 @@ const EllipticalRoi = {
|
||||
FrameOfReferenceUID,
|
||||
referenceSeriesUID: SeriesInstanceUID,
|
||||
referenceStudyUID: StudyInstanceUID,
|
||||
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||
label: measurementData.text,
|
||||
description: measurementData.description,
|
||||
unit: measurementData.unit,
|
||||
|
||||
@ -37,7 +37,11 @@ const Length = {
|
||||
* @param {Object} cornerstone Cornerstone event data
|
||||
* @return {Measurement} Measurement instance
|
||||
*/
|
||||
toMeasurement: (csToolsAnnotation, getValueTypeFromToolType) => {
|
||||
toMeasurement: (
|
||||
csToolsAnnotation,
|
||||
DisplaySetService,
|
||||
getValueTypeFromToolType
|
||||
) => {
|
||||
const { element, measurementData } = csToolsAnnotation;
|
||||
const tool =
|
||||
csToolsAnnotation.toolType ||
|
||||
@ -57,12 +61,18 @@ const Length = {
|
||||
StudyInstanceUID,
|
||||
} = getSOPInstanceAttributes(element);
|
||||
|
||||
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
|
||||
SOPInstanceUID,
|
||||
SeriesInstanceUID
|
||||
);
|
||||
|
||||
return {
|
||||
id: measurementData.id,
|
||||
SOPInstanceUID: SOPInstanceUID,
|
||||
FrameOfReferenceUID,
|
||||
referenceSeriesUID: SeriesInstanceUID,
|
||||
referenceStudyUID: StudyInstanceUID,
|
||||
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||
label: measurementData.text,
|
||||
description: measurementData.description,
|
||||
unit: measurementData.unit,
|
||||
|
||||
@ -3,7 +3,10 @@ import Bidirectional from './Bidirectional';
|
||||
import ArrowAnnotate from './ArrowAnnotate';
|
||||
import EllipticalRoi from './EllipticalRoi';
|
||||
|
||||
const measurementServiceMappingsFactory = measurementService => {
|
||||
const measurementServiceMappingsFactory = (
|
||||
MeasurementService,
|
||||
DisplaySetService
|
||||
) => {
|
||||
/**
|
||||
* Maps measurement service format object to cornerstone annotation object.
|
||||
*
|
||||
@ -18,7 +21,7 @@ const measurementServiceMappingsFactory = measurementService => {
|
||||
ELLIPSE,
|
||||
POINT,
|
||||
BIDIRECTIONAL,
|
||||
} = measurementService.VALUE_TYPES;
|
||||
} = MeasurementService.VALUE_TYPES;
|
||||
|
||||
// TODO -> I get why this was attemped, but its not nearly flexible enough.
|
||||
// A single measurement may have an ellipse + a bidirectional measurement, for instances.
|
||||
@ -37,10 +40,14 @@ const measurementServiceMappingsFactory = measurementService => {
|
||||
Length: {
|
||||
toAnnotation: Length.toAnnotation,
|
||||
toMeasurement: csToolsAnnotation =>
|
||||
Length.toMeasurement(csToolsAnnotation, _getValueTypeFromToolType),
|
||||
Length.toMeasurement(
|
||||
csToolsAnnotation,
|
||||
DisplaySetService,
|
||||
_getValueTypeFromToolType
|
||||
),
|
||||
matchingCriteria: [
|
||||
{
|
||||
valueType: measurementService.VALUE_TYPES.POLYLINE,
|
||||
valueType: MeasurementService.VALUE_TYPES.POLYLINE,
|
||||
points: 2,
|
||||
},
|
||||
],
|
||||
@ -50,17 +57,18 @@ const measurementServiceMappingsFactory = measurementService => {
|
||||
toMeasurement: csToolsAnnotation =>
|
||||
Bidirectional.toMeasurement(
|
||||
csToolsAnnotation,
|
||||
DisplaySetService,
|
||||
_getValueTypeFromToolType
|
||||
),
|
||||
matchingCriteria: [
|
||||
// TODO -> We should eventually do something like shortAxis + longAxis,
|
||||
// But its still a little unclear how these automatic interpretations will work.
|
||||
{
|
||||
valueType: measurementService.VALUE_TYPES.POLYLINE,
|
||||
valueType: MeasurementService.VALUE_TYPES.POLYLINE,
|
||||
points: 2,
|
||||
},
|
||||
{
|
||||
valueType: measurementService.VALUE_TYPES.POLYLINE,
|
||||
valueType: MeasurementService.VALUE_TYPES.POLYLINE,
|
||||
points: 2,
|
||||
},
|
||||
],
|
||||
@ -70,11 +78,12 @@ const measurementServiceMappingsFactory = measurementService => {
|
||||
toMeasurement: csToolsAnnotation =>
|
||||
ArrowAnnotate.toMeasurement(
|
||||
csToolsAnnotation,
|
||||
DisplaySetService,
|
||||
_getValueTypeFromToolType
|
||||
),
|
||||
matchingCriteria: [
|
||||
{
|
||||
valueType: measurementService.VALUE_TYPES.POINT,
|
||||
valueType: MeasurementService.VALUE_TYPES.POINT,
|
||||
points: 1,
|
||||
},
|
||||
],
|
||||
@ -84,11 +93,12 @@ const measurementServiceMappingsFactory = measurementService => {
|
||||
toMeasurement: csToolsAnnotation =>
|
||||
EllipticalRoi.toMeasurement(
|
||||
csToolsAnnotation,
|
||||
DisplaySetService,
|
||||
_getValueTypeFromToolType
|
||||
),
|
||||
matchingCriteria: [
|
||||
{
|
||||
valueType: measurementService.VALUE_TYPES.ELLIPSE,
|
||||
valueType: MeasurementService.VALUE_TYPES.ELLIPSE,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"webpack": "^4.0.0",
|
||||
"dcmjs": "0.16.0"
|
||||
"dcmjs": "0.16.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6"
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "^0.50.0",
|
||||
"dcmjs": "0.16.0",
|
||||
"dcmjs": "0.16.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.11.0",
|
||||
"react-dom": "^16.11.0"
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
"@ohif/core": "^0.50.0",
|
||||
"cornerstone-core": "^2.2.8",
|
||||
"cornerstone-tools": "4.18.1",
|
||||
"dcmjs": "0.16.0",
|
||||
"dcmjs": "0.16.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
"@ohif/core": "^0.50.0",
|
||||
"cornerstone-core": "^2.2.8",
|
||||
"cornerstone-tools": "4.18.1",
|
||||
"dcmjs": "0.16.0",
|
||||
"dcmjs": "0.16.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
"cornerstone-math": "^0.1.8",
|
||||
"cornerstone-tools": "4.18.1",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dcmjs": "0.16.0",
|
||||
"dcmjs": "0.16.1",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"hammerjs": "^2.0.8",
|
||||
"prop-types": "^15.6.2",
|
||||
|
||||
@ -372,6 +372,7 @@ function OHIFCornerstoneSRViewport({
|
||||
const toMeasurementSchema = getToolStateToCornerstoneMeasurementSchema(
|
||||
toolType,
|
||||
MeasurementService,
|
||||
DisplaySetService,
|
||||
imageId
|
||||
);
|
||||
|
||||
@ -436,8 +437,8 @@ function OHIFCornerstoneSRViewport({
|
||||
spacing:
|
||||
PixelSpacing && PixelSpacing.length
|
||||
? `${PixelSpacing[0].toFixed(2)}mm x ${PixelSpacing[1].toFixed(
|
||||
2
|
||||
)}mm`
|
||||
2
|
||||
)}mm`
|
||||
: '',
|
||||
scanner: ManufacturerModelName || '',
|
||||
},
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
export default function getToolStateToCornerstoneMeasurementSchema(
|
||||
toolType,
|
||||
MeasurementService,
|
||||
DisplaySetService,
|
||||
imageId
|
||||
) {
|
||||
const _getValueTypeFromToolType = toolType => {
|
||||
@ -28,20 +29,45 @@ export default function getToolStateToCornerstoneMeasurementSchema(
|
||||
switch (toolType) {
|
||||
case 'Length':
|
||||
return measurementData =>
|
||||
Length(measurementData, imageId, _getValueTypeFromToolType);
|
||||
Length(
|
||||
measurementData,
|
||||
imageId,
|
||||
DisplaySetService,
|
||||
_getValueTypeFromToolType
|
||||
);
|
||||
case 'Bidirectional':
|
||||
return measurementData =>
|
||||
Bidirectional(measurementData, imageId, _getValueTypeFromToolType);
|
||||
Bidirectional(
|
||||
measurementData,
|
||||
imageId,
|
||||
DisplaySetService,
|
||||
_getValueTypeFromToolType
|
||||
);
|
||||
case 'EllipticalRoi':
|
||||
return measurementData =>
|
||||
EllipticalRoi(measurementData, imageId, _getValueTypeFromToolType);
|
||||
EllipticalRoi(
|
||||
measurementData,
|
||||
imageId,
|
||||
DisplaySetService,
|
||||
_getValueTypeFromToolType
|
||||
);
|
||||
case 'ArrowAnnotate':
|
||||
return measurementData =>
|
||||
ArrowAnnotate(measurementData, imageId, _getValueTypeFromToolType);
|
||||
ArrowAnnotate(
|
||||
measurementData,
|
||||
imageId,
|
||||
DisplaySetService,
|
||||
_getValueTypeFromToolType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function Length(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
function Length(
|
||||
measurementData,
|
||||
imageId,
|
||||
DisplaySetService,
|
||||
_getValueTypeFromToolType
|
||||
) {
|
||||
const tool = measurementData.toolType || measurementData.toolName;
|
||||
const instance = cornerstone.metaData.get('instance', imageId);
|
||||
const {
|
||||
@ -51,6 +77,12 @@ function Length(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
StudyInstanceUID,
|
||||
} = instance;
|
||||
|
||||
const displaySetInstanceUID = _getDisplaySetInstanceUID(
|
||||
DisplaySetService,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID
|
||||
);
|
||||
|
||||
const { handles, label } = measurementData;
|
||||
|
||||
const points = [];
|
||||
@ -69,7 +101,7 @@ function Length(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
FrameOfReferenceUID,
|
||||
referenceSeriesUID: SeriesInstanceUID,
|
||||
referenceStudyUID: StudyInstanceUID,
|
||||
label: measurementData.text,
|
||||
displaySetInstanceUID,
|
||||
description: measurementData.description,
|
||||
unit: measurementData.unit,
|
||||
length: measurementData.length,
|
||||
@ -79,7 +111,12 @@ function Length(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
};
|
||||
}
|
||||
|
||||
function Bidirectional(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
function Bidirectional(
|
||||
measurementData,
|
||||
imageId,
|
||||
DisplaySetService,
|
||||
_getValueTypeFromToolType
|
||||
) {
|
||||
const tool = measurementData.toolType || measurementData.toolName;
|
||||
const instance = cornerstone.metaData.get('instance', imageId);
|
||||
const {
|
||||
@ -88,6 +125,11 @@ function Bidirectional(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
SeriesInstanceUID,
|
||||
StudyInstanceUID,
|
||||
} = instance;
|
||||
const displaySetInstanceUID = _getDisplaySetInstanceUID(
|
||||
DisplaySetService,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID
|
||||
);
|
||||
|
||||
const { handles, label } = measurementData;
|
||||
|
||||
@ -100,7 +142,7 @@ function Bidirectional(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
FrameOfReferenceUID,
|
||||
referenceSeriesUID: SeriesInstanceUID,
|
||||
referenceStudyUID: StudyInstanceUID,
|
||||
label: measurementData.text,
|
||||
displaySetInstanceUID,
|
||||
description: measurementData.description,
|
||||
unit: measurementData.unit,
|
||||
shortestDiameter: measurementData.shortestDiameter,
|
||||
@ -111,7 +153,12 @@ function Bidirectional(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
};
|
||||
}
|
||||
|
||||
function EllipticalRoi(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
function EllipticalRoi(
|
||||
measurementData,
|
||||
imageId,
|
||||
DisplaySetService,
|
||||
_getValueTypeFromToolType
|
||||
) {
|
||||
const tool = measurementData.toolType || measurementData.toolName;
|
||||
const instance = cornerstone.metaData.get('instance', imageId);
|
||||
const {
|
||||
@ -121,6 +168,11 @@ function EllipticalRoi(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
StudyInstanceUID,
|
||||
} = instance;
|
||||
|
||||
const displaySetInstanceUID = _getDisplaySetInstanceUID(
|
||||
DisplaySetService,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID
|
||||
);
|
||||
const { handles, label } = measurementData;
|
||||
const { start, end } = handles;
|
||||
|
||||
@ -155,7 +207,7 @@ function EllipticalRoi(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
FrameOfReferenceUID,
|
||||
referenceSeriesUID: SeriesInstanceUID,
|
||||
referenceStudyUID: StudyInstanceUID,
|
||||
label: measurementData.text,
|
||||
displaySetInstanceUID,
|
||||
description: measurementData.description,
|
||||
unit: measurementData.unit,
|
||||
area:
|
||||
@ -168,7 +220,12 @@ function EllipticalRoi(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
};
|
||||
}
|
||||
|
||||
function ArrowAnnotate(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
function ArrowAnnotate(
|
||||
measurementData,
|
||||
imageId,
|
||||
DisplaySetService,
|
||||
_getValueTypeFromToolType
|
||||
) {
|
||||
const tool = measurementData.toolType || measurementData.toolName;
|
||||
const instance = cornerstone.metaData.get('instance', imageId);
|
||||
const {
|
||||
@ -178,6 +235,12 @@ function ArrowAnnotate(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
StudyInstanceUID,
|
||||
} = instance;
|
||||
|
||||
const displaySetInstanceUID = _getDisplaySetInstanceUID(
|
||||
DisplaySetService,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID
|
||||
);
|
||||
|
||||
const { handles } = measurementData;
|
||||
|
||||
const points = [];
|
||||
@ -196,12 +259,25 @@ function ArrowAnnotate(measurementData, imageId, _getValueTypeFromToolType) {
|
||||
FrameOfReferenceUID,
|
||||
referenceSeriesUID: SeriesInstanceUID,
|
||||
referenceStudyUID: StudyInstanceUID,
|
||||
displaySetInstanceUID,
|
||||
label: measurementData.text,
|
||||
description: measurementData.description,
|
||||
unit: measurementData.unit,
|
||||
text: measurementData.text,
|
||||
type: _getValueTypeFromToolType(tool),
|
||||
points,
|
||||
label,
|
||||
};
|
||||
}
|
||||
|
||||
function _getDisplaySetInstanceUID(
|
||||
DisplaySetService,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID
|
||||
) {
|
||||
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
|
||||
SOPInstanceUID,
|
||||
SeriesInstanceUID
|
||||
);
|
||||
|
||||
return displaySet.displaySetInstanceUID;
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "^0.50.0",
|
||||
"cornerstone-tools": "4.18.1",
|
||||
"dcmjs": "0.16.0",
|
||||
"dcmjs": "0.16.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
|
||||
@ -161,29 +161,7 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
||||
}
|
||||
|
||||
const jumpToImage = ({ id, isActive }) => {
|
||||
const measurement = MeasurementService.getMeasurement(id);
|
||||
const { referenceSeriesUID, SOPInstanceUID } = measurement;
|
||||
|
||||
setCornerstoneMeasurementActive(measurement);
|
||||
|
||||
const displaySets = DisplaySetService.getDisplaySetsForSeries(
|
||||
referenceSeriesUID
|
||||
);
|
||||
const displaySet = displaySets.find(ds => {
|
||||
return (
|
||||
ds.images && ds.images.some(i => i.SOPInstanceUID === SOPInstanceUID)
|
||||
);
|
||||
});
|
||||
|
||||
const imageIndex = displaySet.images
|
||||
.map(i => i.SOPInstanceUID)
|
||||
.indexOf(SOPInstanceUID);
|
||||
|
||||
viewportGridService.setDisplaysetForViewport({
|
||||
viewportIndex: viewportGrid.activeViewportIndex,
|
||||
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||
imageIndex,
|
||||
});
|
||||
MeasurementService.jumpToMeasurement(viewportGrid.activeViewportIndex, id);
|
||||
|
||||
onMeasurementItemClickHandler({ id, isActive });
|
||||
};
|
||||
|
||||
@ -16,6 +16,7 @@ import ViewportOverlay from './ViewportOverlay';
|
||||
import ViewportLoadingIndicator from './ViewportLoadingIndicator';
|
||||
import setCornerstoneMeasurementActive from '../_shared/setCornerstoneMeasurementActive';
|
||||
|
||||
const scrollToIndex = cornerstoneTools.importInternal('util/scrollToIndex');
|
||||
const { formatDate } = utils;
|
||||
|
||||
// TODO -> Get this list from the list of tracked measurements.
|
||||
@ -47,12 +48,13 @@ function TrackedCornerstoneViewport({
|
||||
viewportIndex,
|
||||
servicesManager,
|
||||
}) {
|
||||
const { ToolBarService, DisplaySetService } = servicesManager.services;
|
||||
const {
|
||||
ToolBarService,
|
||||
DisplaySetService,
|
||||
MeasurementService,
|
||||
} = servicesManager.services;
|
||||
const [trackedMeasurements] = useTrackedMeasurements();
|
||||
const [
|
||||
{ activeViewportIndex, viewports },
|
||||
viewportGridService,
|
||||
] = useViewportGrid();
|
||||
const [{ activeViewportIndex, viewports }] = useViewportGrid();
|
||||
// viewportIndex, onSubmit
|
||||
const [viewportDialogState, viewportDialogApi] = useViewportDialog();
|
||||
const [viewportData, setViewportData] = useState(null);
|
||||
@ -69,6 +71,28 @@ function TrackedCornerstoneViewport({
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubcribeFromJumpToMeasurementEvents = _subscribeToJumpToMeasurementEvents(
|
||||
MeasurementService,
|
||||
DisplaySetService,
|
||||
element,
|
||||
viewportIndex,
|
||||
displaySet.displaySetInstanceUID
|
||||
);
|
||||
|
||||
_checkForCachedJumpToMeasurementEvents(
|
||||
MeasurementService,
|
||||
DisplaySetService,
|
||||
element,
|
||||
viewportIndex,
|
||||
displaySet.displaySetInstanceUID
|
||||
);
|
||||
|
||||
return () => {
|
||||
unsubcribeFromJumpToMeasurementEvents();
|
||||
};
|
||||
}, [element, displaySet]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!element) {
|
||||
return;
|
||||
@ -167,13 +191,6 @@ function TrackedCornerstoneViewport({
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* This grabs `imageIndex from first matching
|
||||
* We actually want whichever is at our `viewportIndex`
|
||||
*/
|
||||
const { imageIndex } = viewports[viewportIndex];
|
||||
displaySet.imageIndex = imageIndex;
|
||||
|
||||
_getViewportData(dataSource, displaySet).then(setViewportData);
|
||||
}, [dataSource, displaySet, viewports, viewportIndex]);
|
||||
|
||||
@ -275,19 +292,10 @@ function TrackedCornerstoneViewport({
|
||||
|
||||
setCornerstoneMeasurementActive(measurement);
|
||||
|
||||
const {
|
||||
displaySetInstanceUID,
|
||||
imageIndex,
|
||||
} = _getViewportDataFromTrackedMeasurementId(
|
||||
measurement,
|
||||
DisplaySetService
|
||||
);
|
||||
|
||||
viewportGridService.setDisplaysetForViewport({
|
||||
MeasurementService.jumpToMeasurement(
|
||||
viewportIndex,
|
||||
displaySetInstanceUID,
|
||||
imageIndex,
|
||||
});
|
||||
newTrackedMeasurementId
|
||||
);
|
||||
}
|
||||
|
||||
const showNavArrows = isTracked && viewportIndex === activeViewportIndex;
|
||||
@ -336,14 +344,6 @@ function TrackedCornerstoneViewport({
|
||||
viewportIndex={viewportIndex}
|
||||
imageIds={imageIds}
|
||||
imageIdIndex={currentImageIdIndex}
|
||||
onNewImageDebounceTime={700}
|
||||
onNewImageDebounced={({ currentImageIdIndex }) => {
|
||||
viewportGridService.setDisplaysetForViewport({
|
||||
viewportIndex: activeViewportIndex,
|
||||
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||
imageIndex: currentImageIdIndex,
|
||||
});
|
||||
}}
|
||||
// Sync resize throttle w/ sidepanel animation duration to prevent
|
||||
// seizure inducing strobe blinking effect
|
||||
resizeRefreshRateMs={150}
|
||||
@ -402,16 +402,12 @@ const _viewportLabels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
|
||||
* @return {Object} CornerstoneTools Stack
|
||||
*/
|
||||
function _getCornerstoneStack(displaySet, dataSource) {
|
||||
const { imageIndex } = displaySet;
|
||||
|
||||
// Get stack from Stack Manager
|
||||
const storedStack = StackManager.findOrCreateStack(displaySet, dataSource);
|
||||
|
||||
// Clone the stack here so we don't mutate it
|
||||
const stack = Object.assign({}, storedStack);
|
||||
|
||||
stack.currentImageIdIndex = imageIndex;
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
@ -498,26 +494,111 @@ function _getNextMeasurementId(
|
||||
return newTrackedMeasurementId;
|
||||
}
|
||||
|
||||
function _getViewportDataFromTrackedMeasurementId(
|
||||
function _subscribeToJumpToMeasurementEvents(
|
||||
MeasurementService,
|
||||
DisplaySetService,
|
||||
element,
|
||||
viewportIndex,
|
||||
displaySetInstanceUID
|
||||
) {
|
||||
const { unsubscribe } = MeasurementService.subscribe(
|
||||
MeasurementService.EVENTS.JUMP_TO_MEASUREMENT,
|
||||
({ viewportIndex: jumpToMeasurementViewportIndex, measurement }) => {
|
||||
// check if the correct viewport index.
|
||||
if (viewportIndex !== jumpToMeasurementViewportIndex) {
|
||||
// Event for a different viewport.
|
||||
return;
|
||||
}
|
||||
|
||||
if (measurement.displaySetInstanceUID !== displaySetInstanceUID) {
|
||||
// Not for this displaySet.
|
||||
return;
|
||||
}
|
||||
|
||||
_jumpToMeasurement(
|
||||
measurement,
|
||||
element,
|
||||
viewportIndex,
|
||||
MeasurementService,
|
||||
DisplaySetService
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return unsubscribe;
|
||||
}
|
||||
|
||||
function _checkForCachedJumpToMeasurementEvents(
|
||||
MeasurementService,
|
||||
DisplaySetService,
|
||||
element,
|
||||
viewportIndex,
|
||||
displaySetInstanceUID
|
||||
) {
|
||||
// Check if there is a queued jumpToMeasurement event
|
||||
const measurementIdToJumpTo = MeasurementService.getJumpToMeasurement(
|
||||
viewportIndex
|
||||
);
|
||||
|
||||
if (measurementIdToJumpTo && element) {
|
||||
// Jump to measurement if the measurement exists
|
||||
const measurement = MeasurementService.getMeasurement(
|
||||
measurementIdToJumpTo
|
||||
);
|
||||
|
||||
if (measurement.displaySetInstanceUID === displaySetInstanceUID) {
|
||||
_jumpToMeasurement(
|
||||
measurement,
|
||||
element,
|
||||
viewportIndex,
|
||||
MeasurementService,
|
||||
DisplaySetService
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _jumpToMeasurement(
|
||||
measurement,
|
||||
targetElement,
|
||||
viewportIndex,
|
||||
MeasurementService,
|
||||
DisplaySetService
|
||||
) {
|
||||
const { referenceSeriesUID: SeriesInstanceUID, SOPInstanceUID } = measurement;
|
||||
const { displaySetInstanceUID, SOPInstanceUID } = measurement;
|
||||
|
||||
const activeDisplaySets = DisplaySetService.getActiveDisplaySets();
|
||||
|
||||
const displaySet = activeDisplaySets.find(
|
||||
ds => ds.SeriesInstanceUID === SeriesInstanceUID
|
||||
const referencedDisplaySet = DisplaySetService.getDisplaySetByUID(
|
||||
displaySetInstanceUID
|
||||
);
|
||||
|
||||
const imageIndex = displaySet.images.findIndex(
|
||||
image => image.SOPInstanceUID === SOPInstanceUID
|
||||
const imageIndex = referencedDisplaySet.images.findIndex(
|
||||
i => i.SOPInstanceUID === SOPInstanceUID
|
||||
);
|
||||
|
||||
return {
|
||||
imageIndex,
|
||||
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||
};
|
||||
setCornerstoneMeasurementActive(measurement);
|
||||
|
||||
if (targetElement !== null) {
|
||||
const enabledElement = cornerstone.getEnabledElement(targetElement);
|
||||
|
||||
if (enabledElement.image) {
|
||||
// Wait for the image to update or we get a race condition when the element has only just been enabled.
|
||||
const scrollToHandler = evt => {
|
||||
scrollToIndex(targetElement, imageIndex);
|
||||
targetElement.removeEventListener(
|
||||
'cornerstoneimagerendered',
|
||||
scrollToHandler
|
||||
);
|
||||
};
|
||||
targetElement.addEventListener(
|
||||
'cornerstoneimagerendered',
|
||||
scrollToHandler
|
||||
);
|
||||
cornerstone.updateImage(targetElement);
|
||||
}
|
||||
|
||||
// Jump to measurement consumed, remove.
|
||||
MeasurementService.removeJumpToMeasurement(viewportIndex);
|
||||
}
|
||||
}
|
||||
|
||||
export default TrackedCornerstoneViewport;
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
"@ohif/ui": "^2.0.0",
|
||||
"cornerstone-core": "^2.3.0",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dcmjs": "0.16.0",
|
||||
"dcmjs": "0.16.1",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"i18next": "^17.0.3",
|
||||
"i18next-browser-languagedetector": "^3.0.1",
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6",
|
||||
"ajv": "^6.10.0",
|
||||
"dcmjs": "0.16.0",
|
||||
"dcmjs": "0.16.1",
|
||||
"dicomweb-client": "^0.6.0",
|
||||
"immer": "6.0.2",
|
||||
"isomorphic-base64": "^1.0.2",
|
||||
|
||||
@ -46,6 +46,20 @@ export default class DisplaySetService {
|
||||
);
|
||||
};
|
||||
|
||||
getDisplaySetForSOPInstanceUID(SOPInstanceUID, SeriesInstanceUID) {
|
||||
const displaySets = SeriesInstanceUID
|
||||
? this.getDisplaySetsForSeries(SeriesInstanceUID)
|
||||
: this.getDisplaySetCache();
|
||||
|
||||
const displaySet = displaySets.find(ds => {
|
||||
return (
|
||||
ds.images && ds.images.some(i => i.SOPInstanceUID === SOPInstanceUID)
|
||||
);
|
||||
});
|
||||
|
||||
return displaySet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} displaySetInstanceUID
|
||||
* @returns {object} displaySet
|
||||
|
||||
@ -53,6 +53,7 @@ const EVENTS = {
|
||||
MEASUREMENT_ADDED: 'event::measurement_added',
|
||||
MEASUREMENT_REMOVED: 'event::measurement_removed',
|
||||
MEASUREMENTS_CLEARED: 'event::measurements_cleared',
|
||||
JUMP_TO_MEASUREMENT: 'event:jump_to_measurement',
|
||||
};
|
||||
|
||||
const VALUE_TYPES = {
|
||||
@ -70,6 +71,7 @@ class MeasurementService {
|
||||
this.mappings = {};
|
||||
this.measurements = {};
|
||||
this.listeners = {};
|
||||
this._jumpToMeasurementCache = {};
|
||||
Object.defineProperty(this, 'EVENTS', {
|
||||
value: EVENTS,
|
||||
writable: false,
|
||||
@ -498,6 +500,40 @@ class MeasurementService {
|
||||
this._broadcastChange(this.EVENTS.MEASUREMENTS_CLEARED);
|
||||
}
|
||||
|
||||
jumpToMeasurement(viewportIndex, id) {
|
||||
const measurement = this.measurements[id];
|
||||
|
||||
if (!measurement) {
|
||||
log.warn(`No id provided, or unable to find measurement by id.`);
|
||||
return;
|
||||
}
|
||||
|
||||
this._addJumpToMeasurement(viewportIndex, id);
|
||||
|
||||
const eventName = this.EVENTS.JUMP_TO_MEASUREMENT;
|
||||
|
||||
const hasListeners = Object.keys(this.listeners).length > 0;
|
||||
const hasCallbacks = Array.isArray(this.listeners[eventName]);
|
||||
|
||||
if (hasListeners && hasCallbacks) {
|
||||
this.listeners[eventName].forEach(listener => {
|
||||
listener.callback({ viewportIndex, measurement });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_addJumpToMeasurement(viewportIndex, id) {
|
||||
this._jumpToMeasurementCache[viewportIndex] = id;
|
||||
}
|
||||
|
||||
getJumpToMeasurement(viewportIndex) {
|
||||
return this._jumpToMeasurementCache[viewportIndex];
|
||||
}
|
||||
|
||||
removeJumpToMeasurement(viewportIndex) {
|
||||
delete this._jumpToMeasurementCache[viewportIndex];
|
||||
}
|
||||
|
||||
_getMappingByMeasurementSource(measurementId, definition) {
|
||||
const measurement = this.getMeasurement(measurementId);
|
||||
if (this._isValidSource(measurement.source)) {
|
||||
|
||||
@ -27,14 +27,10 @@ export function ViewportGridProvider({ children, service }) {
|
||||
return { ...state, ...{ activeViewportIndex: action.payload } };
|
||||
}
|
||||
case 'SET_DISPLAYSET_FOR_VIEWPORT': {
|
||||
const {
|
||||
viewportIndex,
|
||||
displaySetInstanceUID,
|
||||
imageIndex,
|
||||
} = action.payload;
|
||||
const { viewportIndex, displaySetInstanceUID } = action.payload;
|
||||
const viewports = state.viewports.slice();
|
||||
|
||||
viewports[viewportIndex] = { displaySetInstanceUID, imageIndex };
|
||||
viewports[viewportIndex] = { displaySetInstanceUID };
|
||||
|
||||
return { ...state, ...{ viewports }, cachedLayout: null };
|
||||
}
|
||||
@ -63,7 +59,7 @@ export function ViewportGridProvider({ children, service }) {
|
||||
numCols: 1,
|
||||
numRows: 1,
|
||||
activeViewportIndex: 0,
|
||||
viewports: [{ displaySetInstanceUID: null, imageIndex: null }],
|
||||
viewports: [{ displaySetInstanceUID: null }],
|
||||
cachedLayout: null,
|
||||
};
|
||||
}
|
||||
@ -96,13 +92,12 @@ export function ViewportGridProvider({ children, service }) {
|
||||
[dispatch]
|
||||
);
|
||||
const setDisplaysetForViewport = useCallback(
|
||||
({ viewportIndex, displaySetInstanceUID, imageIndex }) =>
|
||||
({ viewportIndex, displaySetInstanceUID }) =>
|
||||
dispatch({
|
||||
type: 'SET_DISPLAYSET_FOR_VIEWPORT',
|
||||
payload: {
|
||||
viewportIndex,
|
||||
displaySetInstanceUID,
|
||||
imageIndex,
|
||||
},
|
||||
}),
|
||||
[dispatch]
|
||||
|
||||
@ -70,7 +70,7 @@
|
||||
"cornerstone-math": "^0.1.8",
|
||||
"cornerstone-tools": "4.18.1",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dcmjs": "0.16.0",
|
||||
"dcmjs": "0.16.1",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"dicomweb-client": "^0.4.4",
|
||||
"dotenv-webpack": "^1.7.0",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* CSS Grid Reference: http://grid.malven.co/
|
||||
*/
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useCallback } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ViewportGrid, ViewportPane, useViewportGrid } from '@ohif/ui';
|
||||
import EmptyViewport from './EmptyViewport';
|
||||
@ -11,13 +11,18 @@ import classNames from 'classnames';
|
||||
|
||||
function ViewerViewportGrid(props) {
|
||||
const { servicesManager, viewportComponents, dataSource } = props;
|
||||
const [
|
||||
{ numCols, numRows, activeViewportIndex, viewports, cachedLayout },
|
||||
viewportGridService,
|
||||
] = useViewportGrid();
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
|
||||
const {
|
||||
numCols,
|
||||
numRows,
|
||||
activeViewportIndex,
|
||||
viewports,
|
||||
cachedLayout,
|
||||
} = viewportGrid;
|
||||
|
||||
// TODO -> Need some way of selecting which displaySets hit the viewports.
|
||||
const { DisplaySetService } = servicesManager.services;
|
||||
const { DisplaySetService, MeasurementService } = servicesManager.services;
|
||||
|
||||
useEffect(() => {
|
||||
const { unsubscribe } = DisplaySetService.subscribe(
|
||||
@ -40,30 +45,56 @@ function ViewerViewportGrid(props) {
|
||||
};
|
||||
}, []);
|
||||
|
||||
// TODO -> Make a HangingProtocolService
|
||||
const HangingProtocolService = displaySets => {
|
||||
let displaySetInstanceUID;
|
||||
useEffect(() => {
|
||||
const { unsubscribe } = MeasurementService.subscribe(
|
||||
MeasurementService.EVENTS.JUMP_TO_MEASUREMENT,
|
||||
({ viewportIndex, measurement }) => {
|
||||
const referencedDisplaySetInstanceUID =
|
||||
measurement.displaySetInstanceUID;
|
||||
|
||||
// Fallback
|
||||
if (!displaySets || !displaySets.length) {
|
||||
const displaySet = DisplaySetService.activeDisplaySets[0];
|
||||
displaySetInstanceUID = displaySet.displaySetInstanceUID;
|
||||
} else {
|
||||
const displaySet = displaySets[0];
|
||||
displaySetInstanceUID = displaySet.displaySetInstanceUID;
|
||||
}
|
||||
// If the viewport does not contain the displaySet, then hang that displaySet.
|
||||
if (
|
||||
viewports[viewportIndex].displaySetInstanceUID !==
|
||||
referencedDisplaySetInstanceUID
|
||||
) {
|
||||
viewportGridService.setDisplaysetForViewport({
|
||||
viewportIndex,
|
||||
displaySetInstanceUID: referencedDisplaySetInstanceUID,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
numRows: 1,
|
||||
numCols: 1,
|
||||
activeViewportIndex: 0,
|
||||
viewports: [
|
||||
{
|
||||
displaySetInstanceUID,
|
||||
},
|
||||
],
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
};
|
||||
}, [viewports]);
|
||||
|
||||
// TODO -> Make a HangingProtocolService
|
||||
// Commented out whilst not in use to avoid pointlessly regenerating this function.
|
||||
// const HangingProtocolService = displaySets => {
|
||||
// let displaySetInstanceUID;
|
||||
|
||||
// // Fallback
|
||||
// if (!displaySets || !displaySets.length) {
|
||||
// const displaySet = DisplaySetService.activeDisplaySets[0];
|
||||
// displaySetInstanceUID = displaySet.displaySetInstanceUID;
|
||||
// } else {
|
||||
// const displaySet = displaySets[0];
|
||||
// displaySetInstanceUID = displaySet.displaySetInstanceUID;
|
||||
// }
|
||||
|
||||
// return {
|
||||
// numRows: 1,
|
||||
// numCols: 1,
|
||||
// activeViewportIndex: 0,
|
||||
// viewports: [
|
||||
// {
|
||||
// displaySetInstanceUID,
|
||||
// },
|
||||
// ],
|
||||
// };
|
||||
// };
|
||||
|
||||
const onDoubleClick = viewportIndex => {
|
||||
// TODO -> Disabled for now.
|
||||
|
||||
@ -7364,10 +7364,10 @@ dateformat@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
||||
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
|
||||
|
||||
dcmjs@0.16.0:
|
||||
version "0.16.0"
|
||||
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.16.0.tgz#714755d006c3a49cf65ef13e627ff7a23151d35a"
|
||||
integrity sha512-41nY3Isg5i5FoSd1s67aUgUHi146r+fb8JuiRvDsxvm7MEkkdjIzMYMtxjsrVwKRW1xRH+x34nxbV9+8cc7WQw==
|
||||
dcmjs@0.16.1:
|
||||
version "0.16.1"
|
||||
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.16.1.tgz#76bc61cbdf2c58a2f54990080729ca2d7ee19543"
|
||||
integrity sha512-t6vsKi5QXzwX1fwnHY2hdU99FfyzmK8aO0OSBDH6XvJNrBp2A6HpoVWbucybOy8eStIPDqs4v0FGP/m39cTCRA==
|
||||
dependencies:
|
||||
"@babel/polyfill" "^7.8.3"
|
||||
"@babel/runtime" "^7.8.4"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user