[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:
James PettsandDanny Brown authored and GitHub committed 2020-07-22 19:40:40 +02:00
1 parent 4985fbf5a6
commit a4f286feee
26 files changed
+438 -196

No files matched your search

+1 -1
View File
@@ -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 = {
+29 -21
View File
@@ -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,
},
],
},
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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",