Compare commits
36
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7b5f1847a | ||
|
|
5cb6e63b88 | ||
|
|
48eb4a9ec3 | ||
|
|
d9231fd431 | ||
|
|
e5b578bd8e | ||
|
|
f38979037d | ||
|
|
45ca88f5b8 | ||
|
|
a1dee16a3d | ||
|
|
6a37a2a661 | ||
|
|
a8caf4bba4 | ||
|
|
29dcc82e28 | ||
|
|
dbf0501031 | ||
|
|
ef28fa2ac1 | ||
|
|
779a7e0976 | ||
|
|
7f3ca1fc23 | ||
|
|
59ab68b4ed | ||
|
|
248bc0a64a | ||
|
|
5fdace1432 | ||
|
|
71b6b454a3 | ||
|
|
3b02a06f5e | ||
|
|
ebdcde1c4d | ||
|
|
829ac2b410 | ||
|
|
09745a0349 | ||
|
|
cd73dd3027 | ||
|
|
ca511edeff | ||
|
|
bb5f30ce2a | ||
|
|
87d5c68e71 | ||
|
|
0e87ab37c2 | ||
|
|
756b005fe1 | ||
|
|
3d86b5f876 | ||
|
|
2a647fd618 | ||
|
|
f8fc31bcac | ||
|
|
b7ab88b0f1 | ||
|
|
57a30d7c34 | ||
|
|
cd90665b0e | ||
|
|
98c657231e |
No files matched your search
@@ -11,6 +11,7 @@ node -v
|
|||||||
|
|
||||||
# Install build deps and all monorepo package dependencies. Yarn Workspaces
|
# Install build deps and all monorepo package dependencies. Yarn Workspaces
|
||||||
# should also symlink all projects appropriately
|
# should also symlink all projects appropriately
|
||||||
|
yarn run lerna:restore
|
||||||
yarn install --no-ignore-optional --pure-lockfile
|
yarn install --no-ignore-optional --pure-lockfile
|
||||||
|
|
||||||
# Build && Move PWA Output
|
# Build && Move PWA Output
|
||||||
|
|||||||
@@ -3,6 +3,63 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.9.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.9.3...@ohif/extension-cornerstone@2.9.4) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.9.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.9.2...@ohif/extension-cornerstone@2.9.3) (2020-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.9.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.9.1...@ohif/extension-cornerstone@2.9.2) (2020-08-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Updated react-cornerstone-viewport to version 4.0.2 ([#2001](https://github.com/OHIF/Viewers/issues/2001)) ([59ab68b](https://github.com/OHIF/Viewers/commit/59ab68b4edbfec010170c4429c300a53f688bf94))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.9.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.9.0...@ohif/extension-cornerstone@2.9.1) (2020-08-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* **stackPrefetch:** Added stackPrefetch config with 20 max concurrent requests ([#2000](https://github.com/OHIF/Viewers/issues/2000)) ([3b02a06](https://github.com/OHIF/Viewers/commit/3b02a06f5e250660edde4862ce44147db3dc3ab9))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [2.9.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.8.5...@ohif/extension-cornerstone@2.9.0) (2020-08-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Update react-vtkjs-viewport usage to use requestPool ([#1984](https://github.com/OHIF/Viewers/issues/1984)) ([bb5f30c](https://github.com/OHIF/Viewers/commit/bb5f30ce2a0192d2e021beaaadfff22fd38e17b9))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.8.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.8.4...@ohif/extension-cornerstone@2.8.5) (2020-08-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.8.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.8.3...@ohif/extension-cornerstone@2.8.4) (2020-07-13)
|
## [2.8.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.8.3...@ohif/extension-cornerstone@2.8.4) (2020-07-13)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-cornerstone",
|
"name": "@ohif/extension-cornerstone",
|
||||||
"version": "2.8.4",
|
"version": "2.9.4",
|
||||||
"description": "OHIF extension for Cornerstone",
|
"description": "OHIF extension for Cornerstone",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -34,9 +34,9 @@
|
|||||||
"@ohif/ui": "^0.50.0",
|
"@ohif/ui": "^0.50.0",
|
||||||
"cornerstone-core": "^2.2.8",
|
"cornerstone-core": "^2.2.8",
|
||||||
"cornerstone-math": "^0.1.8",
|
"cornerstone-math": "^0.1.8",
|
||||||
"cornerstone-tools": "4.15.1",
|
"cornerstone-tools": "^4.20.1",
|
||||||
"cornerstone-wado-image-loader": "^3.1.0",
|
"cornerstone-wado-image-loader": "^3.1.0",
|
||||||
"dcmjs": "0.16.0",
|
"dcmjs": "0.16.3",
|
||||||
"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",
|
||||||
@@ -51,6 +51,6 @@
|
|||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"lodash.merge": "^4.6.2",
|
"lodash.merge": "^4.6.2",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
"react-cornerstone-viewport": "2.3.9"
|
"react-cornerstone-viewport": "4.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ import init from './init.js';
|
|||||||
import commandsModule from './commandsModule.js';
|
import commandsModule from './commandsModule.js';
|
||||||
import toolbarModule from './toolbarModule.js';
|
import toolbarModule from './toolbarModule.js';
|
||||||
import CornerstoneViewportDownloadForm from './CornerstoneViewportDownloadForm';
|
import CornerstoneViewportDownloadForm from './CornerstoneViewportDownloadForm';
|
||||||
|
import { version } from '../package.json';
|
||||||
|
|
||||||
const Component = React.lazy(() => {
|
const Component = React.lazy(() => {
|
||||||
return import('./OHIFCornerstoneViewport');
|
return import('./OHIFCornerstoneViewport');
|
||||||
@@ -24,6 +25,7 @@ export default {
|
|||||||
* Only required property. Should be a unique value across all extensions.
|
* Only required property. Should be a unique value across all extensions.
|
||||||
*/
|
*/
|
||||||
id: 'cornerstone',
|
id: 'cornerstone',
|
||||||
|
version,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -34,4 +34,11 @@ export default function(configuration = {}) {
|
|||||||
cornerstoneTools.toolColors.setActiveColor('rgb(0, 255, 0)');
|
cornerstoneTools.toolColors.setActiveColor('rgb(0, 255, 0)');
|
||||||
|
|
||||||
cornerstoneTools.store.state.touchProximity = 40;
|
cornerstoneTools.store.state.touchProximity = 40;
|
||||||
|
|
||||||
|
// Configure stack prefetch
|
||||||
|
cornerstoneTools.stackPrefetch.setConfiguration({
|
||||||
|
maxImagesToPrefetch: Infinity,
|
||||||
|
preserveExistingPool: false,
|
||||||
|
maxSimultaneousRequests: 20,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
File renamed without changes.
File renamed without changes.
@@ -3,6 +3,22 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [0.1.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-debugging@0.1.3...@ohif/extension-debugging@0.1.4) (2020-09-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-debugging
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 0.1.3 (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-debugging
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.1.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-p10-downloader@0.1.1...@ohif/extension-dicom-p10-downloader@0.1.2) (2020-06-18)
|
## [0.1.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-p10-downloader@0.1.1...@ohif/extension-dicom-p10-downloader@0.1.2) (2020-06-18)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-dicom-p10-downloader
|
**Note:** Version bump only for package @ohif/extension-dicom-p10-downloader
|
||||||
File renamed without changes.
File renamed without changes.
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-dicom-p10-downloader",
|
"name": "@ohif/extension-debugging",
|
||||||
"version": "0.1.2",
|
"version": "0.1.4",
|
||||||
"description": "OHIF extension for downloading DICOM P10 files",
|
"description": "OHIF extension for debugging.",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "OHIF/Viewers",
|
"repository": "OHIF/Viewers",
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
|
"detect-browser": "5.1.1",
|
||||||
"dicomweb-client": "^0.6.0",
|
"dicomweb-client": "^0.6.0",
|
||||||
"file-saver": "^2.0.2",
|
"file-saver": "^2.0.2",
|
||||||
"jszip": "^3.2.2"
|
"jszip": "^3.2.2"
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
.debugReportModalHeader {
|
||||||
|
padding: 10px 0 10px;
|
||||||
|
color: var(--active-color);
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { detect } from 'detect-browser';
|
||||||
|
import './DebugReportModal.css';
|
||||||
|
|
||||||
|
const DubugReportModal = ({
|
||||||
|
viewports,
|
||||||
|
studies,
|
||||||
|
servers,
|
||||||
|
extensionManager,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
{getAppVersion()}
|
||||||
|
{getExtensionVersions(extensionManager)}
|
||||||
|
{getBrowserInfo()}
|
||||||
|
{getCurrentStudyUrl()}
|
||||||
|
{getLayout(viewports)}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAppVersion = () => {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<tr>
|
||||||
|
<th className="debugReportModalHeader">App</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Version</td>
|
||||||
|
<td>{window.version}</td>
|
||||||
|
</tr>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCurrentStudyUrl = () => {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<tr>
|
||||||
|
<th className="debugReportModalHeader">App</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>URL</td>
|
||||||
|
<td>{window.location.href}</td>
|
||||||
|
</tr>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getExtensionVersions = extensionManager => {
|
||||||
|
const { registeredExtensionVesions } = extensionManager;
|
||||||
|
|
||||||
|
const lineItems = Object.keys(registeredExtensionVesions).map(extensionId => {
|
||||||
|
const version = registeredExtensionVesions[extensionId];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td>{extensionId}</td>
|
||||||
|
<td>{version}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<th className="debugReportModalHeader">Extensions</th>
|
||||||
|
{lineItems}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getLayout = viewports => {
|
||||||
|
const { numRows, numColumns } = viewports;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<tr>
|
||||||
|
<th className="debugReportModalHeader">Viewports</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Layout</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Rows</td>
|
||||||
|
<td>{numRows}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Columns</td>
|
||||||
|
<td>{numColumns}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>SeriesInstanceUIDs</th>
|
||||||
|
</tr>
|
||||||
|
{getSeriesInstanceUIDsPerRow(viewports)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBrowserInfo = () => {
|
||||||
|
const browser = detect();
|
||||||
|
|
||||||
|
const { name, os, type, version } = browser;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<tr>
|
||||||
|
<th className="debugReportModalHeader">Platform</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>name</td>
|
||||||
|
<td>{name}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>os</td>
|
||||||
|
<td>{os}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>type</td>
|
||||||
|
<td>{type}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>version</td>
|
||||||
|
<td>{version}</td>
|
||||||
|
</tr>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSeriesInstanceUIDsPerRow = viewports => {
|
||||||
|
const { viewportSpecificData, numColumns } = viewports;
|
||||||
|
|
||||||
|
// NOTE viewportSpecificData is actually an object with numerical keys.
|
||||||
|
return Object.keys(viewportSpecificData).map(viewportIndex => {
|
||||||
|
const vsd = viewportSpecificData[viewportIndex];
|
||||||
|
|
||||||
|
const [row, column] = _viewportIndexToViewportPosition(
|
||||||
|
viewportIndex,
|
||||||
|
numColumns
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td>{`[${row},${column}]`}</td>
|
||||||
|
<td>{vsd.SeriesInstanceUID}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const _viewportIndexToViewportPosition = (viewportIndex, numColumns) => {
|
||||||
|
const row = Math.floor(viewportIndex / numColumns);
|
||||||
|
const column = viewportIndex % numColumns;
|
||||||
|
|
||||||
|
return [row, column];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DubugReportModal;
|
||||||
+26
-1
@@ -8,12 +8,14 @@ import {
|
|||||||
getSOPInstanceReferencesFromViewports,
|
getSOPInstanceReferencesFromViewports,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import _downloadAndZip, { downloadInstances } from './downloadAndZip';
|
import _downloadAndZip, { downloadInstances } from './downloadAndZip';
|
||||||
|
import DebugReportModal from './DebugReportModal';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
utils: { Queue },
|
utils: { Queue },
|
||||||
} = OHIF;
|
} = OHIF;
|
||||||
|
|
||||||
export function getCommands(context) {
|
export function getCommands(context, servicesManager, extensionManager) {
|
||||||
const queue = new Queue(1);
|
const queue = new Queue(1);
|
||||||
const actions = {
|
const actions = {
|
||||||
/**
|
/**
|
||||||
@@ -87,9 +89,32 @@ export function getCommands(context) {
|
|||||||
serverConfig
|
serverConfig
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
openDebugInfoModal({ viewports, studies, servers }) {
|
||||||
|
const { UIModalService } = servicesManager.services;
|
||||||
|
|
||||||
|
const WrappedDebugReportModal = function() {
|
||||||
|
return (
|
||||||
|
<DebugReportModal
|
||||||
|
viewports={viewports}
|
||||||
|
studies={studies}
|
||||||
|
servers={servers}
|
||||||
|
extensionManager={extensionManager}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIModalService.show({
|
||||||
|
content: WrappedDebugReportModal,
|
||||||
|
title: `Debugging Information`,
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const definitions = {
|
const definitions = {
|
||||||
|
openDebugInfoModal: {
|
||||||
|
commandFn: actions.openDebugInfoModal,
|
||||||
|
storeContexts: ['viewports', 'servers', 'studies'],
|
||||||
|
},
|
||||||
downloadAndZip: {
|
downloadAndZip: {
|
||||||
commandFn: queue.bindSafe(actions.downloadAndZip, error),
|
commandFn: queue.bindSafe(actions.downloadAndZip, error),
|
||||||
storeContexts: ['servers'],
|
storeContexts: ['servers'],
|
||||||
File renamed without changes.
@@ -1,5 +1,7 @@
|
|||||||
import { getDicomWebClientFromConfig } from './utils';
|
import { getDicomWebClientFromConfig } from './utils';
|
||||||
import { getCommands } from './commandsModule';
|
import { getCommands } from './commandsModule';
|
||||||
|
import { version } from '../package.json';
|
||||||
|
import toolbarModule from './toolbarModule';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constants
|
* Constants
|
||||||
@@ -21,6 +23,7 @@ export default {
|
|||||||
* Only required property. Should be a unique value across all extensions.
|
* Only required property. Should be a unique value across all extensions.
|
||||||
*/
|
*/
|
||||||
id: 'dicom-p10-downloader',
|
id: 'dicom-p10-downloader',
|
||||||
|
version,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LIFECYCLE HOOKS
|
* LIFECYCLE HOOKS
|
||||||
@@ -37,7 +40,11 @@ export default {
|
|||||||
* MODULE GETTERS
|
* MODULE GETTERS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
getCommandsModule() {
|
getCommandsModule({ servicesManager, extensionManager }) {
|
||||||
return getCommands(sharedContext);
|
return getCommands(sharedContext, servicesManager, extensionManager);
|
||||||
|
},
|
||||||
|
|
||||||
|
getToolbarModule() {
|
||||||
|
return toolbarModule;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
const TOOLBAR_BUTTON_TYPES = {
|
||||||
|
COMMAND: 'command',
|
||||||
|
};
|
||||||
|
|
||||||
|
const definitions = [
|
||||||
|
{
|
||||||
|
id: 'Debug Info',
|
||||||
|
label: 'Debug Info',
|
||||||
|
icon: 'cog',
|
||||||
|
//
|
||||||
|
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||||
|
commandName: 'openDebugInfoModal',
|
||||||
|
context: 'VIEWER',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
definitions,
|
||||||
|
defaultContext: 'VIEWER',
|
||||||
|
};
|
||||||
File renamed without changes.
@@ -3,6 +3,30 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.2.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.2.6...@ohif/extension-dicom-html@1.2.7) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.2.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.2.5...@ohif/extension-dicom-html@1.2.6) (2020-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.2.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.2.4...@ohif/extension-dicom-html@1.2.5) (2020-08-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.2.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.2.3...@ohif/extension-dicom-html@1.2.4) (2020-07-13)
|
## [1.2.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.2.3...@ohif/extension-dicom-html@1.2.4) (2020-07-13)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-dicom-html
|
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-dicom-html",
|
"name": "@ohif/extension-dicom-html",
|
||||||
"version": "1.2.4",
|
"version": "1.2.7",
|
||||||
"description": "OHIF extension for rendering structured reports to HTML",
|
"description": "OHIF extension for rendering structured reports to HTML",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"dcmjs": "0.16.0",
|
"dcmjs": "0.16.3",
|
||||||
"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"
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ const OHIFDicomHtmlSopClassHandler = {
|
|||||||
getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
|
getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
|
||||||
const instance = series.getFirstInstance();
|
const instance = series.getFirstInstance();
|
||||||
|
|
||||||
|
const {
|
||||||
|
SeriesDate,
|
||||||
|
SeriesTime,
|
||||||
|
SeriesNumber,
|
||||||
|
} = instance._instance.metadata;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
plugin: 'html',
|
plugin: 'html',
|
||||||
Modality: 'SR',
|
Modality: 'SR',
|
||||||
@@ -31,6 +37,9 @@ const OHIFDicomHtmlSopClassHandler = {
|
|||||||
SOPInstanceUID: instance.getSOPInstanceUID(),
|
SOPInstanceUID: instance.getSOPInstanceUID(),
|
||||||
SeriesInstanceUID: series.getSeriesInstanceUID(),
|
SeriesInstanceUID: series.getSeriesInstanceUID(),
|
||||||
StudyInstanceUID: study.getStudyInstanceUID(),
|
StudyInstanceUID: study.getStudyInstanceUID(),
|
||||||
|
SeriesDate,
|
||||||
|
SeriesTime,
|
||||||
|
SeriesNumber,
|
||||||
authorizationHeaders,
|
authorizationHeaders,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import OHIFDicomHtmlSopClassHandler from './OHIFDicomHtmlSopClassHandler.js';
|
import OHIFDicomHtmlSopClassHandler from './OHIFDicomHtmlSopClassHandler.js';
|
||||||
|
import { version } from '../package.json';
|
||||||
|
|
||||||
const Component = React.lazy(() => {
|
const Component = React.lazy(() => {
|
||||||
return import('./OHIFDicomHtmlViewport');
|
return import('./OHIFDicomHtmlViewport');
|
||||||
@@ -18,6 +19,7 @@ export default {
|
|||||||
* Only required property. Should be a unique value across all extensions.
|
* Only required property. Should be a unique value across all extensions.
|
||||||
*/
|
*/
|
||||||
id: 'html',
|
id: 'html',
|
||||||
|
version,
|
||||||
|
|
||||||
getViewportModule() {
|
getViewportModule() {
|
||||||
return OHIFDicomHtmlViewport;
|
return OHIFDicomHtmlViewport;
|
||||||
|
|||||||
@@ -3,6 +3,22 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [0.51.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-microscopy@0.51.1...@ohif/extension-dicom-microscopy@0.51.2) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.51.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-microscopy@0.51.0...@ohif/extension-dicom-microscopy@0.51.1) (2020-08-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [0.51.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-microscopy@0.50.9...@ohif/extension-dicom-microscopy@0.51.0) (2020-06-04)
|
# [0.51.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-microscopy@0.50.9...@ohif/extension-dicom-microscopy@0.51.0) (2020-06-04)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-dicom-microscopy",
|
"name": "@ohif/extension-dicom-microscopy",
|
||||||
"version": "0.51.0",
|
"version": "0.51.2",
|
||||||
"description": "OHIF extension for Dicom Microscopy",
|
"description": "OHIF extension for Dicom Microscopy",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ const DicomMicroscopySopClassHandler = {
|
|||||||
getDisplaySetFromSeries(series, study, dicomWebClient) {
|
getDisplaySetFromSeries(series, study, dicomWebClient) {
|
||||||
const instance = series.getFirstInstance();
|
const instance = series.getFirstInstance();
|
||||||
|
|
||||||
|
const {
|
||||||
|
ContentDate,
|
||||||
|
ContentTime,
|
||||||
|
SeriesNumber,
|
||||||
|
} = instance._instance.metadata;
|
||||||
|
|
||||||
// Note: We are passing the dicomweb client into each viewport!
|
// Note: We are passing the dicomweb client into each viewport!
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -22,6 +28,9 @@ const DicomMicroscopySopClassHandler = {
|
|||||||
SOPInstanceUID: instance.getSOPInstanceUID(),
|
SOPInstanceUID: instance.getSOPInstanceUID(),
|
||||||
SeriesInstanceUID: series.getSeriesInstanceUID(),
|
SeriesInstanceUID: series.getSeriesInstanceUID(),
|
||||||
StudyInstanceUID: study.getStudyInstanceUID(),
|
StudyInstanceUID: study.getStudyInstanceUID(),
|
||||||
|
SeriesDate: ContentDate, // Map ContentDate/Time to SeriesTime for series list sorting.
|
||||||
|
SeriesTime: ContentTime,
|
||||||
|
SeriesNumber,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import DicomMicroscopySopClassHandler from './DicomMicroscopySopClassHandler.js';
|
import DicomMicroscopySopClassHandler from './DicomMicroscopySopClassHandler.js';
|
||||||
|
import { version } from '../package.json';
|
||||||
|
|
||||||
const Component = React.lazy(() => {
|
const Component = React.lazy(() => {
|
||||||
return import('./DicomMicroscopyViewport');
|
return import('./DicomMicroscopyViewport');
|
||||||
@@ -18,6 +19,7 @@ export default {
|
|||||||
* Only required property. Should be a unique value across all extensions.
|
* Only required property. Should be a unique value across all extensions.
|
||||||
*/
|
*/
|
||||||
id: 'microscopy',
|
id: 'microscopy',
|
||||||
|
version,
|
||||||
|
|
||||||
getViewportModule() {
|
getViewportModule() {
|
||||||
return DicomMicroscopyViewport;
|
return DicomMicroscopyViewport;
|
||||||
|
|||||||
@@ -3,6 +3,22 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.0.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-pdf@1.0.4...@ohif/extension-dicom-pdf@1.0.5) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.0.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-pdf@1.0.3...@ohif/extension-dicom-pdf@1.0.4) (2020-08-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.0.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-pdf@1.0.2...@ohif/extension-dicom-pdf@1.0.3) (2020-04-02)
|
## [1.0.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-pdf@1.0.2...@ohif/extension-dicom-pdf@1.0.3) (2020-04-02)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-dicom-pdf",
|
"name": "@ohif/extension-dicom-pdf",
|
||||||
"version": "1.0.3",
|
"version": "1.0.5",
|
||||||
"description": "OHIF extension for Dicom PDF",
|
"description": "OHIF extension for Dicom PDF",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ const OHIFDicomPDFSopClassHandler = {
|
|||||||
getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
|
getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
|
||||||
const instance = series.getFirstInstance();
|
const instance = series.getFirstInstance();
|
||||||
|
|
||||||
|
const {
|
||||||
|
ContentDate,
|
||||||
|
ContentTime,
|
||||||
|
SeriesNumber,
|
||||||
|
} = instance._instance.metadata;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
plugin: 'pdf',
|
plugin: 'pdf',
|
||||||
Modality: 'DOC',
|
Modality: 'DOC',
|
||||||
@@ -21,6 +27,9 @@ const OHIFDicomPDFSopClassHandler = {
|
|||||||
SOPInstanceUID: instance.getSOPInstanceUID(),
|
SOPInstanceUID: instance.getSOPInstanceUID(),
|
||||||
SeriesInstanceUID: series.getSeriesInstanceUID(),
|
SeriesInstanceUID: series.getSeriesInstanceUID(),
|
||||||
StudyInstanceUID: study.getStudyInstanceUID(),
|
StudyInstanceUID: study.getStudyInstanceUID(),
|
||||||
|
SeriesDate: ContentDate, // Map ContentDate/Time to SeriesTime for series list sorting.
|
||||||
|
SeriesTime: ContentTime,
|
||||||
|
SeriesNumber,
|
||||||
authorizationHeaders: authorizationHeaders,
|
authorizationHeaders: authorizationHeaders,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import OHIFDicomPDFSopClassHandler from './OHIFDicomPDFSopClassHandler.js';
|
import OHIFDicomPDFSopClassHandler from './OHIFDicomPDFSopClassHandler.js';
|
||||||
|
import { version } from '../package.json';
|
||||||
|
|
||||||
const Component = React.lazy(() => {
|
const Component = React.lazy(() => {
|
||||||
return import('./ConnectedOHIFDicomPDFViewer');
|
return import('./ConnectedOHIFDicomPDFViewer');
|
||||||
@@ -18,6 +19,7 @@ export default {
|
|||||||
* Only required property. Should be a unique value across all extensions.
|
* Only required property. Should be a unique value across all extensions.
|
||||||
*/
|
*/
|
||||||
id: 'pdf',
|
id: 'pdf',
|
||||||
|
version,
|
||||||
getViewportModule() {
|
getViewportModule() {
|
||||||
return ConnectedOHIFDicomPDFViewer;
|
return ConnectedOHIFDicomPDFViewer;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,76 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [0.4.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.4.3...@ohif/extension-dicom-rt@0.4.4) (2020-09-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.4.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.4.2...@ohif/extension-dicom-rt@0.4.3) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.4.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.4.1...@ohif/extension-dicom-rt@0.4.2) (2020-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.4.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.4.0...@ohif/extension-dicom-rt@0.4.1) (2020-08-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [0.4.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.3.0...@ohif/extension-dicom-rt@0.4.0) (2020-08-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Update react-vtkjs-viewport usage to use requestPool ([#1984](https://github.com/OHIF/Viewers/issues/1984)) ([bb5f30c](https://github.com/OHIF/Viewers/commit/bb5f30ce2a0192d2e021beaaadfff22fd38e17b9))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [0.3.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.2.7...@ohif/extension-dicom-rt@0.3.0) (2020-08-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Add support for POINT and OPEN_PLANAR for RT ([0e87ab3](https://github.com/OHIF/Viewers/commit/0e87ab37c29fcf9af74bbcefca854c6e6b8707bc))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.2.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.2.6...@ohif/extension-dicom-rt@0.2.7) (2020-08-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.2.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.2.5...@ohif/extension-dicom-rt@0.2.6) (2020-08-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.2.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.2.4...@ohif/extension-dicom-rt@0.2.5) (2020-07-13)
|
## [0.2.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.2.4...@ohif/extension-dicom-rt@0.2.5) (2020-07-13)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-dicom-rt",
|
"name": "@ohif/extension-dicom-rt",
|
||||||
"version": "0.2.5",
|
"version": "0.4.4",
|
||||||
"description": "OHIF extension for rendering DICOM RTSTRUCTs on top of cornerstone images.",
|
"description": "OHIF extension for rendering DICOM RTSTRUCTs on top of cornerstone images.",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -30,8 +30,8 @@
|
|||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"cornerstone-core": "^2.2.8",
|
"cornerstone-core": "^2.2.8",
|
||||||
"cornerstone-tools": "4.15.1",
|
"cornerstone-tools": "^4.20.1",
|
||||||
"dcmjs": "0.16.0",
|
"dcmjs": "0.16.3",
|
||||||
"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"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { MODULE_TYPES, utils, DICOMWeb } from '@ohif/core';
|
import { MODULE_TYPES, utils, DICOMWeb } from '@ohif/core';
|
||||||
import loadRTStruct from './loadRTStruct';
|
import loadRTStruct from './loadRTStruct';
|
||||||
|
import getSourceDisplaySet from './getSourceDisplaySet';
|
||||||
|
|
||||||
import id from './id';
|
import id from './id';
|
||||||
|
|
||||||
@@ -26,6 +27,7 @@ const OHIFDicomRTStructSopClassHandler = {
|
|||||||
const {
|
const {
|
||||||
SeriesDate,
|
SeriesDate,
|
||||||
SeriesTime,
|
SeriesTime,
|
||||||
|
SeriesNumber,
|
||||||
SeriesDescription,
|
SeriesDescription,
|
||||||
FrameOfReferenceUID,
|
FrameOfReferenceUID,
|
||||||
SOPInstanceUID,
|
SOPInstanceUID,
|
||||||
@@ -52,6 +54,7 @@ const OHIFDicomRTStructSopClassHandler = {
|
|||||||
isLoaded: false,
|
isLoaded: false,
|
||||||
SeriesDate,
|
SeriesDate,
|
||||||
SeriesTime,
|
SeriesTime,
|
||||||
|
SeriesNumber,
|
||||||
SeriesDescription,
|
SeriesDescription,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -67,6 +70,10 @@ const OHIFDicomRTStructSopClassHandler = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtStructDisplaySet.getSourceDisplaySet = function(studies) {
|
||||||
|
return getSourceDisplaySet(studies, rtStructDisplaySet);
|
||||||
|
};
|
||||||
|
|
||||||
rtStructDisplaySet.load = function(referencedDisplaySet, studies) {
|
rtStructDisplaySet.load = function(referencedDisplaySet, studies) {
|
||||||
return loadRTStruct(
|
return loadRTStruct(
|
||||||
rtStructDisplaySet,
|
rtStructDisplaySet,
|
||||||
|
|||||||
@@ -12,12 +12,14 @@ import StructureSetItem from '../StructureSetItem/StructureSetItem';
|
|||||||
import RTPanelSettings from '../RTSettings/RTSettings';
|
import RTPanelSettings from '../RTSettings/RTSettings';
|
||||||
import PanelSection from '../PanelSection/PanelSection';
|
import PanelSection from '../PanelSection/PanelSection';
|
||||||
import LoadingIndicator from '../LoadingIndicator/LoadingIndicator';
|
import LoadingIndicator from '../LoadingIndicator/LoadingIndicator';
|
||||||
|
import TOOL_NAMES from '../../utils/toolNames';
|
||||||
|
|
||||||
|
const { RTSTRUCT_DISPLAY_TOOL } = TOOL_NAMES;
|
||||||
|
|
||||||
const { studyMetadataManager } = utils;
|
const { studyMetadataManager } = utils;
|
||||||
|
|
||||||
const refreshViewport = () => {
|
const refreshViewport = () => {
|
||||||
cornerstone.getEnabledElements().forEach(enabledElement => {
|
cornerstone.getEnabledElements().forEach(enabledElement => {
|
||||||
debugger;
|
|
||||||
if (enabledElement.image) {
|
if (enabledElement.image) {
|
||||||
cornerstone.updateImage(enabledElement.element);
|
cornerstone.updateImage(enabledElement.element);
|
||||||
}
|
}
|
||||||
@@ -40,7 +42,6 @@ const RTPanel = ({
|
|||||||
activeIndex,
|
activeIndex,
|
||||||
isOpen,
|
isOpen,
|
||||||
onContourItemClick,
|
onContourItemClick,
|
||||||
noContoursNotification,
|
|
||||||
activeContexts = [],
|
activeContexts = [],
|
||||||
contexts = {},
|
contexts = {},
|
||||||
}) => {
|
}) => {
|
||||||
@@ -126,7 +127,7 @@ const RTPanel = ({
|
|||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
|
|
||||||
const toContourItem = (
|
const toContourItem = (
|
||||||
{ ROINumber, ROIName, RTROIObservations, colorArray, visible },
|
{ ROINumber, ROIName, RTROIObservations, colorArray, visible, isSupported },
|
||||||
loadedSet
|
loadedSet
|
||||||
) => {
|
) => {
|
||||||
let interpretedType = '';
|
let interpretedType = '';
|
||||||
@@ -139,19 +140,23 @@ const RTPanel = ({
|
|||||||
<StructureSetItem
|
<StructureSetItem
|
||||||
key={ROINumber}
|
key={ROINumber}
|
||||||
selected={isSameContour}
|
selected={isSameContour}
|
||||||
|
isDisabled={!isSupported}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedContour(isSameContour ? null : ROINumber);
|
setSelectedContour(isSameContour ? null : ROINumber);
|
||||||
|
|
||||||
if (isCornerstone()) {
|
if (isCornerstone()) {
|
||||||
const enabledElements = cornerstone.getEnabledElements();
|
const enabledElements = cornerstone.getEnabledElements();
|
||||||
const element = enabledElements[activeIndex].element;
|
const element = enabledElements[activeIndex].element;
|
||||||
const toolState = cornerstoneTools.getToolState(element, 'stack');
|
const stackToolState = cornerstoneTools.getToolState(
|
||||||
|
element,
|
||||||
|
'stack'
|
||||||
|
);
|
||||||
|
|
||||||
if (!toolState) {
|
if (!stackToolState) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const imageIds = toolState.data[0].imageIds;
|
const imageIds = stackToolState.data[0].imageIds;
|
||||||
|
|
||||||
const module = cornerstoneTools.getModule('rtstruct');
|
const module = cornerstoneTools.getModule('rtstruct');
|
||||||
const imageId = module.getters.imageIdOfCenterFrameOfROIContour(
|
const imageId = module.getters.imageIdOfCenterFrameOfROIContour(
|
||||||
@@ -160,11 +165,17 @@ const RTPanel = ({
|
|||||||
imageIds
|
imageIds
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!imageId) {
|
const toolState = cornerstoneTools.globalImageIdSpecificToolStateManager.saveToolState();
|
||||||
noContoursNotification();
|
const imageIdSpecificToolState = toolState[imageId];
|
||||||
|
|
||||||
return;
|
const rtstructData =
|
||||||
}
|
imageIdSpecificToolState[RTSTRUCT_DISPLAY_TOOL];
|
||||||
|
|
||||||
|
const specificData = rtstructData.data.find(
|
||||||
|
rtData => rtData.ROINumber === ROINumber
|
||||||
|
);
|
||||||
|
|
||||||
|
specificData.highlight = true;
|
||||||
|
|
||||||
const frameIndex = imageIds.indexOf(imageId);
|
const frameIndex = imageIds.indexOf(imageId);
|
||||||
const SOPInstanceUID = cornerstone.metaData.get(
|
const SOPInstanceUID = cornerstone.metaData.get(
|
||||||
@@ -249,7 +260,7 @@ const RTPanel = ({
|
|||||||
key={SeriesInstanceUID}
|
key={SeriesInstanceUID}
|
||||||
title={metadata.StructureSetLabel}
|
title={metadata.StructureSetLabel}
|
||||||
loading={!isLoaded || !loadedSet}
|
loading={!isLoaded || !loadedSet}
|
||||||
visible={isLoaded && loadedSet.visible}
|
visible={isLoaded && loadedSet && loadedSet.visible}
|
||||||
hideVisibleButton={!isLoaded}
|
hideVisibleButton={!isLoaded}
|
||||||
expanded={
|
expanded={
|
||||||
isLoaded &&
|
isLoaded &&
|
||||||
|
|||||||
@@ -22,11 +22,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dcmrt-structure-set-item.selected .item-actions {
|
|
||||||
height: 35px;
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dcmrt-structure-set-item .item-actions {
|
.dcmrt-structure-set-item .item-actions {
|
||||||
margin-left: -1px;
|
margin-left: -1px;
|
||||||
background-color: var(--ui-gray-darker);
|
background-color: var(--ui-gray-darker);
|
||||||
@@ -47,7 +42,8 @@
|
|||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dcmrt-structure-set-item .item-actions .btnAction:hover, .dcmrt-structure-set-item .item-actions .btnAction:active {
|
.dcmrt-structure-set-item .item-actions .btnAction:hover,
|
||||||
|
.dcmrt-structure-set-item .item-actions .btnAction:active {
|
||||||
color: var(--text-primary-color);
|
color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,3 +82,12 @@
|
|||||||
.dcmrt-structure-set-item .item-label .eye-icon.--visible {
|
.dcmrt-structure-set-item .item-label .eye-icon.--visible {
|
||||||
color: var(--default-color);
|
color: var(--default-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dcmrt-structure-set-item.isDisabled .item-color-section {
|
||||||
|
background-color: #e29e4a;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dcmrt-structure-set-item.isDisabled .item-label {
|
||||||
|
color: var(--text-disabled-color);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { TableListItem, Icon } from '@ohif/ui';
|
import { TableListItem, Icon, Tooltip, OverlayTrigger } from '@ohif/ui';
|
||||||
|
|
||||||
import './StructureSetItem.css';
|
import './StructureSetItem.css';
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ ColoredCircle.propTypes = {
|
|||||||
const StructureSetItem = ({
|
const StructureSetItem = ({
|
||||||
index,
|
index,
|
||||||
label,
|
label,
|
||||||
|
isDisabled,
|
||||||
onClick,
|
onClick,
|
||||||
itemClass,
|
itemClass,
|
||||||
color,
|
color,
|
||||||
@@ -31,22 +32,44 @@ const StructureSetItem = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsVisible(visible);
|
setIsVisible(visible);
|
||||||
}, [visible])
|
}, [visible]);
|
||||||
|
|
||||||
return (
|
let dcmrtClassNames = `dcmrt-structure-set-item`;
|
||||||
<div className={`dcmrt-structure-set-item ${selected && 'selected'}`}>
|
|
||||||
<TableListItem
|
if (selected) {
|
||||||
key={index}
|
dcmrtClassNames += ' selected';
|
||||||
itemKey={index}
|
}
|
||||||
itemIndex={index}
|
|
||||||
itemClass={itemClass}
|
if (isDisabled) {
|
||||||
itemMeta={<ColoredCircle color={color} />}
|
dcmrtClassNames += ' isDisabled';
|
||||||
itemMetaClass="item-color-section"
|
}
|
||||||
onItemClick={onClick}
|
|
||||||
>
|
const warningIcon = (
|
||||||
<div>
|
<span>
|
||||||
<div className="item-label" style={{ marginBottom: 4 }}>
|
<Icon name="exclamation-triangle" />
|
||||||
<span>{label}</span>
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
const tableListItem = (
|
||||||
|
<TableListItem
|
||||||
|
key={index}
|
||||||
|
itemKey={index}
|
||||||
|
itemIndex={index}
|
||||||
|
itemClass={itemClass}
|
||||||
|
itemMeta={isDisabled ? warningIcon : <ColoredCircle color={color} />}
|
||||||
|
itemMetaClass="item-color-section"
|
||||||
|
onItemClick={() => {
|
||||||
|
if (isDisabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div className="item-label" style={{ marginBottom: 4 }}>
|
||||||
|
<span>{label}</span>
|
||||||
|
{!isDisabled && (
|
||||||
<Icon
|
<Icon
|
||||||
className={`eye-icon ${isVisible && '--visible'}`}
|
className={`eye-icon ${isVisible && '--visible'}`}
|
||||||
name={isVisible ? 'eye' : 'eye-closed'}
|
name={isVisible ? 'eye' : 'eye-closed'}
|
||||||
@@ -54,37 +77,72 @@ const StructureSetItem = ({
|
|||||||
height="20px"
|
height="20px"
|
||||||
onClick={event => {
|
onClick={event => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
|
if (isDisabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const newVisibility = !isVisible;
|
const newVisibility = !isVisible;
|
||||||
setIsVisible(newVisibility);
|
setIsVisible(newVisibility);
|
||||||
onVisibilityChange(newVisibility);
|
onVisibilityChange(newVisibility);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
{false && <div className="item-info">{'...'}</div>}
|
|
||||||
{false && (
|
|
||||||
<div className="item-actions">
|
|
||||||
<button
|
|
||||||
className="btnAction"
|
|
||||||
onClick={() => console.log('Relabelling...')}
|
|
||||||
>
|
|
||||||
<span style={{ marginRight: '4px' }}>
|
|
||||||
<Icon name="edit" width="14px" height="14px" />
|
|
||||||
</span>
|
|
||||||
Relabel
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="btnAction"
|
|
||||||
onClick={() => console.log('Editing description...')}
|
|
||||||
>
|
|
||||||
<span style={{ marginRight: '4px' }}>
|
|
||||||
<Icon name="edit" width="14px" height="14px" />
|
|
||||||
</span>
|
|
||||||
Description
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</TableListItem>
|
|
||||||
|
{false && <div className="item-info">{'...'}</div>}
|
||||||
|
{false && (
|
||||||
|
<div className="item-actions">
|
||||||
|
<button
|
||||||
|
className="btnAction"
|
||||||
|
onClick={() => console.log('Relabelling...')}
|
||||||
|
>
|
||||||
|
<span style={{ marginRight: '4px' }}>
|
||||||
|
<Icon name="edit" width="14px" height="14px" />
|
||||||
|
</span>
|
||||||
|
Relabel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btnAction"
|
||||||
|
onClick={() => console.log('Editing description...')}
|
||||||
|
>
|
||||||
|
<span style={{ marginRight: '4px' }}>
|
||||||
|
<Icon name="edit" width="14px" height="14px" />
|
||||||
|
</span>
|
||||||
|
Description
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</TableListItem>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={dcmrtClassNames}>
|
||||||
|
<React.Fragment>
|
||||||
|
{isDisabled ? (
|
||||||
|
<OverlayTrigger
|
||||||
|
key={index}
|
||||||
|
placement="left"
|
||||||
|
overlay={
|
||||||
|
<Tooltip
|
||||||
|
placement="left"
|
||||||
|
className="in tooltip-warning"
|
||||||
|
id="tooltip-left"
|
||||||
|
>
|
||||||
|
<div className="warningTitle">Unsupported Region</div>
|
||||||
|
<div className="warningContent">
|
||||||
|
Contour type currently unsupported.
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div>{tableListItem}</div>
|
||||||
|
</OverlayTrigger>
|
||||||
|
) : (
|
||||||
|
<React.Fragment>{tableListItem} </React.Fragment>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -99,7 +157,7 @@ StructureSetItem.propTypes = {
|
|||||||
|
|
||||||
StructureSetItem.defaultProps = {
|
StructureSetItem.defaultProps = {
|
||||||
itemClass: '',
|
itemClass: '',
|
||||||
onClick: () => { },
|
onClick: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default StructureSetItem;
|
export default StructureSetItem;
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
export default function getSourceDisplaySet(studies, rtStructDisplaySet) {
|
||||||
|
const referencedDisplaySet = _getReferencedDisplaySet(
|
||||||
|
rtStructDisplaySet,
|
||||||
|
studies
|
||||||
|
);
|
||||||
|
|
||||||
|
rtStructDisplaySet.load(referencedDisplaySet, studies);
|
||||||
|
|
||||||
|
return referencedDisplaySet;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _getReferencedDisplaySet = (rtStructDisplaySet, studies) => {
|
||||||
|
let allDisplaySets = [];
|
||||||
|
|
||||||
|
studies.forEach(study => {
|
||||||
|
allDisplaySets = allDisplaySets.concat(study.displaySets);
|
||||||
|
});
|
||||||
|
|
||||||
|
const otherDisplaySets = allDisplaySets.filter(
|
||||||
|
ds => ds.displaySetInstanceUID !== rtStructDisplaySet.displaySetInstanceUID
|
||||||
|
);
|
||||||
|
|
||||||
|
const ReferencedSeriesSequence = Array.isArray(
|
||||||
|
rtStructDisplaySet.metadata.ReferencedSeriesSequence
|
||||||
|
)
|
||||||
|
? rtStructDisplaySet.metadata.ReferencedSeriesSequence
|
||||||
|
: [rtStructDisplaySet.metadata.ReferencedSeriesSequence];
|
||||||
|
|
||||||
|
const referencedSeriesInstanceUIDs = ReferencedSeriesSequence.map(
|
||||||
|
ReferencedSeries => ReferencedSeries.SeriesInstanceUID
|
||||||
|
);
|
||||||
|
|
||||||
|
const referencedDisplaySet = otherDisplaySets.find(ds =>
|
||||||
|
referencedSeriesInstanceUIDs.includes(ds.SeriesInstanceUID)
|
||||||
|
);
|
||||||
|
|
||||||
|
return referencedDisplaySet;
|
||||||
|
};
|
||||||
@@ -1,15 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import init from './init.js';
|
import init from './init.js';
|
||||||
import sopClassHandlerModule from './OHIFDicomRTStructSopClassHandler';
|
import sopClassHandlerModule from './OHIFDicomRTStructSopClassHandler';
|
||||||
import id from './id.js';
|
import id from './id.js';
|
||||||
import RTPanel from './components/RTPanel/RTPanel';
|
import RTPanel from './components/RTPanel/RTPanel';
|
||||||
|
import { version } from '../package.json';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
/**
|
/**
|
||||||
* Only required property. Should be a unique value across all extensions.
|
* Only required property. Should be a unique value across all extensions.
|
||||||
*/
|
*/
|
||||||
id,
|
id,
|
||||||
|
version,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -21,20 +22,9 @@ export default {
|
|||||||
init({ servicesManager, configuration });
|
init({ servicesManager, configuration });
|
||||||
},
|
},
|
||||||
getPanelModule({ commandsManager, servicesManager, api }) {
|
getPanelModule({ commandsManager, servicesManager, api }) {
|
||||||
const { UINotificationService } = servicesManager.services;
|
|
||||||
|
|
||||||
const ExtendedRTPanel = props => {
|
const ExtendedRTPanel = props => {
|
||||||
const { activeContexts } = api.hooks.useAppContext();
|
const { activeContexts } = api.hooks.useAppContext();
|
||||||
|
|
||||||
const noContoursNotificationHandler = () => {
|
|
||||||
UINotificationService.show({
|
|
||||||
title: 'ROI Contour empty',
|
|
||||||
message: 'The ROI contour has no structure set data.',
|
|
||||||
type: 'error',
|
|
||||||
autoClose: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const contourItemClickHandler = contourData => {
|
const contourItemClickHandler = contourData => {
|
||||||
commandsManager.runCommand('jumpToImage', contourData);
|
commandsManager.runCommand('jumpToImage', contourData);
|
||||||
};
|
};
|
||||||
@@ -45,7 +35,6 @@ export default {
|
|||||||
onContourItemClick={contourItemClickHandler}
|
onContourItemClick={contourItemClickHandler}
|
||||||
activeContexts={activeContexts}
|
activeContexts={activeContexts}
|
||||||
contexts={api.contexts}
|
contexts={api.contexts}
|
||||||
noContoursNotification={noContoursNotificationHandler}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -74,26 +74,17 @@ export default async function loadRTStruct(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
_setROIContourMetadata(
|
const isSupported = false;
|
||||||
structureSet,
|
|
||||||
StructureSetROISequence,
|
|
||||||
RTROIObservationsSequence,
|
|
||||||
ROIContour
|
|
||||||
);
|
|
||||||
|
|
||||||
for (let c = 0; c < ContourSequence.length; c++) {
|
const ContourSequenceArray = _toArray(ContourSequence);
|
||||||
|
|
||||||
|
for (let c = 0; c < ContourSequenceArray.length; c++) {
|
||||||
const {
|
const {
|
||||||
ContourImageSequence,
|
ContourImageSequence,
|
||||||
ContourData,
|
ContourData,
|
||||||
NumberOfContourPoints,
|
NumberOfContourPoints,
|
||||||
ContourGeometricType,
|
ContourGeometricType,
|
||||||
} = ContourSequence[c];
|
} = ContourSequenceArray[c];
|
||||||
|
|
||||||
if (ContourGeometricType !== 'CLOSED_PLANAR') {
|
|
||||||
// TODO: Do we want to visualise types other than closed planar?
|
|
||||||
// We could easily do open planar.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sopInstanceUID = ContourImageSequence.ReferencedSOPInstanceUID;
|
const sopInstanceUID = ContourImageSequence.ReferencedSOPInstanceUID;
|
||||||
const imageId = _getImageId(imageIdSopInstanceUidPairs, sopInstanceUID);
|
const imageId = _getImageId(imageIdSopInstanceUidPairs, sopInstanceUID);
|
||||||
@@ -105,27 +96,47 @@ export default async function loadRTStruct(
|
|||||||
|
|
||||||
const imagePlane = cornerstone.metaData.get('imagePlaneModule', imageId);
|
const imagePlane = cornerstone.metaData.get('imagePlaneModule', imageId);
|
||||||
const points = [];
|
const points = [];
|
||||||
|
let measurementData;
|
||||||
|
|
||||||
for (let p = 0; p < NumberOfContourPoints * 3; p += 3) {
|
switch (ContourGeometricType) {
|
||||||
points.push({
|
case 'CLOSED_PLANAR':
|
||||||
x: ContourData[p],
|
case 'OPEN_PLANAR':
|
||||||
y: ContourData[p + 1],
|
case 'POINT':
|
||||||
z: ContourData[p + 2],
|
isSupported = true;
|
||||||
});
|
|
||||||
|
for (let p = 0; p < NumberOfContourPoints * 3; p += 3) {
|
||||||
|
points.push({
|
||||||
|
x: ContourData[p],
|
||||||
|
y: ContourData[p + 1],
|
||||||
|
z: ContourData[p + 2],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
transformPointsToImagePlane(points, imagePlane);
|
||||||
|
|
||||||
|
measurementData = {
|
||||||
|
handles: {
|
||||||
|
points,
|
||||||
|
},
|
||||||
|
type: ContourGeometricType,
|
||||||
|
structureSetSeriesInstanceUid: rtStructDataset.SeriesInstanceUID,
|
||||||
|
ROINumber: ReferencedROINumber,
|
||||||
|
};
|
||||||
|
|
||||||
|
imageIdSpecificToolData.push(measurementData);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
transformPointsToImagePlane(points, imagePlane);
|
|
||||||
|
|
||||||
const measurementData = {
|
|
||||||
handles: {
|
|
||||||
points,
|
|
||||||
},
|
|
||||||
structureSetSeriesInstanceUid: rtStructDataset.SeriesInstanceUID,
|
|
||||||
ROINumber: ReferencedROINumber,
|
|
||||||
};
|
|
||||||
|
|
||||||
imageIdSpecificToolData.push(measurementData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setROIContourMetadata(
|
||||||
|
structureSet,
|
||||||
|
StructureSetROISequence,
|
||||||
|
RTROIObservationsSequence,
|
||||||
|
ROIContour,
|
||||||
|
isSupported
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setToolEnabledIfNotEnabled(rtStructDisplayToolName);
|
_setToolEnabledIfNotEnabled(rtStructDisplayToolName);
|
||||||
@@ -155,7 +166,8 @@ function _setROIContourMetadata(
|
|||||||
structureSet,
|
structureSet,
|
||||||
StructureSetROISequence,
|
StructureSetROISequence,
|
||||||
RTROIObservationsSequence,
|
RTROIObservationsSequence,
|
||||||
ROIContour
|
ROIContour,
|
||||||
|
isSupported
|
||||||
) {
|
) {
|
||||||
const StructureSetROI = StructureSetROISequence.find(
|
const StructureSetROI = StructureSetROISequence.find(
|
||||||
structureSetROI =>
|
structureSetROI =>
|
||||||
@@ -167,6 +179,7 @@ function _setROIContourMetadata(
|
|||||||
ROIName: StructureSetROI.ROIName,
|
ROIName: StructureSetROI.ROIName,
|
||||||
ROIGenerationAlgorithm: StructureSetROI.ROIGenerationAlgorithm,
|
ROIGenerationAlgorithm: StructureSetROI.ROIGenerationAlgorithm,
|
||||||
ROIDescription: StructureSetROI.ROIDescription,
|
ROIDescription: StructureSetROI.ROIDescription,
|
||||||
|
isSupported,
|
||||||
visible: true,
|
visible: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -307,3 +320,7 @@ function _getImageIdSopInstanceUidPairsForDisplaySet(
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _toArray(objOrArray) {
|
||||||
|
return Array.isArray(objOrArray) ? objOrArray : [objOrArray];
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import { importInternal, getToolState, toolColors } from 'cornerstone-tools';
|
import { importInternal, getToolState, toolColors } from 'cornerstone-tools';
|
||||||
|
|
||||||
import TOOL_NAMES from '../utils/toolNames';
|
import TOOL_NAMES from '../utils/toolNames';
|
||||||
|
import drawCanvasCrosshairs from '../utils/drawCanvasCrosshairs';
|
||||||
|
|
||||||
// Cornerstone 3rd party dev kit imports
|
// Cornerstone 3rd party dev kit imports
|
||||||
const draw = importInternal('drawing/draw');
|
const draw = importInternal('drawing/draw');
|
||||||
|
const drawCircle = importInternal('drawing/drawCircle');
|
||||||
const drawJoinedLines = importInternal('drawing/drawJoinedLines');
|
const drawJoinedLines = importInternal('drawing/drawJoinedLines');
|
||||||
const getNewContext = importInternal('drawing/getNewContext');
|
const getNewContext = importInternal('drawing/getNewContext');
|
||||||
const BaseTool = importInternal('base/BaseTool');
|
const BaseTool = importInternal('base/BaseTool');
|
||||||
@@ -36,11 +37,17 @@ export default class RTStructDisplayTool extends BaseTool {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { lineWidth, opacity } = rtstructModule.configuration;
|
const {
|
||||||
|
lineWidth,
|
||||||
|
opacity,
|
||||||
|
highlightOpacity,
|
||||||
|
} = rtstructModule.configuration;
|
||||||
|
|
||||||
// We have tool data for this element - iterate over each one and draw it
|
// We have tool data for this element - iterate over each one and draw it
|
||||||
const context = getNewContext(eventData.canvasContext.canvas);
|
const context = getNewContext(eventData.canvasContext.canvas);
|
||||||
|
|
||||||
|
let crossHairCenter;
|
||||||
|
|
||||||
for (let i = 0; i < toolState.data.length; i++) {
|
for (let i = 0; i < toolState.data.length; i++) {
|
||||||
const data = toolState.data[i];
|
const data = toolState.data[i];
|
||||||
|
|
||||||
@@ -72,22 +79,76 @@ export default class RTStructDisplayTool extends BaseTool {
|
|||||||
const colorArray = ROIContourData.colorArray;
|
const colorArray = ROIContourData.colorArray;
|
||||||
const color = `rgba(${colorArray[0]},${colorArray[1]},${
|
const color = `rgba(${colorArray[0]},${colorArray[1]},${
|
||||||
colorArray[2]
|
colorArray[2]
|
||||||
},${opacity})`;
|
},${opacity})`;
|
||||||
|
|
||||||
lineWidth;
|
let highlight = data.highlight;
|
||||||
|
const options = { color, lineWidth };
|
||||||
|
|
||||||
draw(context, context => {
|
if (highlight) {
|
||||||
drawJoinedLines(
|
crossHairCenter = { x: 0, y: 0 };
|
||||||
context,
|
|
||||||
eventData.element,
|
points.forEach(point => {
|
||||||
points[points.length - 1],
|
crossHairCenter.x += point.x;
|
||||||
points,
|
crossHairCenter.y += point.y;
|
||||||
{
|
});
|
||||||
color,
|
|
||||||
lineWidth,
|
crossHairCenter.x /= points.length;
|
||||||
}
|
crossHairCenter.y /= points.length;
|
||||||
);
|
|
||||||
|
// TODO: Disabling hightlight for now, it'd be good to bring it back
|
||||||
|
// when we have a good way of doing this for SEG.
|
||||||
|
|
||||||
|
// options.fillStyle = color = `rgba(${colorArray[0]},${colorArray[1]},${
|
||||||
|
// colorArray[2]
|
||||||
|
// },${highlightOpacity})`;
|
||||||
|
|
||||||
|
// Draw highlight lines.
|
||||||
|
|
||||||
|
delete data.highlight; // Don't highlight on next render.
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (data.type) {
|
||||||
|
case 'CLOSED_PLANAR':
|
||||||
|
this._renderClosedPlanar(context, eventData.element, points, options);
|
||||||
|
break;
|
||||||
|
case 'POINT':
|
||||||
|
this._renderPoint(context, eventData.element, points, options);
|
||||||
|
break;
|
||||||
|
case 'OPEN_PLANAR':
|
||||||
|
this._renderOpenPlanar(context, eventData.element, points, options);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crossHairCenter) {
|
||||||
|
drawCanvasCrosshairs(eventData, crossHairCenter, {
|
||||||
|
color: toolColors.getActiveColor(),
|
||||||
|
lineWidth: 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_renderClosedPlanar(context, element, points, options) {
|
||||||
|
draw(context, context => {
|
||||||
|
drawJoinedLines(
|
||||||
|
context,
|
||||||
|
element,
|
||||||
|
points[points.length - 1],
|
||||||
|
points,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderPoint(context, element, points, options) {
|
||||||
|
draw(context, context => {
|
||||||
|
drawCircle(context, element, points[0], 3, options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderOpenPlanar(context, element, points, options) {
|
||||||
|
draw(context, context => {
|
||||||
|
drawJoinedLines(context, element, points[0], points, options);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,8 @@ function refreshViewport() {
|
|||||||
|
|
||||||
const configuration = {
|
const configuration = {
|
||||||
lineWidth: 3,
|
lineWidth: 3,
|
||||||
opacity: 1.0,
|
opacity: 0.75,
|
||||||
|
highlightOpacity: 0.5,
|
||||||
};
|
};
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import cornerstone from 'cornerstone-core';
|
||||||
|
import cornerstoneTools from 'cornerstone-tools';
|
||||||
|
|
||||||
|
const { importInternal } = cornerstoneTools;
|
||||||
|
const draw = importInternal('drawing/draw');
|
||||||
|
const drawLine = importInternal('drawing/drawLine');
|
||||||
|
const getNewContext = importInternal('drawing/getNewContext');
|
||||||
|
|
||||||
|
export default function _drawCanvasCrosshairs(eventData, center, options) {
|
||||||
|
const context = getNewContext(eventData.canvasContext.canvas);
|
||||||
|
const { element } = eventData;
|
||||||
|
|
||||||
|
const centerCanvas = cornerstone.pixelToCanvas(element, center);
|
||||||
|
|
||||||
|
const { clientWidth: width, clientHeight: height } = element;
|
||||||
|
|
||||||
|
const offset = 10;
|
||||||
|
|
||||||
|
draw(context, context => {
|
||||||
|
drawLine(
|
||||||
|
context,
|
||||||
|
element,
|
||||||
|
{ x: centerCanvas.x + offset, y: centerCanvas.y },
|
||||||
|
{ x: width, y: centerCanvas.y },
|
||||||
|
options,
|
||||||
|
'canvas'
|
||||||
|
);
|
||||||
|
|
||||||
|
drawLine(
|
||||||
|
context,
|
||||||
|
element,
|
||||||
|
{ x: centerCanvas.x - offset, y: centerCanvas.y },
|
||||||
|
{ x: 0, y: centerCanvas.y },
|
||||||
|
options,
|
||||||
|
'canvas'
|
||||||
|
);
|
||||||
|
|
||||||
|
drawLine(
|
||||||
|
context,
|
||||||
|
element,
|
||||||
|
{ x: centerCanvas.x, y: centerCanvas.y + offset },
|
||||||
|
{ x: centerCanvas.x, y: height },
|
||||||
|
options,
|
||||||
|
'canvas'
|
||||||
|
);
|
||||||
|
|
||||||
|
drawLine(
|
||||||
|
context,
|
||||||
|
element,
|
||||||
|
{ x: centerCanvas.x, y: centerCanvas.y - offset },
|
||||||
|
{ x: centerCanvas.x, y: 0 },
|
||||||
|
options,
|
||||||
|
'canvas'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -3,6 +3,57 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [0.4.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.4.3...@ohif/extension-dicom-segmentation@0.4.4) (2020-09-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.4.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.4.2...@ohif/extension-dicom-segmentation@0.4.3) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.4.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.4.1...@ohif/extension-dicom-segmentation@0.4.2) (2020-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.4.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.4.0...@ohif/extension-dicom-segmentation@0.4.1) (2020-08-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [0.4.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.3.4...@ohif/extension-dicom-segmentation@0.4.0) (2020-08-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Update react-vtkjs-viewport usage to use requestPool ([#1984](https://github.com/OHIF/Viewers/issues/1984)) ([bb5f30c](https://github.com/OHIF/Viewers/commit/bb5f30ce2a0192d2e021beaaadfff22fd38e17b9))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.3.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.3.3...@ohif/extension-dicom-segmentation@0.3.4) (2020-08-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.3.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.3.2...@ohif/extension-dicom-segmentation@0.3.3) (2020-07-13)
|
## [0.3.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.3.2...@ohif/extension-dicom-segmentation@0.3.3) (2020-07-13)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-dicom-segmentation",
|
"name": "@ohif/extension-dicom-segmentation",
|
||||||
"version": "0.3.3",
|
"version": "0.4.4",
|
||||||
"description": "OHIF extension for viewing segmentations in the 2D MPR view",
|
"description": "OHIF extension for viewing segmentations in the 2D MPR view",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -30,8 +30,8 @@
|
|||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"cornerstone-core": "^2.2.8",
|
"cornerstone-core": "^2.2.8",
|
||||||
"cornerstone-tools": "4.15.1",
|
"cornerstone-tools": "^4.20.1",
|
||||||
"dcmjs": "0.16.0",
|
"dcmjs": "0.16.3",
|
||||||
"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"
|
||||||
|
|||||||
+55
-85
@@ -5,6 +5,10 @@ import cornerstone from 'cornerstone-core';
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { utils, log } from '@ohif/core';
|
import { utils, log } from '@ohif/core';
|
||||||
import { ScrollableArea, TableList, Icon } from '@ohif/ui';
|
import { ScrollableArea, TableList, Icon } from '@ohif/ui';
|
||||||
|
import DICOMSegTempCrosshairsTool from '../../tools/DICOMSegTempCrosshairsTool';
|
||||||
|
|
||||||
|
import setActiveLabelmap from '../../utils/setActiveLabelMap';
|
||||||
|
import refreshViewports from '../../utils/refreshViewports';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BrushColorSelector,
|
BrushColorSelector,
|
||||||
@@ -19,12 +23,6 @@ import SegmentationSettings from '../SegmentationSettings/SegmentationSettings';
|
|||||||
|
|
||||||
const { studyMetadataManager } = utils;
|
const { studyMetadataManager } = utils;
|
||||||
|
|
||||||
const refreshViewport = () => {
|
|
||||||
cornerstone.getEnabledElements().forEach(enabledElement => {
|
|
||||||
cornerstone.updateImage(enabledElement.element);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SegmentationPanel component
|
* SegmentationPanel component
|
||||||
*
|
*
|
||||||
@@ -68,8 +66,7 @@ const SegmentationPanel = ({
|
|||||||
*/
|
*/
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
brushRadius: DEFAULT_BRUSH_RADIUS,
|
brushRadius: DEFAULT_BRUSH_RADIUS,
|
||||||
brushColor:
|
brushColor: 'rgba(221, 85, 85, 1)',
|
||||||
'rgba(221, 85, 85, 1)',
|
|
||||||
selectedSegment: null,
|
selectedSegment: null,
|
||||||
selectedSegmentation: null,
|
selectedSegmentation: null,
|
||||||
showSegmentationSettings: false,
|
showSegmentationSettings: false,
|
||||||
@@ -78,7 +75,7 @@ const SegmentationPanel = ({
|
|||||||
segmentList: [],
|
segmentList: [],
|
||||||
cachedSegmentsProperties: [],
|
cachedSegmentsProperties: [],
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
isDisabled: true
|
isDisabled: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -112,7 +109,10 @@ const SegmentationPanel = ({
|
|||||||
* allows us to easily watch the module or the segmentations loading process in any other component
|
* allows us to easily watch the module or the segmentations loading process in any other component
|
||||||
* without subscribing to external events.
|
* without subscribing to external events.
|
||||||
*/
|
*/
|
||||||
document.addEventListener('extensiondicomsegmentationsegloaded', refreshSegmentations);
|
document.addEventListener(
|
||||||
|
'extensiondicomsegmentationsegloaded',
|
||||||
|
refreshSegmentations
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These are specific to each element;
|
* These are specific to each element;
|
||||||
@@ -127,7 +127,10 @@ const SegmentationPanel = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('extensiondicomsegmentationsegloaded', refreshSegmentations);
|
document.removeEventListener(
|
||||||
|
'extensiondicomsegmentationsegloaded',
|
||||||
|
refreshSegmentations
|
||||||
|
);
|
||||||
cornerstoneTools.store.state.enabledElements.forEach(enabledElement =>
|
cornerstoneTools.store.state.enabledElements.forEach(enabledElement =>
|
||||||
enabledElement.removeEventListener(
|
enabledElement.removeEventListener(
|
||||||
'cornerstonetoolslabelmapmodified',
|
'cornerstonetoolslabelmapmodified',
|
||||||
@@ -169,26 +172,29 @@ const SegmentationPanel = ({
|
|||||||
selectedSegmentation: brushStackState.activeLabelmapIndex,
|
selectedSegmentation: brushStackState.activeLabelmapIndex,
|
||||||
labelmapList,
|
labelmapList,
|
||||||
segmentList,
|
segmentList,
|
||||||
isDisabled
|
isDisabled,
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
setState(state => ({
|
setState(state => ({
|
||||||
...state,
|
...state,
|
||||||
labelmapList: [],
|
labelmapList: [],
|
||||||
segmentList: [],
|
segmentList: [],
|
||||||
isDisabled
|
isDisabled,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [viewports, activeIndex, state.isLoading]);
|
||||||
viewports,
|
|
||||||
activeIndex,
|
|
||||||
state.isLoading
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refreshSegmentations();
|
refreshSegmentations();
|
||||||
}, [viewports, activeIndex, isOpen, state.selectedSegmentation, activeContexts, state.isLoading]);
|
}, [
|
||||||
|
viewports,
|
||||||
|
activeIndex,
|
||||||
|
isOpen,
|
||||||
|
state.selectedSegmentation,
|
||||||
|
activeContexts,
|
||||||
|
state.isLoading,
|
||||||
|
]);
|
||||||
|
|
||||||
/* Handle open/closed panel behaviour */
|
/* Handle open/closed panel behaviour */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -223,12 +229,10 @@ const SegmentationPanel = ({
|
|||||||
title: displayDescription,
|
title: displayDescription,
|
||||||
description: displayDate,
|
description: displayDate,
|
||||||
onClick: async () => {
|
onClick: async () => {
|
||||||
const activatedLabelmapIndex = await _setActiveLabelmap(
|
const activatedLabelmapIndex = await setActiveLabelmap(
|
||||||
activeViewport,
|
activeViewport,
|
||||||
studies,
|
studies,
|
||||||
displaySet,
|
displaySet,
|
||||||
firstImageId,
|
|
||||||
brushStackState.activeLabelmapIndex,
|
|
||||||
() => onSelectedSegmentationChange(),
|
() => onSelectedSegmentationChange(),
|
||||||
onDisplaySetLoadFailure
|
onDisplaySetLoadFailure
|
||||||
);
|
);
|
||||||
@@ -331,6 +335,12 @@ const SegmentationPanel = ({
|
|||||||
imageId
|
imageId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
DICOMSegTempCrosshairsTool.addCrosshair(
|
||||||
|
element,
|
||||||
|
imageId,
|
||||||
|
segmentNumber
|
||||||
|
);
|
||||||
|
|
||||||
onSegmentItemClick({
|
onSegmentItemClick({
|
||||||
StudyInstanceUID,
|
StudyInstanceUID,
|
||||||
SOPInstanceUID,
|
SOPInstanceUID,
|
||||||
@@ -376,9 +386,13 @@ const SegmentationPanel = ({
|
|||||||
return !segmentsHidden[segmentIndex];
|
return !segmentsHidden[segmentIndex];
|
||||||
};
|
};
|
||||||
|
|
||||||
const cachedSegmentProperties = state.cachedSegmentsProperties[segmentNumber];
|
const cachedSegmentProperties =
|
||||||
|
state.cachedSegmentsProperties[segmentNumber];
|
||||||
let visible = isSegmentVisible();
|
let visible = isSegmentVisible();
|
||||||
if (cachedSegmentProperties && cachedSegmentProperties.visible !== visible) {
|
if (
|
||||||
|
cachedSegmentProperties &&
|
||||||
|
cachedSegmentProperties.visible !== visible
|
||||||
|
) {
|
||||||
toggleSegmentVisibility();
|
toggleSegmentVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,8 +420,10 @@ const SegmentationPanel = ({
|
|||||||
onSegmentVisibilityChange(segmentNumber, newVisibility);
|
onSegmentVisibilityChange(segmentNumber, newVisibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCachedSegmentsProperties(segmentNumber, { visible: newVisibility });
|
updateCachedSegmentsProperties(segmentNumber, {
|
||||||
refreshViewport();
|
visible: newVisibility,
|
||||||
|
});
|
||||||
|
refreshViewports();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -429,10 +445,9 @@ const SegmentationPanel = ({
|
|||||||
const segmentsProperties = state.cachedSegmentsProperties;
|
const segmentsProperties = state.cachedSegmentsProperties;
|
||||||
const segmentProperties = state.cachedSegmentsProperties[segmentNumber];
|
const segmentProperties = state.cachedSegmentsProperties[segmentNumber];
|
||||||
|
|
||||||
segmentsProperties[segmentNumber] =
|
segmentsProperties[segmentNumber] = segmentProperties
|
||||||
segmentProperties ?
|
? { ...segmentProperties, ...properties }
|
||||||
{ ...segmentProperties, ...properties } :
|
: properties;
|
||||||
properties;
|
|
||||||
|
|
||||||
updateState('cachedSegmentsProperties', segmentsProperties);
|
updateState('cachedSegmentsProperties', segmentsProperties);
|
||||||
};
|
};
|
||||||
@@ -499,10 +514,13 @@ const SegmentationPanel = ({
|
|||||||
configuration.fillAlphaInactive = newConfiguration.fillAlphaInactive;
|
configuration.fillAlphaInactive = newConfiguration.fillAlphaInactive;
|
||||||
configuration.outlineAlphaInactive = newConfiguration.outlineAlphaInactive;
|
configuration.outlineAlphaInactive = newConfiguration.outlineAlphaInactive;
|
||||||
onConfigurationChange(newConfiguration);
|
onConfigurationChange(newConfiguration);
|
||||||
refreshViewport();
|
refreshViewports();
|
||||||
};
|
};
|
||||||
|
|
||||||
const disabledConfigurationFields = ['outlineAlpha', 'shouldRenderInactiveLabelmaps'];
|
const disabledConfigurationFields = [
|
||||||
|
'outlineAlpha',
|
||||||
|
'shouldRenderInactiveLabelmaps',
|
||||||
|
];
|
||||||
if (state.showSegmentationSettings) {
|
if (state.showSegmentationSettings) {
|
||||||
return (
|
return (
|
||||||
<SegmentationSettings
|
<SegmentationSettings
|
||||||
@@ -514,7 +532,10 @@ const SegmentationPanel = ({
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div className={`dcmseg-segmentation-panel ${state.isDisabled && 'disabled'}`}>
|
<div
|
||||||
|
className={`dcmseg-segmentation-panel ${state.isDisabled &&
|
||||||
|
'disabled'}`}
|
||||||
|
>
|
||||||
<Icon
|
<Icon
|
||||||
className="cog-icon"
|
className="cog-icon"
|
||||||
name="cog"
|
name="cog"
|
||||||
@@ -613,57 +634,6 @@ const _getReferencedSegDisplaysets = (StudyInstanceUID, SeriesInstanceUID) => {
|
|||||||
return referencedDisplaysets;
|
return referencedDisplaysets;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param {*} viewportSpecificData
|
|
||||||
* @param {*} studies
|
|
||||||
* @param {*} displaySet
|
|
||||||
* @param {*} firstImageId
|
|
||||||
* @param {*} activeLabelmapIndex
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const _setActiveLabelmap = async (
|
|
||||||
viewportSpecificData,
|
|
||||||
studies,
|
|
||||||
displaySet,
|
|
||||||
firstImageId,
|
|
||||||
activeLabelmapIndex,
|
|
||||||
callback = () => { },
|
|
||||||
onDisplaySetLoadFailure
|
|
||||||
) => {
|
|
||||||
if (displaySet.labelmapIndex === activeLabelmapIndex) {
|
|
||||||
log.warn(`${activeLabelmapIndex} is already the active labelmap`);
|
|
||||||
return displaySet.labelmapIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!displaySet.isLoaded) {
|
|
||||||
// What props does this expect `viewportSpecificData` to have?
|
|
||||||
// TODO: Should this return the `labelmapIndex`?
|
|
||||||
|
|
||||||
const loadPromise = displaySet.load(viewportSpecificData, studies);
|
|
||||||
|
|
||||||
loadPromise.catch(error => {
|
|
||||||
onDisplaySetLoadFailure(error);
|
|
||||||
|
|
||||||
// Return old index.
|
|
||||||
return activeLabelmapIndex;
|
|
||||||
});
|
|
||||||
|
|
||||||
await loadPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { state } = cornerstoneTools.getModule('segmentation');
|
|
||||||
const brushStackState = state.series[firstImageId];
|
|
||||||
brushStackState.activeLabelmapIndex = displaySet.labelmapIndex;
|
|
||||||
|
|
||||||
refreshViewport();
|
|
||||||
|
|
||||||
callback();
|
|
||||||
|
|
||||||
return displaySet.labelmapIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {*} firstImageId
|
* @param {*} firstImageId
|
||||||
@@ -683,7 +653,7 @@ const _setActiveSegment = (firstImageId, segmentIndex, activeSegmentIndex) => {
|
|||||||
brushStackState.labelmaps3D[brushStackState.activeLabelmapIndex];
|
brushStackState.labelmaps3D[brushStackState.activeLabelmapIndex];
|
||||||
labelmap3D.activeSegmentIndex = segmentIndex;
|
labelmap3D.activeSegmentIndex = segmentIndex;
|
||||||
|
|
||||||
refreshViewport();
|
refreshViewports();
|
||||||
|
|
||||||
return segmentIndex;
|
return segmentIndex;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
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';
|
||||||
|
|
||||||
// TODO: Should probably use dcmjs for this
|
// TODO: Should probably use dcmjs for this
|
||||||
const SOP_CLASS_UIDS = {
|
const SOP_CLASS_UIDS = {
|
||||||
@@ -27,6 +28,7 @@ export default function getSopClassHandlerModule({ servicesManager }) {
|
|||||||
const {
|
const {
|
||||||
SeriesDate,
|
SeriesDate,
|
||||||
SeriesTime,
|
SeriesTime,
|
||||||
|
SeriesNumber,
|
||||||
SeriesDescription,
|
SeriesDescription,
|
||||||
FrameOfReferenceUID,
|
FrameOfReferenceUID,
|
||||||
SOPInstanceUID,
|
SOPInstanceUID,
|
||||||
@@ -51,9 +53,14 @@ export default function getSopClassHandlerModule({ servicesManager }) {
|
|||||||
isLoaded: false,
|
isLoaded: false,
|
||||||
SeriesDate,
|
SeriesDate,
|
||||||
SeriesTime,
|
SeriesTime,
|
||||||
|
SeriesNumber,
|
||||||
SeriesDescription,
|
SeriesDescription,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
segDisplaySet.getSourceDisplaySet = function(studies) {
|
||||||
|
return getSourceDisplaySet(studies, segDisplaySet);
|
||||||
|
};
|
||||||
|
|
||||||
segDisplaySet.load = function(referencedDisplaySet, studies) {
|
segDisplaySet.load = function(referencedDisplaySet, studies) {
|
||||||
return loadSegmentation(segDisplaySet, referencedDisplaySet, studies);
|
return loadSegmentation(segDisplaySet, referencedDisplaySet, studies);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import setActiveLabelmap from './utils/setActiveLabelMap';
|
||||||
|
import { classes } from '@ohif/core';
|
||||||
|
|
||||||
|
const { ImageSet } = classes;
|
||||||
|
|
||||||
|
export default function getSourceDisplaySet(studies, segDisplaySet) {
|
||||||
|
const referencedDisplaySet = _getReferencedDisplaySet(segDisplaySet, studies);
|
||||||
|
|
||||||
|
setActiveLabelmap(referencedDisplaySet, studies, segDisplaySet);
|
||||||
|
|
||||||
|
return referencedDisplaySet;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _getReferencedDisplaySet = (segDisplaySet, studies) => {
|
||||||
|
let allDisplaySets = [];
|
||||||
|
|
||||||
|
studies.forEach(study => {
|
||||||
|
allDisplaySets = allDisplaySets.concat(study.displaySets);
|
||||||
|
});
|
||||||
|
|
||||||
|
const otherDisplaySets = allDisplaySets.filter(
|
||||||
|
ds => ds.displaySetInstanceUID !== segDisplaySet.displaySetInstanceUID
|
||||||
|
);
|
||||||
|
|
||||||
|
const { metadata } = segDisplaySet;
|
||||||
|
|
||||||
|
let referencedSeriesInstanceUIDs;
|
||||||
|
|
||||||
|
if (metadata.ReferencedSeriesSequence) {
|
||||||
|
const ReferencedSeriesSequence = _toArray(
|
||||||
|
metadata.ReferencedSeriesSequence
|
||||||
|
);
|
||||||
|
|
||||||
|
referencedSeriesInstanceUIDs = ReferencedSeriesSequence.map(
|
||||||
|
ReferencedSeries => ReferencedSeries.SeriesInstanceUID
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const { PerFrameFunctionalGroupsSequence } = metadata;
|
||||||
|
|
||||||
|
let SourceImageSequence;
|
||||||
|
|
||||||
|
if (metadata.SourceImageSequence) {
|
||||||
|
SourceImageSequence = metadata.SourceImageSequence;
|
||||||
|
} else {
|
||||||
|
const firstFunctionalGroups = _toArray(
|
||||||
|
PerFrameFunctionalGroupsSequence
|
||||||
|
)[0];
|
||||||
|
const { DerivationImageSequence } = firstFunctionalGroups;
|
||||||
|
|
||||||
|
SourceImageSequence = DerivationImageSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstSourceImage = _toArray(SourceImageSequence)[0];
|
||||||
|
|
||||||
|
const { ReferencedSOPInstanceUID } = firstSourceImage;
|
||||||
|
|
||||||
|
referencedSeriesInstanceUIDs = _findReferencedSeriesInstanceUIDsFromSOPInstanceUID(
|
||||||
|
otherDisplaySets,
|
||||||
|
ReferencedSOPInstanceUID
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const referencedDisplaySet = otherDisplaySets.find(ds =>
|
||||||
|
referencedSeriesInstanceUIDs.includes(ds.SeriesInstanceUID)
|
||||||
|
);
|
||||||
|
|
||||||
|
return referencedDisplaySet;
|
||||||
|
};
|
||||||
|
|
||||||
|
const _findReferencedSeriesInstanceUIDsFromSOPInstanceUID = (
|
||||||
|
displaySets,
|
||||||
|
SOPInstanceUID
|
||||||
|
) => {
|
||||||
|
const imageSets = displaySets.filter(ds => ds instanceof ImageSet);
|
||||||
|
|
||||||
|
for (let i = 0; i < imageSets.length; i++) {
|
||||||
|
const { images } = imageSets[i];
|
||||||
|
for (let j = 0; j < images.length; j++) {
|
||||||
|
if (images[j].SOPInstanceUID === SOPInstanceUID) {
|
||||||
|
return [images[j].getData().metadata.SeriesInstanceUID];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function _toArray(arrayOrObject) {
|
||||||
|
return Array.isArray(arrayOrObject) ? arrayOrObject : [arrayOrObject];
|
||||||
|
}
|
||||||
@@ -1,15 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import init from './init.js';
|
import init from './init.js';
|
||||||
import toolbarModule from './toolbarModule.js';
|
import toolbarModule from './toolbarModule.js';
|
||||||
import getSopClassHandlerModule from './getOHIFDicomSegSopClassHandler.js';
|
import getSopClassHandlerModule from './getOHIFDicomSegSopClassHandler.js';
|
||||||
import SegmentationPanel from './components/SegmentationPanel/SegmentationPanel.js';
|
import SegmentationPanel from './components/SegmentationPanel/SegmentationPanel.js';
|
||||||
|
import { version } from '../package.json';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
/**
|
/**
|
||||||
* Only required property. Should be a unique value across all extensions.
|
* Only required property. Should be a unique value across all extensions.
|
||||||
*/
|
*/
|
||||||
id: 'com.ohif.dicom-segmentation',
|
id: 'com.ohif.dicom-segmentation',
|
||||||
|
version,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import csTools from 'cornerstone-tools';
|
import csTools from 'cornerstone-tools';
|
||||||
|
import DICOMSegTempCrosshairsTool from './tools/DICOMSegTempCrosshairsTool';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -17,4 +18,6 @@ export default function init({ servicesManager, configuration = {} }) {
|
|||||||
alwaysEraseOnClick: true,
|
alwaysEraseOnClick: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
csTools.addTool(DICOMSegTempCrosshairsTool);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
import cornerstoneTools, {
|
||||||
|
importInternal,
|
||||||
|
getToolState,
|
||||||
|
toolColors,
|
||||||
|
getModule,
|
||||||
|
globalImageIdSpecificToolStateManager,
|
||||||
|
} from 'cornerstone-tools';
|
||||||
|
import cornerstone from 'cornerstone-core';
|
||||||
|
import drawCanvasCrosshairs from '../utils/drawCanvasCrosshairs';
|
||||||
|
import TOOL_NAMES from './TOOL_NAMES';
|
||||||
|
|
||||||
|
const { DICOM_SEG_TEMP_CROSSHAIRS_TOOL } = TOOL_NAMES;
|
||||||
|
const { getters } = getModule('segmentation');
|
||||||
|
|
||||||
|
// Cornerstone 3rd party dev kit imports
|
||||||
|
const BaseTool = importInternal('base/BaseTool');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class RTStructDisplayTool - Renders RTSTRUCT data in a read only manner (i.e. as an overlay).
|
||||||
|
* @extends cornerstoneTools.BaseTool
|
||||||
|
*/
|
||||||
|
export default class DICOMSegTempCrosshairsTool extends BaseTool {
|
||||||
|
constructor(props = {}) {
|
||||||
|
const defaultProps = {
|
||||||
|
mixins: ['enabledOrDisabledBinaryTool'],
|
||||||
|
name: DICOM_SEG_TEMP_CROSSHAIRS_TOOL,
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialProps = Object.assign(defaultProps, props);
|
||||||
|
|
||||||
|
super(initialProps);
|
||||||
|
|
||||||
|
this._rtStructModule = cornerstoneTools.getModule('rtstruct');
|
||||||
|
}
|
||||||
|
|
||||||
|
renderToolData(evt) {
|
||||||
|
const eventData = evt.detail;
|
||||||
|
const { element } = eventData;
|
||||||
|
const toolState = getToolState(evt.currentTarget, this.name);
|
||||||
|
|
||||||
|
if (!toolState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have tool data for this element - iterate over each one and draw it
|
||||||
|
|
||||||
|
for (let i = 0; i < toolState.data.length; i++) {
|
||||||
|
const data = toolState.data[i];
|
||||||
|
const crossHairCenter = data.center;
|
||||||
|
|
||||||
|
drawCanvasCrosshairs(eventData, crossHairCenter, {
|
||||||
|
color: toolColors.getActiveColor(),
|
||||||
|
lineWidth: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove the crosshairs, we only render them for one redraw.
|
||||||
|
toolState.data.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DICOMSegTempCrosshairsTool.addCrosshair = (element, imageId, segmentNumber) => {
|
||||||
|
const labelmap3D = getters.labelmap3D(element);
|
||||||
|
const stackToolState = cornerstoneTools.getToolState(element, 'stack');
|
||||||
|
const enabledElement = cornerstone.getEnabledElement(element);
|
||||||
|
|
||||||
|
const { rows, columns } = enabledElement.image;
|
||||||
|
|
||||||
|
if (!stackToolState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageIds = stackToolState.data[0].imageIds;
|
||||||
|
const imageIdIndex = imageIds.findIndex(imgId => imgId === imageId);
|
||||||
|
|
||||||
|
const labelmap2D = labelmap3D.labelmaps2D[imageIdIndex];
|
||||||
|
const { pixelData } = labelmap2D;
|
||||||
|
|
||||||
|
let xCenter = 0;
|
||||||
|
let yCenter = 0;
|
||||||
|
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
for (let y = 0; y < rows; y++) {
|
||||||
|
for (let x = 0; x < columns; x++) {
|
||||||
|
if (pixelData[y * columns + x] === segmentNumber) {
|
||||||
|
count++;
|
||||||
|
xCenter += x + 0.5;
|
||||||
|
yCenter += y + 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xCenter /= count;
|
||||||
|
yCenter /= count;
|
||||||
|
|
||||||
|
const globalToolState = globalImageIdSpecificToolStateManager.saveToolState();
|
||||||
|
|
||||||
|
if (!globalToolState[imageId]) {
|
||||||
|
globalToolState[imageId] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageIdSpecificToolState = globalToolState[imageId];
|
||||||
|
|
||||||
|
if (!imageIdSpecificToolState[DICOM_SEG_TEMP_CROSSHAIRS_TOOL]) {
|
||||||
|
imageIdSpecificToolState[DICOM_SEG_TEMP_CROSSHAIRS_TOOL] = { data: [] };
|
||||||
|
} else if (!imageIdSpecificToolState[DICOM_SEG_TEMP_CROSSHAIRS_TOOL].data) {
|
||||||
|
imageIdSpecificToolState[DICOM_SEG_TEMP_CROSSHAIRS_TOOL].data = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const toolSpecificData =
|
||||||
|
imageIdSpecificToolState[DICOM_SEG_TEMP_CROSSHAIRS_TOOL].data;
|
||||||
|
|
||||||
|
toolSpecificData.push({ center: { x: xCenter, y: yCenter }, segmentNumber });
|
||||||
|
|
||||||
|
// Enable the tool if not enabled for the element.
|
||||||
|
|
||||||
|
const tool = cornerstoneTools.getToolForElement(
|
||||||
|
element,
|
||||||
|
DICOM_SEG_TEMP_CROSSHAIRS_TOOL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (tool.mode !== 'enabled') {
|
||||||
|
// If not already active or passive, set passive so contours render.
|
||||||
|
cornerstoneTools.setToolEnabled(DICOM_SEG_TEMP_CROSSHAIRS_TOOL);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const TOOL_NAMES = {
|
||||||
|
DICOM_SEG_TEMP_CROSSHAIRS_TOOL: 'DICOMSegTempCrosshairsTool',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TOOL_NAMES;
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import cornerstone from 'cornerstone-core';
|
||||||
|
import cornerstoneTools from 'cornerstone-tools';
|
||||||
|
|
||||||
|
const { importInternal } = cornerstoneTools;
|
||||||
|
const draw = importInternal('drawing/draw');
|
||||||
|
const drawLine = importInternal('drawing/drawLine');
|
||||||
|
const getNewContext = importInternal('drawing/getNewContext');
|
||||||
|
|
||||||
|
export default function _drawCanvasCrosshairs(eventData, center, options) {
|
||||||
|
const context = getNewContext(eventData.canvasContext.canvas);
|
||||||
|
const { element } = eventData;
|
||||||
|
|
||||||
|
const centerCanvas = cornerstone.pixelToCanvas(element, center);
|
||||||
|
|
||||||
|
const { clientWidth: width, clientHeight: height } = element;
|
||||||
|
|
||||||
|
const offset = 10;
|
||||||
|
|
||||||
|
draw(context, context => {
|
||||||
|
drawLine(
|
||||||
|
context,
|
||||||
|
element,
|
||||||
|
{ x: centerCanvas.x + offset, y: centerCanvas.y },
|
||||||
|
{ x: width, y: centerCanvas.y },
|
||||||
|
options,
|
||||||
|
'canvas'
|
||||||
|
);
|
||||||
|
|
||||||
|
drawLine(
|
||||||
|
context,
|
||||||
|
element,
|
||||||
|
{ x: centerCanvas.x - offset, y: centerCanvas.y },
|
||||||
|
{ x: 0, y: centerCanvas.y },
|
||||||
|
options,
|
||||||
|
'canvas'
|
||||||
|
);
|
||||||
|
|
||||||
|
drawLine(
|
||||||
|
context,
|
||||||
|
element,
|
||||||
|
{ x: centerCanvas.x, y: centerCanvas.y + offset },
|
||||||
|
{ x: centerCanvas.x, y: height },
|
||||||
|
options,
|
||||||
|
'canvas'
|
||||||
|
);
|
||||||
|
|
||||||
|
drawLine(
|
||||||
|
context,
|
||||||
|
element,
|
||||||
|
{ x: centerCanvas.x, y: centerCanvas.y - offset },
|
||||||
|
{ x: centerCanvas.x, y: 0 },
|
||||||
|
options,
|
||||||
|
'canvas'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export default function refreshViewports() {
|
||||||
|
cornerstone.getEnabledElements().forEach(enabledElement => {
|
||||||
|
cornerstone.updateImage(enabledElement.element);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import { utils, log } from '@ohif/core';
|
||||||
|
import cornerstoneTools from 'cornerstone-tools';
|
||||||
|
import refreshViewports from './refreshViewports';
|
||||||
|
|
||||||
|
const { studyMetadataManager } = utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {*} viewportSpecificData
|
||||||
|
* @param {*} studies
|
||||||
|
* @param {*} displaySet
|
||||||
|
* @param {*} firstImageId
|
||||||
|
* @param {*} activeLabelmapIndex
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default async function setActiveLabelmap(
|
||||||
|
referencedDisplaySet,
|
||||||
|
studies,
|
||||||
|
displaySet,
|
||||||
|
callback = () => {},
|
||||||
|
onDisplaySetLoadFailure = err => {
|
||||||
|
throw new Error(err.message);
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
const studyMetadata = studyMetadataManager.get(
|
||||||
|
referencedDisplaySet.StudyInstanceUID
|
||||||
|
);
|
||||||
|
const firstImageId = studyMetadata.getFirstImageId(
|
||||||
|
referencedDisplaySet.displaySetInstanceUID
|
||||||
|
);
|
||||||
|
|
||||||
|
let { state } = cornerstoneTools.getModule('segmentation');
|
||||||
|
|
||||||
|
let brushStackState = state.series[firstImageId];
|
||||||
|
const activeLabelmapIndex = brushStackState
|
||||||
|
? brushStackState.activeLabelmapIndex
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (displaySet.labelmapIndex === activeLabelmapIndex) {
|
||||||
|
log.warn(`${activeLabelmapIndex} is already the active labelmap`);
|
||||||
|
return displaySet.labelmapIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!displaySet.isLoaded) {
|
||||||
|
const loadPromise = displaySet.load(referencedDisplaySet, studies);
|
||||||
|
|
||||||
|
loadPromise.catch(error => {
|
||||||
|
onDisplaySetLoadFailure(error);
|
||||||
|
|
||||||
|
// Return old index.
|
||||||
|
return activeLabelmapIndex;
|
||||||
|
});
|
||||||
|
|
||||||
|
await loadPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This might have just been created, so need to use the non-cached value.
|
||||||
|
state = cornerstoneTools.getModule('segmentation').state;
|
||||||
|
brushStackState = state.series[firstImageId];
|
||||||
|
brushStackState.activeLabelmapIndex = displaySet.labelmapIndex;
|
||||||
|
|
||||||
|
refreshViewports();
|
||||||
|
callback();
|
||||||
|
|
||||||
|
return displaySet.labelmapIndex;
|
||||||
|
}
|
||||||
@@ -3,6 +3,14 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [0.2.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-lesion-tracker@0.2.0...@ohif/extension-lesion-tracker@0.2.1) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-lesion-tracker
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [0.2.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-lesion-tracker@0.1.0...@ohif/extension-lesion-tracker@0.2.0) (2020-02-10)
|
# [0.2.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-lesion-tracker@0.1.0...@ohif/extension-lesion-tracker@0.2.0) (2020-02-10)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-lesion-tracker",
|
"name": "@ohif/extension-lesion-tracker",
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"description": "OHIF extension for Lesion Tracker",
|
"description": "OHIF extension for Lesion Tracker",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import MeasurementComparisonTable from './components/MeasurementComparisonTable';
|
import MeasurementComparisonTable from './components/MeasurementComparisonTable';
|
||||||
|
import { version } from '../package.json';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
/**
|
/**
|
||||||
* Only required property. Should be a unique value across all extensions.
|
* Only required property. Should be a unique value across all extensions.
|
||||||
*/
|
*/
|
||||||
id: 'lesion-tracker',
|
id: 'lesion-tracker',
|
||||||
|
version,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {object} params
|
* @param {object} params
|
||||||
@@ -26,7 +28,7 @@ export default {
|
|||||||
component: MeasurementComparisonTable,
|
component: MeasurementComparisonTable,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
defaultContext: ['VIEWER']
|
defaultContext: ['VIEWER'],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,68 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.7.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.4...@ohif/extension-vtk@1.7.5) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.7.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.3...@ohif/extension-vtk@1.7.4) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.7.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.2...@ohif/extension-vtk@1.7.3) (2020-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.7.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.1...@ohif/extension-vtk@1.7.2) (2020-08-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.7.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.0...@ohif/extension-vtk@1.7.1) (2020-08-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 🐛 Fail gracefully on an MPR load error ([#1992](https://github.com/OHIF/Viewers/issues/1992)) ([779a7e0](https://github.com/OHIF/Viewers/commit/779a7e0976aa3a2d2bf1dc8f056950f0545c9fff))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [1.7.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.6.10...@ohif/extension-vtk@1.7.0) (2020-08-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Update react-vtkjs-viewport usage to use requestPool ([#1984](https://github.com/OHIF/Viewers/issues/1984)) ([bb5f30c](https://github.com/OHIF/Viewers/commit/bb5f30ce2a0192d2e021beaaadfff22fd38e17b9))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.6.10](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.6.9...@ohif/extension-vtk@1.6.10) (2020-08-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.6.9](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.6.8...@ohif/extension-vtk@1.6.9) (2020-07-23)
|
## [1.6.9](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.6.8...@ohif/extension-vtk@1.6.9) (2020-07-23)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-vtk
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-vtk",
|
"name": "@ohif/extension-vtk",
|
||||||
"version": "1.6.9",
|
"version": "1.7.5",
|
||||||
"description": "OHIF extension for VTK.js",
|
"description": "OHIF extension for VTK.js",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -33,9 +33,9 @@
|
|||||||
"@ohif/i18n": "^0.50.0",
|
"@ohif/i18n": "^0.50.0",
|
||||||
"@ohif/ui": "^0.50.0",
|
"@ohif/ui": "^0.50.0",
|
||||||
"cornerstone-core": "^2.2.8",
|
"cornerstone-core": "^2.2.8",
|
||||||
"cornerstone-tools": "4.15.1",
|
"cornerstone-tools": "^4.20.1",
|
||||||
"cornerstone-wado-image-loader": "^3.1.0",
|
"cornerstone-wado-image-loader": "^3.1.0",
|
||||||
"dcmjs": "0.16.0",
|
"dcmjs": "0.16.3",
|
||||||
"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",
|
||||||
@@ -50,12 +50,12 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
"react-vtkjs-viewport": "^0.9.0"
|
"react-vtkjs-viewport": "^0.10.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ohif/core": "^2.9.13",
|
"@ohif/core": "^2.10.4",
|
||||||
"@ohif/ui": "^1.5.3",
|
"@ohif/ui": "^1.5.3",
|
||||||
"cornerstone-tools": "4.15.1",
|
"cornerstone-tools": "^4.20.1",
|
||||||
"cornerstone-wado-image-loader": "^3.1.0",
|
"cornerstone-wado-image-loader": "^3.1.0",
|
||||||
"dicom-parser": "^1.8.3",
|
"dicom-parser": "^1.8.3",
|
||||||
"gh-pages": "^2.0.1",
|
"gh-pages": "^2.0.1",
|
||||||
|
|||||||
@@ -32,16 +32,16 @@ class LoadingIndicator extends PureComponent {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="imageViewerLoadingIndicator loadingIndicator">
|
<div className="imageViewerLoadingIndicator loadingIndicator">
|
||||||
<div className="indicatorContents">
|
<div className="indicatorContents">
|
||||||
<p>
|
<p>
|
||||||
{this.props.t('Loading...')}
|
{this.props.t('Loading...')}
|
||||||
<i className="fa fa-spin fa-circle-o-notch fa-fw" />
|
<i className="fa fa-spin fa-circle-o-notch fa-fw" />
|
||||||
{percComplete}
|
{percComplete}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,27 +49,30 @@ class OHIFVTKViewport extends Component {
|
|||||||
state = {
|
state = {
|
||||||
volumes: null,
|
volumes: null,
|
||||||
paintFilterLabelMapImageData: null,
|
paintFilterLabelMapImageData: null,
|
||||||
paintFilterBackgroundImageData: null
|
paintFilterBackgroundImageData: null,
|
||||||
|
percentComplete: 0,
|
||||||
|
isLoaded: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
viewportData: PropTypes.shape({
|
viewportData: PropTypes.shape({
|
||||||
studies: PropTypes.array,
|
studies: PropTypes.array.isRequired,
|
||||||
displaySet: PropTypes.shape({
|
displaySet: PropTypes.shape({
|
||||||
StudyInstanceUID: PropTypes.string,
|
StudyInstanceUID: PropTypes.string.isRequired,
|
||||||
displaySetInstanceUID: PropTypes.string,
|
displaySetInstanceUID: PropTypes.string.isRequired,
|
||||||
sopClassUIDs: PropTypes.arrayOf(PropTypes.string),
|
sopClassUIDs: PropTypes.arrayOf(PropTypes.string),
|
||||||
SOPInstanceUID: PropTypes.string,
|
SOPInstanceUID: PropTypes.string,
|
||||||
frameIndex: PropTypes.number,
|
frameIndex: PropTypes.number,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
viewportIndex: PropTypes.number,
|
viewportIndex: PropTypes.number.isRequired,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
onScroll: PropTypes.func,
|
onScroll: PropTypes.func,
|
||||||
|
servicesManager: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
onScroll: () => { },
|
onScroll: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
static id = 'OHIFVTKViewport';
|
static id = 'OHIFVTKViewport';
|
||||||
@@ -156,9 +159,11 @@ class OHIFVTKViewport extends Component {
|
|||||||
const { activeLabelmapIndex } = brushStackState;
|
const { activeLabelmapIndex } = brushStackState;
|
||||||
const labelmap3D = brushStackState.labelmaps3D[activeLabelmapIndex];
|
const labelmap3D = brushStackState.labelmaps3D[activeLabelmapIndex];
|
||||||
|
|
||||||
this.segmentsDefaultProperties = labelmap3D.segmentsHidden.map(isHidden => {
|
this.segmentsDefaultProperties = labelmap3D.segmentsHidden.map(
|
||||||
return { visible: !isHidden };
|
isHidden => {
|
||||||
});
|
return { visible: !isHidden };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const vtkLabelmapID = `${firstImageId}_${activeLabelmapIndex}`;
|
const vtkLabelmapID = `${firstImageId}_${activeLabelmapIndex}`;
|
||||||
|
|
||||||
@@ -349,7 +354,7 @@ class OHIFVTKViewport extends Component {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
displaySet.displaySetInstanceUID !==
|
displaySet.displaySetInstanceUID !==
|
||||||
prevDisplaySet.displaySetInstanceUID ||
|
prevDisplaySet.displaySetInstanceUID ||
|
||||||
displaySet.SOPInstanceUID !== prevDisplaySet.SOPInstanceUID ||
|
displaySet.SOPInstanceUID !== prevDisplaySet.SOPInstanceUID ||
|
||||||
displaySet.frameIndex !== prevDisplaySet.frameIndex
|
displaySet.frameIndex !== prevDisplaySet.frameIndex
|
||||||
) {
|
) {
|
||||||
@@ -360,34 +365,54 @@ class OHIFVTKViewport extends Component {
|
|||||||
loadProgressively(imageDataObject) {
|
loadProgressively(imageDataObject) {
|
||||||
loadImageData(imageDataObject);
|
loadImageData(imageDataObject);
|
||||||
|
|
||||||
const { isLoading, insertPixelDataPromises } = imageDataObject;
|
const { isLoading, imageIds } = imageDataObject;
|
||||||
|
|
||||||
const NumberOfFrames = insertPixelDataPromises.length;
|
|
||||||
|
|
||||||
if (!isLoading) {
|
if (!isLoading) {
|
||||||
this.setState({ isLoaded: true });
|
this.setState({ isLoaded: true });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
insertPixelDataPromises.forEach(promise => {
|
const NumberOfFrames = imageIds.length;
|
||||||
promise.then(numberProcessed => {
|
|
||||||
const percentComplete = Math.floor(
|
|
||||||
(numberProcessed * 100) / NumberOfFrames
|
|
||||||
);
|
|
||||||
|
|
||||||
if (percentComplete !== this.state.percentComplete) {
|
const onPixelDataInsertedCallback = numberProcessed => {
|
||||||
this.setState({
|
const percentComplete = Math.floor(
|
||||||
percentComplete,
|
(numberProcessed * 100) / NumberOfFrames
|
||||||
|
);
|
||||||
|
|
||||||
|
if (percentComplete !== this.state.percentComplete) {
|
||||||
|
this.setState({
|
||||||
|
percentComplete,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPixelDataInsertedErrorCallback = error => {
|
||||||
|
const { UINotificationService } = this.props.servicesManager.services;
|
||||||
|
|
||||||
|
if (!this.hasError) {
|
||||||
|
if (this.props.viewportIndex === 0) {
|
||||||
|
// Only show the notification from one viewport 1 in MPR2D.
|
||||||
|
UINotificationService.show({
|
||||||
|
title: 'MPR Load Error',
|
||||||
|
message: error.message,
|
||||||
|
type: 'error',
|
||||||
|
autoClose: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Promise.all(insertPixelDataPromises).then(() => {
|
this.hasError = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onAllPixelDataInsertedCallback = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
isLoaded: true,
|
isLoaded: true,
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
|
||||||
|
imageDataObject.onPixelDataInserted(onPixelDataInsertedCallback);
|
||||||
|
imageDataObject.onAllPixelDataInserted(onAllPixelDataInsertedCallback);
|
||||||
|
imageDataObject.onPixelDataInsertedError(onPixelDataInsertedErrorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -435,7 +460,7 @@ class OHIFVTKViewport extends Component {
|
|||||||
segmentsDefaultProperties: this.segmentsDefaultProperties,
|
segmentsDefaultProperties: this.segmentsDefaultProperties,
|
||||||
onNewSegmentationRequested: () => {
|
onNewSegmentationRequested: () => {
|
||||||
this.setStateFromProps();
|
this.setStateFromProps();
|
||||||
}
|
},
|
||||||
}}
|
}}
|
||||||
onScroll={this.props.onScroll}
|
onScroll={this.props.onScroll}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import asyncComponent from './asyncComponent.js';
|
|||||||
import commandsModule from './commandsModule.js';
|
import commandsModule from './commandsModule.js';
|
||||||
import toolbarModule from './toolbarModule.js';
|
import toolbarModule from './toolbarModule.js';
|
||||||
import withCommandsManager from './withCommandsManager.js';
|
import withCommandsManager from './withCommandsManager.js';
|
||||||
|
import { version } from '../package.json';
|
||||||
// This feels weird
|
// This feels weird
|
||||||
// import loadLocales from './loadLocales';
|
// import loadLocales from './loadLocales';
|
||||||
|
|
||||||
@@ -15,9 +16,12 @@ const vtkExtension = {
|
|||||||
* Only required property. Should be a unique value across all extensions.
|
* Only required property. Should be a unique value across all extensions.
|
||||||
*/
|
*/
|
||||||
id: 'vtk',
|
id: 'vtk',
|
||||||
|
version,
|
||||||
|
|
||||||
getViewportModule({ commandsManager }) {
|
getViewportModule({ commandsManager, servicesManager }) {
|
||||||
const ExtendedVTKViewport = props => <OHIFVTKViewport {...props} />;
|
const ExtendedVTKViewport = props => (
|
||||||
|
<OHIFVTKViewport {...props} servicesManager={servicesManager} />
|
||||||
|
);
|
||||||
return withCommandsManager(ExtendedVTKViewport, commandsManager);
|
return withCommandsManager(ExtendedVTKViewport, commandsManager);
|
||||||
},
|
},
|
||||||
getToolbarModule() {
|
getToolbarModule() {
|
||||||
|
|||||||
+2
-3
@@ -34,9 +34,8 @@
|
|||||||
"see-changed": "lerna changed",
|
"see-changed": "lerna changed",
|
||||||
"docs:publish": "chmod +x ./build-and-publish-docs.sh && ./build-and-publish-docs.sh",
|
"docs:publish": "chmod +x ./build-and-publish-docs.sh && ./build-and-publish-docs.sh",
|
||||||
"release": "yarn run lerna:version && yarn run lerna:publish",
|
"release": "yarn run lerna:version && yarn run lerna:publish",
|
||||||
"lerna:cache": "[ $NETLIFY_RESTORE = 1 ] && ./netlify-lerna-cache.sh || :",
|
"lerna:cache": "./netlify-lerna-cache.sh",
|
||||||
"lerna:restore": "[ $NETLIFY_RESTORE = 1 ] && ./netlify-lerna-restore.sh || :",
|
"lerna:restore": "./netlify-lerna-restore.sh",
|
||||||
"preinstall": "yarn lerna:restore",
|
|
||||||
"lerna:version": "npx lerna version prerelease --force-publish",
|
"lerna:version": "npx lerna version prerelease --force-publish",
|
||||||
"lerna:publish": "lerna publish from-package --canary --dist-tag canary",
|
"lerna:publish": "lerna publish from-package --canary --dist-tag canary",
|
||||||
"link-list": "npm ls --depth=0 --link=true"
|
"link-list": "npm ls --depth=0 --link=true"
|
||||||
|
|||||||
@@ -3,6 +3,57 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.10.4](https://github.com/OHIF/Viewers/compare/@ohif/core@2.10.3...@ohif/core@2.10.4) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.10.3](https://github.com/OHIF/Viewers/compare/@ohif/core@2.10.2...@ohif/core@2.10.3) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.10.2](https://github.com/OHIF/Viewers/compare/@ohif/core@2.10.1...@ohif/core@2.10.2) (2020-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.10.1](https://github.com/OHIF/Viewers/compare/@ohif/core@2.10.0...@ohif/core@2.10.1) (2020-08-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [2.10.0](https://github.com/OHIF/Viewers/compare/@ohif/core@2.9.14...@ohif/core@2.10.0) (2020-08-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Update react-vtkjs-viewport usage to use requestPool ([#1984](https://github.com/OHIF/Viewers/issues/1984)) ([bb5f30c](https://github.com/OHIF/Viewers/commit/bb5f30ce2a0192d2e021beaaadfff22fd38e17b9))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.9.14](https://github.com/OHIF/Viewers/compare/@ohif/core@2.9.13...@ohif/core@2.9.14) (2020-08-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.9.13](https://github.com/OHIF/Viewers/compare/@ohif/core@2.9.12...@ohif/core@2.9.13) (2020-07-22)
|
## [2.9.13](https://github.com/OHIF/Viewers/compare/@ohif/core@2.9.12...@ohif/core@2.9.13) (2020-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/core",
|
"name": "@ohif/core",
|
||||||
"version": "2.9.13",
|
"version": "2.10.4",
|
||||||
"description": "Generic business logic for web-based medical imaging applications",
|
"description": "Generic business logic for web-based medical imaging applications",
|
||||||
"author": "OHIF Core Team",
|
"author": "OHIF Core Team",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -32,14 +32,14 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"cornerstone-core": "^2.2.8",
|
"cornerstone-core": "^2.2.8",
|
||||||
"cornerstone-tools": "4.15.1",
|
"cornerstone-tools": "^4.20.1",
|
||||||
"cornerstone-wado-image-loader": "^3.1.0",
|
"cornerstone-wado-image-loader": "^3.1.0",
|
||||||
"dicom-parser": "^1.8.3"
|
"dicom-parser": "^1.8.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"ajv": "^6.10.0",
|
"ajv": "^6.10.0",
|
||||||
"dcmjs": "0.16.0",
|
"dcmjs": "0.16.3",
|
||||||
"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",
|
||||||
|
|||||||
@@ -54,9 +54,6 @@ export class OHIFStudyMetadataSource extends StudyMetadataSource {
|
|||||||
// Get Study display sets
|
// Get Study display sets
|
||||||
const displaySets = studyMetadata.createDisplaySets();
|
const displaySets = studyMetadata.createDisplaySets();
|
||||||
|
|
||||||
// Set studyMetadata display sets
|
|
||||||
studyMetadata.setDisplaySets(displaySets);
|
|
||||||
|
|
||||||
OHIFStudyMetadataSource._updateStudyCollections(studyMetadata);
|
OHIFStudyMetadataSource._updateStudyCollections(studyMetadata);
|
||||||
resolve(studyMetadata);
|
resolve(studyMetadata);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import { api } from 'dicomweb-client';
|
|||||||
// - createStacks
|
// - createStacks
|
||||||
import { isImage } from '../../utils/isImage';
|
import { isImage } from '../../utils/isImage';
|
||||||
import isDisplaySetReconstructable from '../../utils/isDisplaySetReconstructable';
|
import isDisplaySetReconstructable from '../../utils/isDisplaySetReconstructable';
|
||||||
import isLowPriorityModality from '../../utils/isLowPriorityModality';
|
|
||||||
import errorHandler from '../../errorHandler';
|
import errorHandler from '../../errorHandler';
|
||||||
|
import isLowPriorityModality from '../../utils/isLowPriorityModality';
|
||||||
|
|
||||||
export class StudyMetadata extends Metadata {
|
export class StudyMetadata extends Metadata {
|
||||||
constructor(data, uid) {
|
constructor(data, uid) {
|
||||||
@@ -139,9 +139,11 @@ export class StudyMetadata extends Metadata {
|
|||||||
if (displaySet) {
|
if (displaySet) {
|
||||||
displaySet.sopClassModule = true;
|
displaySet.sopClassModule = true;
|
||||||
|
|
||||||
displaySet.isDerived
|
if (displaySet.isDerived) {
|
||||||
? this._addDerivedDisplaySet(displaySet)
|
this._addDerivedDisplaySet(displaySet);
|
||||||
: displaySets.push(displaySet);
|
}
|
||||||
|
|
||||||
|
displaySets.push(displaySet);
|
||||||
|
|
||||||
return displaySets;
|
return displaySets;
|
||||||
}
|
}
|
||||||
@@ -306,14 +308,10 @@ export class StudyMetadata extends Metadata {
|
|||||||
series
|
series
|
||||||
);
|
);
|
||||||
|
|
||||||
displaySets.push(...displaySetsForSeries);
|
displaySetsForSeries.forEach(ds => this._insertDisplaySet(ds));
|
||||||
});
|
});
|
||||||
|
|
||||||
return sortDisplaySetList(displaySets);
|
return this._displaySets;
|
||||||
}
|
|
||||||
|
|
||||||
sortDisplaySets() {
|
|
||||||
sortDisplaySetList(this._displaySets);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -344,25 +342,9 @@ export class StudyMetadata extends Metadata {
|
|||||||
this.addDisplaySet(displaySet);
|
this.addDisplaySet(displaySet);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.sortDisplaySets();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set display sets
|
|
||||||
* @param {Array} displaySets Array of display sets (ImageSet[])
|
|
||||||
*/
|
|
||||||
setDisplaySets(displaySets) {
|
|
||||||
if (Array.isArray(displaySets) && displaySets.length > 0) {
|
|
||||||
// TODO: This is weird, can we just switch it to writable: true?
|
|
||||||
this._displaySets.splice(0);
|
|
||||||
|
|
||||||
displaySets.forEach(displaySet => this.addDisplaySet(displaySet));
|
|
||||||
this.sortDisplaySets();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a single display set to the list
|
* Add a single display set to the list
|
||||||
* @param {Object} displaySet Display set object
|
* @param {Object} displaySet Display set object
|
||||||
@@ -370,7 +352,7 @@ export class StudyMetadata extends Metadata {
|
|||||||
*/
|
*/
|
||||||
addDisplaySet(displaySet) {
|
addDisplaySet(displaySet) {
|
||||||
if (displaySet instanceof ImageSet || displaySet.sopClassModule) {
|
if (displaySet instanceof ImageSet || displaySet.sopClassModule) {
|
||||||
this._displaySets.push(displaySet);
|
this._insertDisplaySet(displaySet);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -391,6 +373,96 @@ export class StudyMetadata extends Metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert the displaySet so that the list has an increasing SeriesNumber,
|
||||||
|
* with the most recent series first for displaySets with the same SeriesNumber.
|
||||||
|
*
|
||||||
|
* If the displaySet is low priority, the same logic is applied, but is sorted within a sub list
|
||||||
|
* At the end of the list, where all low priority data is found.
|
||||||
|
*/
|
||||||
|
_insertDisplaySet(displaySet) {
|
||||||
|
const { SeriesNumber } = displaySet;
|
||||||
|
const displaySets = this._displaySets;
|
||||||
|
let insertIndex = displaySets.length;
|
||||||
|
let firstIndexWithSameSeriesNumber;
|
||||||
|
|
||||||
|
// If low priority, start search from next low priority.
|
||||||
|
if (isLowPriorityModality(displaySet.Modality)) {
|
||||||
|
let startingIndex;
|
||||||
|
|
||||||
|
// Find where the first low priority displaySet is.
|
||||||
|
for (let i = 0; i < displaySets.length; i++) {
|
||||||
|
if (isLowPriorityModality(displaySets[i].Modality)) {
|
||||||
|
startingIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!startingIndex) {
|
||||||
|
startingIndex = displaySets.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the correct SeriesNumber location to insert within the low priority
|
||||||
|
// Modality displaySets
|
||||||
|
for (let i = startingIndex; i < displaySets.length; i++) {
|
||||||
|
if (
|
||||||
|
displaySets[i].SeriesNumber === SeriesNumber &&
|
||||||
|
!firstIndexWithSameSeriesNumber
|
||||||
|
) {
|
||||||
|
firstIndexWithSameSeriesNumber = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displaySets[i].SeriesNumber > SeriesNumber) {
|
||||||
|
insertIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Find correct SeriesNumber to insert or where the low priority modalities start.
|
||||||
|
for (let i = 0; i < displaySets.length; i++) {
|
||||||
|
if (
|
||||||
|
displaySets[i].SeriesNumber === SeriesNumber &&
|
||||||
|
!firstIndexWithSameSeriesNumber
|
||||||
|
) {
|
||||||
|
firstIndexWithSameSeriesNumber = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
displaySets[i].SeriesNumber > SeriesNumber ||
|
||||||
|
isLowPriorityModality(displaySets[i].Modality)
|
||||||
|
) {
|
||||||
|
insertIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have multiple displaySets with the same series number, find the insert position based on
|
||||||
|
// SeriesDate and SeriesTime.
|
||||||
|
if (firstIndexWithSameSeriesNumber !== undefined) {
|
||||||
|
// If no SeriesDate, is just a placeholder displaySet, just insert anywhere, it will be re-added later.
|
||||||
|
if (displaySet.SeriesDate) {
|
||||||
|
const seriesDateTime = `${displaySet.SeriesDate}${displaySet.SeriesTime}`;
|
||||||
|
|
||||||
|
for (let i = firstIndexWithSameSeriesNumber; i < insertIndex; i++) {
|
||||||
|
const displaySetI = displaySets[i];
|
||||||
|
|
||||||
|
if (
|
||||||
|
displaySetI.SeriesDate &&
|
||||||
|
`${displaySetI.SeriesDate}${displaySetI.SeriesTime}` <
|
||||||
|
seriesDateTime
|
||||||
|
) {
|
||||||
|
insertIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._displaySets.splice(insertIndex, 0, displaySet);
|
||||||
|
this.displaySets = this._displaySets;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search the associated display sets using the supplied callback as criteria. The callback is passed
|
* Search the associated display sets using the supplied callback as criteria. The callback is passed
|
||||||
* two arguments: display set (an ImageSet instance) and index (the integer
|
* two arguments: display set (an ImageSet instance) and index (the integer
|
||||||
@@ -546,49 +618,6 @@ export class StudyMetadata extends Metadata {
|
|||||||
return this._series.indexOf(series);
|
return this._series.indexOf(series);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* It sorts the series based on display sets order. Each series must be an instance
|
|
||||||
* of SeriesMetadata and each display sets must be an instance of ImageSet.
|
|
||||||
* Useful example of usage:
|
|
||||||
* Study data provided by backend does not sort series at all and client-side
|
|
||||||
* needs series sorted by the same criteria used for sorting display sets.
|
|
||||||
*/
|
|
||||||
sortSeriesByDisplaySets() {
|
|
||||||
// Object for mapping display sets' index by SeriesInstanceUID
|
|
||||||
const displaySetsMapping = {};
|
|
||||||
|
|
||||||
// Loop through each display set to create the mapping
|
|
||||||
this.forEachDisplaySet((displaySet, index) => {
|
|
||||||
if (!(displaySet instanceof ImageSet)) {
|
|
||||||
throw new OHIFError(
|
|
||||||
`StudyMetadata::sortSeriesByDisplaySets display set at index ${index} is not an instance of ImageSet`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// In case of multiframe studies, just get the first index occurence
|
|
||||||
if (displaySetsMapping[displaySet.SeriesInstanceUID] === void 0) {
|
|
||||||
displaySetsMapping[displaySet.SeriesInstanceUID] = index;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Clone of actual series
|
|
||||||
const actualSeries = this.getSeries();
|
|
||||||
|
|
||||||
actualSeries.forEach((series, index) => {
|
|
||||||
if (!(series instanceof SeriesMetadata)) {
|
|
||||||
throw new OHIFError(
|
|
||||||
`StudyMetadata::sortSeriesByDisplaySets series at index ${index} is not an instance of SeriesMetadata`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the new series index
|
|
||||||
const seriesIndex = displaySetsMapping[series.getSeriesInstanceUID()];
|
|
||||||
|
|
||||||
// Update the series object with the new series position
|
|
||||||
this._series[seriesIndex] = series;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares the current study instance with another one.
|
* Compares the current study instance with another one.
|
||||||
* @param {StudyMetadata} study An instance of the StudyMetadata class.
|
* @param {StudyMetadata} study An instance of the StudyMetadata class.
|
||||||
@@ -863,53 +892,3 @@ function _getDisplaySetFromSopClassModule(
|
|||||||
}
|
}
|
||||||
return displaySet;
|
return displaySet;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort series primarily by Modality (i.e., series with references to other
|
|
||||||
* series like SEG, KO or PR are grouped in the end of the list) and then by
|
|
||||||
* series number:
|
|
||||||
*
|
|
||||||
* --------
|
|
||||||
* | CT #3 |
|
|
||||||
* | CT #4 |
|
|
||||||
* | CT #5 |
|
|
||||||
* --------
|
|
||||||
* | SEG #1 |
|
|
||||||
* | SEG #2 |
|
|
||||||
* --------
|
|
||||||
*
|
|
||||||
* @param {*} a - DisplaySet
|
|
||||||
* @param {*} b - DisplaySet
|
|
||||||
*/
|
|
||||||
|
|
||||||
function seriesSortingCriteria(a, b) {
|
|
||||||
const isLowPriorityA = isLowPriorityModality(a.Modality);
|
|
||||||
const isLowPriorityB = isLowPriorityModality(b.Modality);
|
|
||||||
if (!isLowPriorityA && isLowPriorityB) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (isLowPriorityA && !isLowPriorityB) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return sortBySeriesNumber(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort series by series number. Series with low
|
|
||||||
* @param {*} a - DisplaySet
|
|
||||||
* @param {*} b - DisplaySet
|
|
||||||
*/
|
|
||||||
function sortBySeriesNumber(a, b) {
|
|
||||||
const seriesNumberAIsGreaterOrUndefined =
|
|
||||||
a.SeriesNumber > b.SeriesNumber || (!a.SeriesNumber && b.SeriesNumber);
|
|
||||||
|
|
||||||
return seriesNumberAIsGreaterOrUndefined ? 1 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sorts a list of display set objects
|
|
||||||
* @param {Array} list A list of display sets to be sorted
|
|
||||||
*/
|
|
||||||
function sortDisplaySetList(list) {
|
|
||||||
return list.sort(seriesSortingCriteria);
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ export default class ExtensionManager {
|
|||||||
constructor({ commandsManager, servicesManager, api, appConfig = {} }) {
|
constructor({ commandsManager, servicesManager, api, appConfig = {} }) {
|
||||||
this.modules = {};
|
this.modules = {};
|
||||||
this.registeredExtensionIds = [];
|
this.registeredExtensionIds = [];
|
||||||
|
this.registeredExtensionVesions = {};
|
||||||
this.moduleTypeNames = Object.values(MODULE_TYPES);
|
this.moduleTypeNames = Object.values(MODULE_TYPES);
|
||||||
//
|
//
|
||||||
this._commandsManager = commandsManager;
|
this._commandsManager = commandsManager;
|
||||||
@@ -51,6 +52,7 @@ export default class ExtensionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let extensionId = extension.id;
|
let extensionId = extension.id;
|
||||||
|
const version = extension.version;
|
||||||
|
|
||||||
if (!extensionId) {
|
if (!extensionId) {
|
||||||
extensionId = Math.random()
|
extensionId = Math.random()
|
||||||
@@ -98,6 +100,8 @@ export default class ExtensionManager {
|
|||||||
|
|
||||||
// Track extension registration
|
// Track extension registration
|
||||||
this.registeredExtensionIds.push(extensionId);
|
this.registeredExtensionIds.push(extensionId);
|
||||||
|
|
||||||
|
this.registeredExtensionVesions[extensionId] = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -120,7 +124,8 @@ export default class ExtensionManager {
|
|||||||
commandsManager: this._commandsManager,
|
commandsManager: this._commandsManager,
|
||||||
appConfig: this._appConfig,
|
appConfig: this._appConfig,
|
||||||
configuration,
|
configuration,
|
||||||
api: this._api
|
api: this._api,
|
||||||
|
extensionManager: this,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!extensionModule) {
|
if (!extensionModule) {
|
||||||
|
|||||||
@@ -184,6 +184,8 @@ describe('ExtensionManager.js', () => {
|
|||||||
commandsManager,
|
commandsManager,
|
||||||
appConfig,
|
appConfig,
|
||||||
configuration: extensionConfiguration,
|
configuration: extensionConfiguration,
|
||||||
|
api: undefined,
|
||||||
|
extensionManager,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -226,7 +228,7 @@ describe('ExtensionManager.js', () => {
|
|||||||
return {
|
return {
|
||||||
definitions: {
|
definitions: {
|
||||||
exampleDefinition: {
|
exampleDefinition: {
|
||||||
commandFn: () => { },
|
commandFn: () => {},
|
||||||
storeContexts: [],
|
storeContexts: [],
|
||||||
options: {},
|
options: {},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,12 +11,15 @@ import { retrieveStudyMetadata } from './retrieveStudyMetadata';
|
|||||||
* @param {Array} studyInstanceUIDs The UIDs of the Studies to be retrieved
|
* @param {Array} studyInstanceUIDs The UIDs of the Studies to be retrieved
|
||||||
* @param {Object} [filters] - Object containing filters to be applied on retrieve metadata process
|
* @param {Object} [filters] - Object containing filters to be applied on retrieve metadata process
|
||||||
* @param {string} [filter.seriesInstanceUID] - series instance uid to filter results against
|
* @param {string} [filter.seriesInstanceUID] - series instance uid to filter results against
|
||||||
|
* @param {boolean} [separateSeriesInstanceUIDFilters = false] - If true, split filtered metadata calls into multiple calls,
|
||||||
|
* as some DICOMWeb implementations only support single filters.
|
||||||
* @returns {Promise} that will be resolved with the metadata or rejected with the error
|
* @returns {Promise} that will be resolved with the metadata or rejected with the error
|
||||||
*/
|
*/
|
||||||
export default function retrieveStudiesMetadata(
|
export default function retrieveStudiesMetadata(
|
||||||
server,
|
server,
|
||||||
studyInstanceUIDs,
|
studyInstanceUIDs,
|
||||||
filters
|
filters,
|
||||||
|
separateSeriesInstanceUIDFilters = false
|
||||||
) {
|
) {
|
||||||
// Create an empty array to store the Promises for each metaData retrieval call
|
// Create an empty array to store the Promises for each metaData retrieval call
|
||||||
const promises = [];
|
const promises = [];
|
||||||
@@ -24,7 +27,12 @@ export default function retrieveStudiesMetadata(
|
|||||||
// Loop through the array of studyInstanceUIDs
|
// Loop through the array of studyInstanceUIDs
|
||||||
studyInstanceUIDs.forEach(function(StudyInstanceUID) {
|
studyInstanceUIDs.forEach(function(StudyInstanceUID) {
|
||||||
// Send the call and resolve or reject the related promise based on its outcome
|
// Send the call and resolve or reject the related promise based on its outcome
|
||||||
const promise = retrieveStudyMetadata(server, StudyInstanceUID, filters);
|
const promise = retrieveStudyMetadata(
|
||||||
|
server,
|
||||||
|
StudyInstanceUID,
|
||||||
|
filters,
|
||||||
|
separateSeriesInstanceUIDFilters
|
||||||
|
);
|
||||||
|
|
||||||
// Add the current promise to the array of promises
|
// Add the current promise to the array of promises
|
||||||
promises.push(promise);
|
promises.push(promise);
|
||||||
|
|||||||
@@ -11,9 +11,16 @@ const StudyMetaDataPromises = new Map();
|
|||||||
* @param {string} StudyInstanceUID The UID of the Study to be retrieved
|
* @param {string} StudyInstanceUID The UID of the Study to be retrieved
|
||||||
* @param {Object} [filters] - Object containing filters to be applied on retrieve metadata process
|
* @param {Object} [filters] - Object containing filters to be applied on retrieve metadata process
|
||||||
* @param {string} [filter.seriesInstanceUID] - series instance uid to filter results against
|
* @param {string} [filter.seriesInstanceUID] - series instance uid to filter results against
|
||||||
|
* @param {boolean} [separateSeriesInstanceUIDFilters = false] - If true, split filtered metadata calls into multiple calls,
|
||||||
|
* as some DICOMWeb implementations only support single filters.
|
||||||
* @returns {Promise} that will be resolved with the metadata or rejected with the error
|
* @returns {Promise} that will be resolved with the metadata or rejected with the error
|
||||||
*/
|
*/
|
||||||
export function retrieveStudyMetadata(server, StudyInstanceUID, filters) {
|
export function retrieveStudyMetadata(
|
||||||
|
server,
|
||||||
|
StudyInstanceUID,
|
||||||
|
filters,
|
||||||
|
separateSeriesInstanceUIDFilters = false
|
||||||
|
) {
|
||||||
// @TODO: Whenever a study metadata request has failed, its related promise will be rejected once and for all
|
// @TODO: Whenever a study metadata request has failed, its related promise will be rejected once and for all
|
||||||
// and further requests for that metadata will always fail. On failure, we probably need to remove the
|
// and further requests for that metadata will always fail. On failure, we probably need to remove the
|
||||||
// corresponding promise from the "StudyMetaDataPromises" map...
|
// corresponding promise from the "StudyMetaDataPromises" map...
|
||||||
@@ -33,11 +40,29 @@ export function retrieveStudyMetadata(server, StudyInstanceUID, filters) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a promise to handle the data retrieval
|
// Create a promise to handle the data retrieval
|
||||||
const promise = new Promise((resolve, reject) => {
|
let promise;
|
||||||
RetrieveMetadata(server, StudyInstanceUID, filters).then(function(data) {
|
|
||||||
resolve(data);
|
if (
|
||||||
}, reject);
|
filters &&
|
||||||
});
|
filters.seriesInstanceUID &&
|
||||||
|
separateSeriesInstanceUIDFilters
|
||||||
|
) {
|
||||||
|
promise = __separateSeriesRequestToAggregatePromiseateSeriesRequestToAggregatePromise(
|
||||||
|
server,
|
||||||
|
StudyInstanceUID,
|
||||||
|
filters
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
promise = RetrieveMetadata(server, StudyInstanceUID, filters);
|
||||||
|
|
||||||
|
/*
|
||||||
|
promise = new Promise((resolve, reject) => {
|
||||||
|
RetrieveMetadata(server, StudyInstanceUID, filters).then(function(data) {
|
||||||
|
resolve(data);
|
||||||
|
}, reject);
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
// Store the promise in cache
|
// Store the promise in cache
|
||||||
StudyMetaDataPromises.set(StudyInstanceUID, promise);
|
StudyMetaDataPromises.set(StudyInstanceUID, promise);
|
||||||
@@ -45,6 +70,49 @@ export function retrieveStudyMetadata(server, StudyInstanceUID, filters) {
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits up seriesInstanceUID filters to multiple calls for platforms
|
||||||
|
* @param {Object} server Object with server configuration parameters
|
||||||
|
* @param {string} StudyInstanceUID The UID of the Study to be retrieved
|
||||||
|
* @param {Object} filters - Object containing filters to be applied on retrieve metadata process
|
||||||
|
*/
|
||||||
|
function __separateSeriesRequestToAggregatePromiseateSeriesRequestToAggregatePromise(
|
||||||
|
server,
|
||||||
|
StudyInstanceUID,
|
||||||
|
filters
|
||||||
|
) {
|
||||||
|
const { seriesInstanceUID } = filters;
|
||||||
|
const seriesInstanceUIDs = seriesInstanceUID.split(',');
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
|
seriesInstanceUIDs.forEach(uid => {
|
||||||
|
const seriesSpecificFilters = Object.assign({}, filters, {
|
||||||
|
seriesInstanceUID: uid,
|
||||||
|
});
|
||||||
|
|
||||||
|
promises.push(
|
||||||
|
RetrieveMetadata(server, StudyInstanceUID, seriesSpecificFilters)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Promise.all(promises).then(results => {
|
||||||
|
const data = results[0];
|
||||||
|
|
||||||
|
let series = [];
|
||||||
|
|
||||||
|
results.forEach(result => {
|
||||||
|
series = [...series, ...result.series];
|
||||||
|
});
|
||||||
|
|
||||||
|
data.series = series;
|
||||||
|
|
||||||
|
resolve(data);
|
||||||
|
}, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the cached study metadata retrieval promise to ensure that the browser will
|
* Delete the cached study metadata retrieval promise to ensure that the browser will
|
||||||
* re-retrieve the study metadata when it is next requested
|
* re-retrieve the study metadata when it is next requested
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
const LOW_PRIORITY_MODALITIES = Object.freeze(['SEG', 'KO', 'PR']);
|
const LOW_PRIORITY_MODALITIES = Object.freeze([
|
||||||
|
'SEG',
|
||||||
|
'DOC',
|
||||||
|
'RTSTRUCT',
|
||||||
|
'SR',
|
||||||
|
'KO',
|
||||||
|
'PR',
|
||||||
|
]);
|
||||||
|
|
||||||
export default function isLowPriorityModality(Modality) {
|
export default function isLowPriorityModality(Modality) {
|
||||||
return LOW_PRIORITY_MODALITIES.includes(Modality);
|
return LOW_PRIORITY_MODALITIES.includes(Modality);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ services:
|
|||||||
max-size: '10m'
|
max-size: '10m'
|
||||||
ports:
|
ports:
|
||||||
- '389:389'
|
- '389:389'
|
||||||
env_file: ./dcm4che/docker-compose-dcm4che.env
|
env_file: ./docker-compose-dcm4che.env
|
||||||
volumes:
|
volumes:
|
||||||
- ./dcm4che/etc/localtime:/etc/localtime:ro
|
- ./dcm4che/etc/localtime:/etc/localtime:ro
|
||||||
- ./dcm4che/etc/timezone:/etc/timezone:ro
|
- ./dcm4che/etc/timezone:/etc/timezone:ro
|
||||||
@@ -25,7 +25,7 @@ services:
|
|||||||
max-size: '10m'
|
max-size: '10m'
|
||||||
ports:
|
ports:
|
||||||
- '5432:5432'
|
- '5432:5432'
|
||||||
env_file: ./dcm4che/docker-compose-dcm4che.env
|
env_file: ./docker-compose-dcm4che.env
|
||||||
volumes:
|
volumes:
|
||||||
- ./dcm4che/etc/localtime:/etc/localtime:ro
|
- ./dcm4che/etc/localtime:/etc/localtime:ro
|
||||||
- ./dcm4che/etc/timezone:/etc/timezone:ro
|
- ./dcm4che/etc/timezone:/etc/timezone:ro
|
||||||
@@ -44,7 +44,7 @@ services:
|
|||||||
- '9990:9990'
|
- '9990:9990'
|
||||||
- '11112:11112'
|
- '11112:11112'
|
||||||
- '2575:2575'
|
- '2575:2575'
|
||||||
env_file: ./dcm4che/docker-compose-dcm4che.env
|
env_file: ./docker-compose-dcm4che.env
|
||||||
environment:
|
environment:
|
||||||
WILDFLY_CHOWN: /opt/wildfly/standalone /storage
|
WILDFLY_CHOWN: /opt/wildfly/standalone /storage
|
||||||
WILDFLY_WAIT_FOR: ldap:389 db:5432
|
WILDFLY_WAIT_FOR: ldap:389 db:5432
|
||||||
@@ -73,5 +73,4 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
- dcm4che_default
|
- dcm4che_default
|
||||||
|
networks: dcm4che_default:
|
||||||
networks: dcm4che_default:
|
|
||||||
@@ -3,6 +3,146 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [4.5.8](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.5.7...@ohif/viewer@4.5.8) (2020-09-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.5.7](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.5.6...@ohif/viewer@4.5.7) (2020-09-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.5.6](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.5.5...@ohif/viewer@4.5.6) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.5.5](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.5.4...@ohif/viewer@4.5.5) (2020-09-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.5.4](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.5.3...@ohif/viewer@4.5.4) (2020-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.5.3](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.5.2...@ohif/viewer@4.5.3) (2020-08-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.5.2](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.5.1...@ohif/viewer@4.5.2) (2020-08-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.5.1](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.5.0...@ohif/viewer@4.5.1) (2020-08-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [4.5.0](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.4.1...@ohif/viewer@4.5.0) (2020-08-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Filter/promote multiple series instances ([#1533](https://github.com/OHIF/Viewers/issues/1533)) ([5fdace1](https://github.com/OHIF/Viewers/commit/5fdace1432b4b1bd31a60c5db6bd681610ec2b8e))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.4.1](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.4.0...@ohif/viewer@4.4.1) (2020-08-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Fix incorrect command name in Percy test ([#1999](https://github.com/OHIF/Viewers/issues/1999)) ([ebdcde1](https://github.com/OHIF/Viewers/commit/ebdcde1c4d9c95393cf79cc9994f5d60f6d66fdd))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [4.4.0](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.3.1...@ohif/viewer@4.4.0) (2020-08-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Update react-vtkjs-viewport usage to use requestPool ([#1984](https://github.com/OHIF/Viewers/issues/1984)) ([bb5f30c](https://github.com/OHIF/Viewers/commit/bb5f30ce2a0192d2e021beaaadfff22fd38e17b9))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.3.1](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.3.0...@ohif/viewer@4.3.1) (2020-08-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [4.3.0](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.2.16...@ohif/viewer@4.3.0) (2020-08-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Optional disable measurements panel in app config ([#1912](https://github.com/OHIF/Viewers/issues/1912)) ([3d86b5f](https://github.com/OHIF/Viewers/commit/3d86b5f876d6481bcc57de88a0ba1f974f4ee263)), closes [#1864](https://github.com/OHIF/Viewers/issues/1864)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.2.16](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.2.15...@ohif/viewer@4.2.16) (2020-08-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.2.15](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.2.14...@ohif/viewer@4.2.15) (2020-08-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.2.14](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.2.13...@ohif/viewer@4.2.14) (2020-08-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [4.2.13](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.2.12...@ohif/viewer@4.2.13) (2020-07-23)
|
## [4.2.13](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.2.12...@ohif/viewer@4.2.13) (2020-07-23)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/viewer
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ describe('OHIF Microscopy Extension', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('drags and drop a SM thumbnail into viewport', () => {
|
it('drags and drop a SM thumbnail into viewport', () => {
|
||||||
|
// Waiting for series list to load all displaySets (lots of SRs, before defining which dom element to grab.)
|
||||||
|
cy.wait(3000);
|
||||||
cy.get('[data-cy="thumbnail-list"]')
|
cy.get('[data-cy="thumbnail-list"]')
|
||||||
.contains('SM')
|
.contains('SM')
|
||||||
.drag('.viewport-drop-target');
|
.drag('.viewport-drop-target');
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ describe('Visual Regression - OHIF VTK Extension', () => {
|
|||||||
cy.get('[data-cy="2d mpr"]').click();
|
cy.get('[data-cy="2d mpr"]').click();
|
||||||
|
|
||||||
//Wait waitVTKLoading Images
|
//Wait waitVTKLoading Images
|
||||||
cy.waitVTKwaitVTKLoading();
|
cy.waitVTKLoading();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ Cypress.Commands.add('waitVTKLoading', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Wait for finish loading
|
// Wait for finish loading
|
||||||
cy.get('[data-cy="viewprt-grid"]', { timeout: 30000 }).should($grid => {
|
cy.get('[data-cy="viewprt-grid"]', { timeout: 90000 }).should($grid => {
|
||||||
expect($grid).not.to.contain.text('Loading');
|
expect($grid).not.to.contain.text('Loading');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/viewer",
|
"name": "@ohif/viewer",
|
||||||
"version": "4.2.13",
|
"version": "4.5.8",
|
||||||
"description": "OHIF Viewer",
|
"description": "OHIF Viewer",
|
||||||
"author": "OHIF Contributors",
|
"author": "OHIF Contributors",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -48,16 +48,16 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"@ohif/core": "^2.9.13",
|
"@ohif/core": "^2.10.4",
|
||||||
"@ohif/extension-cornerstone": "^2.8.4",
|
"@ohif/extension-cornerstone": "^2.9.4",
|
||||||
"@ohif/extension-dicom-html": "^1.2.4",
|
"@ohif/extension-debugging": "^0.1.4",
|
||||||
"@ohif/extension-dicom-microscopy": "^0.51.0",
|
"@ohif/extension-dicom-html": "^1.2.7",
|
||||||
"@ohif/extension-dicom-p10-downloader": "^0.1.2",
|
"@ohif/extension-dicom-microscopy": "^0.51.2",
|
||||||
"@ohif/extension-dicom-pdf": "^1.0.3",
|
"@ohif/extension-dicom-pdf": "^1.0.5",
|
||||||
"@ohif/extension-dicom-rt": "^0.2.5",
|
"@ohif/extension-dicom-rt": "^0.4.4",
|
||||||
"@ohif/extension-dicom-segmentation": "^0.3.3",
|
"@ohif/extension-dicom-segmentation": "^0.4.4",
|
||||||
"@ohif/extension-lesion-tracker": "^0.2.0",
|
"@ohif/extension-lesion-tracker": "^0.2.1",
|
||||||
"@ohif/extension-vtk": "^1.6.9",
|
"@ohif/extension-vtk": "^1.7.5",
|
||||||
"@ohif/i18n": "^0.52.8",
|
"@ohif/i18n": "^0.52.8",
|
||||||
"@ohif/ui": "^1.5.3",
|
"@ohif/ui": "^1.5.3",
|
||||||
"@tanem/react-nprogress": "^1.1.25",
|
"@tanem/react-nprogress": "^1.1.25",
|
||||||
@@ -65,9 +65,9 @@
|
|||||||
"core-js": "^3.2.1",
|
"core-js": "^3.2.1",
|
||||||
"cornerstone-core": "^2.2.8",
|
"cornerstone-core": "^2.2.8",
|
||||||
"cornerstone-math": "^0.1.8",
|
"cornerstone-math": "^0.1.8",
|
||||||
"cornerstone-tools": "4.15.1",
|
"cornerstone-tools": "^4.20.1",
|
||||||
"cornerstone-wado-image-loader": "^3.1.0",
|
"cornerstone-wado-image-loader": "^3.1.0",
|
||||||
"dcmjs": "0.16.0",
|
"dcmjs": "0.16.3",
|
||||||
"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",
|
||||||
|
|||||||
@@ -2,13 +2,17 @@ window.config = function(props) {
|
|||||||
var servicesManager = props.servicesManager;
|
var servicesManager = props.servicesManager;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
disableMeasurementPanel: true,
|
||||||
routerBasename: '/',
|
routerBasename: '/',
|
||||||
enableGoogleCloudAdapter: true,
|
enableGoogleCloudAdapter: true,
|
||||||
|
splitQueryParameterCalls: true, // Allows the user to split QIDO SeriesInstanceUID filters into multiple calls, if the server does not support multi-valued query parameters.
|
||||||
enableGoogleCloudAdapterUI: false,
|
enableGoogleCloudAdapterUI: false,
|
||||||
showStudyList: true,
|
showStudyList: true,
|
||||||
|
filterQueryParam: true,
|
||||||
httpErrorHandler: error => {
|
httpErrorHandler: error => {
|
||||||
// This is 429 when rejected from the public idc sandbox too often.
|
// This is 429 when rejected from the public idc sandbox too often.
|
||||||
console.warn(error.status);
|
console.warn(error.status);
|
||||||
|
|
||||||
// Could use services manager here to bring up a dialog/modal if needed.
|
// Could use services manager here to bring up a dialog/modal if needed.
|
||||||
console.warn('test, navigate to https://ohif.org/');
|
console.warn('test, navigate to https://ohif.org/');
|
||||||
window.location = 'https://ohif.org/';
|
window.location = 'https://ohif.org/';
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
ModalProvider,
|
ModalProvider,
|
||||||
DialogProvider,
|
DialogProvider,
|
||||||
OHIFModal,
|
OHIFModal,
|
||||||
ErrorBoundary
|
ErrorBoundary,
|
||||||
} from '@ohif/ui';
|
} from '@ohif/ui';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -168,7 +168,7 @@ class App extends Component {
|
|||||||
|
|
||||||
if (this._userManager) {
|
if (this._userManager) {
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary context='App'>
|
<ErrorBoundary context="App">
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<AppProvider config={this._appConfig}>
|
<AppProvider config={this._appConfig}>
|
||||||
<I18nextProvider i18n={i18n}>
|
<I18nextProvider i18n={i18n}>
|
||||||
@@ -200,7 +200,7 @@ class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary context='App'>
|
<ErrorBoundary context="App">
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<AppProvider config={this._appConfig}>
|
<AppProvider config={this._appConfig}>
|
||||||
<I18nextProvider i18n={i18n}>
|
<I18nextProvider i18n={i18n}>
|
||||||
@@ -271,17 +271,21 @@ function _initExtensions(extensions, cornerstoneExtensionConfig, appConfig) {
|
|||||||
api: {
|
api: {
|
||||||
contexts: CONTEXTS,
|
contexts: CONTEXTS,
|
||||||
hooks: {
|
hooks: {
|
||||||
useAppContext
|
useAppContext,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const requiredExtensions = [
|
const requiredExtensions = [
|
||||||
GenericViewerCommands,
|
GenericViewerCommands,
|
||||||
[OHIFCornerstoneExtension, cornerstoneExtensionConfig],
|
[OHIFCornerstoneExtension, cornerstoneExtensionConfig],
|
||||||
/* WARNING: MUST BE REGISTERED _AFTER_ OHIFCornerstoneExtension */
|
|
||||||
MeasurementsPanel,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (appConfig.disableMeasurementPanel !== true) {
|
||||||
|
/* WARNING: MUST BE REGISTERED _AFTER_ OHIFCornerstoneExtension */
|
||||||
|
requiredExtensions.push(MeasurementsPanel);
|
||||||
|
}
|
||||||
|
|
||||||
const mergedExtensions = requiredExtensions.concat(extensions);
|
const mergedExtensions = requiredExtensions.concat(extensions);
|
||||||
extensionManager.registerExtensions(mergedExtensions);
|
extensionManager.registerExtensions(mergedExtensions);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ import commandsModule from './commandsModule.js';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
id: 'generic-viewer-commands',
|
id: 'generic-viewer-commands',
|
||||||
|
get version() {
|
||||||
|
return window.version;
|
||||||
|
},
|
||||||
getCommandsModule({ commandsManager }) {
|
getCommandsModule({ commandsManager }) {
|
||||||
return commandsModule({ commandsManager });
|
return commandsModule({ commandsManager });
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ export default {
|
|||||||
* Only required property. Should be a unique value across all extensions.
|
* Only required property. Should be a unique value across all extensions.
|
||||||
*/
|
*/
|
||||||
id: 'measurements-table',
|
id: 'measurements-table',
|
||||||
|
get version() {
|
||||||
|
return window.version;
|
||||||
|
},
|
||||||
|
|
||||||
preRegistration({ servicesManager, commandsManager, configuration = {} }) {
|
preRegistration({ servicesManager, commandsManager, configuration = {} }) {
|
||||||
init({ servicesManager, commandsManager, configuration });
|
init({ servicesManager, commandsManager, configuration });
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ const ViewportGrid = function(props) {
|
|||||||
// - When updating a panel, ensure that the currently enabled plugin
|
// - When updating a panel, ensure that the currently enabled plugin
|
||||||
// in the viewport is capable of rendering this display set. If not
|
// in the viewport is capable of rendering this display set. If not
|
||||||
// then use the most capable available plugin
|
// then use the most capable available plugin
|
||||||
|
|
||||||
const pluginName =
|
const pluginName =
|
||||||
!layout.plugin && displaySet && displaySet.plugin
|
!layout.plugin && displaySet && displaySet.plugin
|
||||||
? displaySet.plugin
|
? displaySet.plugin
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { StudyBrowser } from '@ohif/ui';
|
|||||||
import cloneDeep from 'lodash.clonedeep';
|
import cloneDeep from 'lodash.clonedeep';
|
||||||
import findDisplaySetByUID from './findDisplaySetByUID';
|
import findDisplaySetByUID from './findDisplaySetByUID';
|
||||||
|
|
||||||
|
const { studyMetadataManager } = OHIF.utils;
|
||||||
|
|
||||||
const { setActiveViewportSpecificData } = OHIF.redux.actions;
|
const { setActiveViewportSpecificData } = OHIF.redux.actions;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
@@ -39,11 +41,27 @@ const mapStateToProps = (state, ownProps) => {
|
|||||||
const mapDispatchToProps = (dispatch, ownProps) => {
|
const mapDispatchToProps = (dispatch, ownProps) => {
|
||||||
return {
|
return {
|
||||||
onThumbnailClick: displaySetInstanceUID => {
|
onThumbnailClick: displaySetInstanceUID => {
|
||||||
const displaySet = findDisplaySetByUID(
|
let displaySet = findDisplaySetByUID(
|
||||||
ownProps.studyMetadata,
|
ownProps.studyMetadata,
|
||||||
displaySetInstanceUID
|
displaySetInstanceUID
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (displaySet.isDerived) {
|
||||||
|
const { Modality } = displaySet;
|
||||||
|
|
||||||
|
displaySet = displaySet.getSourceDisplaySet(ownProps.studyMetadata);
|
||||||
|
|
||||||
|
if (!displaySet) {
|
||||||
|
throw new Error(
|
||||||
|
`Referenced series for ${Modality} dataset not present.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!displaySet) {
|
||||||
|
throw new Error('Source data not present');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(setActiveViewportSpecificData(displaySet));
|
dispatch(setActiveViewportSpecificData(displaySet));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import UserManagerContext from '../context/UserManagerContext';
|
|||||||
import AppContext from '../context/AppContext';
|
import AppContext from '../context/AppContext';
|
||||||
|
|
||||||
import './Viewer.css';
|
import './Viewer.css';
|
||||||
|
import { finished } from 'stream';
|
||||||
|
|
||||||
class Viewer extends Component {
|
class Viewer extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@@ -189,6 +190,7 @@ class Viewer extends Component {
|
|||||||
currentTimepointId,
|
currentTimepointId,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
thumbnails: _mapStudiesToThumbnails(studies),
|
thumbnails: _mapStudiesToThumbnails(studies),
|
||||||
});
|
});
|
||||||
@@ -197,6 +199,7 @@ class Viewer extends Component {
|
|||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const { studies, isStudyLoaded } = this.props;
|
const { studies, isStudyLoaded } = this.props;
|
||||||
|
|
||||||
if (studies !== prevProps.studies) {
|
if (studies !== prevProps.studies) {
|
||||||
this.setState({
|
this.setState({
|
||||||
thumbnails: _mapStudiesToThumbnails(studies),
|
thumbnails: _mapStudiesToThumbnails(studies),
|
||||||
@@ -355,7 +358,6 @@ export default withDialog(Viewer);
|
|||||||
* a mapping layer?
|
* a mapping layer?
|
||||||
*
|
*
|
||||||
* TODO[react]:
|
* TODO[react]:
|
||||||
* - Add sorting of display sets
|
|
||||||
* - Add showStackLoadingProgressBar option
|
* - Add showStackLoadingProgressBar option
|
||||||
*
|
*
|
||||||
* @param {Study[]} studies
|
* @param {Study[]} studies
|
||||||
@@ -369,9 +371,9 @@ const _mapStudiesToThumbnails = function(studies) {
|
|||||||
const {
|
const {
|
||||||
displaySetInstanceUID,
|
displaySetInstanceUID,
|
||||||
SeriesDescription,
|
SeriesDescription,
|
||||||
SeriesNumber,
|
|
||||||
InstanceNumber,
|
InstanceNumber,
|
||||||
numImageFrames,
|
numImageFrames,
|
||||||
|
SeriesNumber,
|
||||||
} = displaySet;
|
} = displaySet;
|
||||||
|
|
||||||
let imageId;
|
let imageId;
|
||||||
@@ -395,9 +397,9 @@ const _mapStudiesToThumbnails = function(studies) {
|
|||||||
altImageText,
|
altImageText,
|
||||||
displaySetInstanceUID,
|
displaySetInstanceUID,
|
||||||
SeriesDescription,
|
SeriesDescription,
|
||||||
SeriesNumber,
|
|
||||||
InstanceNumber,
|
InstanceNumber,
|
||||||
numImageFrames,
|
numImageFrames,
|
||||||
|
SeriesNumber,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ class ViewerLocalFileData extends Component {
|
|||||||
study.displaySets =
|
study.displaySets =
|
||||||
study.displaySets ||
|
study.displaySets ||
|
||||||
studyMetadata.createDisplaySets(sopClassHandlerModules);
|
studyMetadata.createDisplaySets(sopClassHandlerModules);
|
||||||
studyMetadata.setDisplaySets(study.displaySets);
|
|
||||||
|
|
||||||
studyMetadata.forEachDisplaySet(displayset => {
|
studyMetadata.forEachDisplaySet(displayset => {
|
||||||
displayset.localFile = true;
|
displayset.localFile = true;
|
||||||
|
|||||||
@@ -133,12 +133,23 @@ class ViewerMain extends Component {
|
|||||||
StudyInstanceUID,
|
StudyInstanceUID,
|
||||||
displaySetInstanceUID,
|
displaySetInstanceUID,
|
||||||
}) => {
|
}) => {
|
||||||
const displaySet = this.findDisplaySet(
|
let displaySet = this.findDisplaySet(
|
||||||
this.props.studies,
|
this.props.studies,
|
||||||
StudyInstanceUID,
|
StudyInstanceUID,
|
||||||
displaySetInstanceUID
|
displaySetInstanceUID
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (displaySet.isDerived) {
|
||||||
|
const { Modality } = displaySet;
|
||||||
|
displaySet = displaySet.getSourceDisplaySet(this.props.studies);
|
||||||
|
|
||||||
|
if (!displaySet) {
|
||||||
|
throw new Error(
|
||||||
|
`Referenced series for ${Modality} dataset not present.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.props.setViewportSpecificData(viewportIndex, displaySet);
|
this.props.setViewportSpecificData(viewportIndex, displaySet);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,23 +14,25 @@ const { OHIFStudyMetadata, OHIFSeriesMetadata } = metadata;
|
|||||||
const { retrieveStudiesMetadata, deleteStudyMetadataPromise } = studies;
|
const { retrieveStudiesMetadata, deleteStudyMetadataPromise } = studies;
|
||||||
const { studyMetadataManager, makeCancelable } = utils;
|
const { studyMetadataManager, makeCancelable } = utils;
|
||||||
|
|
||||||
const _promoteToFront = (list, value, searchMethod) => {
|
const _promoteToFront = (list, values, searchMethod) => {
|
||||||
let response = [...list];
|
let listCopy = [...list];
|
||||||
let promoted = false;
|
let response = [];
|
||||||
const index = response.findIndex(searchMethod.bind(undefined, value));
|
let promotedCount = 0;
|
||||||
|
|
||||||
if (index > 0) {
|
const arrayValues = values.split(',');
|
||||||
const first = response.splice(index, 1);
|
arrayValues.forEach(value => {
|
||||||
response = [...first, ...response];
|
const index = listCopy.findIndex(searchMethod.bind(undefined, value));
|
||||||
}
|
|
||||||
|
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
promoted = true;
|
const [itemToPromote] = listCopy.splice(index, 1);
|
||||||
}
|
response[promotedCount] = itemToPromote;
|
||||||
|
promotedCount++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
promoted,
|
promoted: promotedCount === arrayValues.length,
|
||||||
data: response,
|
data: [...response, ...listCopy],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,7 +47,6 @@ const _promoteList = (study, studyMetadata, filters, isFilterStrategy) => {
|
|||||||
let promoted = false;
|
let promoted = false;
|
||||||
// Promote only if no filter should be applied
|
// Promote only if no filter should be applied
|
||||||
if (!isFilterStrategy) {
|
if (!isFilterStrategy) {
|
||||||
_sortStudyDisplaySet(study, studyMetadata);
|
|
||||||
promoted = _promoteStudyDisplaySet(study, studyMetadata, filters);
|
promoted = _promoteStudyDisplaySet(study, studyMetadata, filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,15 +88,52 @@ const _isQueryParamApplied = (study, filters = {}, isFilterStrategy) => {
|
|||||||
const { seriesInstanceUID } = filters;
|
const { seriesInstanceUID } = filters;
|
||||||
let applied = true;
|
let applied = true;
|
||||||
// skip in case no filter or no toast manager
|
// skip in case no filter or no toast manager
|
||||||
|
|
||||||
if (!seriesInstanceUID) {
|
if (!seriesInstanceUID) {
|
||||||
return applied;
|
return applied;
|
||||||
}
|
}
|
||||||
|
const seriesInstanceUIDs = seriesInstanceUID.split(',');
|
||||||
|
|
||||||
|
let validateFilterApplied = () => {
|
||||||
|
const sameSize = arrayToInspect.length === seriesInstanceUIDs.length;
|
||||||
|
if (!sameSize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return arrayToInspect.every(item =>
|
||||||
|
seriesInstanceUIDs.some(
|
||||||
|
seriesInstanceUIDStr => seriesInstanceUIDStr === item.SeriesInstanceUID
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let validatePromoteApplied = () => {
|
||||||
|
let isValid = true;
|
||||||
|
for (let index = 0; index < seriesInstanceUIDs.length; index++) {
|
||||||
|
const seriesInstanceUIDStr = seriesInstanceUIDs[index];
|
||||||
|
const resultSeries = arrayToInspect[index];
|
||||||
|
|
||||||
|
if (
|
||||||
|
!resultSeries ||
|
||||||
|
resultSeries.SeriesInstanceUID !== seriesInstanceUIDStr
|
||||||
|
) {
|
||||||
|
isValid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isValid;
|
||||||
|
};
|
||||||
|
|
||||||
const { series = [], displaySets = [] } = study;
|
const { series = [], displaySets = [] } = study;
|
||||||
const firstSeries = isFilterStrategy ? series[0] : displaySets[0];
|
const arrayToInspect = isFilterStrategy ? series : displaySets;
|
||||||
|
const validateMethod = isFilterStrategy
|
||||||
|
? validateFilterApplied
|
||||||
|
: validatePromoteApplied;
|
||||||
|
|
||||||
if (!firstSeries || firstSeries.SeriesInstanceUID !== seriesInstanceUID) {
|
if (!arrayToInspect) {
|
||||||
applied = false;
|
applied = false;
|
||||||
|
} else {
|
||||||
|
applied = validateMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
return applied;
|
return applied;
|
||||||
@@ -155,12 +193,6 @@ const _updateStudyDisplaySets = (study, studyMetadata) => {
|
|||||||
if (study.derivedDisplaySets) {
|
if (study.derivedDisplaySets) {
|
||||||
studyMetadata._addDerivedDisplaySets(study.derivedDisplaySets);
|
studyMetadata._addDerivedDisplaySets(study.derivedDisplaySets);
|
||||||
}
|
}
|
||||||
|
|
||||||
studyMetadata.setDisplaySets(study.displaySets);
|
|
||||||
};
|
|
||||||
|
|
||||||
const _sortStudyDisplaySet = (study, studyMetadata) => {
|
|
||||||
studyMetadata.sortDisplaySets(study.displaySets);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const _thinStudyData = study => {
|
const _thinStudyData = study => {
|
||||||
@@ -221,7 +253,7 @@ function ViewerRetrieveStudyData({
|
|||||||
// Show message in case not promoted neither filtered but should to
|
// Show message in case not promoted neither filtered but should to
|
||||||
_showUserMessage(
|
_showUserMessage(
|
||||||
isQueryParamApplied,
|
isQueryParamApplied,
|
||||||
'Query parameters were not applied. Using original series list for given study.',
|
'Query parameters were not totally applied. It might be using original series list for given study.',
|
||||||
snackbarContext
|
snackbarContext
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -233,7 +265,7 @@ function ViewerRetrieveStudyData({
|
|||||||
* Method to process studies. It will update displaySet, studyMetadata, load remaining series, ...
|
* Method to process studies. It will update displaySet, studyMetadata, load remaining series, ...
|
||||||
* @param {Array} studiesData Array of studies retrieved from server
|
* @param {Array} studiesData Array of studies retrieved from server
|
||||||
* @param {Object} [filters] - Object containing filters to be applied
|
* @param {Object} [filters] - Object containing filters to be applied
|
||||||
* @param {string} [filter.seriesInstanceUID] - series instance uid to filter results against
|
* @param {string} [filters.seriesInstanceUID] - series instance uid to filter results against
|
||||||
*/
|
*/
|
||||||
const processStudies = (studiesData, filters) => {
|
const processStudies = (studiesData, filters) => {
|
||||||
if (Array.isArray(studiesData) && studiesData.length > 0) {
|
if (Array.isArray(studiesData) && studiesData.length > 0) {
|
||||||
@@ -299,7 +331,6 @@ function ViewerRetrieveStudyData({
|
|||||||
const filters = {};
|
const filters = {};
|
||||||
// Use the first, discard others
|
// Use the first, discard others
|
||||||
const seriesInstanceUID = seriesInstanceUIDs && seriesInstanceUIDs[0];
|
const seriesInstanceUID = seriesInstanceUIDs && seriesInstanceUIDs[0];
|
||||||
|
|
||||||
const retrieveParams = [server, studyInstanceUIDs];
|
const retrieveParams = [server, studyInstanceUIDs];
|
||||||
|
|
||||||
if (seriesInstanceUID) {
|
if (seriesInstanceUID) {
|
||||||
@@ -310,6 +341,13 @@ function ViewerRetrieveStudyData({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
appConfig.splitQueryParameterCalls ||
|
||||||
|
appConfig.enableGoogleCloudAdapter
|
||||||
|
) {
|
||||||
|
retrieveParams.push(true); // Seperate SeriesInstanceUID filter calls.
|
||||||
|
}
|
||||||
|
|
||||||
cancelableStudiesPromises[studyInstanceUIDs] = makeCancelable(
|
cancelableStudiesPromises[studyInstanceUIDs] = makeCancelable(
|
||||||
retrieveStudiesMetadata(...retrieveParams)
|
retrieveStudiesMetadata(...retrieveParams)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ import OHIFDicomSegmentationExtension from '@ohif/extension-dicom-segmentation';
|
|||||||
import OHIFDicomRtExtension from '@ohif/extension-dicom-rt';
|
import OHIFDicomRtExtension from '@ohif/extension-dicom-rt';
|
||||||
import OHIFDicomMicroscopyExtension from '@ohif/extension-dicom-microscopy';
|
import OHIFDicomMicroscopyExtension from '@ohif/extension-dicom-microscopy';
|
||||||
import OHIFDicomPDFExtension from '@ohif/extension-dicom-pdf';
|
import OHIFDicomPDFExtension from '@ohif/extension-dicom-pdf';
|
||||||
import OHIFDicomP10DownloaderExtension from '@ohif/extension-dicom-p10-downloader';
|
// Add this for Debugging purposes:
|
||||||
|
//import OHIFDebuggingExtension from '@ohif/extension-debugging';
|
||||||
|
import { version } from '../package.json';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default Settings
|
* Default Settings
|
||||||
@@ -38,6 +40,8 @@ let config = {};
|
|||||||
|
|
||||||
if (window) {
|
if (window) {
|
||||||
config = window.config || {};
|
config = window.config || {};
|
||||||
|
|
||||||
|
window.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
const appProps = {
|
const appProps = {
|
||||||
@@ -49,7 +53,7 @@ const appProps = {
|
|||||||
OHIFDicomPDFExtension,
|
OHIFDicomPDFExtension,
|
||||||
OHIFDicomSegmentationExtension,
|
OHIFDicomSegmentationExtension,
|
||||||
OHIFDicomRtExtension,
|
OHIFDicomRtExtension,
|
||||||
OHIFDicomP10DownloaderExtension,
|
//OHIFDebuggingExtension,
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -194,7 +194,6 @@ const _mapStudiesToNewFormat = studies => {
|
|||||||
study.displaySets =
|
study.displaySets =
|
||||||
study.displaySets ||
|
study.displaySets ||
|
||||||
studyMetadata.createDisplaySets(sopClassHandlerModules);
|
studyMetadata.createDisplaySets(sopClassHandlerModules);
|
||||||
studyMetadata.setDisplaySets(study.displaySets);
|
|
||||||
|
|
||||||
studyMetadataManager.add(studyMetadata);
|
studyMetadataManager.add(studyMetadata);
|
||||||
uniqueStudyUIDs.add(study.StudyInstanceUID);
|
uniqueStudyUIDs.add(study.StudyInstanceUID);
|
||||||
|
|||||||
@@ -1247,34 +1247,13 @@
|
|||||||
pirates "^4.0.0"
|
pirates "^4.0.0"
|
||||||
source-map-support "^0.5.9"
|
source-map-support "^0.5.9"
|
||||||
|
|
||||||
"@babel/runtime@7.1.2":
|
"@babel/runtime@7.1.2", "@babel/runtime@7.5.5", "@babel/runtime@7.6.0", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.6":
|
||||||
version "7.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.1.2.tgz#81c89935f4647706fc54541145e6b4ecfef4b8e3"
|
|
||||||
integrity sha512-Y3SCjmhSupzFB6wcv1KmmFucH6gDVnI30WjOcicV10ju0cZjak3Jcs67YLIXBrmZYw1xCrVeJPbycFwrqNyxpg==
|
|
||||||
dependencies:
|
|
||||||
regenerator-runtime "^0.12.0"
|
|
||||||
|
|
||||||
"@babel/runtime@7.6.0":
|
|
||||||
version "7.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.0.tgz#4fc1d642a9fd0299754e8b5de62c631cf5568205"
|
|
||||||
integrity sha512-89eSBLJsxNxOERC0Op4vd+0Bqm6wRMqMbFtV3i0/fbaWw/mJ8Q3eBvgX0G4SyrOOLCtbu98HspF8o09MRT+KzQ==
|
|
||||||
dependencies:
|
|
||||||
regenerator-runtime "^0.13.2"
|
|
||||||
|
|
||||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5":
|
|
||||||
version "7.5.5"
|
version "7.5.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132"
|
||||||
integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==
|
integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.2"
|
regenerator-runtime "^0.13.2"
|
||||||
|
|
||||||
"@babel/runtime@^7.6.0", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.6":
|
|
||||||
version "7.10.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.5.tgz#303d8bd440ecd5a491eae6117fd3367698674c5c"
|
|
||||||
integrity sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg==
|
|
||||||
dependencies:
|
|
||||||
regenerator-runtime "^0.13.4"
|
|
||||||
|
|
||||||
"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0":
|
"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0":
|
||||||
version "7.6.0"
|
version "7.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6"
|
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6"
|
||||||
@@ -5971,10 +5950,10 @@ cornerstone-math@^0.1.8:
|
|||||||
resolved "https://registry.yarnpkg.com/cornerstone-math/-/cornerstone-math-0.1.8.tgz#68ab1f9e4fdcd7c5cb23a0d2eb4263f9f894f1c5"
|
resolved "https://registry.yarnpkg.com/cornerstone-math/-/cornerstone-math-0.1.8.tgz#68ab1f9e4fdcd7c5cb23a0d2eb4263f9f894f1c5"
|
||||||
integrity sha512-x7NEQHBtVG7j1yeyj/aRoKTpXv1Vh2/H9zNLMyqYJDtJkNng8C4Q8M3CgZ1qer0Yr7eVq2x+Ynmj6kfOm5jXKw==
|
integrity sha512-x7NEQHBtVG7j1yeyj/aRoKTpXv1Vh2/H9zNLMyqYJDtJkNng8C4Q8M3CgZ1qer0Yr7eVq2x+Ynmj6kfOm5jXKw==
|
||||||
|
|
||||||
cornerstone-tools@4.15.1:
|
cornerstone-tools@^4.20.1:
|
||||||
version "4.15.1"
|
version "4.20.1"
|
||||||
resolved "https://registry.yarnpkg.com/cornerstone-tools/-/cornerstone-tools-4.15.1.tgz#f0b1026da9c7758defc088bb2f1e78426a23d91e"
|
resolved "https://registry.yarnpkg.com/cornerstone-tools/-/cornerstone-tools-4.20.1.tgz#90f6c28356622eac037683b19f9175f85d33dff7"
|
||||||
integrity sha512-fJuTUJW/NDSD520jPB++tX//Kq80jPDngChHZrhx2xjj/9dCnexD9kmTX30Z0WUq0a2JEHZ6FlcOX38kSmw1hQ==
|
integrity sha512-SyQsrg3bnGHUvWGZpUq7ia7/gj12S9zQFK2VMhpyAYxK9pWz+PRv8HBi0eEe/fWGAo/Vc62IRkdP3uF9MJlqiQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "7.1.2"
|
"@babel/runtime" "7.1.2"
|
||||||
cornerstone-math "0.1.7"
|
cornerstone-math "0.1.7"
|
||||||
@@ -6560,10 +6539,10 @@ 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.0:
|
dcmjs@0.16.3:
|
||||||
version "0.16.0"
|
version "0.16.3"
|
||||||
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.16.0.tgz#714755d006c3a49cf65ef13e627ff7a23151d35a"
|
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.16.3.tgz#ef44ccc4988a473fd40e1601122c57f2babded11"
|
||||||
integrity sha512-41nY3Isg5i5FoSd1s67aUgUHi146r+fb8JuiRvDsxvm7MEkkdjIzMYMtxjsrVwKRW1xRH+x34nxbV9+8cc7WQw==
|
integrity sha512-pMQGifMpMW9i9ufCdUoEPHrLWnm6ilnpfLqUc+PPoWr7OnuBhiRVRunbv39oTtFDZOLhQ2Ampm7UrkidWAbqiA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/polyfill" "^7.8.3"
|
"@babel/polyfill" "^7.8.3"
|
||||||
"@babel/runtime" "^7.8.4"
|
"@babel/runtime" "^7.8.4"
|
||||||
@@ -6803,6 +6782,11 @@ detab@2.0.2, detab@^2.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
repeat-string "^1.5.4"
|
repeat-string "^1.5.4"
|
||||||
|
|
||||||
|
detect-browser@5.1.1:
|
||||||
|
version "5.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.1.1.tgz#a800db91d3fd60d0861669f5984f1be9ffbe009c"
|
||||||
|
integrity sha512-5n2aWI57qC3kZaK4j2zYsG6L1LrxgLptGCNhMQgdKhVn6cSdcq43pp6xHPfTHG3TYM6myF4tIPWiZtfdVDgb9w==
|
||||||
|
|
||||||
detect-file@^1.0.0:
|
detect-file@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
|
resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
|
||||||
@@ -15617,13 +15601,14 @@ react-codemirror2@^6.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/react-codemirror2/-/react-codemirror2-6.0.0.tgz#180065df57a64026026cde569a9708fdf7656525"
|
resolved "https://registry.yarnpkg.com/react-codemirror2/-/react-codemirror2-6.0.0.tgz#180065df57a64026026cde569a9708fdf7656525"
|
||||||
integrity sha512-D7y9qZ05FbUh9blqECaJMdDwKluQiO3A9xB+fssd5jKM7YAXucRuEOlX32mJQumUvHUkHRHqXIPBjm6g0FW0Ag==
|
integrity sha512-D7y9qZ05FbUh9blqECaJMdDwKluQiO3A9xB+fssd5jKM7YAXucRuEOlX32mJQumUvHUkHRHqXIPBjm6g0FW0Ag==
|
||||||
|
|
||||||
react-cornerstone-viewport@2.3.9:
|
react-cornerstone-viewport@4.0.2:
|
||||||
version "2.3.9"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-cornerstone-viewport/-/react-cornerstone-viewport-2.3.9.tgz#f9761da8e536f0a217137c6ca1a983f5882249f9"
|
resolved "https://registry.yarnpkg.com/react-cornerstone-viewport/-/react-cornerstone-viewport-4.0.2.tgz#49bc8f8464164d8e779138dd9244d5c2524e0418"
|
||||||
integrity sha512-qrhq8CbX/jq6b93cQjV2qC/mhHOvFBpxzxcHlvHzEQZt/rmRMcaYxCqjpNaNbUmmBu61wNkxesUVsggkPTTcqg==
|
integrity sha512-mF/piahoPG5U5TbxVMtc15bXrQZxcaPycbu4i4KD2rZkiWh1Zs24ryY1S+lFlDB/RcOAm0u+luEEt1tOg8F+UQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
classnames "^2.2.6"
|
classnames "^2.2.6"
|
||||||
date-fns "^2.2.1"
|
date-fns "^2.2.1"
|
||||||
|
lodash.debounce "^4.0.8"
|
||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
react-resize-detector "^4.2.1"
|
react-resize-detector "^4.2.1"
|
||||||
|
|
||||||
@@ -16067,10 +16052,10 @@ react-transition-group@^4.1.1:
|
|||||||
loose-envify "^1.4.0"
|
loose-envify "^1.4.0"
|
||||||
prop-types "^15.6.2"
|
prop-types "^15.6.2"
|
||||||
|
|
||||||
react-vtkjs-viewport@^0.9.0:
|
react-vtkjs-viewport@^0.10.4:
|
||||||
version "0.9.0"
|
version "0.10.4"
|
||||||
resolved "https://registry.yarnpkg.com/react-vtkjs-viewport/-/react-vtkjs-viewport-0.9.0.tgz#5a7890643e511946f960db6b05142318be2dfe80"
|
resolved "https://registry.yarnpkg.com/react-vtkjs-viewport/-/react-vtkjs-viewport-0.10.4.tgz#eb038b0bf5c384bd3b45f2a0a57f52c682607fea"
|
||||||
integrity sha512-kjpNr1n+eW0nU736HH07IsSYQXphxfn/RBvKtpBer9tNsl+FyLH8h+uY8KWdv8kVBHkEoaH6/srxB0JBa8l+jA==
|
integrity sha512-J1WxwHbjlttEWvdkM33DJx8QxHr3J7HR6wFSDVBDKY7McK2lwDAdRN8wSqy2BVNILlyurUUVwg2tK2txiJ+tuw==
|
||||||
dependencies:
|
dependencies:
|
||||||
date-fns "^2.2.1"
|
date-fns "^2.2.1"
|
||||||
gl-matrix "^3.1.0"
|
gl-matrix "^3.1.0"
|
||||||
@@ -16433,11 +16418,6 @@ regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1:
|
|||||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
||||||
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
|
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
|
||||||
|
|
||||||
regenerator-runtime@^0.12.0:
|
|
||||||
version "0.12.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
|
|
||||||
integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
|
|
||||||
|
|
||||||
regenerator-runtime@^0.13.1, regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.4:
|
regenerator-runtime@^0.13.1, regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.4:
|
||||||
version "0.13.5"
|
version "0.13.5"
|
||||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
|
||||||
|
|||||||
Reference in new issue
Block a user