OHIF-208 (#1842)
* Set measurement as active * Add basic dialog component * Update styles and prop types * Jump to image * Update dialog * Format date * Update summary to use primary modalities * delete empty studySummary page * add missing PropTypes import * fix for accidental sync'd viewports * CR Updates * CR Update avoid cache of measurements * Use get measurement * Add comment to edit function * Remove request and merge modalities from series * Update dependency: react-cornerstone-viewport@2.3.9 react-cornerstone-viewport * @ohif/extension-cornerstone: 2.3.8 → 2.3.9 * @ohif/extension-dicom-sr: 2.3.8 → 2.3.9 * Update extensions/measurement-tracking/src/panels/PanelMeasurementTableTracking/index.js Co-authored-by: Danny Brown <danny.ri.brown@gmail.com> * Add debugs * remove console.debug * Update frameindex to imageindex * Use new rcv debounced function * Fix hovering * Update dialog text * Dismiss dialogs on esc * Update dependency: react-cornerstone-viewport@3.0.0 react-cornerstone-viewport * @ohif/extension-cornerstone: 2.3.9 → 3.0.0 * @ohif/extension-dicom-sr: 2.3.9 → 3.0.0 * OHIF-237 * remove console.debug * Remove dead code brought in from rebase * EmptyViewport should not display a message * Remove more dead code from rebase * fix variable naming * remove unused hook * bump yarn lock * formatting * Add arrow dialog * Filter based on trackedSeries Co-authored-by: Danny Brown <danny.ri.brown@gmail.com>
This commit is contained in:
1 parent
ae05de18af
commit
a156eadcb7
34 files changed
+603
-758
No files matched your search
@@ -50,6 +50,6 @@
|
||||
"classnames": "^2.2.6",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"react-cornerstone-viewport": "2.3.8"
|
||||
"react-cornerstone-viewport": "3.0.0"
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import CornerstoneViewport from 'react-cornerstone-viewport';
|
||||
//import ConnectedCornerstoneViewport from './ConnectedCornerstoneViewport';
|
||||
import OHIF from '@ohif/core';
|
||||
import PropTypes from 'prop-types';
|
||||
import cornerstone from 'cornerstone-core';
|
||||
import debounce from 'lodash.debounce';
|
||||
import throttle from 'lodash.throttle';
|
||||
|
||||
@@ -68,7 +67,7 @@ class OHIFCornerstoneViewport extends Component {
|
||||
* @return {Object} CornerstoneTools Stack
|
||||
*/
|
||||
static getCornerstoneStack(displaySet, dataSource) {
|
||||
const { frameIndex } = displaySet;
|
||||
const { imageIndex } = displaySet;
|
||||
|
||||
// Get stack from Stack Manager
|
||||
const storedStack = StackManager.findOrCreateStack(displaySet, dataSource);
|
||||
@@ -76,7 +75,7 @@ class OHIFCornerstoneViewport extends Component {
|
||||
// Clone the stack here so we don't mutate it
|
||||
const stack = Object.assign({}, storedStack);
|
||||
|
||||
stack.currentImageIdIndex = frameIndex;
|
||||
stack.currentImageIdIndex = imageIndex;
|
||||
|
||||
// TODO -> Do we ever use this like this?
|
||||
// if (SOPInstanceUID) {
|
||||
@@ -155,9 +154,9 @@ class OHIFCornerstoneViewport extends Component {
|
||||
|
||||
if (
|
||||
displaySet.displaySetInstanceUID !==
|
||||
prevDisplaySet.displaySetInstanceUID ||
|
||||
prevDisplaySet.displaySetInstanceUID ||
|
||||
displaySet.SOPInstanceUID !== prevDisplaySet.SOPInstanceUID ||
|
||||
displaySet.frameIndex !== prevDisplaySet.frameIndex
|
||||
displaySet.imageIndex !== prevDisplaySet.imageIndex
|
||||
) {
|
||||
this.setStateFromProps();
|
||||
}
|
||||
@@ -199,7 +198,7 @@ class OHIFCornerstoneViewport extends Component {
|
||||
this.props.onNewImage({
|
||||
StudyInstanceUID,
|
||||
SOPInstanceUID: sopInstanceUid,
|
||||
frameIndex: currentImageIdIndex,
|
||||
imageIndex: currentImageIdIndex,
|
||||
activeViewportIndex: viewportIndex,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ const commandsModule = ({ servicesManager }) => {
|
||||
jumpToImage: ({
|
||||
StudyInstanceUID,
|
||||
SOPInstanceUID,
|
||||
frameIndex,
|
||||
imageIndex,
|
||||
activeViewportIndex,
|
||||
}) => {
|
||||
const study = studyMetadataManager.get(StudyInstanceUID);
|
||||
@@ -284,7 +284,7 @@ const commandsModule = ({ servicesManager }) => {
|
||||
});
|
||||
|
||||
displaySet.SOPInstanceUID = SOPInstanceUID;
|
||||
displaySet.frameIndex = frameIndex;
|
||||
displaySet.imageIndex = imageIndex;
|
||||
|
||||
window.store.dispatch(
|
||||
setViewportSpecificData(activeViewportIndex, displaySet)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import OHIF from '@ohif/core';
|
||||
import { SimpleDialog } from '@ohif/ui';
|
||||
import { Dialog, Input } from '@ohif/ui';
|
||||
import cornerstone from 'cornerstone-core';
|
||||
import csTools from 'cornerstone-tools';
|
||||
import merge from 'lodash.merge';
|
||||
@@ -23,18 +24,48 @@ export default function init({ servicesManager, configuration }) {
|
||||
let dialogId = UIDialogService.create({
|
||||
centralize: true,
|
||||
isDraggable: false,
|
||||
content: SimpleDialog.InputDialog,
|
||||
content: Dialog,
|
||||
useLastPosition: false,
|
||||
showOverlay: true,
|
||||
contentProps: {
|
||||
title: 'Enter your annotation',
|
||||
label: 'New label',
|
||||
measurementData: data ? { description: data.text } : {},
|
||||
value: { label: data ? data.text : '' },
|
||||
noCloseButton: true,
|
||||
onClose: () => UIDialogService.dismiss({ id: dialogId }),
|
||||
onSubmit: value => {
|
||||
callback(value);
|
||||
actions: [
|
||||
{ id: 'cancel', text: 'Cancel', type: 'secondary' },
|
||||
{ id: 'save', text: 'Save', type: 'primary' },
|
||||
],
|
||||
onSubmit: ({ action, value }) => {
|
||||
switch (action.id) {
|
||||
case 'save': callback(value.label);
|
||||
}
|
||||
UIDialogService.dismiss({ id: dialogId });
|
||||
},
|
||||
body: ({ value, setValue }) => {
|
||||
const onChangeHandler = (event) => {
|
||||
event.persist();
|
||||
setValue(value => ({ ...value, label: event.target.value }));
|
||||
};
|
||||
const onKeyPressHandler = event => {
|
||||
if (event.key === 'Enter') {
|
||||
onSubmitHandler({ value, action: { id: 'save' } });
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="p-4 bg-primary-dark">
|
||||
<Input
|
||||
autoFocus
|
||||
className="mt-2 bg-black border-primary-main"
|
||||
type="text"
|
||||
containerClassName="mr-2"
|
||||
value={value.label}
|
||||
onChange={onChangeHandler}
|
||||
onKeyPress={onKeyPressHandler}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -62,7 +93,7 @@ export default function init({ servicesManager, configuration }) {
|
||||
// THIS
|
||||
// is a way for extensions that "depend" on this extension to notify it of
|
||||
// new cornerstone enabled elements so it's commands continue to work.
|
||||
const handleOhifCornerstoneEnabledElementEvent = function(evt) {
|
||||
const handleOhifCornerstoneEnabledElementEvent = function (evt) {
|
||||
const { viewportIndex, enabledElement } = evt.detail;
|
||||
|
||||
setEnabledElement(viewportIndex, enabledElement);
|
||||
@@ -108,7 +139,6 @@ export default function init({ servicesManager, configuration }) {
|
||||
|
||||
/* Add extension tools configuration here. */
|
||||
const internalToolsConfig = {
|
||||
/* TODO ArrowAnnotate input
|
||||
ArrowAnnotate: {
|
||||
configuration: {
|
||||
getTextCallback: (callback, eventDetails) =>
|
||||
@@ -117,7 +147,6 @@ export default function init({ servicesManager, configuration }) {
|
||||
callInputDialog(data, eventDetails, callback),
|
||||
},
|
||||
},
|
||||
*/
|
||||
};
|
||||
|
||||
/* Abstract tools configuration using extension configuration. */
|
||||
|
||||
@@ -51,8 +51,8 @@ export default function PanelMeasurementTable({
|
||||
title="Measurements"
|
||||
amount={displayMeasurements.length}
|
||||
data={displayMeasurements}
|
||||
onClick={() => {}}
|
||||
onEdit={id => alert(`Edit: ${id}`)}
|
||||
onClick={({ id }) => alert(`Click: ${id}`)}
|
||||
onEdit={({ id }) => alert(`Edit: ${id}`)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -150,7 +150,7 @@ const RTPanel = ({
|
||||
imageIds
|
||||
);
|
||||
|
||||
const frameIndex = imageIds.indexOf(imageId);
|
||||
const imageIndex = imageIds.indexOf(imageId);
|
||||
const SOPInstanceUID = cornerstone.metaData.get(
|
||||
'SOPInstanceUID',
|
||||
imageId
|
||||
@@ -163,7 +163,7 @@ const RTPanel = ({
|
||||
onContourItemClick({
|
||||
StudyInstanceUID,
|
||||
SOPInstanceUID,
|
||||
frameIndex,
|
||||
imageIndex,
|
||||
activeViewportIndex: activeIndex,
|
||||
});
|
||||
}}
|
||||
@@ -237,7 +237,7 @@ const RTPanel = ({
|
||||
expanded={
|
||||
isLoaded &&
|
||||
loadedSet.SeriesInstanceUID ===
|
||||
state.selectedSet.SeriesInstanceUID
|
||||
state.selectedSet.SeriesInstanceUID
|
||||
}
|
||||
onVisibilityChange={newVisibility => {
|
||||
const module = cornerstoneTools.getModule('rtstruct');
|
||||
|
||||
@@ -320,7 +320,7 @@ const SegmentationPanel = ({
|
||||
|
||||
const imageIds = toolState.data[0].imageIds;
|
||||
const imageId = imageIds[closest];
|
||||
const frameIndex = imageIds.indexOf(imageId);
|
||||
const imageIndex = imageIds.indexOf(imageId);
|
||||
|
||||
const SOPInstanceUID = cornerstone.metaData.get(
|
||||
'SOPInstanceUID',
|
||||
@@ -334,7 +334,7 @@ const SegmentationPanel = ({
|
||||
onSegmentItemClick({
|
||||
StudyInstanceUID,
|
||||
SOPInstanceUID,
|
||||
frameIndex,
|
||||
imageIndex,
|
||||
activeViewportIndex: activeIndex,
|
||||
});
|
||||
}
|
||||
@@ -360,7 +360,7 @@ const SegmentationPanel = ({
|
||||
SOPClassUID: viewports[activeIndex].sopClassUIDs[0],
|
||||
SOPInstanceUID: currentDisplaySet.SOPInstanceUID,
|
||||
segmentNumber,
|
||||
frameIndex: closest,
|
||||
imageIndex: closest,
|
||||
frame,
|
||||
});
|
||||
}
|
||||
@@ -637,7 +637,7 @@ const _setActiveLabelmap = async (
|
||||
displaySet,
|
||||
firstImageId,
|
||||
activeLabelmapIndex,
|
||||
callback = () => {},
|
||||
callback = () => { },
|
||||
onDisplaySetLoadFailure
|
||||
) => {
|
||||
if (displaySet.labelmapIndex === activeLabelmapIndex) {
|
||||
|
||||
@@ -50,6 +50,6 @@
|
||||
"classnames": "^2.2.6",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"react-cornerstone-viewport": "2.3.8"
|
||||
"react-cornerstone-viewport": "3.0.0"
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ function _getDisplaySetsFromSeries(
|
||||
if (
|
||||
!ConceptNameCodeSequence ||
|
||||
ConceptNameCodeSequence.CodeValue !==
|
||||
CodeNameCodeSequenceValues.ImagingMeasurementReport
|
||||
CodeNameCodeSequenceValues.ImagingMeasurementReport
|
||||
) {
|
||||
console.warn(
|
||||
'Only support Imaging Measurement Report SRs (TID1500) for now'
|
||||
@@ -282,7 +282,7 @@ function _getMeasurements(ImagingMeasurementReportContentSequence) {
|
||||
trackingUniqueIdentifier => {
|
||||
const mergedContentSequence =
|
||||
mergedContentSequencesByTrackingUniqueIdentifiers[
|
||||
trackingUniqueIdentifier
|
||||
trackingUniqueIdentifier
|
||||
];
|
||||
|
||||
const measurement = _processMeasurement(mergedContentSequence);
|
||||
@@ -322,7 +322,7 @@ function _getMergedContentSequencesByTrackingUniqueIdentifiers(
|
||||
|
||||
if (
|
||||
mergedContentSequencesByTrackingUniqueIdentifiers[
|
||||
trackingUniqueIdentifier
|
||||
trackingUniqueIdentifier
|
||||
] === undefined
|
||||
) {
|
||||
// Add the full ContentSequence
|
||||
@@ -448,9 +448,9 @@ function _processNonGeometricallyDefinedMeasurement(mergedContentSequence) {
|
||||
const cornerstoneFreeTextFinding = Findings.find(
|
||||
Finding =>
|
||||
Finding.ConceptCodeSequence.CodingSchemeDesignator ===
|
||||
CORNERSTONE_CODING_SCHEME_DESIGNATOR &&
|
||||
CORNERSTONE_CODING_SCHEME_DESIGNATOR &&
|
||||
Finding.ConceptCodeSequence.CodeValue ===
|
||||
CORNERSTONE_FREETEXT_CODE_VALUE
|
||||
CORNERSTONE_FREETEXT_CODE_VALUE
|
||||
);
|
||||
if (cornerstoneFreeTextFinding) {
|
||||
measurement.labels.push({
|
||||
|
||||
+128
-16
@@ -1,12 +1,20 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StudySummary, MeasurementTable } from '@ohif/ui';
|
||||
import { DicomMetadataStore, DICOMSR } from '@ohif/core';
|
||||
import {
|
||||
StudySummary,
|
||||
MeasurementTable,
|
||||
Dialog,
|
||||
Input,
|
||||
useViewportGrid,
|
||||
} from '@ohif/ui';
|
||||
import { DicomMetadataStore, DICOMSR, utils } from '@ohif/core';
|
||||
import { useDebounce } from '@hooks';
|
||||
import ActionButtons from './ActionButtons';
|
||||
import { useTrackedMeasurements } from '../../getContextModule';
|
||||
import createReportAsync from './../../_shared/createReportAsync.js';
|
||||
|
||||
const { formatDate } = utils;
|
||||
|
||||
const DISPLAY_STUDY_SUMMARY_INITIAL_VALUE = {
|
||||
key: undefined, //
|
||||
date: undefined, // '07-Sep-2010',
|
||||
@@ -15,6 +23,7 @@ const DISPLAY_STUDY_SUMMARY_INITIAL_VALUE = {
|
||||
};
|
||||
|
||||
function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
const [measurementChangeTimestamp, setMeasurementsUpdated] = useState(
|
||||
Date.now().toString()
|
||||
);
|
||||
@@ -22,11 +31,8 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
||||
measurementChangeTimestamp,
|
||||
200
|
||||
);
|
||||
const { MeasurementService } = servicesManager.services;
|
||||
const [
|
||||
trackedMeasurements,
|
||||
sendTrackedMeasurementsEvent,
|
||||
] = useTrackedMeasurements();
|
||||
const { MeasurementService, UINotificationService, UIDialogService, DisplaySetService } = servicesManager.services;
|
||||
const [trackedMeasurements, sendTrackedMeasurementsEvent] = useTrackedMeasurements();
|
||||
const { trackedStudy, trackedSeries } = trackedMeasurements.context;
|
||||
const [displayStudySummary, setDisplayStudySummary] = useState(
|
||||
DISPLAY_STUDY_SUMMARY_INITIAL_VALUE
|
||||
@@ -53,25 +59,37 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
||||
debouncedMeasurementChangeTimestamp,
|
||||
]);
|
||||
|
||||
// ~~ DisplayStudySummary
|
||||
useEffect(() => {
|
||||
const updateDisplayStudySummary = async () => {
|
||||
if (trackedMeasurements.matches('tracking')) {
|
||||
const StudyInstanceUID = trackedStudy;
|
||||
const studyMeta = DicomMetadataStore.getStudy(StudyInstanceUID);
|
||||
const instanceMeta = studyMeta.series[0].instances[0];
|
||||
const { Modality, StudyDate, StudyDescription } = instanceMeta;
|
||||
const { StudyDate, StudyDescription } = instanceMeta;
|
||||
|
||||
const modalities = new Set();
|
||||
studyMeta.series.forEach(series => {
|
||||
if (trackedSeries.includes(series.SeriesInstanceUID)) {
|
||||
modalities.add(series.instances[0].Modality);
|
||||
}
|
||||
});
|
||||
const modality = Array.from(modalities).join('/');
|
||||
|
||||
if (displayStudySummary.key !== StudyInstanceUID) {
|
||||
setDisplayStudySummary({
|
||||
key: StudyInstanceUID,
|
||||
date: StudyDate, // TODO: Format: '07-Sep-2010'
|
||||
modality: Modality,
|
||||
modality,
|
||||
description: StudyDescription,
|
||||
});
|
||||
}
|
||||
} else if (trackedStudy === '' || trackedStudy === undefined) {
|
||||
setDisplayStudySummary(DISPLAY_STUDY_SUMMARY_INITIAL_VALUE);
|
||||
}
|
||||
};
|
||||
|
||||
// ~~ DisplayStudySummary
|
||||
useEffect(() => {
|
||||
updateDisplayStudySummary();
|
||||
}, [displayStudySummary.key, trackedMeasurements, trackedStudy]);
|
||||
|
||||
// TODO: Better way to consolidated, debounce, check on change?
|
||||
@@ -129,12 +147,106 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
||||
DICOMSR.downloadReport(trackedMeasurements, dataSource);
|
||||
}
|
||||
|
||||
const jumpToImage = ({ id, isActive }) => {
|
||||
const measurement = MeasurementService.getMeasurement(id);
|
||||
const { referenceSeriesUID, SOPInstanceUID } = 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
|
||||
});
|
||||
|
||||
onMeasurementItemClickHandler({ id, isActive });
|
||||
};
|
||||
|
||||
const onMeasurementItemEditHandler = ({ id }) => {
|
||||
const measurement = MeasurementService.getMeasurement(id);
|
||||
|
||||
let dialogId;
|
||||
const onSubmitHandler = ({ action, value }) => {
|
||||
switch (action.id) {
|
||||
case 'save': {
|
||||
MeasurementService.update(id, {
|
||||
...measurement,
|
||||
...value
|
||||
});
|
||||
UINotificationService.show({
|
||||
title: 'Measurements',
|
||||
message: 'Label updated successfully',
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
}
|
||||
UIDialogService.dismiss({ id: dialogId });
|
||||
};
|
||||
dialogId = UIDialogService.create({
|
||||
centralize: true,
|
||||
isDraggable: false,
|
||||
useLastPosition: false,
|
||||
showOverlay: true,
|
||||
content: Dialog,
|
||||
contentProps: {
|
||||
title: 'Enter your annotation',
|
||||
noCloseButton: true,
|
||||
value: { label: measurement.label || '' },
|
||||
body: ({ value, setValue }) => {
|
||||
const onChangeHandler = (event) => {
|
||||
event.persist();
|
||||
setValue(value => ({ ...value, label: event.target.value }));
|
||||
};
|
||||
|
||||
const onKeyPressHandler = event => {
|
||||
if (event.key === 'Enter') {
|
||||
onSubmitHandler({ value, action: { id: 'save' } });
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="p-4 bg-primary-dark">
|
||||
<Input
|
||||
autoFocus
|
||||
className="mt-2 bg-black border-primary-main"
|
||||
type="text"
|
||||
containerClassName="mr-2"
|
||||
value={value.label}
|
||||
onChange={onChangeHandler}
|
||||
onKeyPress={onKeyPressHandler}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
actions: [
|
||||
{ id: 'cancel', text: 'Cancel', type: 'secondary' },
|
||||
{ id: 'save', text: 'Save', type: 'primary' },
|
||||
],
|
||||
onSubmit: onSubmitHandler
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onMeasurementItemClickHandler = ({ id, isActive }) => {
|
||||
if (!isActive) {
|
||||
const measurements = [...displayMeasurements];
|
||||
const measurement = measurements.find(m => m.id === id);
|
||||
measurements.forEach(m => m.isActive = m.id !== id ? false : true);
|
||||
measurement.isActive = true;
|
||||
setDisplayMeasurements(measurements);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="overflow-x-hidden overflow-y-auto invisible-scrollbar">
|
||||
{displayStudySummary.key && (
|
||||
<StudySummary
|
||||
date={displayStudySummary.date}
|
||||
date={formatDate(displayStudySummary.date)}
|
||||
modality={displayStudySummary.modality}
|
||||
description={displayStudySummary.description}
|
||||
/>
|
||||
@@ -143,8 +255,8 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
||||
title="Measurements"
|
||||
amount={displayMeasurements.length}
|
||||
data={displayMeasurements}
|
||||
onClick={() => { }}
|
||||
onEdit={id => alert(`Edit: ${id}`)}
|
||||
onClick={jumpToImage}
|
||||
onEdit={onMeasurementItemEditHandler}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-center p-4">
|
||||
@@ -187,8 +299,8 @@ function _mapMeasurementToDisplay(measurement, index, types) {
|
||||
const { PixelSpacing, SeriesNumber, InstanceNumber } = instance;
|
||||
|
||||
return {
|
||||
id: index + 1,
|
||||
label: '(empty)', // 'Label short description',
|
||||
id: measurement.id,
|
||||
label: measurement.label || '(empty)',
|
||||
displayText:
|
||||
_getDisplayText(
|
||||
measurement,
|
||||
|
||||
@@ -33,7 +33,6 @@ const BaseAnnotationTool = cornerstoneTools.importInternal(
|
||||
);
|
||||
|
||||
// const cine = viewportSpecificData.cine;
|
||||
|
||||
// isPlaying = cine.isPlaying === true;
|
||||
// frameRate = cine.cineFrameRate || frameRate;
|
||||
|
||||
@@ -47,7 +46,10 @@ function TrackedCornerstoneViewport({
|
||||
ToolBarService,
|
||||
}) {
|
||||
const [trackedMeasurements] = useTrackedMeasurements();
|
||||
const [{ activeViewportIndex, viewports }] = useViewportGrid();
|
||||
const [
|
||||
{ activeViewportIndex, viewports },
|
||||
viewportGridService,
|
||||
] = useViewportGrid();
|
||||
// viewportIndex, onSubmit
|
||||
const [viewportDialogState, viewportDialogApi] = useViewportDialog();
|
||||
const [viewportData, setViewportData] = useState(null);
|
||||
@@ -159,16 +161,15 @@ function TrackedCornerstoneViewport({
|
||||
);
|
||||
}
|
||||
|
||||
_getViewportData(dataSource, displaySet).then(viewportData => {
|
||||
setViewportData({ ...viewportData });
|
||||
});
|
||||
}, [
|
||||
dataSource,
|
||||
displaySet,
|
||||
displaySet.StudyInstanceUID,
|
||||
displaySet.displaySetInstanceUID,
|
||||
displaySet.frameIndex,
|
||||
]);
|
||||
/*
|
||||
* 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]);
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
let childrenWithProps = null;
|
||||
@@ -268,8 +269,8 @@ function TrackedCornerstoneViewport({
|
||||
spacing:
|
||||
PixelSpacing && PixelSpacing.length
|
||||
? `${PixelSpacing[0].toFixed(2)}mm x ${PixelSpacing[1].toFixed(
|
||||
2
|
||||
)}mm`
|
||||
2
|
||||
)}mm`
|
||||
: '',
|
||||
scanner: ManufacturerModelName || '',
|
||||
},
|
||||
@@ -282,6 +283,14 @@ function TrackedCornerstoneViewport({
|
||||
viewportIndex={viewportIndex}
|
||||
imageIds={imageIds}
|
||||
imageIdIndex={currentImageIdIndex}
|
||||
onNewImageDebounceTime={700}
|
||||
onNewImageDebounced={({ currentImageIdIndex }) => {
|
||||
viewportGridService.setDisplaysetForViewport({
|
||||
viewportIndex: activeViewportIndex,
|
||||
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||
imageIndex: currentImageIdIndex,
|
||||
});
|
||||
}}
|
||||
// TODO: ViewportGrid Context?
|
||||
isActive={true} // todo
|
||||
isStackPrefetchEnabled={true} // todo
|
||||
@@ -336,7 +345,7 @@ const _viewportLabels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
|
||||
* @return {Object} CornerstoneTools Stack
|
||||
*/
|
||||
function _getCornerstoneStack(displaySet, dataSource) {
|
||||
const { frameIndex } = displaySet;
|
||||
const { imageIndex } = displaySet;
|
||||
|
||||
// Get stack from Stack Manager
|
||||
const storedStack = StackManager.findOrCreateStack(displaySet, dataSource);
|
||||
@@ -344,17 +353,22 @@ function _getCornerstoneStack(displaySet, dataSource) {
|
||||
// Clone the stack here so we don't mutate it
|
||||
const stack = Object.assign({}, storedStack);
|
||||
|
||||
stack.currentImageIdIndex = frameIndex;
|
||||
stack.currentImageIdIndex = imageIndex;
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the viewport data from a datasource and a displayset.
|
||||
*
|
||||
* @param {Object} dataSource
|
||||
* @param {Object} displaySet
|
||||
* @return {Object} viewport data
|
||||
*/
|
||||
async function _getViewportData(dataSource, displaySet) {
|
||||
let viewportData;
|
||||
|
||||
const stack = _getCornerstoneStack(displaySet, dataSource);
|
||||
|
||||
viewportData = {
|
||||
const viewportData = {
|
||||
StudyInstanceUID: displaySet.StudyInstanceUID,
|
||||
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||
stack,
|
||||
|
||||
@@ -40,9 +40,9 @@ const ViewportOverlay = ({
|
||||
{isWwwcActive && (
|
||||
<div className="flex flex-row">
|
||||
<span className="mr-1">W:</span>
|
||||
<span className="font-thin ml-1 mr-2">{windowWidth.toFixed(0)}</span>
|
||||
<span className="ml-1 mr-2 font-thin">{windowWidth.toFixed(0)}</span>
|
||||
<span className="mr-1">L:</span>
|
||||
<span className="font-thin ml-1">{windowCenter.toFixed(0)}</span>
|
||||
<span className="ml-1 font-thin">{windowCenter.toFixed(0)}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -51,15 +51,13 @@ const ViewportOverlay = ({
|
||||
<div className="flex flex-row">
|
||||
<span className="mr-1">I:</span>
|
||||
<span className="font-thin">
|
||||
{`${instanceNumber}/${stackSize}`}
|
||||
{`${instanceNumber} ${imageIndex}/${stackSize}`}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={classnames(overlay, bottomRight)}>
|
||||
</div>
|
||||
<div className={classnames(overlay, bottomLeft)}>
|
||||
</div>
|
||||
<div className={classnames(overlay, bottomRight)}></div>
|
||||
<div className={classnames(overlay, bottomLeft)}></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -60,7 +60,7 @@ class OHIFVTKViewport extends Component {
|
||||
displaySetInstanceUID: PropTypes.string,
|
||||
sopClassUIDs: PropTypes.arrayOf(PropTypes.string),
|
||||
SOPInstanceUID: PropTypes.string,
|
||||
frameIndex: PropTypes.number,
|
||||
imageIndex: PropTypes.number,
|
||||
}),
|
||||
}),
|
||||
viewportIndex: PropTypes.number,
|
||||
@@ -69,7 +69,7 @@ class OHIFVTKViewport extends Component {
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
onScroll: () => {},
|
||||
onScroll: () => { },
|
||||
};
|
||||
|
||||
static id = 'OHIFVTKViewport';
|
||||
@@ -88,7 +88,7 @@ class OHIFVTKViewport extends Component {
|
||||
StudyInstanceUID,
|
||||
displaySetInstanceUID,
|
||||
SOPInstanceUID,
|
||||
frameIndex
|
||||
imageIndex
|
||||
) {
|
||||
// Create shortcut to displaySet
|
||||
const study = studies.find(
|
||||
@@ -105,8 +105,8 @@ class OHIFVTKViewport extends Component {
|
||||
// Clone the stack here so we don't mutate it
|
||||
const stack = Object.assign({}, storedStack);
|
||||
|
||||
if (frameIndex !== undefined) {
|
||||
stack.currentImageIdIndex = frameIndex;
|
||||
if (imageIndex !== undefined) {
|
||||
stack.currentImageIdIndex = imageIndex;
|
||||
} else if (SOPInstanceUID) {
|
||||
const index = stack.imageIds.findIndex(imageId => {
|
||||
const imageIdSOPInstanceUID = cornerstone.metaData.get(
|
||||
@@ -133,7 +133,7 @@ class OHIFVTKViewport extends Component {
|
||||
displaySetInstanceUID,
|
||||
SOPClassUID,
|
||||
SOPInstanceUID,
|
||||
frameIndex
|
||||
imageIndex
|
||||
) => {
|
||||
const stack = OHIFVTKViewport.getCornerstoneStack(
|
||||
studies,
|
||||
@@ -141,7 +141,7 @@ class OHIFVTKViewport extends Component {
|
||||
displaySetInstanceUID,
|
||||
SOPClassUID,
|
||||
SOPInstanceUID,
|
||||
frameIndex
|
||||
imageIndex
|
||||
);
|
||||
|
||||
const imageDataObject = getImageData(stack.imageIds, displaySetInstanceUID);
|
||||
@@ -270,7 +270,7 @@ class OHIFVTKViewport extends Component {
|
||||
displaySetInstanceUID,
|
||||
sopClassUIDs,
|
||||
SOPInstanceUID,
|
||||
frameIndex,
|
||||
imageIndex,
|
||||
} = displaySet;
|
||||
|
||||
if (sopClassUIDs.length > 1) {
|
||||
@@ -302,7 +302,7 @@ class OHIFVTKViewport extends Component {
|
||||
StudyInstanceUID,
|
||||
displaySetInstanceUID,
|
||||
SOPInstanceUID,
|
||||
frameIndex
|
||||
imageIndex
|
||||
);
|
||||
|
||||
this.imageDataObject = imageDataObject;
|
||||
@@ -351,9 +351,9 @@ class OHIFVTKViewport extends Component {
|
||||
|
||||
if (
|
||||
displaySet.displaySetInstanceUID !==
|
||||
prevDisplaySet.displaySetInstanceUID ||
|
||||
prevDisplaySet.displaySetInstanceUID ||
|
||||
displaySet.SOPInstanceUID !== prevDisplaySet.SOPInstanceUID ||
|
||||
displaySet.frameIndex !== prevDisplaySet.frameIndex
|
||||
displaySet.imageIndex !== prevDisplaySet.imageIndex
|
||||
) {
|
||||
this.setStateFromProps();
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ const commandsModule = ({ commandsManager }) => {
|
||||
segmentNumber,
|
||||
frameIndex,
|
||||
frame,
|
||||
done = () => {},
|
||||
done = () => { },
|
||||
}) => {
|
||||
let api = apis[viewports.activeViewportIndex];
|
||||
|
||||
|
||||
Reference in new issue
Block a user