feat!: Ability to configure cornerstone tools via extension configuration (#1229)
* Fix ExtensionManager bug and add test to bandaid * Add tools configuration to extension manager preinit * Fix reducing of configs * Merge internal with external configs * Merge internal with external configs * Remove dialog from init in measurementstable * Testing injected configuration * New way to set config * Add new prop to dialog provider to allow disabling last position * Remove code from preinit in cornerstone * Add new prop to dialog provider to allow disabling last position * Add centralize to dialogs * Reorder dialogs when adding them * Fix draggable styles (cursor) * Remove repositioning methods from labelling flow and remove overlay from labelling manager * Fix empty array being set in bringToFront * Add new command to update table and pass commands manager to modules/preinit hook * Ad UIContextMenu service / factory * Use new contextmenu service in measurementspanel extension * Use dialogs for arrow annotate in default * Remove positioning funcionality from tool context menu * Add context menu service * Pass commandsModule to extension * Update edit description dialog and simple dialog to position relative * Remove style code from labelling flow and manager * Remove eventdata from labelling * Remove labelling code from measurement init * Add commandsmanager to provider * Update contextmenu provider and service * Add touchstart and mouseclick to hide contextmenu * Hide labelling if click/touch * Remove labelling and context menu dead code * Fix undefined bug if ViewerMain grid has no children * Fix broken prop on context menu * Update commandsmodule based on master * Fix broken configuration * Update script tag config * Remove cornerstone from toolcontextmenu * Remove cornerstone from toolcontextmenu * Split labelling and context menu providers * Split labelling and context menu providers * Update test * Destructure extensions into new array * CR Update: Move default arrow config to cornerstone instead of default * CR Update: Fix app configuration props structure * CR Update: Fix app configuration prop in script tag and extract commands manager from providers * CR Update: Create custom providers to use commandsManager * CR Update: Use services directly in measurementspanel * CR Update: Pass components to providers * CR Update: Remove position from dialog * CR Update: fix dialog prop check * CR Update: Fix comments * CR Update: Update documentation * CR Update: Add test default configuration * CR Update: Add default empy array to extensions * CR Update: Update i18n configuration all ot match current function configuration * CR Update: Add defaults to injected dependencies in configuration and extension configuration * CR Update: Add defaults to configuration with no args * Update documentation * CR Update: Add default for tools * CR Update: Update config object to i18n * CR Update: spread defaults * CR Update: Add tool configuration example to cornerstone extension * CR Update: Add tool configuration to netlify (testing) * CR Update: Remove netlify config for tools * CR Update: Rollback changes to i18n to be fixed later * CR Update: Update documentation and pass whole cornerstone config object instead of tools key SEE: https://www.conventionalcommits.org/en/v1.0.0/#commit-message-with-both-and-breaking-change-footer BREAKING CHANGE: modifies the exposed react <App /> components props. The contract for providing configuration for the app has changed. Please reference updated documentation for guidance.
This commit is contained in:
1 parent
fd7620ced9
commit
55a580659e
66 files changed
+1464
-1223
No files matched your search
@@ -4,9 +4,7 @@ import OHIF from '@ohif/core';
|
||||
import moment from 'moment';
|
||||
import cornerstone from 'cornerstone-core';
|
||||
|
||||
//
|
||||
import jumpToRowItem from './jumpToRowItem.js';
|
||||
import getMeasurementLocationCallback from './getMeasurementLocationCallback';
|
||||
|
||||
const { setViewportSpecificData } = OHIF.redux.actions;
|
||||
const { MeasurementApi } = OHIF.measurements;
|
||||
@@ -155,9 +153,11 @@ const mapStateToProps = state => {
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
const mapDispatchToProps = (dispatch, ownProps) => {
|
||||
return {
|
||||
dispatchRelabel: (event, measurementData, viewportsState) => {
|
||||
event.persist();
|
||||
|
||||
const activeViewportIndex =
|
||||
(viewportsState && viewportsState.activeViewportIndex) || 0;
|
||||
|
||||
@@ -167,31 +167,21 @@ const mapDispatchToProps = dispatch => {
|
||||
return;
|
||||
}
|
||||
|
||||
const { element } = enabledElements[activeViewportIndex];
|
||||
|
||||
const eventData = {
|
||||
event: {
|
||||
clientX: event.clientX,
|
||||
clientY: event.clientY,
|
||||
},
|
||||
element,
|
||||
};
|
||||
|
||||
const { toolType, measurementId } = measurementData;
|
||||
const tool = MeasurementApi.Instance.tools[toolType].find(measurement => {
|
||||
return measurement._id === measurementId;
|
||||
});
|
||||
|
||||
const options = {
|
||||
skipAddLabelButton: true,
|
||||
editLocation: true,
|
||||
};
|
||||
|
||||
// Clone the tool not to set empty location initially
|
||||
const toolForLocation = Object.assign({}, tool, { location: null });
|
||||
getMeasurementLocationCallback(eventData, toolForLocation, options);
|
||||
|
||||
if (ownProps.onRelabel) {
|
||||
ownProps.onRelabel(toolForLocation);
|
||||
}
|
||||
},
|
||||
dispatchEditDescription: (event, measurementData, viewportsState) => {
|
||||
event.persist();
|
||||
|
||||
const activeViewportIndex =
|
||||
(viewportsState && viewportsState.activeViewportIndex) || 0;
|
||||
|
||||
@@ -201,26 +191,14 @@ const mapDispatchToProps = dispatch => {
|
||||
return;
|
||||
}
|
||||
|
||||
const { element } = enabledElements[activeViewportIndex];
|
||||
|
||||
const eventData = {
|
||||
event: {
|
||||
clientX: event.clientX,
|
||||
clientY: event.clientY,
|
||||
},
|
||||
element,
|
||||
};
|
||||
|
||||
const { toolType, measurementId } = measurementData;
|
||||
const tool = MeasurementApi.Instance.tools[toolType].find(measurement => {
|
||||
return measurement._id === measurementId;
|
||||
});
|
||||
|
||||
const options = {
|
||||
editDescriptionOnDialog: true,
|
||||
};
|
||||
|
||||
getMeasurementLocationCallback(eventData, tool, options);
|
||||
if (ownProps.onEditDescription) {
|
||||
ownProps.onEditDescription(tool);
|
||||
}
|
||||
},
|
||||
dispatchJumpToRowItem: (
|
||||
measurementData,
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
const setLabellingFlowDataAction = labellingFlowData => ({
|
||||
type: 'SET_LABELLING_FLOW_DATA',
|
||||
labellingFlowData,
|
||||
});
|
||||
|
||||
const resetLabellingAndContextMenuAction = state => ({
|
||||
type: 'RESET_LABELLING_AND_CONTEXT_MENU',
|
||||
state,
|
||||
});
|
||||
|
||||
const setToolContextMenuDataAction = (viewportIndex, toolContextMenuData) => ({
|
||||
type: 'SET_TOOL_CONTEXT_MENU_DATA',
|
||||
viewportIndex,
|
||||
toolContextMenuData,
|
||||
});
|
||||
|
||||
export {
|
||||
resetLabellingAndContextMenuAction,
|
||||
setLabellingFlowDataAction,
|
||||
setToolContextMenuDataAction,
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
import cornerstoneTools from 'cornerstone-tools';
|
||||
import updateTableWithNewMeasurementData from './updateTableWithNewMeasurementData.js';
|
||||
|
||||
export default function getMeasurementLocationCallback(
|
||||
eventData,
|
||||
tool,
|
||||
options
|
||||
) {
|
||||
const { toolType } = tool;
|
||||
const { element } = eventData;
|
||||
const doneCallback = updateTableWithNewMeasurementData;
|
||||
|
||||
const ToolInstance = cornerstoneTools.getToolForElement(element, toolType);
|
||||
|
||||
if (
|
||||
!ToolInstance ||
|
||||
!ToolInstance.configuration ||
|
||||
!ToolInstance.configuration.getMeasurementLocationCallback
|
||||
) {
|
||||
console.warn(
|
||||
'Tool instance configuration is missing: getMeasurementLocationCallback'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ToolInstance.configuration.getMeasurementLocationCallback(
|
||||
tool,
|
||||
eventData,
|
||||
doneCallback,
|
||||
options
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import React from 'react';
|
||||
import ConnectedMeasurementTable from './ConnectedMeasurementTable.js';
|
||||
import init from './init.js';
|
||||
|
||||
@@ -7,10 +8,38 @@ export default {
|
||||
*/
|
||||
id: 'measurements-table',
|
||||
|
||||
preRegistration({ servicesManager, configuration = {} }) {
|
||||
init({ servicesManager, configuration });
|
||||
preRegistration({ servicesManager, commandsManager, configuration = {} }) {
|
||||
init({ servicesManager, commandsManager, configuration });
|
||||
},
|
||||
getPanelModule({ servicesManager }) {
|
||||
getPanelModule({ servicesManager, commandsManager }) {
|
||||
const { UILabellingFlowService } = servicesManager.services;
|
||||
const ExtendedConnectedMeasurementTable = () => (
|
||||
<ConnectedMeasurementTable
|
||||
onRelabel={tool => {
|
||||
if (UILabellingFlowService) {
|
||||
UILabellingFlowService.show({
|
||||
centralize: true,
|
||||
props: {
|
||||
skipAddLabelButton: true,
|
||||
editLocation: true,
|
||||
measurementData: tool,
|
||||
},
|
||||
});
|
||||
}
|
||||
}}
|
||||
onEditDescription={tool => {
|
||||
if (UILabellingFlowService) {
|
||||
UILabellingFlowService.show({
|
||||
centralize: true,
|
||||
props: {
|
||||
editDescriptionOnDialog: true,
|
||||
measurementData: tool,
|
||||
},
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
return {
|
||||
menuOptions: [
|
||||
{
|
||||
@@ -22,7 +51,7 @@ export default {
|
||||
components: [
|
||||
{
|
||||
id: 'measurement-panel',
|
||||
component: ConnectedMeasurementTable,
|
||||
component: ExtendedConnectedMeasurementTable,
|
||||
},
|
||||
],
|
||||
defaultContext: ['VIEWER'],
|
||||
|
||||
@@ -1,19 +1,7 @@
|
||||
import OHIF from '@ohif/core';
|
||||
import cornerstone from 'cornerstone-core';
|
||||
import csTools from 'cornerstone-tools';
|
||||
import {
|
||||
getToolLabellingFlowCallback,
|
||||
getOnRightClickCallback,
|
||||
getOnTouchPressCallback,
|
||||
getResetLabellingAndContextMenu,
|
||||
} from './labelingFlowCallbacks.js';
|
||||
import throttle from 'lodash.throttle';
|
||||
import { SimpleDialog } from '@ohif/ui';
|
||||
|
||||
// TODO: This only works because we have a hard dependency on this extension
|
||||
// We need to decouple and make stuff like this possible w/o bundling this at
|
||||
// build time
|
||||
import store from './../../store';
|
||||
|
||||
const {
|
||||
onAdded,
|
||||
@@ -33,92 +21,18 @@ const MEASUREMENT_ACTION_MAP = {
|
||||
*
|
||||
*
|
||||
* @export
|
||||
* @param {*} configuration
|
||||
* @param {Object} servicesManager
|
||||
* @param {Object} configuration
|
||||
*/
|
||||
export default function init({ servicesManager, configuration = {} }) {
|
||||
const { UIDialogService } = servicesManager.services;
|
||||
const callInputDialog = (data, event, callback) => {
|
||||
let dialogId = UIDialogService.create({
|
||||
content: SimpleDialog.InputDialog,
|
||||
defaultPosition: {
|
||||
x: (event && event.currentPoints.canvas.x) || 0,
|
||||
y: (event && event.currentPoints.canvas.y) || 0,
|
||||
},
|
||||
showOverlay: true,
|
||||
contentProps: {
|
||||
title: 'Enter your annotation',
|
||||
label: 'New label',
|
||||
defaultValue: data ? data.text : '',
|
||||
onClose: () => UIDialogService.dismiss({ id: dialogId }),
|
||||
onSubmit: value => {
|
||||
callback(value);
|
||||
UIDialogService.dismiss({ id: dialogId });
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// If these tools were already added by a different extension, we want to replace
|
||||
// them with the same tools that have an alternative configuration. By passing in
|
||||
// our custom `getMeasurementLocationCallback`, we can...
|
||||
const toolLabellingFlowCallback = getToolLabellingFlowCallback(store);
|
||||
|
||||
// Removes all tools from all enabled elements w/ provided name
|
||||
// Not commonly used API, so :eyes: for unknown side-effects
|
||||
csTools.removeTool('Bidirectional');
|
||||
csTools.removeTool('Length');
|
||||
csTools.removeTool('Angle');
|
||||
csTools.removeTool('FreehandRoi');
|
||||
csTools.removeTool('EllipticalRoi');
|
||||
csTools.removeTool('CircleRoi');
|
||||
csTools.removeTool('RectangleRoi');
|
||||
csTools.removeTool('ArrowAnnotate');
|
||||
|
||||
// Re-add each tool w/ our custom configuration
|
||||
csTools.addTool(csTools.BidirectionalTool, {
|
||||
configuration: {
|
||||
getMeasurementLocationCallback: toolLabellingFlowCallback,
|
||||
},
|
||||
});
|
||||
csTools.addTool(csTools.LengthTool, {
|
||||
configuration: {
|
||||
getMeasurementLocationCallback: toolLabellingFlowCallback,
|
||||
},
|
||||
});
|
||||
csTools.addTool(csTools.AngleTool, {
|
||||
configuration: {
|
||||
getMeasurementLocationCallback: toolLabellingFlowCallback,
|
||||
},
|
||||
});
|
||||
csTools.addTool(csTools.FreehandRoiTool, {
|
||||
configuration: {
|
||||
getMeasurementLocationCallback: toolLabellingFlowCallback,
|
||||
},
|
||||
});
|
||||
csTools.addTool(csTools.EllipticalRoiTool, {
|
||||
configuration: {
|
||||
getMeasurementLocationCallback: toolLabellingFlowCallback,
|
||||
},
|
||||
});
|
||||
csTools.addTool(csTools.CircleRoiTool, {
|
||||
configuration: {
|
||||
getMeasurementLocationCallback: toolLabellingFlowCallback,
|
||||
},
|
||||
});
|
||||
csTools.addTool(csTools.RectangleRoiTool, {
|
||||
configuration: {
|
||||
getMeasurementLocationCallback: toolLabellingFlowCallback,
|
||||
},
|
||||
});
|
||||
csTools.addTool(csTools.ArrowAnnotateTool, {
|
||||
configuration: {
|
||||
getMeasurementLocationCallback: toolLabellingFlowCallback,
|
||||
getTextCallback: (callback, eventDetails) =>
|
||||
callInputDialog(null, eventDetails, callback),
|
||||
changeTextCallback: (data, eventDetails, callback) =>
|
||||
callInputDialog(data, eventDetails, callback),
|
||||
},
|
||||
});
|
||||
export default function init({
|
||||
servicesManager,
|
||||
commandsManager,
|
||||
configuration,
|
||||
}) {
|
||||
const {
|
||||
UIContextMenuService,
|
||||
UILabellingFlowService,
|
||||
} = servicesManager.services;
|
||||
|
||||
// TODO: MEASUREMENT_COMPLETED (not present in initial implementation)
|
||||
const onMeasurementsChanged = (action, event) => {
|
||||
@@ -131,15 +45,43 @@ export default function init({ servicesManager, configuration = {} }) {
|
||||
this,
|
||||
'labelmapModified'
|
||||
);
|
||||
//
|
||||
const onRightClick = getOnRightClickCallback(store);
|
||||
const onTouchPress = getOnTouchPressCallback(store);
|
||||
const onNewImage = getResetLabellingAndContextMenu(store);
|
||||
const onMouseClick = getResetLabellingAndContextMenu(store);
|
||||
const onTouchStart = getResetLabellingAndContextMenu(store);
|
||||
|
||||
// Because click gives us the native "mouse up", buttons will always be `0`
|
||||
// Need to fallback to event.which;
|
||||
const onRightClick = event => {
|
||||
if (UIContextMenuService) {
|
||||
UIContextMenuService.show({ event: event.detail });
|
||||
}
|
||||
};
|
||||
|
||||
const onTouchPress = event => {
|
||||
if (UIContextMenuService) {
|
||||
UIContextMenuService.show({
|
||||
event: event.detail,
|
||||
props: {
|
||||
isTouchEvent: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onTouchStart = () => resetLabelligAndContextMenu();
|
||||
|
||||
const onMouseClick = () => resetLabelligAndContextMenu();
|
||||
|
||||
const resetLabelligAndContextMenu = () => {
|
||||
if (UILabellingFlowService && UIContextMenuService) {
|
||||
UILabellingFlowService.hide();
|
||||
UIContextMenuService.hide();
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: This makes scrolling painfully slow
|
||||
// const onNewImage = ...
|
||||
|
||||
/*
|
||||
* Because click gives us the native "mouse up", buttons will always be `0`
|
||||
* Need to fallback to event.which;
|
||||
*
|
||||
*/
|
||||
const handleClick = cornerstoneMouseClickEvent => {
|
||||
const mouseUpEvent = cornerstoneMouseClickEvent.detail.event;
|
||||
const isRightClick = mouseUpEvent.which === 3;
|
||||
@@ -170,10 +112,11 @@ export default function init({ servicesManager, configuration = {} }) {
|
||||
csTools.EVENTS.LABELMAP_MODIFIED,
|
||||
onLabelmapModified
|
||||
);
|
||||
//
|
||||
|
||||
element.addEventListener(csTools.EVENTS.TOUCH_PRESS, onTouchPress);
|
||||
element.addEventListener(csTools.EVENTS.MOUSE_CLICK, handleClick);
|
||||
element.addEventListener(csTools.EVENTS.TOUCH_START, onTouchStart);
|
||||
|
||||
// TODO: This makes scrolling painfully slow
|
||||
// element.addEventListener(cornerstone.EVENTS.NEW_IMAGE, onNewImage);
|
||||
}
|
||||
@@ -197,10 +140,12 @@ export default function init({ servicesManager, configuration = {} }) {
|
||||
csTools.EVENTS.LABELMAP_MODIFIED,
|
||||
onLabelmapModified
|
||||
);
|
||||
//
|
||||
|
||||
element.removeEventListener(csTools.EVENTS.TOUCH_PRESS, onTouchPress);
|
||||
element.removeEventListener(csTools.EVENTS.MOUSE_CLICK, handleClick);
|
||||
element.removeEventListener(csTools.EVENTS.TOUCH_START, onTouchStart);
|
||||
|
||||
// TODO: This makes scrolling painfully slow
|
||||
// element.removeEventListener(cornerstone.EVENTS.NEW_IMAGE, onNewImage);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
import {
|
||||
resetLabellingAndContextMenuAction,
|
||||
setToolContextMenuDataAction,
|
||||
setLabellingFlowDataAction,
|
||||
} from './actions.js';
|
||||
import updateTableWithNewMeasurementData from './updateTableWithNewMeasurementData.js';
|
||||
|
||||
const VIEWPORT_INDEX = 0;
|
||||
|
||||
function getOnRightClickCallback(store) {
|
||||
const setToolContextMenuData = (viewportIndex, toolContextMenuData) => {
|
||||
store.dispatch(resetLabellingAndContextMenuAction());
|
||||
store.dispatch(
|
||||
setToolContextMenuDataAction(viewportIndex, toolContextMenuData)
|
||||
);
|
||||
};
|
||||
|
||||
const getOnCloseCallback = viewportIndex => {
|
||||
return function onClose() {
|
||||
const toolContextMenuData = {
|
||||
visible: false,
|
||||
};
|
||||
|
||||
store.dispatch(
|
||||
setToolContextMenuDataAction(viewportIndex, toolContextMenuData)
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
return function onRightClick(event) {
|
||||
const eventData = event.detail;
|
||||
const viewportIndex = VIEWPORT_INDEX; // parseInt(eventData.element.dataset.viewportIndex, 10);
|
||||
|
||||
const toolContextMenuData = {
|
||||
eventData,
|
||||
isTouchEvent: false,
|
||||
onClose: getOnCloseCallback(viewportIndex),
|
||||
};
|
||||
|
||||
// setToolContextMenuData(viewportIndex, toolContextMenuData);
|
||||
setToolContextMenuData(0, toolContextMenuData);
|
||||
};
|
||||
}
|
||||
|
||||
function getOnTouchPressCallback(store) {
|
||||
const setToolContextMenuData = (viewportIndex, toolContextMenuData) => {
|
||||
store.dispatch(resetLabellingAndContextMenuAction());
|
||||
store.dispatch(
|
||||
setToolContextMenuDataAction(viewportIndex, toolContextMenuData)
|
||||
);
|
||||
};
|
||||
|
||||
const getOnCloseCallback = viewportIndex => {
|
||||
return function onClose() {
|
||||
const toolContextMenuData = {
|
||||
visible: false,
|
||||
};
|
||||
|
||||
store.dispatch(
|
||||
setToolContextMenuDataAction(viewportIndex, toolContextMenuData)
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
return function onTouchPress(event) {
|
||||
const eventData = event.detail;
|
||||
const viewportIndex = parseInt(eventData.element.dataset.viewportIndex, 10);
|
||||
|
||||
const toolContextMenuData = {
|
||||
eventData,
|
||||
isTouchEvent: true,
|
||||
onClose: getOnCloseCallback(viewportIndex),
|
||||
};
|
||||
|
||||
setToolContextMenuData(viewportIndex, toolContextMenuData);
|
||||
};
|
||||
}
|
||||
|
||||
function getResetLabellingAndContextMenu(store) {
|
||||
return function resetLabellingAndContextMenu() {
|
||||
store.dispatch(resetLabellingAndContextMenuAction());
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param {*} store
|
||||
* @returns
|
||||
*/
|
||||
function getToolLabellingFlowCallback(store) {
|
||||
const setLabellingFlowData = labellingFlowData => {
|
||||
store.dispatch(setLabellingFlowDataAction(labellingFlowData));
|
||||
};
|
||||
|
||||
return function toolLabellingFlowCallback(
|
||||
measurementData,
|
||||
eventData,
|
||||
doneCallback,
|
||||
options = {}
|
||||
) {
|
||||
const updateLabelling = ({ location, response, description }) => {
|
||||
// Update the measurement data with the labelling parameters
|
||||
|
||||
if (location) {
|
||||
measurementData.location = location;
|
||||
}
|
||||
|
||||
measurementData.description = description || '';
|
||||
|
||||
if (response) {
|
||||
measurementData.response = response;
|
||||
}
|
||||
|
||||
updateTableWithNewMeasurementData(measurementData);
|
||||
};
|
||||
|
||||
const labellingDoneCallback = () => {
|
||||
setLabellingFlowData({ visible: false });
|
||||
};
|
||||
|
||||
const labellingFlowData = {
|
||||
visible: true,
|
||||
eventData,
|
||||
measurementData,
|
||||
skipAddLabelButton: options.skipAddLabelButton,
|
||||
editLocation: options.editLocation,
|
||||
editDescription: options.editDescription,
|
||||
editResponse: options.editResponse,
|
||||
editDescriptionOnDialog: options.editDescriptionOnDialog,
|
||||
labellingDoneCallback,
|
||||
updateLabelling,
|
||||
};
|
||||
|
||||
setLabellingFlowData(labellingFlowData);
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
getToolLabellingFlowCallback,
|
||||
getOnRightClickCallback,
|
||||
getOnTouchPressCallback,
|
||||
getResetLabellingAndContextMenu,
|
||||
};
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
import OHIF from '@ohif/core';
|
||||
import cornerstone from 'cornerstone-core';
|
||||
|
||||
export default function updateTableWithNewMeasurementData({
|
||||
toolType,
|
||||
measurementNumber,
|
||||
location,
|
||||
description,
|
||||
}) {
|
||||
// Update all measurements by measurement number
|
||||
const measurementApi = OHIF.measurements.MeasurementApi.Instance;
|
||||
const measurements = measurementApi.tools[toolType].filter(
|
||||
m => m.measurementNumber === measurementNumber
|
||||
);
|
||||
|
||||
measurements.forEach(measurement => {
|
||||
measurement.location = location;
|
||||
measurement.description = description;
|
||||
|
||||
measurementApi.updateMeasurement(measurement.toolType, measurement);
|
||||
});
|
||||
|
||||
measurementApi.syncMeasurementsAndToolData();
|
||||
|
||||
// Update images in all active viewports
|
||||
cornerstone.getEnabledElements().forEach(enabledElement => {
|
||||
cornerstone.updateImage(enabledElement.element);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user