feat(measurements): add CircleROI Tool (#3211)

* [refactor] measurement service mapping files - rename to .ts files

* [fix] RectangleROI - measurement service mapping _getReport() function - tool name fix

* [feat] added CircleROI tool from updated cornerstone3D

* [refactor] fix for typescript strong typing warnings

* [feat] cornerstone-dicom-sr extension - added CircleROI tool

* [feat] added toolbar button for CircleROI tool

* [doc] doc updates for CircleROI tool

* [update] library - dcmjs to 0.29.5

* [fix] roundNumber() function when given strings

* [fix] refactor after upgrading conerstonejs library 0.49.0

* yarn.lock file change
This commit is contained in:
M.D 2023-04-17 08:23:03 -04:00 committed by GitHub
parent 83b4606357
commit 47c25f4364
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 412 additions and 69 deletions

View File

@ -36,7 +36,7 @@
"@ohif/extension-cornerstone": "^3.0.0",
"@ohif/extension-measurement-tracking": "^3.0.0",
"@ohif/ui": "^2.0.0",
"dcmjs": "^0.29.4",
"dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",

View File

@ -6,6 +6,7 @@ import {
BidirectionalTool,
CobbAngleTool,
EllipticalROITool,
CircleROITool,
LengthTool,
PlanarFreehandROITool,
} from '@cornerstonejs/tools';
@ -24,6 +25,7 @@ export default function init({
addToolInstance(toolNames.SRLength, LengthTool, {});
addToolInstance(toolNames.SRBidirectional, BidirectionalTool);
addToolInstance(toolNames.SREllipticalROI, EllipticalROITool);
addToolInstance(toolNames.SRCircleROI, CircleROITool);
addToolInstance(toolNames.SRArrowAnnotate, ArrowAnnotateTool);
addToolInstance(toolNames.SRAngle, AngleTool);
// TODO - fix the SR display of Cobb Angle, as it joins the two lines
@ -40,6 +42,7 @@ export default function init({
SRLength: dashedLine,
SRBidirectional: dashedLine,
SREllipticalROI: dashedLine,
SRCircleROI: dashedLine,
SRArrowAnnotate: dashedLine,
SRCobbAngle: dashedLine,
SRAngle: dashedLine,

View File

@ -5,6 +5,7 @@ const toolNames = {
SRLength: 'SRLength',
SRBidirectional: 'SRBidirectional',
SREllipticalROI: 'SREllipticalROI',
SRCircleROI: 'SRCircleROI',
SRArrowAnnotate: 'SRArrowAnnotate',
SRAngle: 'SRAngle',
SRCobbAngle: 'SRCobbAngle',

View File

@ -30,7 +30,7 @@
"@ohif/core": "^3.0.0",
"@ohif/ui": "^2.0.0",
"cornerstone-wado-image-loader": "^4.13.0",
"dcmjs": "^0.29.4",
"dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",

View File

@ -9,6 +9,7 @@ import {
LengthTool,
RectangleROITool,
EllipticalROITool,
CircleROITool,
BidirectionalTool,
ArrowAnnotateTool,
DragProbeTool,
@ -41,6 +42,7 @@ export default function initCornerstoneTools(configuration = {}) {
addTool(LengthTool);
addTool(RectangleROITool);
addTool(EllipticalROITool);
addTool(CircleROITool);
addTool(BidirectionalTool);
addTool(ArrowAnnotateTool);
addTool(DragProbeTool);
@ -83,6 +85,7 @@ const toolNames = {
Probe: ProbeTool.toolName,
RectangleROI: RectangleROITool.toolName,
EllipticalROI: EllipticalROITool.toolName,
CircleROI: CircleROITool.toolName,
Bidirectional: BidirectionalTool.toolName,
Angle: AngleTool.toolName,
CobbAngle: CobbAngleTool.toolName,

View File

@ -24,6 +24,7 @@ const initMeasurementService = (
Length,
Bidirectional,
EllipticalROI,
CircleROI,
ArrowAnnotate,
Angle,
CobbAngle,
@ -78,6 +79,14 @@ const initMeasurementService = (
EllipticalROI.toMeasurement
);
measurementService.addMapping(
csTools3DVer1MeasurementSource,
'CircleROI',
CircleROI.matchingCriteria,
CircleROI.toAnnotation,
CircleROI.toMeasurement
);
measurementService.addMapping(
csTools3DVer1MeasurementSource,
'ArrowAnnotate',

View File

@ -0,0 +1,228 @@
import SUPPORTED_TOOLS from './constants/supportedTools';
import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes';
import getModalityUnit from './utils/getModalityUnit';
import { utils } from '@ohif/core';
const CircleROI = {
toAnnotation: measurement => {},
toMeasurement: (
csToolsEventDetail,
DisplaySetService,
CornerstoneViewportService,
getValueTypeFromToolType
) => {
const { annotation, viewportId } = csToolsEventDetail;
const { metadata, data, annotationUID } = annotation;
if (!metadata || !data) {
console.warn('Length tool: Missing metadata or data');
return null;
}
const { toolName, referencedImageId, FrameOfReferenceUID } = metadata;
const validToolType = SUPPORTED_TOOLS.includes(toolName);
if (!validToolType) {
throw new Error('Tool not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = getSOPInstanceAttributes(
referencedImageId,
CornerstoneViewportService,
viewportId
);
let displaySet;
if (SOPInstanceUID) {
displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
SeriesInstanceUID
);
} else {
displaySet = DisplaySetService.getDisplaySetsForSeries(SeriesInstanceUID);
}
const { points } = data.handles;
const mappedAnnotations = getMappedAnnotations(
annotation,
DisplaySetService
);
const displayText = getDisplayText(mappedAnnotations, displaySet);
const getReport = () =>
_getReport(mappedAnnotations, points, FrameOfReferenceUID);
return {
uid: annotationUID,
SOPInstanceUID,
FrameOfReferenceUID,
points,
metadata,
referenceSeriesUID: SeriesInstanceUID,
referenceStudyUID: StudyInstanceUID,
frameNumber: mappedAnnotations[0]?.frameNumber || 1,
toolName: metadata.toolName,
displaySetInstanceUID: displaySet.displaySetInstanceUID,
label: data.label,
displayText: displayText,
data: data.cachedStats,
type: getValueTypeFromToolType(toolName),
getReport,
};
},
};
function getMappedAnnotations(annotation, DisplaySetService) {
const { metadata, data } = annotation;
const { cachedStats } = data;
const { referencedImageId } = metadata;
const targets = Object.keys(cachedStats);
if (!targets.length) {
return [];
}
const annotations = [];
Object.keys(cachedStats).forEach(targetId => {
const targetStats = cachedStats[targetId];
if (!referencedImageId) {
// Todo: Non-acquisition plane measurement mapping not supported yet
throw new Error(
'Non-acquisition plane measurement mapping not supported'
);
}
const {
SOPInstanceUID,
SeriesInstanceUID,
frameNumber,
} = getSOPInstanceAttributes(referencedImageId);
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
SeriesInstanceUID,
frameNumber
);
const { SeriesNumber } = displaySet;
const { mean, stdDev, max, area, Modality } = targetStats;
const unit = getModalityUnit(Modality);
annotations.push({
SeriesInstanceUID,
SOPInstanceUID,
SeriesNumber,
frameNumber,
Modality,
unit,
mean,
stdDev,
max,
area,
});
});
return annotations;
}
/*
This function is used to convert the measurement data to a format that is
suitable for the report generation (e.g. for the csv report). The report
returns a list of columns and corresponding values.
*/
function _getReport(mappedAnnotations, points, FrameOfReferenceUID) {
const columns = [];
const values = [];
// Add Type
columns.push('AnnotationType');
values.push('Cornerstone:CircleROI');
mappedAnnotations.forEach(annotation => {
const { mean, stdDev, max, area, unit } = annotation;
if (!mean || !unit || !max || !area) {
return;
}
columns.push(
`max (${unit})`,
`mean (${unit})`,
`std (${unit})`,
`area (mm2)`
);
values.push(max, mean, stdDev, area);
});
if (FrameOfReferenceUID) {
columns.push('FrameOfReferenceUID');
values.push(FrameOfReferenceUID);
}
if (points) {
columns.push('points');
// points has the form of [[x1, y1, z1], [x2, y2, z2], ...]
// convert it to string of [[x1 y1 z1];[x2 y2 z2];...]
// so that it can be used in the csv report
values.push(points.map(p => p.join(' ')).join(';'));
}
return {
columns,
values,
};
}
function getDisplayText(mappedAnnotations, displaySet) {
if (!mappedAnnotations || !mappedAnnotations.length) {
return '';
}
const displayText = [];
// Area is the same for all series
const { area, SOPInstanceUID, frameNumber } = mappedAnnotations[0];
const instance = displaySet.images.find(
image => image.SOPInstanceUID === SOPInstanceUID
);
let InstanceNumber;
if (instance) {
InstanceNumber = instance.InstanceNumber;
}
const instanceText = InstanceNumber ? ` I: ${InstanceNumber}` : '';
const frameText = displaySet.isMultiFrame ? ` F: ${frameNumber}` : '';
// Area sometimes becomes undefined if `preventHandleOutsideImage` is off.
const roundedArea = utils.roundNumber(area || 0, 2);
displayText.push(`${roundedArea} mm<sup>2</sup>`);
// Todo: we need a better UI for displaying all these information
mappedAnnotations.forEach(mappedAnnotation => {
const { unit, max, SeriesNumber } = mappedAnnotation;
let maxStr = '';
if (max) {
const roundedMax = utils.roundNumber(max, 2);
maxStr = `Max: ${roundedMax} <small>${unit}</small> `;
}
const str = `${maxStr}(S:${SeriesNumber}${instanceText}${frameText})`;
if (!displayText.includes(str)) {
displayText.push(str);
}
});
return displayText;
}
export default CircleROI;

View File

@ -1,6 +1,6 @@
import SUPPORTED_TOOLS from './constants/supportedTools';
import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes';
import { displaySetService, utils } from '@ohif/core';
import { utils } from '@ohif/core';
const Length = {
toAnnotation: measurement => {},
@ -32,15 +32,12 @@ const Length = {
throw new Error('Tool not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = getSOPInstanceAttributes(
referencedImageId,
cornerstoneViewportService,
viewportId
);
const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } =
getSOPInstanceAttributes(
referencedImageId,
cornerstoneViewportService,
viewportId
);
let displaySet;
@ -104,11 +101,8 @@ function getMappedAnnotations(annotation, displaySetService) {
);
}
const {
SOPInstanceUID,
SeriesInstanceUID,
frameNumber,
} = getSOPInstanceAttributes(referencedImageId);
const { SOPInstanceUID, SeriesInstanceUID, frameNumber } =
getSOPInstanceAttributes(referencedImageId);
const displaySet = displaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
@ -179,12 +173,8 @@ function getDisplayText(mappedAnnotations, displaySet) {
const displayText = [];
// Area is the same for all series
const {
length,
SeriesNumber,
SOPInstanceUID,
frameNumber,
} = mappedAnnotations[0];
const { length, SeriesNumber, SOPInstanceUID, frameNumber } =
mappedAnnotations[0];
const instance = displaySet.images.find(
image => image.SOPInstanceUID === SOPInstanceUID

View File

@ -4,7 +4,7 @@ import getModalityUnit from './utils/getModalityUnit';
import { utils } from '@ohif/core';
const RectangleROI = {
toAnnotation: measurement => { },
toAnnotation: measurement => {},
toMeasurement: (
csToolsEventDetail,
DisplaySetService,
@ -26,15 +26,12 @@ const RectangleROI = {
throw new Error('Tool not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = getSOPInstanceAttributes(
referencedImageId,
CornerstoneViewportService,
viewportId
);
const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } =
getSOPInstanceAttributes(
referencedImageId,
CornerstoneViewportService,
viewportId
);
let displaySet;
@ -99,11 +96,8 @@ function getMappedAnnotations(annotation, DisplaySetService) {
);
}
const {
SOPInstanceUID,
SeriesInstanceUID,
frameNumber,
} = getSOPInstanceAttributes(referencedImageId);
const { SOPInstanceUID, SeriesInstanceUID, frameNumber } =
getSOPInstanceAttributes(referencedImageId);
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
@ -143,7 +137,7 @@ function _getReport(mappedAnnotations, points, FrameOfReferenceUID) {
// Add Type
columns.push('AnnotationType');
values.push('Cornerstone:EllipticalROI');
values.push('Cornerstone:RectangleROI');
mappedAnnotations.forEach(annotation => {
const { mean, stdDev, max, area, unit } = annotation;

View File

@ -1,6 +1,7 @@
export default [
'Length',
'EllipticalROI',
'CircleROI',
'Bidirectional',
'ArrowAnnotate',
'Angle',

View File

@ -2,6 +2,7 @@ import { MeasurementService } from '@ohif/core';
import Length from './Length';
import Bidirectional from './Bidirectional';
import EllipticalROI from './EllipticalROI';
import CircleROI from './CircleROI';
import ArrowAnnotate from './ArrowAnnotate';
import CobbAngle from './CobbAngle';
import Angle from './Angle';
@ -25,6 +26,7 @@ const measurementServiceMappingsFactory = (
const {
POLYLINE,
ELLIPSE,
CIRCLE,
RECTANGLE,
BIDIRECTIONAL,
POINT,
@ -37,6 +39,7 @@ const measurementServiceMappingsFactory = (
const TOOL_TYPE_TO_VALUE_TYPE = {
Length: POLYLINE,
EllipticalROI: ELLIPSE,
CircleROI: CIRCLE,
RectangleROI: RECTANGLE,
PlanarFreehandROI: POLYLINE,
Bidirectional: BIDIRECTIONAL,
@ -104,6 +107,22 @@ const measurementServiceMappingsFactory = (
],
},
CircleROI: {
toAnnotation: CircleROI.toAnnotation,
toMeasurement: csToolsAnnotation =>
CircleROI.toMeasurement(
csToolsAnnotation,
displaySetService,
cornerstoneViewportService,
_getValueTypeFromToolType
),
matchingCriteria: [
{
valueType: MeasurementService.VALUE_TYPES.CIRCLE,
},
],
},
RectangleROI: {
toAnnotation: RectangleROI.toAnnotation,
toMeasurement: csToolsAnnotation =>

View File

@ -13,8 +13,8 @@ import * as cornerstone from '@cornerstonejs/core';
*/
export default function getSOPInstanceAttributes(
imageId,
cornerstoneViewportService,
viewportId
cornerstoneViewportService = undefined,
viewportId = undefined
) {
if (imageId) {
return _getUIDFromImageID(imageId);

View File

@ -32,7 +32,7 @@
"peerDependencies": {
"@ohif/core": "^3.0.0",
"@ohif/i18n": "^1.0.0",
"dcmjs": "^0.29.4",
"dcmjs": "^0.29.5",
"dicomweb-client": "^0.8.4",
"prop-types": "^15.6.2",
"react": "^17.0.2",

View File

@ -30,7 +30,7 @@
"peerDependencies": {
"@ohif/core": "^3.0.0",
"@ohif/ui": "^2.0.0",
"dcmjs": "^0.29.4",
"dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",

View File

@ -30,7 +30,7 @@
"peerDependencies": {
"@ohif/core": "^3.0.0",
"@ohif/ui": "^2.0.0",
"dcmjs": "^0.29.4",
"dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",

View File

@ -35,7 +35,7 @@
"@cornerstonejs/core": "^0.40.0",
"@cornerstonejs/tools": "^0.60.1",
"@ohif/extension-cornerstone-dicom-sr": "^3.0.0",
"dcmjs": "^0.29.4",
"dcmjs": "^0.29.5",
"lodash.debounce": "^4.17.21",
"prop-types": "^15.6.2",
"react": "^17.0.2",

View File

@ -30,7 +30,7 @@
"peerDependencies": {
"@ohif/core": "^3.0.0",
"@ohif/ui": "^2.0.0",
"dcmjs": "^0.29.4",
"dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",

View File

@ -81,6 +81,7 @@ function modeFactory({ modeConfiguration }) {
{ toolName: toolNames.Bidirectional },
{ toolName: toolNames.Probe },
{ toolName: toolNames.EllipticalROI },
{ toolName: toolNames.CircleROI },
{ toolName: toolNames.RectangleROI },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.CalibrationLine },
@ -134,11 +135,8 @@ function modeFactory({ modeConfiguration }) {
]);
},
onModeExit: ({ servicesManager }) => {
const {
toolGroupService,
measurementService,
toolbarService,
} = servicesManager.services;
const { toolGroupService, measurementService, toolbarService } =
servicesManager.services;
toolGroupService.destroy();
},

View File

@ -130,6 +130,21 @@ const toolbarButtons = [
],
'Ellipse Tool'
),
_createToolButton(
'CircleROI',
'tool-circle',
'Circle',
[
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'CircleROI',
},
context: 'CORNERSTONE',
},
],
'Circle Tool'
),
],
},
},

View File

@ -32,6 +32,7 @@ function initDefaultToolGroup(
{ toolName: toolNames.Bidirectional },
{ toolName: toolNames.DragProbe },
{ toolName: toolNames.EllipticalROI },
{ toolName: toolNames.CircleROI },
{ toolName: toolNames.RectangleROI },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.Angle },
@ -110,6 +111,7 @@ function initSRToolGroup(extensionManager, toolGroupService, commandsManager) {
{ toolName: SRToolNames.SRArrowAnnotate },
{ toolName: SRToolNames.SRBidirectional },
{ toolName: SRToolNames.SREllipticalROI },
{ toolName: SRToolNames.SRCircleROI },
],
enabled: [
{
@ -170,6 +172,7 @@ function initMPRToolGroup(extensionManager, toolGroupService, commandsManager) {
{ toolName: toolNames.Bidirectional },
{ toolName: toolNames.DragProbe },
{ toolName: toolNames.EllipticalROI },
{ toolName: toolNames.CircleROI },
{ toolName: toolNames.RectangleROI },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.Angle },

View File

@ -200,6 +200,29 @@ const toolbarButtons = [
],
'Ellipse Tool'
),
_createToolButton(
'CircleROI',
'tool-circle',
'Circle',
[
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'CircleROI',
},
context: 'CORNERSTONE',
},
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'SRCircleROI',
toolGroupId: 'SRToolGroup',
},
context: 'CORNERSTONE',
},
],
'Circle Tool'
),
],
},
},

View File

@ -32,6 +32,7 @@ function initDefaultToolGroup(
{ toolName: toolNames.Bidirectional },
{ toolName: toolNames.DragProbe },
{ toolName: toolNames.EllipticalROI },
{ toolName: toolNames.CircleROI },
{ toolName: toolNames.RectangleROI },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.Angle },
@ -113,6 +114,7 @@ function initSRToolGroup(extensionManager, toolGroupService, commandsManager) {
{ toolName: SRToolNames.SRArrowAnnotate },
{ toolName: SRToolNames.SRBidirectional },
{ toolName: SRToolNames.SREllipticalROI },
{ toolName: SRToolNames.SRCircleROI },
],
enabled: [
{
@ -173,6 +175,7 @@ function initMPRToolGroup(extensionManager, toolGroupService, commandsManager) {
{ toolName: toolNames.Bidirectional },
{ toolName: toolNames.DragProbe },
{ toolName: toolNames.EllipticalROI },
{ toolName: toolNames.CircleROI },
{ toolName: toolNames.RectangleROI },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.Angle },

View File

@ -208,6 +208,29 @@ const toolbarButtons = [
],
'Ellipse Tool'
),
_createToolButton(
'CircleROI',
'tool-circle',
'Circle',
[
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'CircleROI',
},
context: 'CORNERSTONE',
},
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'SRCircleROI',
toolGroupId: 'SRToolGroup',
},
context: 'CORNERSTONE',
},
],
'Circle Tool'
),
],
},
},

View File

@ -173,6 +173,20 @@ const toolbarButtons = [
],
'Ellipse Tool'
),
_createToolButton(
'CircleROI',
'tool-circle',
'Circle',
[
..._createCommands('setToolActive', 'CircleROI', [
toolGroupIds.CT,
toolGroupIds.PT,
toolGroupIds.Fusion,
// toolGroupIds.MPR,
]),
],
'Circle Tool'
),
],
},
},
@ -299,8 +313,7 @@ const toolbarButtons = [
commandName: 'displayNotification',
commandOptions: {
title: 'RectangleROI Threshold Tip',
text:
'RectangleROI Threshold tool should be used on PT Axial Viewport',
text: 'RectangleROI Threshold tool should be used on PT Axial Viewport',
type: 'info',
},
},

View File

@ -37,7 +37,7 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"dcmjs": "^0.29.4",
"dcmjs": "^0.29.5",
"dicomweb-client": "^0.8.4",
"isomorphic-base64": "^1.0.2",
"lodash.merge": "^4.6.1",

View File

@ -1,5 +1,9 @@
/**
* @param {string | number} value
* @param {number} decimals
*/
function _round(value, decimals) {
return Number(value.toFixed(decimals));
return Number(value).toFixed(decimals);
}
export default _round;

View File

@ -184,6 +184,16 @@ to create `MeasurementTools` nested button
toolName: 'EllipticalRoi',
}
},
// Circle tool
{
id: 'CircleROI',
icon: 'tool-circle',
label: 'Circle',
type: 'tool',
commandOptions: {
toolName: 'CircleROI',
}
},
],
},
}

