2020-07-02 22:53:38 +02:00
|
|
|
import React from 'react';
|
2019-10-09 16:23:14 +02:00
|
|
|
import OHIF from '@ohif/core';
|
2020-07-02 22:53:38 +02:00
|
|
|
import { Dialog, Input } from '@ohif/ui';
|
2019-10-09 16:23:14 +02:00
|
|
|
import cornerstone from 'cornerstone-core';
|
|
|
|
|
import csTools from 'cornerstone-tools';
|
2019-12-09 18:47:23 +01:00
|
|
|
import merge from 'lodash.merge';
|
2019-12-16 17:47:02 +01:00
|
|
|
import initCornerstoneTools from './initCornerstoneTools.js';
|
2020-07-03 19:18:59 +02:00
|
|
|
import cornerstoneTools from 'cornerstone-tools';
|
2020-05-15 12:48:00 +02:00
|
|
|
import initWADOImageLoader from './initWADOImageLoader.js';
|
2020-02-10 20:15:05 +01:00
|
|
|
import measurementServiceMappingsFactory from './utils/measurementServiceMappings/measurementServiceMappingsFactory';
|
2020-06-26 20:14:25 +02:00
|
|
|
//
|
|
|
|
|
import { setEnabledElement } from './state';
|
2019-11-08 13:55:56 +01:00
|
|
|
|
2019-10-09 16:23:14 +02:00
|
|
|
/**
|
|
|
|
|
*
|
2019-12-09 18:47:23 +01:00
|
|
|
* @param {Object} servicesManager
|
|
|
|
|
* @param {Object} configuration
|
2019-10-09 16:23:14 +02:00
|
|
|
* @param {Object|Array} configuration.csToolsConfig
|
|
|
|
|
*/
|
2019-12-09 18:47:23 +01:00
|
|
|
export default function init({ servicesManager, configuration }) {
|
2020-07-22 19:40:40 +02:00
|
|
|
const {
|
|
|
|
|
UIDialogService,
|
|
|
|
|
MeasurementService,
|
|
|
|
|
DisplaySetService,
|
|
|
|
|
} = servicesManager.services;
|
2019-12-09 18:47:23 +01:00
|
|
|
|
2020-02-10 20:15:05 +01:00
|
|
|
const callInputDialog = (data, event, callback) => {
|
2019-12-09 18:47:23 +01:00
|
|
|
if (UIDialogService) {
|
|
|
|
|
let dialogId = UIDialogService.create({
|
|
|
|
|
centralize: true,
|
|
|
|
|
isDraggable: false,
|
2020-07-02 22:53:38 +02:00
|
|
|
content: Dialog,
|
2019-12-09 18:47:23 +01:00
|
|
|
useLastPosition: false,
|
|
|
|
|
showOverlay: true,
|
|
|
|
|
contentProps: {
|
|
|
|
|
title: 'Enter your annotation',
|
2020-07-02 22:53:38 +02:00
|
|
|
value: { label: data ? data.text : '' },
|
|
|
|
|
noCloseButton: true,
|
2019-12-09 18:47:23 +01:00
|
|
|
onClose: () => UIDialogService.dismiss({ id: dialogId }),
|
2020-07-02 22:53:38 +02:00
|
|
|
actions: [
|
|
|
|
|
{ id: 'cancel', text: 'Cancel', type: 'secondary' },
|
|
|
|
|
{ id: 'save', text: 'Save', type: 'primary' },
|
|
|
|
|
],
|
|
|
|
|
onSubmit: ({ action, value }) => {
|
|
|
|
|
switch (action.id) {
|
2020-07-03 19:12:33 +02:00
|
|
|
case 'save':
|
|
|
|
|
callback(value.label);
|
2020-07-24 16:34:10 +02:00
|
|
|
break;
|
|
|
|
|
case 'cancel':
|
|
|
|
|
callback();
|
|
|
|
|
break;
|
2020-07-02 22:53:38 +02:00
|
|
|
}
|
2019-12-09 18:47:23 +01:00
|
|
|
UIDialogService.dismiss({ id: dialogId });
|
|
|
|
|
},
|
2020-07-02 22:53:38 +02:00
|
|
|
body: ({ value, setValue }) => {
|
2020-07-03 19:12:33 +02:00
|
|
|
const onChangeHandler = event => {
|
2020-07-02 22:53:38 +02:00
|
|
|
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>
|
|
|
|
|
);
|
|
|
|
|
},
|
2019-11-25 23:13:42 +01:00
|
|
|
},
|
2019-12-09 18:47:23 +01:00
|
|
|
});
|
|
|
|
|
}
|
2019-11-25 23:13:42 +01:00
|
|
|
};
|
|
|
|
|
|
2019-10-09 16:23:14 +02:00
|
|
|
const { csToolsConfig } = configuration;
|
2020-03-09 20:03:23 +01:00
|
|
|
const metadataProvider = OHIF.cornerstone.metadataProvider;
|
2019-10-09 16:23:14 +02:00
|
|
|
|
|
|
|
|
cornerstone.metaData.addProvider(
|
2020-03-09 20:03:23 +01:00
|
|
|
metadataProvider.get.bind(metadataProvider),
|
|
|
|
|
9999
|
2019-10-09 16:23:14 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// ~~
|
|
|
|
|
const defaultCsToolsConfig = csToolsConfig || {
|
|
|
|
|
globalToolSyncEnabled: true,
|
|
|
|
|
showSVGCursors: true,
|
|
|
|
|
autoResizeViewports: false,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
initCornerstoneTools(defaultCsToolsConfig);
|
2020-06-26 20:14:25 +02:00
|
|
|
// TODO: Extensions are still registered at time of registration globally
|
|
|
|
|
// These should be registered as a part of mode route spin up,
|
|
|
|
|
// and they need to self-clean on mode route destroy
|
|
|
|
|
// 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.
|
2020-07-03 19:12:33 +02:00
|
|
|
const handleOhifCornerstoneEnabledElementEvent = function(evt) {
|
2020-06-26 20:14:25 +02:00
|
|
|
const { viewportIndex, enabledElement } = evt.detail;
|
|
|
|
|
|
|
|
|
|
setEnabledElement(viewportIndex, enabledElement);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
document.addEventListener(
|
|
|
|
|
'ohif-cornerstone-enabled-element-event',
|
|
|
|
|
handleOhifCornerstoneEnabledElementEvent
|
|
|
|
|
);
|
2019-10-09 16:23:14 +02:00
|
|
|
|
2019-12-20 18:15:40 +01:00
|
|
|
const toolsGroupedByType = {
|
|
|
|
|
touch: [csTools.PanMultiTouchTool, csTools.ZoomTouchPinchTool],
|
|
|
|
|
annotations: [
|
|
|
|
|
csTools.ArrowAnnotateTool,
|
|
|
|
|
csTools.BidirectionalTool,
|
|
|
|
|
csTools.LengthTool,
|
|
|
|
|
csTools.AngleTool,
|
|
|
|
|
csTools.FreehandRoiTool,
|
|
|
|
|
csTools.EllipticalRoiTool,
|
|
|
|
|
csTools.DragProbeTool,
|
|
|
|
|
csTools.RectangleRoiTool,
|
|
|
|
|
],
|
|
|
|
|
other: [
|
|
|
|
|
csTools.PanTool,
|
|
|
|
|
csTools.ZoomTool,
|
|
|
|
|
csTools.WwwcTool,
|
2020-03-04 16:56:04 +01:00
|
|
|
csTools.WwwcRegionTool,
|
2020-03-04 16:57:27 +01:00
|
|
|
csTools.MagnifyTool,
|
2019-12-20 18:15:40 +01:00
|
|
|
csTools.StackScrollTool,
|
|
|
|
|
csTools.StackScrollMouseWheelTool,
|
2020-01-28 13:40:03 +01:00
|
|
|
csTools.OverlayTool,
|
2019-12-20 18:15:40 +01:00
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let tools = [];
|
|
|
|
|
Object.keys(toolsGroupedByType).forEach(toolsGroup =>
|
|
|
|
|
tools.push(...toolsGroupedByType[toolsGroup])
|
|
|
|
|
);
|
2019-10-09 16:23:14 +02:00
|
|
|
|
2020-02-10 20:15:05 +01:00
|
|
|
/* Measurement Service */
|
2020-07-22 19:40:40 +02:00
|
|
|
_connectToolsToMeasurementService(MeasurementService, DisplaySetService);
|
2020-02-10 20:15:05 +01:00
|
|
|
|
2019-12-09 18:47:23 +01:00
|
|
|
/* Add extension tools configuration here. */
|
2019-12-11 10:54:41 +01:00
|
|
|
const internalToolsConfig = {
|
2019-12-09 18:47:23 +01:00
|
|
|
ArrowAnnotate: {
|
|
|
|
|
configuration: {
|
|
|
|
|
getTextCallback: (callback, eventDetails) =>
|
|
|
|
|
callInputDialog(null, eventDetails, callback),
|
|
|
|
|
changeTextCallback: (data, eventDetails, callback) =>
|
|
|
|
|
callInputDialog(data, eventDetails, callback),
|
2020-07-24 16:34:10 +02:00
|
|
|
allowEmptyLabel: true,
|
2019-12-09 18:47:23 +01:00
|
|
|
},
|
2019-11-25 23:13:42 +01:00
|
|
|
},
|
2020-07-24 08:53:10 +02:00
|
|
|
DragProbe: {
|
2020-07-24 16:32:44 +02:00
|
|
|
defaultStrategy: 'minimal',
|
|
|
|
|
},
|
2019-12-09 18:47:23 +01:00
|
|
|
};
|
|
|
|
|
|
2019-12-20 18:15:40 +01:00
|
|
|
/* Abstract tools configuration using extension configuration. */
|
|
|
|
|
const parseToolProps = (props, tool) => {
|
|
|
|
|
const { annotations } = toolsGroupedByType;
|
|
|
|
|
// An alternative approach would be to remove the `drawHandlesOnHover` config
|
|
|
|
|
// from the supported configuration properties in `cornerstone-tools`
|
|
|
|
|
const toolsWithHideableHandles = annotations.filter(
|
|
|
|
|
tool => !['RectangleRoiTool', 'EllipticalRoiTool'].includes(tool.name)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let parsedProps = { ...props };
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* drawHandles - Never/Always show handles
|
|
|
|
|
* drawHandlesOnHover - Only show handles on handle hover (pointNearHandle)
|
2020-07-03 11:51:38 +02:00
|
|
|
* hideHandlesIfMoving - Hides the handles whilst you are moving them, for better visibility.
|
2019-12-20 18:15:40 +01:00
|
|
|
*
|
|
|
|
|
* Does not apply to tools where handles aren't placed in predictable
|
|
|
|
|
* locations.
|
|
|
|
|
*/
|
|
|
|
|
if (
|
|
|
|
|
configuration.hideHandles !== false &&
|
|
|
|
|
toolsWithHideableHandles.includes(tool)
|
|
|
|
|
) {
|
|
|
|
|
if (props.configuration) {
|
|
|
|
|
parsedProps.configuration.drawHandlesOnHover = true;
|
2020-07-03 11:51:38 +02:00
|
|
|
parsedProps.configuration.hideHandlesIfMoving = true;
|
2019-12-20 18:15:40 +01:00
|
|
|
} else {
|
2020-07-03 11:51:38 +02:00
|
|
|
parsedProps.configuration = {
|
|
|
|
|
drawHandlesOnHover: true,
|
|
|
|
|
hideHandlesIfMoving: true,
|
|
|
|
|
};
|
2019-12-20 18:15:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return parsedProps;
|
|
|
|
|
};
|
|
|
|
|
|
2019-12-11 10:54:41 +01:00
|
|
|
/* Add tools with its custom props through extension configuration. */
|
|
|
|
|
tools.forEach(tool => {
|
2020-07-24 11:10:38 +02:00
|
|
|
const toolName = new tool().name;
|
2019-12-11 10:54:41 +01:00
|
|
|
const externalToolsConfig = configuration.tools || {};
|
|
|
|
|
const externalToolProps = externalToolsConfig[toolName] || {};
|
|
|
|
|
const internalToolProps = internalToolsConfig[toolName] || {};
|
2019-12-20 18:15:40 +01:00
|
|
|
const props = merge(
|
|
|
|
|
internalToolProps,
|
|
|
|
|
parseToolProps(externalToolProps, tool)
|
|
|
|
|
);
|
2019-12-11 10:54:41 +01:00
|
|
|
csTools.addTool(tool, props);
|
|
|
|
|
});
|
2019-11-25 23:13:42 +01:00
|
|
|
|
2019-12-11 17:14:01 +01:00
|
|
|
// TODO -> We need a better way to do this with maybe global tool state setting all tools passive.
|
|
|
|
|
const BaseAnnotationTool = csTools.importInternal('base/BaseAnnotationTool');
|
|
|
|
|
tools.forEach(tool => {
|
|
|
|
|
if (tool.prototype instanceof BaseAnnotationTool) {
|
|
|
|
|
// BaseAnnotationTool would likely come from csTools lib exports
|
|
|
|
|
const toolName = new tool().name;
|
|
|
|
|
csTools.setToolPassive(toolName); // there may be a better place to determine name; may not be on uninstantiated class
|
|
|
|
|
}
|
|
|
|
|
});
|
2019-12-16 17:47:02 +01:00
|
|
|
|
2019-10-09 16:23:14 +02:00
|
|
|
csTools.setToolActive('Pan', { mouseButtonMask: 4 });
|
|
|
|
|
csTools.setToolActive('Zoom', { mouseButtonMask: 2 });
|
|
|
|
|
csTools.setToolActive('Wwwc', { mouseButtonMask: 1 });
|
|
|
|
|
csTools.setToolActive('StackScrollMouseWheel', {}); // TODO: Empty options should not be required
|
|
|
|
|
csTools.setToolActive('PanMultiTouch', { pointers: 2 }); // TODO: Better error if no options
|
|
|
|
|
csTools.setToolActive('ZoomTouchPinch', {});
|
2020-01-28 13:40:03 +01:00
|
|
|
csTools.setToolEnabled('Overlay', {});
|
2019-10-09 16:23:14 +02:00
|
|
|
}
|
2020-02-10 20:15:05 +01:00
|
|
|
|
2020-07-22 19:40:40 +02:00
|
|
|
const _initMeasurementService = (MeasurementService, DisplaySetService) => {
|
2020-02-10 20:15:05 +01:00
|
|
|
/* Initialization */
|
2020-06-25 18:13:31 +02:00
|
|
|
const {
|
|
|
|
|
Length,
|
|
|
|
|
Bidirectional,
|
|
|
|
|
EllipticalRoi,
|
|
|
|
|
ArrowAnnotate,
|
2020-07-22 19:40:40 +02:00
|
|
|
} = measurementServiceMappingsFactory(MeasurementService, DisplaySetService);
|
|
|
|
|
const csToolsVer4MeasurementSource = MeasurementService.createSource(
|
2020-02-10 20:15:05 +01:00
|
|
|
'CornerstoneTools',
|
|
|
|
|
'4'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* Mappings */
|
2020-07-22 19:40:40 +02:00
|
|
|
MeasurementService.addMapping(
|
2020-02-10 20:15:05 +01:00
|
|
|
csToolsVer4MeasurementSource,
|
|
|
|
|
'Length',
|
2020-06-25 18:13:31 +02:00
|
|
|
Length.matchingCriteria,
|
|
|
|
|
Length.toAnnotation,
|
|
|
|
|
Length.toMeasurement
|
|
|
|
|
);
|
|
|
|
|
|
2020-07-22 19:40:40 +02:00
|
|
|
MeasurementService.addMapping(
|
2020-06-25 18:13:31 +02:00
|
|
|
csToolsVer4MeasurementSource,
|
|
|
|
|
'Bidirectional',
|
|
|
|
|
Bidirectional.matchingCriteria,
|
|
|
|
|
Bidirectional.toAnnotation,
|
|
|
|
|
Bidirectional.toMeasurement
|
|
|
|
|
);
|
|
|
|
|
|
2020-07-22 19:40:40 +02:00
|
|
|
MeasurementService.addMapping(
|
2020-06-25 18:13:31 +02:00
|
|
|
csToolsVer4MeasurementSource,
|
|
|
|
|
'EllipticalRoi',
|
|
|
|
|
EllipticalRoi.matchingCriteria,
|
|
|
|
|
EllipticalRoi.toAnnotation,
|
|
|
|
|
EllipticalRoi.toMeasurement
|
|
|
|
|
);
|
|
|
|
|
|
2020-07-22 19:40:40 +02:00
|
|
|
MeasurementService.addMapping(
|
2020-06-25 18:13:31 +02:00
|
|
|
csToolsVer4MeasurementSource,
|
|
|
|
|
'ArrowAnnotate',
|
|
|
|
|
ArrowAnnotate.matchingCriteria,
|
|
|
|
|
ArrowAnnotate.toAnnotation,
|
|
|
|
|
ArrowAnnotate.toMeasurement
|
2020-02-10 20:15:05 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return csToolsVer4MeasurementSource;
|
|
|
|
|
};
|
|
|
|
|
|
2020-07-22 19:40:40 +02:00
|
|
|
const _connectToolsToMeasurementService = (
|
|
|
|
|
MeasurementService,
|
|
|
|
|
DisplaySetService
|
|
|
|
|
) => {
|
2020-02-21 20:27:32 +01:00
|
|
|
const csToolsVer4MeasurementSource = _initMeasurementService(
|
2020-07-22 19:40:40 +02:00
|
|
|
MeasurementService,
|
|
|
|
|
DisplaySetService
|
2020-02-21 20:27:32 +01:00
|
|
|
);
|
2020-07-03 19:12:33 +02:00
|
|
|
_connectMeasurementServiceToTools(
|
2020-07-22 19:40:40 +02:00
|
|
|
MeasurementService,
|
2020-07-03 19:12:33 +02:00
|
|
|
csToolsVer4MeasurementSource
|
|
|
|
|
);
|
2020-06-09 19:37:26 +02:00
|
|
|
const { addOrUpdate, remove } = csToolsVer4MeasurementSource;
|
|
|
|
|
const elementEnabledEvt = cornerstone.EVENTS.ELEMENT_ENABLED;
|
2020-02-10 20:15:05 +01:00
|
|
|
|
|
|
|
|
/* Measurement Service Events */
|
2020-06-09 19:37:26 +02:00
|
|
|
cornerstone.events.addEventListener(elementEnabledEvt, evt => {
|
|
|
|
|
// TODO: Debounced update of measurements that are modified
|
|
|
|
|
|
|
|
|
|
function addMeasurement(csToolsEvent) {
|
|
|
|
|
console.log('CSTOOLS::addOrUpdate', csToolsEvent, csToolsEvent.detail);
|
2020-07-01 11:08:56 +02:00
|
|
|
|
2020-06-09 19:37:26 +02:00
|
|
|
try {
|
|
|
|
|
const evtDetail = csToolsEvent.detail;
|
|
|
|
|
const { toolName, toolType, measurementData } = evtDetail;
|
|
|
|
|
const csToolName = toolName || measurementData.toolType || toolType;
|
2020-07-01 11:08:56 +02:00
|
|
|
|
2020-06-09 19:37:26 +02:00
|
|
|
const measurementId = addOrUpdate(csToolName, evtDetail);
|
|
|
|
|
|
|
|
|
|
if (measurementId) {
|
|
|
|
|
measurementData.id = measurementId;
|
2020-02-10 20:15:05 +01:00
|
|
|
}
|
2020-06-09 19:37:26 +02:00
|
|
|
} catch (error) {
|
|
|
|
|
console.warn('Failed to add measurement:', error);
|
|
|
|
|
}
|
2020-02-10 20:15:05 +01:00
|
|
|
}
|
2020-06-09 19:37:26 +02:00
|
|
|
|
|
|
|
|
function updateMeasurement(csToolsEvent) {
|
|
|
|
|
try {
|
|
|
|
|
if (!csToolsEvent.detail.measurementData.id) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const evtDetail = csToolsEvent.detail;
|
|
|
|
|
const { toolName, toolType, measurementData } = evtDetail;
|
|
|
|
|
const csToolName = toolName || measurementData.toolType || toolType;
|
|
|
|
|
|
|
|
|
|
evtDetail.id = csToolsEvent.detail.measurementData.id;
|
|
|
|
|
addOrUpdate(csToolName, evtDetail);
|
|
|
|
|
//
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.warn('Failed to update measurement:', error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-04 11:11:23 +02:00
|
|
|
/**
|
|
|
|
|
* When csTools fires a removed event, remove the same measurement
|
|
|
|
|
* from the measurement service
|
|
|
|
|
*
|
|
|
|
|
* @param {*} csToolsEvent
|
|
|
|
|
*/
|
2020-06-09 19:37:26 +02:00
|
|
|
function removeMeasurement(csToolsEvent) {
|
|
|
|
|
console.log('~~ removeEvt', csToolsEvent);
|
|
|
|
|
try {
|
|
|
|
|
if (csToolsEvent.detail.measurementData.id) {
|
|
|
|
|
remove(csToolsEvent.detail.measurementData.id);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.warn('Failed to remove measurement:', error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-22 19:40:40 +02:00
|
|
|
const { MEASUREMENTS_CLEARED } = MeasurementService.EVENTS;
|
2020-07-03 19:18:59 +02:00
|
|
|
|
2020-07-22 19:40:40 +02:00
|
|
|
MeasurementService.subscribe(MEASUREMENTS_CLEARED, () => {
|
2020-07-03 19:18:59 +02:00
|
|
|
cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState(
|
|
|
|
|
{}
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
2020-06-09 19:37:26 +02:00
|
|
|
const enabledElement = evt.detail.element;
|
|
|
|
|
const completedEvt = csTools.EVENTS.MEASUREMENT_COMPLETED;
|
|
|
|
|
const updatedEvt = csTools.EVENTS.MEASUREMENT_MODIFIED;
|
|
|
|
|
const removedEvt = csTools.EVENTS.MEASUREMENT_REMOVED;
|
|
|
|
|
|
|
|
|
|
enabledElement.addEventListener(completedEvt, addMeasurement);
|
|
|
|
|
enabledElement.addEventListener(updatedEvt, updateMeasurement);
|
|
|
|
|
enabledElement.addEventListener(removedEvt, removeMeasurement);
|
|
|
|
|
});
|
2020-02-10 20:15:05 +01:00
|
|
|
};
|
2020-06-09 19:37:26 +02:00
|
|
|
|
2020-07-03 19:12:33 +02:00
|
|
|
const _connectMeasurementServiceToTools = (
|
2020-07-22 19:40:40 +02:00
|
|
|
MeasurementService,
|
2020-07-03 19:12:33 +02:00
|
|
|
measurementSource
|
|
|
|
|
) => {
|
|
|
|
|
const {
|
|
|
|
|
MEASUREMENTS_CLEARED,
|
|
|
|
|
MEASUREMENT_REMOVED,
|
2020-07-22 19:40:40 +02:00
|
|
|
} = MeasurementService.EVENTS;
|
2020-07-03 18:39:41 +02:00
|
|
|
const sourceId = measurementSource.id;
|
|
|
|
|
|
2020-07-22 19:40:40 +02:00
|
|
|
MeasurementService.subscribe(MEASUREMENTS_CLEARED, () => {
|
2020-07-03 19:12:33 +02:00
|
|
|
cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState({});
|
2020-07-03 18:39:41 +02:00
|
|
|
cornerstone.getEnabledElements().forEach(enabledElement => {
|
|
|
|
|
cornerstone.updateImage(enabledElement.element);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2020-08-04 11:11:23 +02:00
|
|
|
// TODO: This is an unsafe delete
|
|
|
|
|
// Cornerstone-tools should probably expose a more generic "delete by id"
|
|
|
|
|
// And have toolState managers expose a method to find any of their toolState by ID
|
|
|
|
|
// --> csTools.deleteById --> internally checks all registered modules/managers?
|
|
|
|
|
//
|
|
|
|
|
// This implementation assumes a single globalImageIdSpecificToolStateManager
|
|
|
|
|
// It iterates all toolState for all toolTypes, and deletes any with a matching id
|
|
|
|
|
//
|
|
|
|
|
// Could potentially use "source" from event to determine tool type and skip some
|
|
|
|
|
// iterations?
|
|
|
|
|
MeasurementService.subscribe(
|
|
|
|
|
MEASUREMENT_REMOVED,
|
|
|
|
|
({ source, measurement: removedMeasurementId }) => {
|
|
|
|
|
// THIS POINTS TO ORIGINAL; Not a copy
|
|
|
|
|
const imageIdSpecificToolState = cornerstoneTools.globalImageIdSpecificToolStateManager.saveToolState();
|
|
|
|
|
|
|
|
|
|
// ImageId -->
|
|
|
|
|
Object.keys(imageIdSpecificToolState).forEach(imageId => {
|
|
|
|
|
// ImageId --> Tool -->
|
|
|
|
|
Object.keys(imageIdSpecificToolState[imageId]).forEach(toolName => {
|
|
|
|
|
const toolState = imageIdSpecificToolState[imageId][toolName];
|
|
|
|
|
|
|
|
|
|
let annotationIndex = toolState.data.length - 1;
|
|
|
|
|
while (annotationIndex >= 0) {
|
|
|
|
|
const annotation = toolState.data[annotationIndex];
|
|
|
|
|
|
|
|
|
|
if (annotation.id === removedMeasurementId) {
|
|
|
|
|
toolState.data.splice(annotationIndex, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
annotationIndex--;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
2020-07-03 18:39:41 +02:00
|
|
|
}
|
2020-08-04 11:11:23 +02:00
|
|
|
);
|
2020-07-03 18:39:41 +02:00
|
|
|
};
|
|
|
|
|
|
2020-06-09 19:37:26 +02:00
|
|
|
// const {
|
|
|
|
|
// MEASUREMENT_ADDED,
|
|
|
|
|
// MEASUREMENT_UPDATED,
|
2020-07-22 19:40:40 +02:00
|
|
|
// } = MeasurementService.EVENTS;
|
2020-06-09 19:37:26 +02:00
|
|
|
|
2020-07-22 19:40:40 +02:00
|
|
|
// MeasurementService.subscribe(
|
2020-06-09 19:37:26 +02:00
|
|
|
// MEASUREMENT_ADDED,
|
|
|
|
|
// ({ source, measurement }) => {
|
|
|
|
|
// if (![sourceId].includes(source.id)) {
|
|
|
|
|
// const annotation = getAnnotation('Length', measurement.id);
|
|
|
|
|
|
|
|
|
|
// console.log(
|
|
|
|
|
// 'Measurement Service [Cornerstone]: Measurement added',
|
|
|
|
|
// measurement
|
|
|
|
|
// );
|
|
|
|
|
// console.log('Mapped annotation:', annotation);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// );
|
|
|
|
|
|
2020-07-22 19:40:40 +02:00
|
|
|
// MeasurementService.subscribe(
|
2020-06-09 19:37:26 +02:00
|
|
|
// MEASUREMENT_UPDATED,
|
|
|
|
|
// ({ source, measurement }) => {
|
|
|
|
|
// if (![sourceId].includes(source.id)) {
|
|
|
|
|
// const annotation = getAnnotation('Length', measurement.id);
|
|
|
|
|
|
|
|
|
|
// console.log(
|
|
|
|
|
// 'Measurement Service [Cornerstone]: Measurement updated',
|
|
|
|
|
// measurement
|
|
|
|
|
// );
|
|
|
|
|
// console.log('Mapped annotation:', annotation);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// );
|