Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e5a385e53 | ||
|
|
a3caeb381e | ||
|
|
be995f93b6 | ||
|
|
5036615e00 | ||
|
|
2e215aed4c | ||
|
|
ffd27d6db4 | ||
|
|
6540e36818 | ||
|
|
a436436def | ||
|
|
d6d92afbda | ||
|
|
e1142910e4 | ||
|
|
067e6c769b | ||
|
|
d375d02a4b | ||
|
|
63594d36b0 |
No files matched your search
@@ -30,6 +30,7 @@ docker/dcm4che/dcm4che-arc
|
|||||||
|
|
||||||
# Cypress test results
|
# Cypress test results
|
||||||
videos/
|
videos/
|
||||||
|
screenshots/
|
||||||
|
|
||||||
# Locize settings
|
# Locize settings
|
||||||
.locize
|
.locize
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
# Viewer: Configuration
|
# Viewer: Configuration
|
||||||
|
|
||||||
We maintain a number of common viewer application configurations at [`<root>/platform/viewer/public/configs`][config-dir]. How these values are passed to the viewer depend on how it's deployed, but the two most common paths are:
|
We maintain a number of common viewer application configurations at
|
||||||
|
[`<root>/platform/viewer/public/configs`][config-dir]. How these values are
|
||||||
|
passed to the viewer depend on how it's deployed, but the two most common paths
|
||||||
|
are:
|
||||||
|
|
||||||
- `index.html` looks for `https://your-website.com/app-config.js` OR
|
- `index.html` looks for `https://your-website.com/app-config.js` OR
|
||||||
- `index.html` passes the values to `OHIF.installViewer()`
|
- `index.html` passes the values to `OHIF.installViewer()`
|
||||||
@@ -42,8 +45,16 @@ window.config = {
|
|||||||
keys: ['v'],
|
keys: ['v'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
// Config to pass to the bundled cornerstone extension
|
/* Configuration passed to the bundled cornerstone extension
|
||||||
cornerstoneExtensionConfig: {},
|
*
|
||||||
|
* The cornerstone extension is currently tightly coupled to the platform.
|
||||||
|
* Until we're able to decouple it, this key will serve as a workaround to
|
||||||
|
* pass it configuration.
|
||||||
|
*/
|
||||||
|
cornerstoneExtensionConfig: {
|
||||||
|
/* Whether to show/hide annotation "handles" */
|
||||||
|
hideHandles: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,28 @@
|
|||||||
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.2.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.2.0...@ohif/extension-cornerstone@2.2.1) (2019-12-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 🐛 1241: Make Plugin switch part of ToolbarModule ([#1322](https://github.com/OHIF/Viewers/issues/1322)) ([6540e36](https://github.com/OHIF/Viewers/commit/6540e36818944ac2eccc696186366ae495b33a04)), closes [#1241](https://github.com/OHIF/Viewers/issues/1241)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [2.2.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.1.1...@ohif/extension-cornerstone@2.2.0) (2019-12-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Configuration so viewer tools can nix handles ([#1304](https://github.com/OHIF/Viewers/issues/1304)) ([63594d3](https://github.com/OHIF/Viewers/commit/63594d36b0bdba59f0901095aed70b75fb05172d)), closes [#1223](https://github.com/OHIF/Viewers/issues/1223)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.1.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.1.0...@ohif/extension-cornerstone@2.1.1) (2019-12-16)
|
## [2.1.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.1.0...@ohif/extension-cornerstone@2.1.1) (2019-12-16)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -85,6 +85,20 @@ Tools can be configured through extension configuration using the tools key:
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Annotate Tools Configuration
|
||||||
|
|
||||||
|
*We currently support one property for annotation tools.*
|
||||||
|
|
||||||
|
### Hide handles
|
||||||
|
This extension configuration allows you to toggle on/off handle rendering for all annotate tools:
|
||||||
|
|
||||||
|
```js
|
||||||
|
...
|
||||||
|
cornerstoneExtensionConfig: {
|
||||||
|
hideHandles: true,
|
||||||
|
},
|
||||||
|
...
|
||||||
|
|
||||||
## Resources
|
## Resources
|
||||||
|
|
||||||
### Repositories
|
### Repositories
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-cornerstone",
|
"name": "@ohif/extension-cornerstone",
|
||||||
"version": "2.1.1",
|
"version": "2.2.1",
|
||||||
"description": "OHIF extension for Cornerstone",
|
"description": "OHIF extension for Cornerstone",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"@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.8.0",
|
"cornerstone-tools": "^4.9.0",
|
||||||
"cornerstone-wado-image-loader": "^3.0.0",
|
"cornerstone-wado-image-loader": "^3.0.0",
|
||||||
"dcmjs": "^0.8.2",
|
"dcmjs": "^0.8.2",
|
||||||
"dicom-parser": "^1.8.3",
|
"dicom-parser": "^1.8.3",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import cornerstone from 'cornerstone-core';
|
|||||||
import cornerstoneTools from 'cornerstone-tools';
|
import cornerstoneTools from 'cornerstone-tools';
|
||||||
import OHIF from '@ohif/core';
|
import OHIF from '@ohif/core';
|
||||||
|
|
||||||
|
import setCornerstoneLayout from './utils/setCornerstoneLayout.js';
|
||||||
import { getEnabledElement } from './state';
|
import { getEnabledElement } from './state';
|
||||||
import CornerstoneViewportDownloadForm from './CornerstoneViewportDownloadForm';
|
import CornerstoneViewportDownloadForm from './CornerstoneViewportDownloadForm';
|
||||||
const scroll = cornerstoneTools.import('util/scroll');
|
const scroll = cornerstoneTools.import('util/scroll');
|
||||||
@@ -242,6 +243,9 @@ const commandsModule = ({ servicesManager }) => {
|
|||||||
cornerstoneTools.removeToolState(element, toolType, tool);
|
cornerstoneTools.removeToolState(element, toolType, tool);
|
||||||
cornerstone.updateImage(element);
|
cornerstone.updateImage(element);
|
||||||
},
|
},
|
||||||
|
setCornerstoneLayout: () => {
|
||||||
|
setCornerstoneLayout();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const definitions = {
|
const definitions = {
|
||||||
@@ -348,6 +352,12 @@ const commandsModule = ({ servicesManager }) => {
|
|||||||
storeContexts: [],
|
storeContexts: [],
|
||||||
options: {},
|
options: {},
|
||||||
},
|
},
|
||||||
|
setCornerstoneLayout: {
|
||||||
|
commandFn: actions.setCornerstoneLayout,
|
||||||
|
storeContexts: [],
|
||||||
|
options: {},
|
||||||
|
context: 'VIEWER',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -76,31 +76,35 @@ export default function init({ servicesManager, configuration }) {
|
|||||||
|
|
||||||
initCornerstoneTools(defaultCsToolsConfig);
|
initCornerstoneTools(defaultCsToolsConfig);
|
||||||
|
|
||||||
// ~~ Toooools 🙌
|
const toolsGroupedByType = {
|
||||||
const tools = [
|
touch: [csTools.PanMultiTouchTool, csTools.ZoomTouchPinchTool],
|
||||||
csTools.PanTool,
|
annotations: [
|
||||||
csTools.ZoomTool,
|
csTools.ArrowAnnotateTool,
|
||||||
csTools.WwwcTool,
|
csTools.EraserTool,
|
||||||
csTools.WwwcRegionTool,
|
csTools.BidirectionalTool,
|
||||||
csTools.MagnifyTool,
|
csTools.LengthTool,
|
||||||
csTools.StackScrollTool,
|
csTools.AngleTool,
|
||||||
csTools.StackScrollMouseWheelTool,
|
csTools.FreehandRoiTool,
|
||||||
// Touch
|
csTools.EllipticalRoiTool,
|
||||||
csTools.PanMultiTouchTool,
|
csTools.DragProbeTool,
|
||||||
csTools.ZoomTouchPinchTool,
|
csTools.RectangleRoiTool,
|
||||||
// Annotations
|
],
|
||||||
csTools.ArrowAnnotateTool,
|
segmentation: [csTools.BrushTool],
|
||||||
csTools.EraserTool,
|
other: [
|
||||||
csTools.BidirectionalTool,
|
csTools.PanTool,
|
||||||
csTools.LengthTool,
|
csTools.ZoomTool,
|
||||||
csTools.AngleTool,
|
csTools.WwwcTool,
|
||||||
csTools.FreehandRoiTool,
|
csTools.WwwcRegionTool,
|
||||||
csTools.EllipticalRoiTool,
|
csTools.MagnifyTool,
|
||||||
csTools.DragProbeTool,
|
csTools.StackScrollTool,
|
||||||
csTools.RectangleRoiTool,
|
csTools.StackScrollMouseWheelTool,
|
||||||
// Segmentation
|
],
|
||||||
csTools.BrushTool,
|
};
|
||||||
];
|
|
||||||
|
let tools = [];
|
||||||
|
Object.keys(toolsGroupedByType).forEach(toolsGroup =>
|
||||||
|
tools.push(...toolsGroupedByType[toolsGroup])
|
||||||
|
);
|
||||||
|
|
||||||
/* Add extension tools configuration here. */
|
/* Add extension tools configuration here. */
|
||||||
const internalToolsConfig = {
|
const internalToolsConfig = {
|
||||||
@@ -114,13 +118,48 @@ export default function init({ servicesManager, configuration }) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Abstract tools configuration using extension configuration. */
|
||||||
|
const parseToolProps = (props, tool) => {
|
||||||
|
const { annotations } = toolsGroupedByType;
|
||||||
|
// An alternative approach would be to remove the `drawHandlesOnHover` config
|
||||||
|
// from the supported configuration properties in `cornerstone-tools`
|
||||||
|
const toolsWithHideableHandles = annotations.filter(
|
||||||
|
tool => !['RectangleRoiTool', 'EllipticalRoiTool'].includes(tool.name)
|
||||||
|
);
|
||||||
|
|
||||||
|
let parsedProps = { ...props };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drawHandles - Never/Always show handles
|
||||||
|
* drawHandlesOnHover - Only show handles on handle hover (pointNearHandle)
|
||||||
|
*
|
||||||
|
* Does not apply to tools where handles aren't placed in predictable
|
||||||
|
* locations.
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
configuration.hideHandles !== false &&
|
||||||
|
toolsWithHideableHandles.includes(tool)
|
||||||
|
) {
|
||||||
|
if (props.configuration) {
|
||||||
|
parsedProps.configuration.drawHandlesOnHover = true;
|
||||||
|
} else {
|
||||||
|
parsedProps.configuration = { drawHandlesOnHover: true };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedProps;
|
||||||
|
};
|
||||||
|
|
||||||
/* Add tools with its custom props through extension configuration. */
|
/* Add tools with its custom props through extension configuration. */
|
||||||
tools.forEach(tool => {
|
tools.forEach(tool => {
|
||||||
const toolName = tool.name.replace('Tool', '');
|
const toolName = tool.name.replace('Tool', '');
|
||||||
const externalToolsConfig = configuration.tools || {};
|
const externalToolsConfig = configuration.tools || {};
|
||||||
const externalToolProps = externalToolsConfig[toolName] || {};
|
const externalToolProps = externalToolsConfig[toolName] || {};
|
||||||
const internalToolProps = internalToolsConfig[toolName] || {};
|
const internalToolProps = internalToolsConfig[toolName] || {};
|
||||||
const props = merge(internalToolProps, externalToolProps);
|
const props = merge(
|
||||||
|
internalToolProps,
|
||||||
|
parseToolProps(externalToolProps, tool)
|
||||||
|
);
|
||||||
csTools.addTool(tool, props);
|
csTools.addTool(tool, props);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -237,6 +237,15 @@ const definitions = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'Exit2DMPR',
|
||||||
|
label: 'Exit 2D MPR',
|
||||||
|
icon: 'times',
|
||||||
|
//
|
||||||
|
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||||
|
commandName: 'setCornerstoneLayout',
|
||||||
|
context: 'ACTIVE_VIEWPORT::VTK',
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { redux } from '@ohif/core';
|
||||||
|
|
||||||
|
const { setLayout } = redux.actions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the current layout with a simple Cornerstone one
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
const setCornerstoneLayout = () => {
|
||||||
|
const layout = {
|
||||||
|
numRows: 1,
|
||||||
|
numColumns: 1,
|
||||||
|
viewports: [{ plugin: 'cornerstone' }],
|
||||||
|
};
|
||||||
|
|
||||||
|
const action = setLayout(layout);
|
||||||
|
|
||||||
|
window.store.dispatch(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default setCornerstoneLayout;
|
||||||
@@ -3,6 +3,60 @@
|
|||||||
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.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.2.4...@ohif/extension-vtk@1.2.5) (2020-01-06)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.2.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.2.3...@ohif/extension-vtk@1.2.4) (2019-12-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.2.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.2.2...@ohif/extension-vtk@1.2.3) (2019-12-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 🐛 1241: Make Plugin switch part of ToolbarModule ([#1322](https://github.com/OHIF/Viewers/issues/1322)) ([6540e36](https://github.com/OHIF/Viewers/commit/6540e36818944ac2eccc696186366ae495b33a04)), closes [#1241](https://github.com/OHIF/Viewers/issues/1241)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.2.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.2.1...@ohif/extension-vtk@1.2.2) (2019-12-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.2.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.2.0...@ohif/extension-vtk@1.2.1) (2019-12-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [1.2.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.1.7...@ohif/extension-vtk@1.2.0) (2019-12-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Configuration so viewer tools can nix handles ([#1304](https://github.com/OHIF/Viewers/issues/1304)) ([63594d3](https://github.com/OHIF/Viewers/commit/63594d36b0bdba59f0901095aed70b75fb05172d)), closes [#1223](https://github.com/OHIF/Viewers/issues/1223)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.1.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.1.6...@ohif/extension-vtk@1.1.7) (2019-12-19)
|
## [1.1.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.1.6...@ohif/extension-vtk@1.1.7) (2019-12-19)
|
||||||
|
|
||||||
**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.1.7",
|
"version": "1.2.5",
|
||||||
"description": "OHIF extension for VTK.js",
|
"description": "OHIF extension for VTK.js",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -52,9 +52,9 @@
|
|||||||
"react-vtkjs-viewport": "^0.3.9"
|
"react-vtkjs-viewport": "^0.3.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ohif/core": "^2.2.1",
|
"@ohif/core": "^2.3.2",
|
||||||
"@ohif/ui": "^1.1.5",
|
"@ohif/ui": "^1.1.7",
|
||||||
"cornerstone-tools": "^4.8.0",
|
"cornerstone-tools": "^4.9.0",
|
||||||
"cornerstone-wado-image-loader": "^3.0.0",
|
"cornerstone-wado-image-loader": "^3.0.0",
|
||||||
"dicom-parser": "^1.8.3",
|
"dicom-parser": "^1.8.3",
|
||||||
"gh-pages": "^2.0.1",
|
"gh-pages": "^2.0.1",
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { ToolbarButton } from '@ohif/ui';
|
||||||
|
import { utils } from '@ohif/core';
|
||||||
|
|
||||||
|
const { studyMetadataManager } = utils;
|
||||||
|
|
||||||
|
let isVisible = true;
|
||||||
|
|
||||||
|
const _isDisplaySetReconstructable = (viewportSpecificData = {}, activeViewportIndex) => {
|
||||||
|
if (!viewportSpecificData[activeViewportIndex]) {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { displaySetInstanceUid, studyInstanceUid } = viewportSpecificData[
|
||||||
|
activeViewportIndex
|
||||||
|
];
|
||||||
|
|
||||||
|
const studies = studyMetadataManager.all();
|
||||||
|
|
||||||
|
const study = studies.find(
|
||||||
|
study => study.studyInstanceUID === studyInstanceUid
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!study) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const displaySet = study._displaySets.find(set => set.displaySetInstanceUid === displaySetInstanceUid);
|
||||||
|
|
||||||
|
if (!displaySet) {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
return displaySet.isReconstructable;
|
||||||
|
};
|
||||||
|
|
||||||
|
function VTKMPRToolbarButton({
|
||||||
|
parentContext,
|
||||||
|
toolbarClickCallback,
|
||||||
|
button,
|
||||||
|
activeButtons,
|
||||||
|
isActive,
|
||||||
|
className,
|
||||||
|
}) {
|
||||||
|
const { id, label, icon } = button;
|
||||||
|
const { viewportSpecificData, activeViewportIndex } = useSelector(state => {
|
||||||
|
const { viewports = {} } = state;
|
||||||
|
const { viewportSpecificData, activeViewportIndex } = viewports;
|
||||||
|
|
||||||
|
return {
|
||||||
|
viewportSpecificData,
|
||||||
|
activeViewportIndex,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
isVisible = _isDisplaySetReconstructable(
|
||||||
|
viewportSpecificData,
|
||||||
|
activeViewportIndex,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{isVisible && (
|
||||||
|
<ToolbarButton
|
||||||
|
key={id}
|
||||||
|
label={label}
|
||||||
|
icon={icon}
|
||||||
|
onClick={evt => toolbarClickCallback(button, evt)}
|
||||||
|
isActive={isActive}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
VTKMPRToolbarButton.propTypes = {
|
||||||
|
parentContext: PropTypes.object.isRequired,
|
||||||
|
toolbarClickCallback: PropTypes.func.isRequired,
|
||||||
|
button: PropTypes.object.isRequired,
|
||||||
|
activeButtons: PropTypes.array.isRequired,
|
||||||
|
isActive: PropTypes.bool,
|
||||||
|
className: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VTKMPRToolbarButton;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import SlabThicknessToolbarComponent from './toolbarComponents/SlabThicknessToolbarComponent';
|
import SlabThicknessToolbarComponent from './toolbarComponents/SlabThicknessToolbarComponent';
|
||||||
|
import VTKMPRToolbarButton from './toolbarComponents/VTKMPRToolbarButton';
|
||||||
|
|
||||||
const TOOLBAR_BUTTON_TYPES = {
|
const TOOLBAR_BUTTON_TYPES = {
|
||||||
COMMAND: 'command',
|
COMMAND: 'command',
|
||||||
@@ -115,9 +116,19 @@ const definitions = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: '2DMPR',
|
||||||
|
label: '2D MPR',
|
||||||
|
icon: 'cube',
|
||||||
|
//
|
||||||
|
CustomComponent: VTKMPRToolbarButton,
|
||||||
|
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||||
|
commandName: 'mpr2d',
|
||||||
|
context: 'ACTIVE_VIEWPORT::CORNERSTONE',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
definitions,
|
definitions,
|
||||||
defaultContext: 'ACTIVE_VIEWPORT::VTK',
|
defaultContext: 'ACTIVE_VIEWPORT::VTK',
|
||||||
};
|
}
|
||||||
@@ -3,6 +3,36 @@
|
|||||||
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.3.2](https://github.com/OHIF/Viewers/compare/@ohif/core@2.3.1...@ohif/core@2.3.2) (2020-01-06)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.3.1](https://github.com/OHIF/Viewers/compare/@ohif/core@2.3.0...@ohif/core@2.3.1) (2019-12-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 🐛 1241: Make Plugin switch part of ToolbarModule ([#1322](https://github.com/OHIF/Viewers/issues/1322)) ([6540e36](https://github.com/OHIF/Viewers/commit/6540e36818944ac2eccc696186366ae495b33a04)), closes [#1241](https://github.com/OHIF/Viewers/issues/1241)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [2.3.0](https://github.com/OHIF/Viewers/compare/@ohif/core@2.2.1...@ohif/core@2.3.0) (2019-12-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Configuration so viewer tools can nix handles ([#1304](https://github.com/OHIF/Viewers/issues/1304)) ([63594d3](https://github.com/OHIF/Viewers/commit/63594d36b0bdba59f0901095aed70b75fb05172d)), closes [#1223](https://github.com/OHIF/Viewers/issues/1223)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.2.1](https://github.com/OHIF/Viewers/compare/@ohif/core@2.2.0...@ohif/core@2.2.1) (2019-12-18)
|
## [2.2.1](https://github.com/OHIF/Viewers/compare/@ohif/core@2.2.0...@ohif/core@2.2.1) (2019-12-18)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/core
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/core",
|
"name": "@ohif/core",
|
||||||
"version": "2.2.1",
|
"version": "2.3.2",
|
||||||
"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,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"cornerstone-core": "^2.2.8",
|
"cornerstone-core": "^2.2.8",
|
||||||
"cornerstone-tools": "^4.8.0",
|
"cornerstone-tools": "^4.9.0",
|
||||||
"cornerstone-wado-image-loader": "^3.0.0",
|
"cornerstone-wado-image-loader": "^3.0.0",
|
||||||
"dicom-parser": "^1.8.3"
|
"dicom-parser": "^1.8.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ describe('ExtensionManager.js', () => {
|
|||||||
return {
|
return {
|
||||||
definitions: {
|
definitions: {
|
||||||
exampleDefinition: {
|
exampleDefinition: {
|
||||||
commandFn: () => {},
|
commandFn: () => { },
|
||||||
storeContexts: [],
|
storeContexts: [],
|
||||||
options: {},
|
options: {},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ export default class RetrieveMetadataLoader {
|
|||||||
if (result && result.length) {
|
if (result && result.length) {
|
||||||
break; // closes iterator in case data is retrieved successfully
|
break; // closes iterator in case data is retrieved successfully
|
||||||
}
|
}
|
||||||
} catch (e) { }
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loaders.next().done && !result) {
|
if (loaders.next().done && !result) {
|
||||||
@@ -51,8 +53,8 @@ export default class RetrieveMetadataLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Methods to be overwrite
|
// Methods to be overwrite
|
||||||
async configLoad() { }
|
async configLoad() {}
|
||||||
async preLoad() { }
|
async preLoad() {}
|
||||||
async load(preLoadData) { }
|
async load(preLoadData) {}
|
||||||
async posLoad(loadData) { }
|
async posLoad(loadData) {}
|
||||||
}
|
}
|
||||||
@@ -1,413 +0,0 @@
|
|||||||
import DICOMWeb from '../DICOMWeb/';
|
|
||||||
|
|
||||||
const WADOProxy = {
|
|
||||||
convertURL: (url, server) => {
|
|
||||||
// TODO: Remove all WADOProxy stuff from this file
|
|
||||||
return url;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
function parseFloatArray(obj) {
|
|
||||||
const result = [];
|
|
||||||
|
|
||||||
if (!obj) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const objs = obj.split('\\');
|
|
||||||
for (let i = 0; i < objs.length; i++) {
|
|
||||||
result.push(parseFloat(objs[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a plain JS object that describes a study (a study descriptor object)
|
|
||||||
* @param {Object} server Object with server configuration parameters
|
|
||||||
* @param {Object} aSopInstance a SOP Instance from which study information will be added
|
|
||||||
*/
|
|
||||||
function createStudy(server, aSopInstance) {
|
|
||||||
// TODO: Pass a reference ID to the server instead of including the URLs here
|
|
||||||
return {
|
|
||||||
seriesList: [],
|
|
||||||
seriesMap: Object.create(null),
|
|
||||||
seriesLoader: null,
|
|
||||||
wadoUriRoot: server.wadoUriRoot,
|
|
||||||
wadoRoot: server.wadoRoot,
|
|
||||||
qidoRoot: server.qidoRoot,
|
|
||||||
patientName: DICOMWeb.getName(aSopInstance['00100010']),
|
|
||||||
patientId: DICOMWeb.getString(aSopInstance['00100020']),
|
|
||||||
patientAge: DICOMWeb.getNumber(aSopInstance['00101010']),
|
|
||||||
patientSize: DICOMWeb.getNumber(aSopInstance['00101020']),
|
|
||||||
patientWeight: DICOMWeb.getNumber(aSopInstance['00101030']),
|
|
||||||
accessionNumber: DICOMWeb.getString(aSopInstance['00080050']),
|
|
||||||
studyDate: DICOMWeb.getString(aSopInstance['00080020']),
|
|
||||||
modalities: DICOMWeb.getString(aSopInstance['00080061']),
|
|
||||||
studyDescription: DICOMWeb.getString(aSopInstance['00081030']),
|
|
||||||
imageCount: DICOMWeb.getString(aSopInstance['00201208']),
|
|
||||||
studyInstanceUid: DICOMWeb.getString(aSopInstance['0020000D']),
|
|
||||||
institutionName: DICOMWeb.getString(aSopInstance['00080080']),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a WADO url for an instance
|
|
||||||
*
|
|
||||||
* @param studyInstanceUid
|
|
||||||
* @param seriesInstanceUid
|
|
||||||
* @param sopInstanceUid
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function buildInstanceWadoUrl(
|
|
||||||
server,
|
|
||||||
studyInstanceUid,
|
|
||||||
seriesInstanceUid,
|
|
||||||
sopInstanceUid
|
|
||||||
) {
|
|
||||||
// TODO: This can be removed, since DICOMWebClient has the same function. Not urgent, though
|
|
||||||
const params = [];
|
|
||||||
|
|
||||||
params.push('requestType=WADO');
|
|
||||||
params.push(`studyUID=${studyInstanceUid}`);
|
|
||||||
params.push(`seriesUID=${seriesInstanceUid}`);
|
|
||||||
params.push(`objectUID=${sopInstanceUid}`);
|
|
||||||
params.push('contentType=application/dicom');
|
|
||||||
params.push('transferSyntax=*');
|
|
||||||
|
|
||||||
const paramString = params.join('&');
|
|
||||||
|
|
||||||
return `${server.wadoUriRoot}?${paramString}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildInstanceWadoRsUri(
|
|
||||||
server,
|
|
||||||
studyInstanceUid,
|
|
||||||
seriesInstanceUid,
|
|
||||||
sopInstanceUid
|
|
||||||
) {
|
|
||||||
return `${server.wadoRoot}/studies/${studyInstanceUid}/series/${seriesInstanceUid}/instances/${sopInstanceUid}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildInstanceFrameWadoRsUri(
|
|
||||||
server,
|
|
||||||
studyInstanceUid,
|
|
||||||
seriesInstanceUid,
|
|
||||||
sopInstanceUid,
|
|
||||||
frame
|
|
||||||
) {
|
|
||||||
const baseWadoRsUri = buildInstanceWadoRsUri(
|
|
||||||
server,
|
|
||||||
studyInstanceUid,
|
|
||||||
seriesInstanceUid,
|
|
||||||
sopInstanceUid
|
|
||||||
);
|
|
||||||
frame = frame != null || 1;
|
|
||||||
|
|
||||||
return `${baseWadoRsUri}/frames/${frame}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFrameIncrementPointer(element) {
|
|
||||||
const frameIncrementPointerNames = {
|
|
||||||
'00181065': 'frameTimeVector',
|
|
||||||
'00181063': 'frameTime',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!element || !element.Value || !element.Value.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const value = element.Value[0];
|
|
||||||
return frameIncrementPointerNames[value];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRadiopharmaceuticalInfo(instance) {
|
|
||||||
const modality = DICOMWeb.getString(instance['00080060']);
|
|
||||||
|
|
||||||
if (modality !== 'PT') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const radiopharmaceuticalInfo = instance['00540016'];
|
|
||||||
if (
|
|
||||||
radiopharmaceuticalInfo === undefined ||
|
|
||||||
!radiopharmaceuticalInfo.Value ||
|
|
||||||
!radiopharmaceuticalInfo.Value.length
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const firstPetRadiopharmaceuticalInfo = radiopharmaceuticalInfo.Value[0];
|
|
||||||
return {
|
|
||||||
radiopharmaceuticalStartTime: DICOMWeb.getString(
|
|
||||||
firstPetRadiopharmaceuticalInfo['00181072']
|
|
||||||
),
|
|
||||||
radionuclideTotalDose: DICOMWeb.getNumber(
|
|
||||||
firstPetRadiopharmaceuticalInfo['00181074']
|
|
||||||
),
|
|
||||||
radionuclideHalfLife: DICOMWeb.getNumber(
|
|
||||||
firstPetRadiopharmaceuticalInfo['00181075']
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the SourceImageSequence, if it exists, in order
|
|
||||||
* to return a ReferenceSOPInstanceUID. The ReferenceSOPInstanceUID
|
|
||||||
* is used to refer to this image in any accompanying DICOM-SR documents.
|
|
||||||
*
|
|
||||||
* @param instance
|
|
||||||
* @returns {String} The ReferenceSOPInstanceUID
|
|
||||||
*/
|
|
||||||
function getSourceImageInstanceUid(instance) {
|
|
||||||
// TODO= Parse the whole Source Image Sequence
|
|
||||||
// This is a really poor workaround for now.
|
|
||||||
// Later we should probably parse the whole sequence.
|
|
||||||
var SourceImageSequence = instance['00082112'];
|
|
||||||
if (
|
|
||||||
SourceImageSequence &&
|
|
||||||
SourceImageSequence.Value &&
|
|
||||||
SourceImageSequence.Value.length &&
|
|
||||||
SourceImageSequence.Value[0]['00081155'].Value
|
|
||||||
) {
|
|
||||||
return SourceImageSequence.Value[0]['00081155'].Value[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function makeSOPInstance(server, study, instance) {
|
|
||||||
const { studyInstanceUid } = study;
|
|
||||||
const seriesInstanceUid = DICOMWeb.getString(instance['0020000E']);
|
|
||||||
let series = study.seriesMap[seriesInstanceUid];
|
|
||||||
|
|
||||||
if (!series) {
|
|
||||||
series = {
|
|
||||||
seriesInstanceUid,
|
|
||||||
seriesDescription: DICOMWeb.getString(instance['0008103E']),
|
|
||||||
modality: DICOMWeb.getString(instance['00080060']),
|
|
||||||
seriesNumber: DICOMWeb.getNumber(instance['00200011']),
|
|
||||||
seriesDate: DICOMWeb.getString(instance['00080021']),
|
|
||||||
seriesTime: DICOMWeb.getString(instance['00080031']),
|
|
||||||
instances: [],
|
|
||||||
};
|
|
||||||
study.seriesMap[seriesInstanceUid] = series;
|
|
||||||
study.seriesList.push(series);
|
|
||||||
}
|
|
||||||
|
|
||||||
const sopInstanceUid = DICOMWeb.getString(instance['00080018']);
|
|
||||||
const wadouri = buildInstanceWadoUrl(
|
|
||||||
server,
|
|
||||||
studyInstanceUid,
|
|
||||||
seriesInstanceUid,
|
|
||||||
sopInstanceUid
|
|
||||||
);
|
|
||||||
const baseWadoRsUri = buildInstanceWadoRsUri(
|
|
||||||
server,
|
|
||||||
studyInstanceUid,
|
|
||||||
seriesInstanceUid,
|
|
||||||
sopInstanceUid
|
|
||||||
);
|
|
||||||
const wadorsuri = buildInstanceFrameWadoRsUri(
|
|
||||||
server,
|
|
||||||
studyInstanceUid,
|
|
||||||
seriesInstanceUid,
|
|
||||||
sopInstanceUid
|
|
||||||
);
|
|
||||||
|
|
||||||
const sopInstance = {
|
|
||||||
imageType: DICOMWeb.getString(instance['00080008']),
|
|
||||||
sopClassUid: DICOMWeb.getString(instance['00080016']),
|
|
||||||
modality: DICOMWeb.getString(instance['00080060']),
|
|
||||||
sopInstanceUid,
|
|
||||||
instanceNumber: DICOMWeb.getNumber(instance['00200013']),
|
|
||||||
imagePositionPatient: DICOMWeb.getString(instance['00200032']),
|
|
||||||
imageOrientationPatient: DICOMWeb.getString(instance['00200037']),
|
|
||||||
frameOfReferenceUID: DICOMWeb.getString(instance['00200052']),
|
|
||||||
sliceLocation: DICOMWeb.getNumber(instance['00201041']),
|
|
||||||
samplesPerPixel: DICOMWeb.getNumber(instance['00280002']),
|
|
||||||
photometricInterpretation: DICOMWeb.getString(instance['00280004']),
|
|
||||||
planarConfiguration: DICOMWeb.getNumber(instance['00280006']),
|
|
||||||
rows: DICOMWeb.getNumber(instance['00280010']),
|
|
||||||
columns: DICOMWeb.getNumber(instance['00280011']),
|
|
||||||
pixelSpacing: DICOMWeb.getString(instance['00280030']),
|
|
||||||
pixelAspectRatio: DICOMWeb.getString(instance['00280034']),
|
|
||||||
bitsAllocated: DICOMWeb.getNumber(instance['00280100']),
|
|
||||||
bitsStored: DICOMWeb.getNumber(instance['00280101']),
|
|
||||||
highBit: DICOMWeb.getNumber(instance['00280102']),
|
|
||||||
pixelRepresentation: DICOMWeb.getNumber(instance['00280103']),
|
|
||||||
smallestPixelValue: DICOMWeb.getNumber(instance['00280106']),
|
|
||||||
largestPixelValue: DICOMWeb.getNumber(instance['00280107']),
|
|
||||||
windowCenter: DICOMWeb.getString(instance['00281050']),
|
|
||||||
windowWidth: DICOMWeb.getString(instance['00281051']),
|
|
||||||
rescaleIntercept: DICOMWeb.getNumber(instance['00281052']),
|
|
||||||
rescaleSlope: DICOMWeb.getNumber(instance['00281053']),
|
|
||||||
rescaleType: DICOMWeb.getNumber(instance['00281054']),
|
|
||||||
sourceImageInstanceUid: getSourceImageInstanceUid(instance),
|
|
||||||
laterality: DICOMWeb.getString(instance['00200062']),
|
|
||||||
viewPosition: DICOMWeb.getString(instance['00185101']),
|
|
||||||
acquisitionDateTime: DICOMWeb.getString(instance['0008002A']),
|
|
||||||
numberOfFrames: DICOMWeb.getNumber(instance['00280008']),
|
|
||||||
frameIncrementPointer: getFrameIncrementPointer(instance['00280009']),
|
|
||||||
frameTime: DICOMWeb.getNumber(instance['00181063']),
|
|
||||||
frameTimeVector: parseFloatArray(DICOMWeb.getString(instance['00181065'])),
|
|
||||||
sliceThickness: DICOMWeb.getNumber(instance['00180050']),
|
|
||||||
spacingBetweenSlices: DICOMWeb.getString(instance['00180088']),
|
|
||||||
lossyImageCompression: DICOMWeb.getString(instance['00282110']),
|
|
||||||
derivationDescription: DICOMWeb.getString(instance['00282111']),
|
|
||||||
lossyImageCompressionRatio: DICOMWeb.getString(instance['00282112']),
|
|
||||||
lossyImageCompressionMethod: DICOMWeb.getString(instance['00282114']),
|
|
||||||
echoNumber: DICOMWeb.getString(instance['00180086']),
|
|
||||||
contrastBolusAgent: DICOMWeb.getString(instance['00180010']),
|
|
||||||
radiopharmaceuticalInfo: getRadiopharmaceuticalInfo(instance),
|
|
||||||
baseWadoRsUri: baseWadoRsUri,
|
|
||||||
wadouri: WADOProxy.convertURL(wadouri, server),
|
|
||||||
wadorsuri: WADOProxy.convertURL(wadorsuri, server),
|
|
||||||
wadoRoot: server.wadoRoot,
|
|
||||||
imageRendering: server.imageRendering,
|
|
||||||
thumbnailRendering: server.thumbnailRendering,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get additional information if the instance uses "PALETTE COLOR" photometric interpretation
|
|
||||||
if (sopInstance.photometricInterpretation === 'PALETTE COLOR') {
|
|
||||||
const redPaletteColorLookupTableDescriptor = parseFloatArray(
|
|
||||||
DICOMWeb.getString(instance['00281101'])
|
|
||||||
);
|
|
||||||
const greenPaletteColorLookupTableDescriptor = parseFloatArray(
|
|
||||||
DICOMWeb.getString(instance['00281102'])
|
|
||||||
);
|
|
||||||
const bluePaletteColorLookupTableDescriptor = parseFloatArray(
|
|
||||||
DICOMWeb.getString(instance['00281103'])
|
|
||||||
);
|
|
||||||
const palettes = await getPaletteColors(
|
|
||||||
server,
|
|
||||||
instance,
|
|
||||||
redPaletteColorLookupTableDescriptor
|
|
||||||
);
|
|
||||||
|
|
||||||
if (palettes) {
|
|
||||||
if (palettes.uid) {
|
|
||||||
sopInstance.paletteColorLookupTableUID = palettes.uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
sopInstance.redPaletteColorLookupTableData = palettes.red;
|
|
||||||
sopInstance.greenPaletteColorLookupTableData = palettes.green;
|
|
||||||
sopInstance.bluePaletteColorLookupTableData = palettes.blue;
|
|
||||||
sopInstance.redPaletteColorLookupTableDescriptor = redPaletteColorLookupTableDescriptor;
|
|
||||||
sopInstance.greenPaletteColorLookupTableDescriptor = greenPaletteColorLookupTableDescriptor;
|
|
||||||
sopInstance.bluePaletteColorLookupTableDescriptor = bluePaletteColorLookupTableDescriptor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
series.instances.push(sopInstance);
|
|
||||||
return sopInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPaletteColor(server, instance, tag, lutDescriptor) {
|
|
||||||
const numLutEntries = lutDescriptor[0];
|
|
||||||
const bits = lutDescriptor[2];
|
|
||||||
|
|
||||||
let uri = WADOProxy.convertURL(instance[tag].BulkDataURI, server);
|
|
||||||
|
|
||||||
// TODO: Workaround for dcm4chee behind SSL-terminating proxy returning
|
|
||||||
// incorrect bulk data URIs
|
|
||||||
if (server.wadoRoot.indexOf('https') === 0 && !uri.includes('https')) {
|
|
||||||
uri = uri.replace('http', 'https');
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
url: server.wadoRoot, //BulkDataURI is absolute, so this isn't used
|
|
||||||
headers: DICOMWeb.getAuthorizationHeader(server),
|
|
||||||
};
|
|
||||||
const dicomWeb = new api.DICOMwebClient(config);
|
|
||||||
const options = {
|
|
||||||
BulkDataURI: uri,
|
|
||||||
};
|
|
||||||
|
|
||||||
const readUInt16 = (byteArray, position) => {
|
|
||||||
return byteArray[position] + byteArray[position + 1] * 256;
|
|
||||||
};
|
|
||||||
|
|
||||||
const arrayBufferToPaletteColorLUT = result => {
|
|
||||||
const arraybuffer = result[0];
|
|
||||||
const byteArray = new Uint8Array(arraybuffer);
|
|
||||||
const lut = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < numLutEntries; i++) {
|
|
||||||
if (bits === 16) {
|
|
||||||
lut[i] = readUInt16(byteArray, i * 2);
|
|
||||||
} else {
|
|
||||||
lut[i] = byteArray[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lut;
|
|
||||||
};
|
|
||||||
|
|
||||||
return dicomWeb.retrieveBulkData(options).then(arrayBufferToPaletteColorLUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch palette colors for instances with "PALETTE COLOR" photometricInterpretation.
|
|
||||||
*
|
|
||||||
* @param server {Object} Current server;
|
|
||||||
* @param instance {Object} The retrieved instance metadata;
|
|
||||||
* @returns {String} The ReferenceSOPInstanceUID
|
|
||||||
*/
|
|
||||||
async function getPaletteColors(server, instance, lutDescriptor) {
|
|
||||||
let paletteUID = DICOMWeb.getString(instance['00281199']);
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let entry;
|
|
||||||
if (paletteColorCache.isValidUID(paletteUID)) {
|
|
||||||
entry = paletteColorCache.get(paletteUID);
|
|
||||||
|
|
||||||
if (entry) {
|
|
||||||
return resolve(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no entry in cache... Fetch remote data.
|
|
||||||
const r = getPaletteColor(server, instance, '00281201', lutDescriptor);
|
|
||||||
const g = getPaletteColor(server, instance, '00281202', lutDescriptor);
|
|
||||||
const b = getPaletteColor(server, instance, '00281203', lutDescriptor);
|
|
||||||
|
|
||||||
const promises = [r, g, b];
|
|
||||||
|
|
||||||
Promise.all(promises).then(args => {
|
|
||||||
entry = {
|
|
||||||
red: args[0],
|
|
||||||
green: args[1],
|
|
||||||
blue: args[2],
|
|
||||||
};
|
|
||||||
|
|
||||||
// when paletteUID is present, the entry can be cached...
|
|
||||||
entry.uid = paletteUID;
|
|
||||||
paletteColorCache.add(entry);
|
|
||||||
|
|
||||||
resolve(entry);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a list of SOP Instances to a given study object descriptor
|
|
||||||
* @param {Object} server Object with server configuration parameters
|
|
||||||
* @param {Object} study The study descriptor to which the given SOP instances will be added
|
|
||||||
* @param {Array} sopInstanceList A list of SOP instance objects
|
|
||||||
*/
|
|
||||||
async function addInstancesToStudy(server, study, sopInstanceList) {
|
|
||||||
return Promise.all(
|
|
||||||
sopInstanceList.map(function(sopInstance) {
|
|
||||||
return makeSOPInstance(server, study, sopInstance);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const createStudyFromSOPInstanceList = async (server, sopInstanceList) => {
|
|
||||||
if (Array.isArray(sopInstanceList) && sopInstanceList.length > 0) {
|
|
||||||
const firstSopInstance = sopInstanceList[0];
|
|
||||||
const study = createStudy(server, firstSopInstance);
|
|
||||||
await addInstancesToStudy(server, study, sopInstanceList);
|
|
||||||
return study;
|
|
||||||
}
|
|
||||||
throw new Error('Failed to create study out of provided SOP instance list');
|
|
||||||
};
|
|
||||||
|
|
||||||
export { createStudyFromSOPInstanceList, addInstancesToStudy };
|
|
||||||
@@ -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.1.7](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.1.6...@ohif/ui@1.1.7) (2019-12-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/ui
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.1.6](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.1.5...@ohif/ui@1.1.6) (2019-12-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/ui
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.1.5](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.1.4...@ohif/ui@1.1.5) (2019-12-19)
|
## [1.1.5](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.1.4...@ohif/ui@1.1.5) (2019-12-19)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/ui",
|
"name": "@ohif/ui",
|
||||||
"version": "1.1.5",
|
"version": "1.1.7",
|
||||||
"description": "A set of React components for Medical Imaging Viewers",
|
"description": "A set of React components for Medical Imaging Viewers",
|
||||||
"author": "OHIF Contributors",
|
"author": "OHIF Contributors",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -79,7 +79,11 @@ class MeasurementTable extends Component {
|
|||||||
</ScrollableArea>
|
</ScrollableArea>
|
||||||
<div className="measurementTableFooter">
|
<div className="measurementTableFooter">
|
||||||
{saveFunction && (
|
{saveFunction && (
|
||||||
<button onClick={this.saveFunction} className="saveBtn">
|
<button
|
||||||
|
onClick={this.saveFunction}
|
||||||
|
className="saveBtn"
|
||||||
|
data-cy="save-measurements-btn"
|
||||||
|
>
|
||||||
<Icon name="save" width="14px" height="14px" />
|
<Icon name="save" width="14px" height="14px" />
|
||||||
Save measurements
|
Save measurements
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ const renderTabsHeader = (tabs, activeTabIndex, onHeaderChanged) => {
|
|||||||
? tabs.map((tab, index) => {
|
? tabs.map((tab, index) => {
|
||||||
const { name, hidden = false } = tab;
|
const { name, hidden = false } = tab;
|
||||||
|
|
||||||
|
const cypressSelectorId = name.toLowerCase();
|
||||||
const tabClass =
|
const tabClass =
|
||||||
index === activeTabIndex ? 'nav-link active' : 'nav-link';
|
index === activeTabIndex ? 'nav-link active' : 'nav-link';
|
||||||
return !hidden ? (
|
return !hidden ? (
|
||||||
@@ -52,6 +53,7 @@ const renderTabsHeader = (tabs, activeTabIndex, onHeaderChanged) => {
|
|||||||
onHeaderChanged(index);
|
onHeaderChanged(index);
|
||||||
}}
|
}}
|
||||||
className={tabClass}
|
className={tabClass}
|
||||||
|
data-cy={cypressSelectorId}
|
||||||
>
|
>
|
||||||
<button>{name}</button>
|
<button>{name}</button>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -23,8 +23,14 @@ export function ToolbarButton(props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const cypressSelectorId = props.label.toLowerCase();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className} onClick={handleClick}>
|
<div
|
||||||
|
className={className}
|
||||||
|
onClick={handleClick}
|
||||||
|
data-cy={cypressSelectorId}
|
||||||
|
>
|
||||||
{iconProps && <Icon {...iconProps} />}
|
{iconProps && <Icon {...iconProps} />}
|
||||||
<div className="toolbar-button-label">
|
<div className="toolbar-button-label">
|
||||||
{t(label)}
|
{t(label)}
|
||||||
|
|||||||
@@ -3,6 +3,60 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
## [3.3.5](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.3.4...@ohif/viewer@3.3.5) (2020-01-06)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.3.4](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.3.3...@ohif/viewer@3.3.4) (2019-12-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.3.3](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.3.2...@ohif/viewer@3.3.3) (2019-12-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 🐛 1241: Make Plugin switch part of ToolbarModule ([#1322](https://github.com/OHIF/Viewers/issues/1322)) ([6540e36](https://github.com/OHIF/Viewers/commit/6540e36818944ac2eccc696186366ae495b33a04)), closes [#1241](https://github.com/OHIF/Viewers/issues/1241)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.3.2](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.3.1...@ohif/viewer@3.3.2) (2019-12-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.3.1](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.3.0...@ohif/viewer@3.3.1) (2019-12-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/viewer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [3.3.0](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.2.2...@ohif/viewer@3.3.0) (2019-12-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 Configuration so viewer tools can nix handles ([#1304](https://github.com/OHIF/Viewers/issues/1304)) ([63594d3](https://github.com/OHIF/Viewers/commit/63594d36b0bdba59f0901095aed70b75fb05172d)), closes [#1223](https://github.com/OHIF/Viewers/issues/1223)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [3.2.2](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.2.1...@ohif/viewer@3.2.2) (2019-12-19)
|
## [3.2.2](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.2.1...@ohif/viewer@3.2.2) (2019-12-19)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ describe('OHIF Cornerstone Toolbar', () => {
|
|||||||
|
|
||||||
let iconName;
|
let iconName;
|
||||||
//Click on one of the secondary tools from the overlay
|
//Click on one of the secondary tools from the overlay
|
||||||
cy.get('.tooltip-inner > :nth-child(1)')
|
cy.get('[data-cy="magnify"]')
|
||||||
.click()
|
.click()
|
||||||
.then($magnifyBtn => {
|
.then($magnifyBtn => {
|
||||||
cy.wrap($magnifyBtn)
|
cy.wrap($magnifyBtn)
|
||||||
@@ -407,9 +407,7 @@ describe('OHIF Cornerstone Toolbar', () => {
|
|||||||
.as('toolbarOverlay')
|
.as('toolbarOverlay')
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
//Click on Clear button
|
//Click on Clear button
|
||||||
cy.get('.tooltip-inner')
|
cy.get('[data-cy="clear"]').click();
|
||||||
.contains('Clear')
|
|
||||||
.click();
|
|
||||||
|
|
||||||
//Verify if measurements were removed from the measurements panel
|
//Verify if measurements were removed from the measurements panel
|
||||||
cy.get('.measurementItem').should('not.exist');
|
cy.get('.measurementItem').should('not.exist');
|
||||||
@@ -446,9 +444,7 @@ describe('OHIF Cornerstone Toolbar', () => {
|
|||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.then(() => {
|
.then(() => {
|
||||||
//Click Eraser button
|
//Click Eraser button
|
||||||
cy.get('.tooltip-inner')
|
cy.get('[data-cy="eraser"]').click({ force: true });
|
||||||
.contains('Eraser')
|
|
||||||
.click({ force: true });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//Erase measurement #1 and Verify if it was removed from the measurements panel
|
//Erase measurement #1 and Verify if it was removed from the measurements panel
|
||||||
@@ -471,9 +467,7 @@ describe('OHIF Cornerstone Toolbar', () => {
|
|||||||
cy.get('.tooltip-toolbar-overlay').should('be.visible');
|
cy.get('.tooltip-toolbar-overlay').should('be.visible');
|
||||||
|
|
||||||
// Click on Invert button
|
// Click on Invert button
|
||||||
cy.get('.tooltip-inner')
|
cy.get('[data-cy="invert"]').click();
|
||||||
.contains('Invert')
|
|
||||||
.click();
|
|
||||||
|
|
||||||
// Visual comparison
|
// Visual comparison
|
||||||
cy.screenshot('Invert tool - Should Invert Canvas');
|
cy.screenshot('Invert tool - Should Invert Canvas');
|
||||||
@@ -488,9 +482,7 @@ describe('OHIF Cornerstone Toolbar', () => {
|
|||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.then(() => {
|
.then(() => {
|
||||||
//Click on Rotate button
|
//Click on Rotate button
|
||||||
cy.get('.tooltip-inner')
|
cy.get('[data-cy="rotate right"]').click({ force: true });
|
||||||
.contains('Rotate')
|
|
||||||
.click({ force: true });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Visual comparison
|
// Visual comparison
|
||||||
@@ -505,9 +497,7 @@ describe('OHIF Cornerstone Toolbar', () => {
|
|||||||
cy.get('.tooltip-toolbar-overlay').should('be.visible');
|
cy.get('.tooltip-toolbar-overlay').should('be.visible');
|
||||||
|
|
||||||
//Click on Flip H button
|
//Click on Flip H button
|
||||||
cy.get('.tooltip-inner')
|
cy.get('[data-cy="flip h"]').click();
|
||||||
.contains('Flip H')
|
|
||||||
.click();
|
|
||||||
|
|
||||||
// Visual comparison
|
// Visual comparison
|
||||||
cy.screenshot('Flip H tool - Should Flip Image on Y axis');
|
cy.screenshot('Flip H tool - Should Flip Image on Y axis');
|
||||||
@@ -521,9 +511,7 @@ describe('OHIF Cornerstone Toolbar', () => {
|
|||||||
cy.get('.tooltip-toolbar-overlay').should('be.visible');
|
cy.get('.tooltip-toolbar-overlay').should('be.visible');
|
||||||
|
|
||||||
//Click on Flip V button
|
//Click on Flip V button
|
||||||
cy.get('.tooltip-inner')
|
cy.get('[data-cy="flip v"]').click();
|
||||||
.contains('Flip V')
|
|
||||||
.click();
|
|
||||||
|
|
||||||
// Visual comparison
|
// Visual comparison
|
||||||
cy.screenshot('Flip V tool - Should Flip Image on X axis');
|
cy.screenshot('Flip V tool - Should Flip Image on X axis');
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
//We are keeping the hardcoded results values for the study list tests
|
//We are keeping the hardcoded results values for the study list tests
|
||||||
//this is intended to be running in a controled docker environment with test data.
|
//this is intended to be running in a controled docker environment with test data.
|
||||||
describe('OHIF Study List', function () {
|
describe('OHIF Study List', function() {
|
||||||
context('Desktop resolution', function () {
|
context('Desktop resolution', function() {
|
||||||
beforeEach(function () {
|
beforeEach(function() {
|
||||||
cy.viewport(1750, 720);
|
cy.viewport(1750, 720);
|
||||||
cy.openStudyList();
|
cy.openStudyList();
|
||||||
cy.initStudyListAliasesOnDesktop();
|
cy.initStudyListAliasesOnDesktop();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('searches Patient Name with exact string', function () {
|
it('searches Patient Name with exact string', function() {
|
||||||
cy.get('@patientName').type('Juno');
|
cy.get('@patientName').type('Juno');
|
||||||
//Wait result list to be displayed
|
//Wait result list to be displayed
|
||||||
cy.waitStudyList();
|
cy.waitStudyList();
|
||||||
@@ -18,7 +18,7 @@ describe('OHIF Study List', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('searches MRN with exact string', function () {
|
it('searches MRN with exact string', function() {
|
||||||
cy.get('@MRN').type('ProstateX-0000');
|
cy.get('@MRN').type('ProstateX-0000');
|
||||||
//Wait result list to be displayed
|
//Wait result list to be displayed
|
||||||
cy.waitStudyList();
|
cy.waitStudyList();
|
||||||
@@ -28,7 +28,7 @@ describe('OHIF Study List', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('searches Accession with exact string', function () {
|
it('searches Accession with exact string', function() {
|
||||||
cy.get('@accessionNumber').type('fpcben98890');
|
cy.get('@accessionNumber').type('fpcben98890');
|
||||||
//Wait result list to be displayed
|
//Wait result list to be displayed
|
||||||
cy.waitStudyList();
|
cy.waitStudyList();
|
||||||
@@ -38,17 +38,17 @@ describe('OHIF Study List', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('searches Modality with camel case', function () {
|
it('searches Modality with camel case', function() {
|
||||||
cy.get('@modalities').type('Mr');
|
cy.get('@modalities').type('Mr');
|
||||||
//Wait result list to be displayed
|
//Wait result list to be displayed
|
||||||
cy.waitStudyList();
|
cy.waitStudyList();
|
||||||
cy.get('@searchResult').should($list => {
|
cy.get('@searchResult').should($list => {
|
||||||
expect($list.length).to.be.eq(18);
|
expect($list.length).to.be.eq(17);
|
||||||
expect($list).to.contain('MR');
|
expect($list).to.contain('MR');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('searches Description with exact string', function () {
|
it('searches Description with exact string', function() {
|
||||||
cy.get('@studyDescription').type('CHEST');
|
cy.get('@studyDescription').type('CHEST');
|
||||||
//Wait result list to be displayed
|
//Wait result list to be displayed
|
||||||
cy.waitStudyList();
|
cy.waitStudyList();
|
||||||
@@ -58,7 +58,7 @@ describe('OHIF Study List', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('changes rows per page and checks the study count', function () {
|
it('changes rows per page and checks the study count', function() {
|
||||||
//Show rows per page options
|
//Show rows per page options
|
||||||
const pageRows = [25, 50, 100];
|
const pageRows = [25, 50, 100];
|
||||||
|
|
||||||
@@ -100,14 +100,14 @@ describe('OHIF Study List', function () {
|
|||||||
// });
|
// });
|
||||||
});
|
});
|
||||||
|
|
||||||
context('Tablet resolution', function () {
|
context('Tablet resolution', function() {
|
||||||
beforeEach(function () {
|
beforeEach(function() {
|
||||||
cy.viewport(1000, 660);
|
cy.viewport(1000, 660);
|
||||||
cy.openStudyList();
|
cy.openStudyList();
|
||||||
cy.initStudyListAliasesOnTablet();
|
cy.initStudyListAliasesOnTablet();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('searches Patient Name with exact string', function () {
|
it('searches Patient Name with exact string', function() {
|
||||||
cy.get('@patientNameOrMRN').type('Juno');
|
cy.get('@patientNameOrMRN').type('Juno');
|
||||||
//Wait result list to be displayed
|
//Wait result list to be displayed
|
||||||
cy.waitStudyList();
|
cy.waitStudyList();
|
||||||
@@ -117,7 +117,7 @@ describe('OHIF Study List', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('searches MRN with with exact string', function () {
|
it('searches MRN with with exact string', function() {
|
||||||
cy.get('@patientNameOrMRN').type('ProstateX-0000');
|
cy.get('@patientNameOrMRN').type('ProstateX-0000');
|
||||||
//Wait result list to be displayed
|
//Wait result list to be displayed
|
||||||
cy.waitStudyList();
|
cy.waitStudyList();
|
||||||
@@ -127,17 +127,17 @@ describe('OHIF Study List', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('searches Modality with exact string', function () {
|
it('searches Modality with exact string', function() {
|
||||||
cy.get('@accessionModalityDescription').type('MR');
|
cy.get('@accessionModalityDescription').type('MR');
|
||||||
//Wait result list to be displayed
|
//Wait result list to be displayed
|
||||||
cy.waitStudyList();
|
cy.waitStudyList();
|
||||||
cy.get('@searchResult').should($list => {
|
cy.get('@searchResult').should($list => {
|
||||||
expect($list.length).to.be.eq(18);
|
expect($list.length).to.be.eq(17);
|
||||||
expect($list).to.contain('MR');
|
expect($list).to.contain('MR');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('searches Accession with exact string', function () {
|
it('searches Accession with exact string', function() {
|
||||||
cy.get('@accessionModalityDescription').type('fpcben98890');
|
cy.get('@accessionModalityDescription').type('fpcben98890');
|
||||||
//Wait result list to be displayed
|
//Wait result list to be displayed
|
||||||
cy.waitStudyList();
|
cy.waitStudyList();
|
||||||
@@ -147,7 +147,7 @@ describe('OHIF Study List', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('searches Description with exact string', function () {
|
it('searches Description with exact string', function() {
|
||||||
cy.get('@accessionModalityDescription').type('CHEST');
|
cy.get('@accessionModalityDescription').type('CHEST');
|
||||||
//Wait result list to be displayed
|
//Wait result list to be displayed
|
||||||
cy.waitStudyList();
|
cy.waitStudyList();
|
||||||
@@ -157,7 +157,7 @@ describe('OHIF Study List', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('changes rows per page and checks the study count', function () {
|
it('changes rows per page and checks the study count', function() {
|
||||||
//Show rows per page options
|
//Show rows per page options
|
||||||
const pageRows = [25, 50, 100];
|
const pageRows = [25, 50, 100];
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,9 @@ describe('OHIF VTK Extension', () => {
|
|||||||
cy.get('[data-cy="thumbnail-list"]')
|
cy.get('[data-cy="thumbnail-list"]')
|
||||||
.contains('CT WB 5.0 B35f')
|
.contains('CT WB 5.0 B35f')
|
||||||
.drag('.viewport-drop-target')
|
.drag('.viewport-drop-target')
|
||||||
.wait(1000); // TODO: Once issue #1167 is fixed, the wait command should be removed. (https://github.com/OHIF/Viewers/issues/1167)
|
|
||||||
|
|
||||||
//Select 2D MPR button
|
//Select 2D MPR button
|
||||||
cy.get('.PluginSwitch > .toolbar-button').click();
|
cy.get('[data-cy="2d mpr"]').click();
|
||||||
|
|
||||||
//Wait Reformatting Images
|
//Wait Reformatting Images
|
||||||
cy.waitVTKReformatting();
|
cy.waitVTKReformatting();
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
describe('OHIF Save Measurements', function() {
|
||||||
|
before(() => {
|
||||||
|
cy.openStudy('Fall 1');
|
||||||
|
cy.expectMinimumThumbnails(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// Drags Study thumbnail into viewport
|
||||||
|
cy.get('[data-cy="thumbnail-list"]:nth-child(1)')
|
||||||
|
.scrollIntoView()
|
||||||
|
.drag('.viewport-drop-target');
|
||||||
|
|
||||||
|
// Wait image to load on viewport
|
||||||
|
cy.wait(2000);
|
||||||
|
|
||||||
|
cy.resetViewport();
|
||||||
|
cy.initCommonElementsAliases();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('saves new measurement annotation', function() {
|
||||||
|
// Add measurement in the viewport
|
||||||
|
cy.addLengthMeasurement();
|
||||||
|
|
||||||
|
// Verify if measurement annotation was added into the measurements panel
|
||||||
|
cy.get('@measurementsBtn').click();
|
||||||
|
cy.get('.measurementItem')
|
||||||
|
.its('length')
|
||||||
|
.should('be.at.least', 1);
|
||||||
|
|
||||||
|
// Save new measurement
|
||||||
|
cy.get('[data-cy="save-measurements-btn"]').click();
|
||||||
|
|
||||||
|
// Verify that success message overlay is displayed
|
||||||
|
cy.get('.sb-success')
|
||||||
|
.should('be.visible')
|
||||||
|
.and('contains.text', 'Measurements were saved with success');
|
||||||
|
|
||||||
|
// Visual test comparison
|
||||||
|
cy.screenshot('Save Measurements - new measurement added');
|
||||||
|
cy.percyCanvasSnapshot('Save Measurements - new measurement added');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('retrieves saved measurements', function() {
|
||||||
|
// Add measurement in the viewport
|
||||||
|
cy.addLengthMeasurement();
|
||||||
|
|
||||||
|
// Verify if measurement annotation was added into the measurements panel
|
||||||
|
cy.get('@measurementsBtn').click();
|
||||||
|
cy.get('.measurementDisplayText') // Get label size of the recently added measurement
|
||||||
|
.last()
|
||||||
|
.then($measurementSizeLabel => {
|
||||||
|
// Save new measurement
|
||||||
|
cy.get('[data-cy="save-measurements-btn"]').click();
|
||||||
|
|
||||||
|
// Verify that success message overlay is displayed
|
||||||
|
cy.get('.sb-success').should('be.visible');
|
||||||
|
|
||||||
|
// Reload the page
|
||||||
|
cy.reload();
|
||||||
|
|
||||||
|
//Verify that recently added measurement was retrieved
|
||||||
|
cy.get('@measurementsBtn').click();
|
||||||
|
cy.get('.measurementDisplayText') // Get label size of the recently added measurement
|
||||||
|
.last()
|
||||||
|
.then($retrivedMeasurementSizeLabel => {
|
||||||
|
expect($retrivedMeasurementSizeLabel.textContent).to.eq(
|
||||||
|
$measurementSizeLabel.textContent
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('checks error message when saving without any measurement', function() {
|
||||||
|
// Checks that measurement list is empty
|
||||||
|
cy.get('.numberOfItems').should('have.text', '0');
|
||||||
|
|
||||||
|
// Click on Save Measurement button
|
||||||
|
cy.get('[data-cy="save-measurements-btn"]').click();
|
||||||
|
|
||||||
|
// Verify that error message overlay is displayed
|
||||||
|
cy.get('.sb-error')
|
||||||
|
.should('be.visible')
|
||||||
|
.and('contains.text', 'Error while saving the measurements');
|
||||||
|
// Close message overlay
|
||||||
|
cy.get('.sb-closeIcon').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('checks if warning message is displayed on measurements of unsupported tools', function() {
|
||||||
|
// Add measurement for unsupported tool in the viewport
|
||||||
|
cy.addAngleMeasurement();
|
||||||
|
|
||||||
|
// Verify if measurement annotation was added into the measurements panel
|
||||||
|
cy.get('@measurementsBtn').click();
|
||||||
|
cy.get('.measurementItem')
|
||||||
|
.its('length')
|
||||||
|
.should('be.at.least', 1);
|
||||||
|
|
||||||
|
// Check that warning is displayed for unsupported tool
|
||||||
|
cy.get('.hasWarnings').should('be.visible');
|
||||||
|
|
||||||
|
// Save new measurement
|
||||||
|
cy.get('[data-cy="save-measurements-btn"]').click();
|
||||||
|
|
||||||
|
// Verify that error message overlay is displayed
|
||||||
|
cy.get('.sb-error')
|
||||||
|
.should('be.visible')
|
||||||
|
.and('contains.text', 'Error while saving the measurements');
|
||||||
|
// Close message overlay
|
||||||
|
cy.get('.sb-closeIcon').click();
|
||||||
|
// Close Measurements panel
|
||||||
|
cy.get('@measurementsBtn').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('checks if measurements of unsupported tools were not saved', function() {
|
||||||
|
// Add measurement for supported tool in the viewport
|
||||||
|
cy.addLengthMeasurement();
|
||||||
|
// Add measurement for unsupported tool in the viewport
|
||||||
|
cy.addAngleMeasurement();
|
||||||
|
|
||||||
|
// Verify if measurement annotation was added into the measurements panel
|
||||||
|
cy.get('@measurementsBtn').click();
|
||||||
|
cy.get('.measurementItem')
|
||||||
|
.its('length')
|
||||||
|
.should('be.eq', 2);
|
||||||
|
|
||||||
|
// Check that warning is displayed for unsupported tool
|
||||||
|
cy.get('.hasWarnings').should('be.visible');
|
||||||
|
|
||||||
|
// Save new measurement
|
||||||
|
cy.get('[data-cy="save-measurements-btn"]').click();
|
||||||
|
|
||||||
|
// Verify that success message overlay is displayed
|
||||||
|
cy.get('.sb-success')
|
||||||
|
.should('be.visible')
|
||||||
|
.and('contains.text', 'Measurements were saved with success');
|
||||||
|
|
||||||
|
// Reload the page
|
||||||
|
cy.reload();
|
||||||
|
|
||||||
|
//Verify that measurement for unsupported tool was not saved
|
||||||
|
cy.get('@measurementsBtn').click();
|
||||||
|
cy.get('.measurementItem')
|
||||||
|
.its('length')
|
||||||
|
.should('be.eq', 1);
|
||||||
|
|
||||||
|
// Close Measurements panel
|
||||||
|
cy.get('@measurementsBtn').click();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
//Creating aliases for Cornerstone tools buttons
|
//Creating aliases for Cornerstone tools buttons
|
||||||
export function initCornerstoneToolsAliases() {
|
export function initCornerstoneToolsAliases() {
|
||||||
cy.get('.ToolbarRow > :nth-child(2)').as('stackScrollBtn');
|
cy.get('[data-cy="stack scroll"]').as('stackScrollBtn');
|
||||||
cy.get('.ToolbarRow > :nth-child(3)').as('zoomBtn');
|
cy.get('[data-cy="zoom"]').as('zoomBtn');
|
||||||
cy.get('.ToolbarRow > :nth-child(4)').as('levelsBtn');
|
cy.get('[data-cy="levels"]').as('levelsBtn');
|
||||||
cy.get('.ToolbarRow > :nth-child(5)').as('panBtn');
|
cy.get('[data-cy="pan"]').as('panBtn');
|
||||||
cy.get('.ToolbarRow > :nth-child(6)').as('lengthBtn');
|
cy.get('[data-cy="length"]').as('lengthBtn');
|
||||||
cy.get('.ToolbarRow > :nth-child(7)').as('annotateBtn');
|
cy.get('[data-cy="annotate"]').as('annotateBtn');
|
||||||
cy.get('.ToolbarRow > :nth-child(8)').as('angleBtn');
|
cy.get('[data-cy="angle"]').as('angleBtn');
|
||||||
cy.get('.ToolbarRow > :nth-child(9)').as('resetBtn');
|
cy.get('[data-cy="reset"]').as('resetBtn');
|
||||||
cy.get('.ToolbarRow > :nth-child(10)').as('cineBtn');
|
cy.get('[data-cy="cine"]').as('cineBtn');
|
||||||
cy.get('.expandableToolMenu').as('moreBtn');
|
cy.get('[data-cy="more"]').as('moreBtn');
|
||||||
cy.get('.btn-group > .toolbar-button').as('layoutBtn');
|
cy.get('[data-cy="layout"]').as('layoutBtn');
|
||||||
cy.get('.viewport-element').as('viewport');
|
cy.get('.viewport-element').as('viewport');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,14 +44,14 @@ export function initRouteAliases() {
|
|||||||
|
|
||||||
//Creating aliases for VTK tools buttons
|
//Creating aliases for VTK tools buttons
|
||||||
export function initVTKToolsAliases() {
|
export function initVTKToolsAliases() {
|
||||||
cy.get('.PluginSwitch > .toolbar-button').as('twodmprBtn');
|
cy.get('[data-cy="exit 2d mpr"]').as('exit2dmprBtn');
|
||||||
cy.get('.ToolbarRow > :nth-child(2)').as('crosshairsBtn');
|
cy.get('[data-cy="crosshairs"]').as('crosshairsBtn');
|
||||||
cy.get('.ToolbarRow > :nth-child(3)').as('wwwcBtn');
|
cy.get('[data-cy="wwwc"]').as('wwwcBtn');
|
||||||
cy.get('.ToolbarRow > :nth-child(4)').as('rotateBtn');
|
cy.get('[data-cy="rotate"]').as('rotateBtn');
|
||||||
cy.get('.slab-thickness').as('slabSlider');
|
cy.get('.slab-thickness').as('slabSlider');
|
||||||
cy.get('.select-ohif').as('modeDropdown');
|
cy.get('.select-ohif').as('modeDropdown');
|
||||||
cy.get('.ohif-check-label').as('modeCheckbox');
|
cy.get('.ohif-check-label').as('modeCheckbox');
|
||||||
cy.get('.btn-group > .toolbar-button').as('layoutBtn');
|
cy.get('[data-cy="layout"]').as('layoutBtn');
|
||||||
}
|
}
|
||||||
|
|
||||||
//Creating aliases for Study List page elements on Desktop experience
|
//Creating aliases for Study List page elements on Desktop experience
|
||||||
@@ -82,12 +82,8 @@ export function initStudyListAliasesOnTablet() {
|
|||||||
//Creating aliases for User Preferences modal
|
//Creating aliases for User Preferences modal
|
||||||
export function initPreferencesModalAliases() {
|
export function initPreferencesModalAliases() {
|
||||||
cy.get('.OHIFModal').as('preferencesModal');
|
cy.get('.OHIFModal').as('preferencesModal');
|
||||||
cy.get('.nav-link')
|
cy.get('[data-cy="hotkeys"]').as('userPreferencesHotkeysTab');
|
||||||
.first()
|
cy.get('[data-cy="general"]').as('userPreferencesGeneralTab');
|
||||||
.as('userPreferencesHotkeysTab');
|
|
||||||
cy.get('.nav-link')
|
|
||||||
.last()
|
|
||||||
.as('userPreferencesGeneralTab');
|
|
||||||
cy.get('[data-cy="reset-default-btn"]').as('restoreBtn');
|
cy.get('[data-cy="reset-default-btn"]').as('restoreBtn');
|
||||||
cy.get('[data-cy="cancel-btn"]').as('cancelBtn');
|
cy.get('[data-cy="cancel-btn"]').as('cancelBtn');
|
||||||
cy.get('[data-cy="save-btn"]').as('saveBtn');
|
cy.get('[data-cy="save-btn"]').as('saveBtn');
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ Cypress.Commands.add('waitDicomImage', (timeout = 20000) => {
|
|||||||
//Command to reset and clear all the changes made to the viewport
|
//Command to reset and clear all the changes made to the viewport
|
||||||
Cypress.Commands.add('resetViewport', () => {
|
Cypress.Commands.add('resetViewport', () => {
|
||||||
//Click on More button
|
//Click on More button
|
||||||
cy.get('.expandableToolMenu')
|
cy.get('[data-cy="more"]')
|
||||||
.as('moreBtn')
|
.as('moreBtn')
|
||||||
.click();
|
.click();
|
||||||
//Verify if overlay is displayed
|
//Verify if overlay is displayed
|
||||||
@@ -219,11 +219,11 @@ Cypress.Commands.add('resetViewport', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
//Click on Clear button
|
//Click on Clear button
|
||||||
cy.get('.tooltip-inner > :nth-child(10)')
|
cy.get('[data-cy="clear"]')
|
||||||
.as('clearBtn')
|
.as('clearBtn')
|
||||||
.click();
|
.click();
|
||||||
//Click on Reset button
|
//Click on Reset button
|
||||||
cy.get('.ToolbarRow > :nth-child(9)')
|
cy.get('[data-cy="reset"]')
|
||||||
.as('resetBtn')
|
.as('resetBtn')
|
||||||
.click();
|
.click();
|
||||||
});
|
});
|
||||||
@@ -284,9 +284,8 @@ Cypress.Commands.add('initStudyListAliasesOnTablet', () => {
|
|||||||
Cypress.Commands.add(
|
Cypress.Commands.add(
|
||||||
'addLengthMeasurement',
|
'addLengthMeasurement',
|
||||||
(firstClick = [150, 100], secondClick = [130, 170]) => {
|
(firstClick = [150, 100], secondClick = [130, 170]) => {
|
||||||
cy.initCornerstoneToolsAliases();
|
cy.get('[data-cy="length"]').click();
|
||||||
cy.get('@lengthBtn').click();
|
cy.addLine('.viewport-element', firstClick, secondClick);
|
||||||
cy.addLine('@viewport', firstClick, secondClick);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -294,9 +293,8 @@ Cypress.Commands.add(
|
|||||||
Cypress.Commands.add(
|
Cypress.Commands.add(
|
||||||
'addAngleMeasurement',
|
'addAngleMeasurement',
|
||||||
(initPos = [180, 390], midPos = [300, 410], finalPos = [180, 450]) => {
|
(initPos = [180, 390], midPos = [300, 410], finalPos = [180, 450]) => {
|
||||||
cy.initCornerstoneToolsAliases();
|
cy.get('[data-cy="angle"]').click();
|
||||||
cy.get('@angleBtn').click();
|
cy.addAngle('.viewport-element', initPos, midPos, finalPos);
|
||||||
cy.addAngle('@viewport', initPos, midPos, finalPos);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -369,7 +367,7 @@ Cypress.Commands.add('percyCanvasSnapshot', (name, options = {}) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('setLayout', (columns = 1, rows = 1) => {
|
Cypress.Commands.add('setLayout', (columns = 1, rows = 1) => {
|
||||||
cy.get('.btn-group > .toolbar-button').click();
|
cy.get('[data-cy="layout"]').click();
|
||||||
|
|
||||||
cy.get('.layoutChooser')
|
cy.get('.layoutChooser')
|
||||||
.find('tr')
|
.find('tr')
|
||||||
@@ -471,12 +469,12 @@ Cypress.Commands.add(
|
|||||||
|
|
||||||
Cypress.Commands.add('openDownloadImageModal', () => {
|
Cypress.Commands.add('openDownloadImageModal', () => {
|
||||||
// Click on More button
|
// Click on More button
|
||||||
cy.get('.expandableToolMenu')
|
cy.get('[data-cy="more"]')
|
||||||
.as('moreBtn')
|
.as('moreBtn')
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
// Click on Download button
|
// Click on Download button
|
||||||
cy.get('.tooltip-inner > :nth-child(13)')
|
cy.get('[data-cy="download"]')
|
||||||
.as('downloadBtn')
|
.as('downloadBtn')
|
||||||
.click();
|
.click();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/viewer",
|
"name": "@ohif/viewer",
|
||||||
"version": "3.2.2",
|
"version": "3.3.5",
|
||||||
"description": "OHIF Viewer",
|
"description": "OHIF Viewer",
|
||||||
"author": "OHIF Contributors",
|
"author": "OHIF Contributors",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -45,20 +45,20 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"@ohif/core": "^2.2.1",
|
"@ohif/core": "^2.3.2",
|
||||||
"@ohif/extension-cornerstone": "^2.1.1",
|
"@ohif/extension-cornerstone": "^2.2.1",
|
||||||
"@ohif/extension-dicom-html": "^1.1.0",
|
"@ohif/extension-dicom-html": "^1.1.0",
|
||||||
"@ohif/extension-dicom-microscopy": "^0.50.6",
|
"@ohif/extension-dicom-microscopy": "^0.50.6",
|
||||||
"@ohif/extension-dicom-pdf": "^1.0.1",
|
"@ohif/extension-dicom-pdf": "^1.0.1",
|
||||||
"@ohif/extension-vtk": "^1.1.7",
|
"@ohif/extension-vtk": "^1.2.5",
|
||||||
"@ohif/i18n": "^0.52.4",
|
"@ohif/i18n": "^0.52.4",
|
||||||
"@ohif/ui": "^1.1.5",
|
"@ohif/ui": "^1.1.7",
|
||||||
"@tanem/react-nprogress": "^1.1.25",
|
"@tanem/react-nprogress": "^1.1.25",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"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.8.0",
|
"cornerstone-tools": "^4.9.0",
|
||||||
"cornerstone-wado-image-loader": "^3.0.0",
|
"cornerstone-wado-image-loader": "^3.0.0",
|
||||||
"dcmjs": "^0.8.2",
|
"dcmjs": "^0.8.2",
|
||||||
"dicom-parser": "^1.8.3",
|
"dicom-parser": "^1.8.3",
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
import OHIF from '@ohif/core';
|
|
||||||
import React from 'react';
|
|
||||||
import PluginSwitch from './PluginSwitch.js';
|
|
||||||
import { commandsManager } from './../App.js';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
const { setLayout } = OHIF.redux.actions;
|
|
||||||
|
|
||||||
const ConnectedPluginSwitch = props => {
|
|
||||||
return <PluginSwitch {...props} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
|
||||||
const { activeViewportIndex, layout, viewportSpecificData } = state.viewports;
|
|
||||||
|
|
||||||
return {
|
|
||||||
activeViewportIndex,
|
|
||||||
viewportSpecificData,
|
|
||||||
layout,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
|
||||||
return {
|
|
||||||
setLayout: data => {
|
|
||||||
dispatch(setLayout(data));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/*function setSingleLayoutData(originalArray, viewportIndex, data) {
|
|
||||||
const viewports = originalArray.slice();
|
|
||||||
const layoutData = Object.assign({}, viewports[viewportIndex], data);
|
|
||||||
|
|
||||||
viewports[viewportIndex] = layoutData;
|
|
||||||
|
|
||||||
return viewports;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
|
|
||||||
const { activeViewportIndex, viewportSpecificData } = propsFromState;
|
|
||||||
const { studies } = ownProps;
|
|
||||||
const { setLayout } = propsFromDispatch;
|
|
||||||
|
|
||||||
const mpr = () => {
|
|
||||||
commandsManager.runCommand('mpr2d');
|
|
||||||
};
|
|
||||||
|
|
||||||
const exitMpr = () => {
|
|
||||||
const layout = {
|
|
||||||
numRows: 1,
|
|
||||||
numColumns: 1,
|
|
||||||
viewports: [{ plugin: 'cornerstone' }],
|
|
||||||
};
|
|
||||||
|
|
||||||
setLayout(layout);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
mpr,
|
|
||||||
exitMpr,
|
|
||||||
activeViewportIndex,
|
|
||||||
viewportSpecificData,
|
|
||||||
studies,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps,
|
|
||||||
mergeProps
|
|
||||||
)(ConnectedPluginSwitch);
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
.icon-rotate-120 {
|
|
||||||
transform: rotate(120deg);
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { ToolbarButton } from '@ohif/ui';
|
|
||||||
import './PluginSwitch.css';
|
|
||||||
|
|
||||||
class PluginSwitch extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
mpr: PropTypes.func,
|
|
||||||
activeViewportIndex: PropTypes.number,
|
|
||||||
viewportSpecificData: PropTypes.object,
|
|
||||||
studies: PropTypes.array,
|
|
||||||
exitMpr: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {};
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
isPlugSwitchOn: false,
|
|
||||||
label: '2D MPR',
|
|
||||||
icon: 'cube',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClick = () => {
|
|
||||||
if (this.state.isPlugSwitchOn) {
|
|
||||||
this.setState({
|
|
||||||
isPlugSwitchOn: false,
|
|
||||||
label: '2D MPR',
|
|
||||||
icon: 'cube',
|
|
||||||
});
|
|
||||||
this.props.exitMpr();
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
isPlugSwitchOn: true,
|
|
||||||
label: 'Exit 2D MPR',
|
|
||||||
icon: 'times',
|
|
||||||
});
|
|
||||||
this.props.mpr();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { label, icon } = this.state;
|
|
||||||
|
|
||||||
// Render exit mpr if switched on, otherwise check if mpr button should be displayed.
|
|
||||||
const shouldRender =
|
|
||||||
this.state.isPlugSwitchOn || _shouldRenderMpr2DButton.call(this);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{shouldRender && (
|
|
||||||
<div className="PluginSwitch">
|
|
||||||
<ToolbarButton
|
|
||||||
label={label}
|
|
||||||
icon={icon}
|
|
||||||
onClick={this.handleClick}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function _shouldRenderMpr2DButton() {
|
|
||||||
const { viewportSpecificData, studies, activeViewportIndex } = this.props;
|
|
||||||
|
|
||||||
if (!viewportSpecificData[activeViewportIndex]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { displaySetInstanceUid, studyInstanceUid } = viewportSpecificData[
|
|
||||||
activeViewportIndex
|
|
||||||
];
|
|
||||||
|
|
||||||
const displaySet = _getDisplaySet(
|
|
||||||
studies,
|
|
||||||
studyInstanceUid,
|
|
||||||
displaySetInstanceUid
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!displaySet) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return displaySet.isReconstructable;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _getDisplaySet(studies, studyInstanceUid, displaySetInstanceUid) {
|
|
||||||
const study = studies.find(
|
|
||||||
study => study.studyInstanceUid === studyInstanceUid
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!study) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const displaySet = study.displaySets.find(set => {
|
|
||||||
return set.displaySetInstanceUid === displaySetInstanceUid;
|
|
||||||
});
|
|
||||||
|
|
||||||
return displaySet;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PluginSwitch;
|
|
||||||
@@ -16,7 +16,6 @@ import { commandsManager, extensionManager } from './../App.js';
|
|||||||
|
|
||||||
import ConnectedCineDialog from './ConnectedCineDialog';
|
import ConnectedCineDialog from './ConnectedCineDialog';
|
||||||
import ConnectedLayoutButton from './ConnectedLayoutButton';
|
import ConnectedLayoutButton from './ConnectedLayoutButton';
|
||||||
import ConnectedPluginSwitch from './ConnectedPluginSwitch.js';
|
|
||||||
|
|
||||||
class ToolbarRow extends Component {
|
class ToolbarRow extends Component {
|
||||||
// TODO: Simplify these? isOpen can be computed if we say "any" value for selected,
|
// TODO: Simplify these? isOpen can be computed if we say "any" value for selected,
|
||||||
@@ -124,7 +123,6 @@ class ToolbarRow extends Component {
|
|||||||
</div>
|
</div>
|
||||||
{buttonComponents}
|
{buttonComponents}
|
||||||
<ConnectedLayoutButton />
|
<ConnectedLayoutButton />
|
||||||
<ConnectedPluginSwitch studies={this.props.studies} />
|
|
||||||
<div
|
<div
|
||||||
className="pull-right m-t-1 rm-x-1"
|
className="pull-right m-t-1 rm-x-1"
|
||||||
style={{ marginLeft: 'auto' }}
|
style={{ marginLeft: 'auto' }}
|
||||||
|
|||||||
@@ -5962,10 +5962,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.8.0:
|
cornerstone-tools@^4.9.0:
|
||||||
version "4.8.0"
|
version "4.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/cornerstone-tools/-/cornerstone-tools-4.8.0.tgz#1972546e13e9a09b8aa25a3541ffc345283eec01"
|
resolved "https://registry.yarnpkg.com/cornerstone-tools/-/cornerstone-tools-4.9.0.tgz#8b68603c32aceb84baf860f4dd0d36ac176e8b75"
|
||||||
integrity sha512-PO7/jYbVwc+ddF9JW/o/JXqNPFZV7y1PUTzlRATC9FeXLXNKIkSFBCF5SA1EGJoyjzRYGDBgTZuTYhfm96AlAA==
|
integrity sha512-6yHzXm4qn7VuHMRiaV/oS3khdMidtTho6P1OIYICqZ2pmorsH8jN8LvNgqz+Ky9Nf+wvrvi7ul8ZzcD1sJTkWA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "7.1.2"
|
"@babel/runtime" "7.1.2"
|
||||||
cornerstone-math "0.1.7"
|
cornerstone-math "0.1.7"
|
||||||
|
|||||||
Reference in new issue
Block a user