[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:
1 parent
4985fbf5a6
commit
a4f286feee
26 files changed
+438
-196
No files matched your search
@@ -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,
|
||||
|
||||
+18
-8
@@ -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",
|
||||
|
||||
Reference in new issue
Block a user