feat: visualize overlapping segments in cornerstone (#2185)
* feat: visualize overlapping segments load multiple labelMaps (splitted by dcmjs because overlapping) in a segmentations [IDC2164] Dynamically update active labelmap [IDC2164] Co-authored-by: Davide Punzo <punzodavide@hotmail.it> Co-authored-by: Igor Octaviano <igoroctaviano@gmail.com>
This commit is contained in:
parent
a7a5a359dc
commit
29fceacee9
@ -36,7 +36,7 @@
|
|||||||
"cornerstone-math": "^0.1.8",
|
"cornerstone-math": "^0.1.8",
|
||||||
"cornerstone-tools": "^4.20.1",
|
"cornerstone-tools": "^4.20.1",
|
||||||
"cornerstone-wado-image-loader": "^3.1.0",
|
"cornerstone-wado-image-loader": "^3.1.0",
|
||||||
"dcmjs": "0.16.5",
|
"dcmjs": "0.17.0",
|
||||||
"dicom-parser": "^1.8.3",
|
"dicom-parser": "^1.8.3",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"dcmjs": "0.16.5",
|
"dcmjs": "0.17.0",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6"
|
"react-dom": "^16.8.6"
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"cornerstone-core": "^2.2.8",
|
"cornerstone-core": "^2.2.8",
|
||||||
"cornerstone-tools": "^4.20.1",
|
"cornerstone-tools": "^4.20.1",
|
||||||
"dcmjs": "0.16.5",
|
"dcmjs": "0.17.0",
|
||||||
"gl-matrix": "^3.3.0",
|
"gl-matrix": "^3.3.0",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"cornerstone-core": "^2.2.8",
|
"cornerstone-core": "^2.2.8",
|
||||||
"cornerstone-tools": "^4.20.1",
|
"cornerstone-tools": "^4.20.1",
|
||||||
"dcmjs": "0.16.5",
|
"dcmjs": "0.17.0",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6"
|
"react-dom": "^16.8.6"
|
||||||
|
|||||||
@ -159,12 +159,12 @@ const SegmentationPanel = ({
|
|||||||
const labelmapList = getLabelmapList(
|
const labelmapList = getLabelmapList(
|
||||||
brushStackState,
|
brushStackState,
|
||||||
firstImageId,
|
firstImageId,
|
||||||
activeViewport
|
activeViewport,
|
||||||
);
|
);
|
||||||
const segmentList = getSegmentList(
|
const segmentList = getSegmentList(
|
||||||
labelmap3D,
|
labelmap3D,
|
||||||
firstImageId,
|
firstImageId,
|
||||||
brushStackState
|
brushStackState,
|
||||||
);
|
);
|
||||||
setState(state => ({
|
setState(state => ({
|
||||||
...state,
|
...state,
|
||||||
@ -292,10 +292,13 @@ const SegmentationPanel = ({
|
|||||||
|
|
||||||
const sameSegment = state.selectedSegment === segmentNumber;
|
const sameSegment = state.selectedSegment === segmentNumber;
|
||||||
const setCurrentSelectedSegment = () => {
|
const setCurrentSelectedSegment = () => {
|
||||||
|
const activeViewport = viewports[activeIndex];
|
||||||
|
|
||||||
_setActiveSegment(
|
_setActiveSegment(
|
||||||
firstImageId,
|
firstImageId,
|
||||||
segmentNumber,
|
segmentNumber,
|
||||||
labelmap3D.activeSegmentIndex
|
labelmap3D.activeSegmentIndex,
|
||||||
|
activeViewport
|
||||||
);
|
);
|
||||||
updateState('selectedSegment', sameSegment ? null : segmentNumber);
|
updateState('selectedSegment', sameSegment ? null : segmentNumber);
|
||||||
|
|
||||||
@ -640,7 +643,7 @@ const _getReferencedSegDisplaysets = (StudyInstanceUID, SeriesInstanceUID) => {
|
|||||||
* @param {*} activeSegmentIndex
|
* @param {*} activeSegmentIndex
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const _setActiveSegment = (firstImageId, segmentIndex, activeSegmentIndex) => {
|
const _setActiveSegment = (firstImageId, segmentIndex, activeSegmentIndex, activeViewport) => {
|
||||||
if (segmentIndex === activeSegmentIndex) {
|
if (segmentIndex === activeSegmentIndex) {
|
||||||
log.info(`${activeSegmentIndex} is already the active segment`);
|
log.info(`${activeSegmentIndex} is already the active segment`);
|
||||||
return;
|
return;
|
||||||
@ -653,8 +656,27 @@ const _setActiveSegment = (firstImageId, segmentIndex, activeSegmentIndex) => {
|
|||||||
brushStackState.labelmaps3D[brushStackState.activeLabelmapIndex];
|
brushStackState.labelmaps3D[brushStackState.activeLabelmapIndex];
|
||||||
labelmap3D.activeSegmentIndex = segmentIndex;
|
labelmap3D.activeSegmentIndex = segmentIndex;
|
||||||
|
|
||||||
refreshViewports();
|
/**
|
||||||
|
* Activates the correct label map if clicked segment
|
||||||
|
* does not belong to the active labelmap
|
||||||
|
*/
|
||||||
|
const { StudyInstanceUID } = activeViewport;
|
||||||
|
const studyMetadata = studyMetadataManager.get(StudyInstanceUID);
|
||||||
|
const allDisplaySets = studyMetadata.getDisplaySets();
|
||||||
|
let newLabelmapIndex = brushStackState.activeLabelmapIndex;
|
||||||
|
allDisplaySets.forEach(displaySet => {
|
||||||
|
if (displaySet.labelmapSegments) {
|
||||||
|
Object.keys(displaySet.labelmapSegments).forEach(labelmapIndex => {
|
||||||
|
if (displaySet.labelmapSegments[labelmapIndex].includes(segmentIndex)) {
|
||||||
|
newLabelmapIndex = labelmapIndex;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
brushStackState.activeLabelmapIndex = newLabelmapIndex;
|
||||||
|
|
||||||
|
refreshViewports();
|
||||||
return segmentIndex;
|
return segmentIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
import { MODULE_TYPES, utils } from '@ohif/core';
|
import { MODULE_TYPES, utils } from '@ohif/core';
|
||||||
import loadSegmentation from './loadSegmentation';
|
import loadSegmentation from './loadSegmentation';
|
||||||
import getSourceDisplaySet from './getSourceDisplaySet';
|
import getSourceDisplaySet from './getSourceDisplaySet';
|
||||||
|
import OHIF from '@ohif/core';
|
||||||
|
import dcmjs from 'dcmjs';
|
||||||
|
|
||||||
|
const { DicomLoaderService } = OHIF.utils;
|
||||||
|
const { DicomMessage, DicomMetaDictionary } = dcmjs.data;
|
||||||
|
|
||||||
// TODO: Should probably use dcmjs for this
|
// TODO: Should probably use dcmjs for this
|
||||||
const SOP_CLASS_UIDS = {
|
const SOP_CLASS_UIDS = {
|
||||||
@ -16,7 +21,7 @@ export default function getSopClassHandlerModule({ servicesManager }) {
|
|||||||
id: 'OHIFDicomSegSopClassHandler',
|
id: 'OHIFDicomSegSopClassHandler',
|
||||||
type: MODULE_TYPES.SOP_CLASS_HANDLER,
|
type: MODULE_TYPES.SOP_CLASS_HANDLER,
|
||||||
sopClassUIDs,
|
sopClassUIDs,
|
||||||
getDisplaySetFromSeries: function(
|
getDisplaySetFromSeries: function (
|
||||||
series,
|
series,
|
||||||
study,
|
study,
|
||||||
dicomWebClient,
|
dicomWebClient,
|
||||||
@ -46,7 +51,6 @@ export default function getSopClassHandlerModule({ servicesManager }) {
|
|||||||
StudyInstanceUID,
|
StudyInstanceUID,
|
||||||
FrameOfReferenceUID,
|
FrameOfReferenceUID,
|
||||||
authorizationHeaders,
|
authorizationHeaders,
|
||||||
metadata,
|
|
||||||
isDerived: true,
|
isDerived: true,
|
||||||
referencedDisplaySetUID: null, // Assigned when loaded.
|
referencedDisplaySetUID: null, // Assigned when loaded.
|
||||||
labelmapIndex: null, // Assigned when loaded.
|
labelmapIndex: null, // Assigned when loaded.
|
||||||
@ -58,15 +62,85 @@ export default function getSopClassHandlerModule({ servicesManager }) {
|
|||||||
metadata,
|
metadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
segDisplaySet.getSourceDisplaySet = function(studies) {
|
segDisplaySet.getSourceDisplaySet = function (studies) {
|
||||||
return getSourceDisplaySet(studies, segDisplaySet);
|
return getSourceDisplaySet(studies, segDisplaySet);
|
||||||
};
|
};
|
||||||
|
|
||||||
segDisplaySet.load = function(referencedDisplaySet, studies) {
|
segDisplaySet.load = async function (referencedDisplaySet, studies) {
|
||||||
return loadSegmentation(segDisplaySet, referencedDisplaySet, studies);
|
segDisplaySet.isLoaded = true;
|
||||||
|
const { StudyInstanceUID } = referencedDisplaySet;
|
||||||
|
const segArrayBuffer = await DicomLoaderService.findDicomDataPromise(
|
||||||
|
segDisplaySet,
|
||||||
|
studies
|
||||||
|
);
|
||||||
|
const dicomData = DicomMessage.readFile(segArrayBuffer);
|
||||||
|
const dataset = DicomMetaDictionary.naturalizeDataset(dicomData.dict);
|
||||||
|
dataset._meta = DicomMetaDictionary.namifyDataset(dicomData.meta);
|
||||||
|
const imageIds = _getImageIdsForDisplaySet(
|
||||||
|
studies,
|
||||||
|
StudyInstanceUID,
|
||||||
|
referencedDisplaySet.SeriesInstanceUID
|
||||||
|
);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let results;
|
||||||
|
try {
|
||||||
|
results = _parseSeg(segArrayBuffer, imageIds);
|
||||||
|
} catch (error) {
|
||||||
|
segDisplaySet.isLoaded = false;
|
||||||
|
segDisplaySet.loadError = true;
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
const { labelmapBufferArray, segMetadata, segmentsOnFrame, segmentsOnFrameArray } = results;
|
||||||
|
|
||||||
|
if (labelmapBufferArray.length > 1) {
|
||||||
|
for (let i = 0; i < labelmapBufferArray.length; ++i) {
|
||||||
|
loadSegmentation(imageIds, segDisplaySet, labelmapBufferArray[i], segMetadata, segmentsOnFrame, segmentsOnFrameArray[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loadSegmentation(imageIds, segDisplaySet, labelmapBufferArray[0], segMetadata, segmentsOnFrame, []);
|
||||||
|
}
|
||||||
|
segDisplaySet.labelmapIndex = 0;
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return segDisplaySet;
|
return segDisplaySet;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _parseSeg(arrayBuffer, imageIds) {
|
||||||
|
return dcmjs.adapters.Cornerstone.Segmentation.generateToolState(
|
||||||
|
imageIds,
|
||||||
|
arrayBuffer,
|
||||||
|
cornerstone.metaData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getImageIdsForDisplaySet(
|
||||||
|
studies,
|
||||||
|
StudyInstanceUID,
|
||||||
|
SeriesInstanceUID
|
||||||
|
) {
|
||||||
|
const study = studies.find(
|
||||||
|
study => study.StudyInstanceUID === StudyInstanceUID
|
||||||
|
);
|
||||||
|
|
||||||
|
const displaySets = study.displaySets.filter(displaySet => {
|
||||||
|
return displaySet.SeriesInstanceUID === SeriesInstanceUID;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (displaySets.length > 1) {
|
||||||
|
console.warn(
|
||||||
|
'More than one display set with the same SeriesInstanceUID. This is not supported yet...'
|
||||||
|
);
|
||||||
|
// TODO -> We could make check the instance list and see if any match?
|
||||||
|
// Do we split the segmentation into two cornerstoneTools segmentations if there are images in both series?
|
||||||
|
// ^ Will that even happen?
|
||||||
|
}
|
||||||
|
|
||||||
|
const referencedDisplaySet = displaySets[0];
|
||||||
|
|
||||||
|
return referencedDisplaySet.images.map(image => image.getImageId());
|
||||||
|
}
|
||||||
|
|||||||
@ -1,51 +1,15 @@
|
|||||||
import OHIF from '@ohif/core';
|
|
||||||
import dcmjs from 'dcmjs';
|
import dcmjs from 'dcmjs';
|
||||||
import cornerstone from 'cornerstone-core';
|
import cornerstone from 'cornerstone-core';
|
||||||
import cornerstoneTools from 'cornerstone-tools';
|
import cornerstoneTools from 'cornerstone-tools';
|
||||||
|
|
||||||
const { DicomLoaderService } = OHIF.utils;
|
|
||||||
|
|
||||||
export default async function loadSegmentation(
|
export default async function loadSegmentation(
|
||||||
|
imageIds,
|
||||||
segDisplaySet,
|
segDisplaySet,
|
||||||
referencedDisplaySet,
|
labelmapBuffer,
|
||||||
studies
|
segMetadata,
|
||||||
|
segmentsOnFrame,
|
||||||
|
labelmapSegments
|
||||||
) {
|
) {
|
||||||
const { StudyInstanceUID } = referencedDisplaySet;
|
|
||||||
|
|
||||||
// Set here is loading is asynchronous.
|
|
||||||
// If this function throws its set back to false.
|
|
||||||
segDisplaySet.isLoaded = true;
|
|
||||||
|
|
||||||
const segArrayBuffer = await DicomLoaderService.findDicomDataPromise(
|
|
||||||
segDisplaySet,
|
|
||||||
studies
|
|
||||||
);
|
|
||||||
|
|
||||||
const dicomData = dcmjs.data.DicomMessage.readFile(segArrayBuffer);
|
|
||||||
const dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(
|
|
||||||
dicomData.dict
|
|
||||||
);
|
|
||||||
|
|
||||||
dataset._meta = dcmjs.data.DicomMetaDictionary.namifyDataset(dicomData.meta);
|
|
||||||
|
|
||||||
const imageIds = _getImageIdsForDisplaySet(
|
|
||||||
studies,
|
|
||||||
StudyInstanceUID,
|
|
||||||
referencedDisplaySet.SeriesInstanceUID
|
|
||||||
);
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let results;
|
|
||||||
|
|
||||||
try {
|
|
||||||
results = _parseSeg(segArrayBuffer, imageIds);
|
|
||||||
} catch (error) {
|
|
||||||
segDisplaySet.isLoaded = false;
|
|
||||||
segDisplaySet.loadError = true;
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { labelmapBuffer, segMetadata, segmentsOnFrame } = results;
|
|
||||||
const { setters } = cornerstoneTools.getModule('segmentation');
|
const { setters } = cornerstoneTools.getModule('segmentation');
|
||||||
|
|
||||||
// TODO: Could define a color LUT based on colors in the SEG.
|
// TODO: Could define a color LUT based on colors in the SEG.
|
||||||
@ -62,6 +26,15 @@ export default async function loadSegmentation(
|
|||||||
colorLUTIndex
|
colorLUTIndex
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!segDisplaySet.labelmapSegments) {
|
||||||
|
segDisplaySet.labelmapSegments = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache each labelmap segments.
|
||||||
|
* This data is used to determine the active label map when a given segment is activated/clicked.
|
||||||
|
*/
|
||||||
|
segDisplaySet.labelmapSegments[labelmapIndex] = labelmapSegments.length ? Array.from(new Set(labelmapSegments.filter(a => !!a).reduce((a, b) => a.concat(b)))) : [];
|
||||||
segDisplaySet.labelmapIndex = labelmapIndex;
|
segDisplaySet.labelmapIndex = labelmapIndex;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -84,9 +57,6 @@ export default async function loadSegmentation(
|
|||||||
console.log('Segmentation loaded.');
|
console.log('Segmentation loaded.');
|
||||||
const event = new CustomEvent('extensiondicomsegmentationsegloaded');
|
const event = new CustomEvent('extensiondicomsegmentationsegloaded');
|
||||||
document.dispatchEvent(event);
|
document.dispatchEvent(event);
|
||||||
|
|
||||||
resolve(labelmapIndex);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getNextLabelmapIndex(firstImageId) {
|
function _getNextLabelmapIndex(firstImageId) {
|
||||||
@ -172,38 +142,3 @@ function _getNextColorLUTIndex() {
|
|||||||
|
|
||||||
return colorLUTIndex;
|
return colorLUTIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _parseSeg(arrayBuffer, imageIds) {
|
|
||||||
return dcmjs.adapters.Cornerstone.Segmentation.generateToolState(
|
|
||||||
imageIds,
|
|
||||||
arrayBuffer,
|
|
||||||
cornerstone.metaData
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _getImageIdsForDisplaySet(
|
|
||||||
studies,
|
|
||||||
StudyInstanceUID,
|
|
||||||
SeriesInstanceUID
|
|
||||||
) {
|
|
||||||
const study = studies.find(
|
|
||||||
study => study.StudyInstanceUID === StudyInstanceUID
|
|
||||||
);
|
|
||||||
|
|
||||||
const displaySets = study.displaySets.filter(displaySet => {
|
|
||||||
return displaySet.SeriesInstanceUID === SeriesInstanceUID;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (displaySets.length > 1) {
|
|
||||||
console.warn(
|
|
||||||
'More than one display set with the same SeriesInstanceUID. This is not supported yet...'
|
|
||||||
);
|
|
||||||
// TODO -> We could make check the instance list and see if any match?
|
|
||||||
// Do we split the segmentation into two cornerstoneTools segmentations if there are images in both series?
|
|
||||||
// ^ Will that even happen?
|
|
||||||
}
|
|
||||||
|
|
||||||
const referencedDisplaySet = displaySets[0];
|
|
||||||
|
|
||||||
return referencedDisplaySet.images.map(image => image.getImageId());
|
|
||||||
}
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "^2.6.0",
|
"@ohif/core": "^2.6.0",
|
||||||
"dcmjs": "0.16.5",
|
"dcmjs": "0.17.0",
|
||||||
"react": "^16.8.6"
|
"react": "^16.8.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
"cornerstone-core": "^2.2.8",
|
"cornerstone-core": "^2.2.8",
|
||||||
"cornerstone-tools": "^4.20.1",
|
"cornerstone-tools": "^4.20.1",
|
||||||
"cornerstone-wado-image-loader": "^3.1.0",
|
"cornerstone-wado-image-loader": "^3.1.0",
|
||||||
"dcmjs": "0.16.5",
|
"dcmjs": "0.17.0",
|
||||||
"dicom-parser": "^1.8.3",
|
"dicom-parser": "^1.8.3",
|
||||||
"i18next": "^17.0.3",
|
"i18next": "^17.0.3",
|
||||||
"i18next-browser-languagedetector": "^3.0.1",
|
"i18next-browser-languagedetector": "^3.0.1",
|
||||||
|
|||||||
@ -72,7 +72,7 @@ class OHIFVTKViewport extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
onScroll: () => {},
|
onScroll: () => { },
|
||||||
};
|
};
|
||||||
|
|
||||||
static id = 'OHIFVTKViewport';
|
static id = 'OHIFVTKViewport';
|
||||||
@ -159,6 +159,15 @@ class OHIFVTKViewport extends Component {
|
|||||||
const { activeLabelmapIndex } = brushStackState;
|
const { activeLabelmapIndex } = brushStackState;
|
||||||
const labelmap3D = brushStackState.labelmaps3D[activeLabelmapIndex];
|
const labelmap3D = brushStackState.labelmaps3D[activeLabelmapIndex];
|
||||||
|
|
||||||
|
if (brushStackState.labelmaps3D.length > 1 && this.props.viewportIndex === 0) {
|
||||||
|
const { UINotificationService } = this.props.servicesManager.services;
|
||||||
|
UINotificationService.show({
|
||||||
|
title: 'Overlapping Segmentation Found',
|
||||||
|
message: 'Overlapping segmentations cannot be displayed when in MPR mode',
|
||||||
|
type: 'info',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.segmentsDefaultProperties = labelmap3D.segmentsHidden.map(
|
this.segmentsDefaultProperties = labelmap3D.segmentsHidden.map(
|
||||||
isHidden => {
|
isHidden => {
|
||||||
return { visible: !isHidden };
|
return { visible: !isHidden };
|
||||||
|
|||||||
@ -39,7 +39,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"ajv": "^6.10.0",
|
"ajv": "^6.10.0",
|
||||||
"dcmjs": "0.16.5",
|
"dcmjs": "0.17.0",
|
||||||
"dicomweb-client": "^0.6.0",
|
"dicomweb-client": "^0.6.0",
|
||||||
"immer": "6.0.2",
|
"immer": "6.0.2",
|
||||||
"isomorphic-base64": "^1.0.2",
|
"isomorphic-base64": "^1.0.2",
|
||||||
|
|||||||
@ -37,6 +37,10 @@ const SnackbarProvider = ({ children, service }) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.type === 'error') {
|
||||||
|
console.error(options.error);
|
||||||
|
}
|
||||||
|
|
||||||
const newItem = {
|
const newItem = {
|
||||||
...DEFAULT_OPTIONS,
|
...DEFAULT_OPTIONS,
|
||||||
...options,
|
...options,
|
||||||
|
|||||||
@ -68,7 +68,7 @@
|
|||||||
"cornerstone-math": "^0.1.8",
|
"cornerstone-math": "^0.1.8",
|
||||||
"cornerstone-tools": "^4.20.1",
|
"cornerstone-tools": "^4.20.1",
|
||||||
"cornerstone-wado-image-loader": "^3.1.0",
|
"cornerstone-wado-image-loader": "^3.1.0",
|
||||||
"dcmjs": "0.16.5",
|
"dcmjs": "0.17.0",
|
||||||
"dicom-parser": "^1.8.3",
|
"dicom-parser": "^1.8.3",
|
||||||
"dicomweb-client": "^0.4.4",
|
"dicomweb-client": "^0.4.4",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import EmptyViewport from './EmptyViewport.js';
|
|||||||
|
|
||||||
const { loadAndCacheDerivedDisplaySets } = utils;
|
const { loadAndCacheDerivedDisplaySets } = utils;
|
||||||
|
|
||||||
const ViewportGrid = function(props) {
|
const ViewportGrid = function (props) {
|
||||||
const {
|
const {
|
||||||
activeViewportIndex,
|
activeViewportIndex,
|
||||||
availablePlugins,
|
availablePlugins,
|
||||||
@ -48,6 +48,7 @@ const ViewportGrid = function(props) {
|
|||||||
title: 'Error loading derived display set:',
|
title: 'Error loading derived display set:',
|
||||||
message: error.message,
|
message: error.message,
|
||||||
type: 'error',
|
type: 'error',
|
||||||
|
error,
|
||||||
autoClose: false,
|
autoClose: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6619,14 +6619,15 @@ dateformat@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
||||||
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
|
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
|
||||||
|
|
||||||
dcmjs@0.16.5:
|
dcmjs@0.17.0:
|
||||||
version "0.16.5"
|
version "0.17.0"
|
||||||
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.16.5.tgz#05aa0c8d539a4d5777f996b9b796932d1f848993"
|
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.17.0.tgz#dbfd6db3efd2936f9bead9c902b7db396f64e9f5"
|
||||||
integrity sha512-Y92KAx4JSfev79xjYhaukQZjWgyJlaHnXSTdbtkGkJAHERjIakgHcCIPmACuVmtW/nHViTu04zIGAB0pmZ4GaA==
|
integrity sha512-7JnNqNWXqjGyspLRwKM4nn+TU/+w3iMl9boU4eHrr831M4crMWWIiSQDejpOnfDT9+opqyeaYcNkiekr7p6TFg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/polyfill" "^7.8.3"
|
"@babel/polyfill" "^7.8.3"
|
||||||
"@babel/runtime" "^7.8.4"
|
"@babel/runtime" "^7.8.4"
|
||||||
gl-matrix "^3.1.0"
|
gl-matrix "^3.1.0"
|
||||||
|
lodash.clonedeep "^4.5.0"
|
||||||
loglevelnext "^3.0.1"
|
loglevelnext "^3.0.1"
|
||||||
ndarray "^1.0.19"
|
ndarray "^1.0.19"
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user