View File

@ -210,6 +210,16 @@ to create `MeasurementTools` nested button
toolName: 'EllipticalRoi',
}
},
// Circle tool
{
id: 'CircleROI',
icon: 'tool-circle',
label: 'Circle',
type: 'tool',
commandOptions: {
toolName: 'CircleROI',
}
},
],
},
}

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<circle stroke="currentColor" fill="none" stroke-width="2" cx="16" cy="16" r="14" />
</svg>

After

Width:  |  Height:  |  Size: 157 B

View File

@ -81,6 +81,7 @@ import toolWindow from './../../assets/icons/tool-window-level.svg';
import toolAnnotate from './../../assets/icons/tool-annotate.svg';
import toolBidirectional from './../../assets/icons/tool-bidirectional.svg';
import toolElipse from './../../assets/icons/tool-elipse.svg';
import toolCircle from './../../assets/icons/tool-circle.svg';
import toolLength from './../../assets/icons/tool-length.svg';
import toolStackScroll from './../../assets/icons/tool-stack-scroll.svg';
import toolMagnify from './../../assets/icons/tool-magnify.svg';
@ -199,6 +200,7 @@ const ICONS = {
'tool-annotate': toolAnnotate,
'tool-bidirectional': toolBidirectional,
'tool-elipse': toolElipse,
'tool-circle': toolCircle,
'tool-length': toolLength,
'tool-stack-scroll': toolStackScroll,
'tool-magnify': toolMagnify,

View File

@ -66,7 +66,7 @@
"core-js": "^3.16.1",
"cornerstone-math": "^0.1.9",
"cornerstone-wado-image-loader": "^4.13.0",
"dcmjs": "^0.29.4",
"dcmjs": "^0.29.5",
"detect-gpu": "^4.0.16",
"dicom-parser": "^1.8.9",
"dotenv-webpack": "^1.7.0",

View File

@ -9247,21 +9247,9 @@ dayjs@^1.10.4:
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2"
integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==
dcmjs@^0.29.4:
version "0.29.4"
resolved "https://registry.npmjs.org/dcmjs/-/dcmjs-0.29.4.tgz#3fb13945611979f756bc91b3f199fd87b4eabdb4"
integrity sha512-PzD6C4oB7v/AVTIPbkS6D6hjgVcSW7+T+DsxFpkD1xcEgU4qjGM16WGEHH3ZAPDBF0Xgm2d9FXUu/lXZIyfmow==
dependencies:
"@babel/runtime-corejs2" "^7.17.8"
gl-matrix "^3.1.0"
lodash.clonedeep "^4.5.0"
loglevelnext "^3.0.1"
ndarray "^1.0.19"
pako "^2.0.4"
dcmjs@^0.29.5:
version "0.29.5"
resolved "https://registry.npmjs.org/dcmjs/-/dcmjs-0.29.5.tgz#3e2311fc47aafc70f21e236ad89e2ff9ba6589fd"
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.29.5.tgz#3e2311fc47aafc70f21e236ad89e2ff9ba6589fd"
integrity sha512-CcLo3pwitf9JhhvW3/icCraxUhaIKJRyOys9XJlBBDn5TQskyJzxgveLKejcryHn4DooqlJPeMuM4ixdPFEERQ==
dependencies:
"@babel/runtime-corejs2" "^7.17.8"