feat(extensions): Toolbar module depends on plugin in active viewport
This commit is contained in:
parent
2fdc1687d0
commit
f111411046
5
.gitmodules
vendored
5
.gitmodules
vendored
@ -6,4 +6,7 @@
|
||||
url = https://github.com/OHIF/react-viewerbase.git
|
||||
[submodule "Packages-react/react-cornerstone-viewport"]
|
||||
path = Packages-react/react-cornerstone-viewport
|
||||
url = https://github.com/cornerstonejs/react-cornerstone-viewport.git
|
||||
url = https://github.com/cornerstonejs/react-cornerstone-viewport.git
|
||||
[submodule "Packages-react/react-vtkjs-viewport"]
|
||||
path = Packages-react/react-vtkjs-viewport
|
||||
url = https://github.com/OHIF/react-vtkjs-viewport.git
|
||||
|
||||
@ -22,4 +22,5 @@ yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.idea
|
||||
|
||||
yalc.lock
|
||||
yalc.lock
|
||||
.yalc
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ohif-cornerstone-extension",
|
||||
"version": "0.0.17",
|
||||
"version": "0.0.20",
|
||||
"description": "OHIF extension for Cornerstone",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@ -26,12 +26,13 @@
|
||||
"dcmjs": "^0.3.3",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"hammerjs": "^2.0.8",
|
||||
"ohif-core": "^0.3.0",
|
||||
"ohif-core": "^0.3.3",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^15.0.0 || ^16.0.0",
|
||||
"react-dom": "^15.0.0 || ^16.0.0",
|
||||
"react-redux": "^6.0.0",
|
||||
"react-resize-detector": "^3.4.0",
|
||||
"react-viewerbase": "^0.2.10",
|
||||
"redux": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -51,6 +52,7 @@
|
||||
"gh-pages": "^2.0.1",
|
||||
"husky": "^1.3.1",
|
||||
"lint-staged": "^8.1.0",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"prettier": "^1.15.3",
|
||||
"react": "^16.6.3",
|
||||
"react-dom": "^16.6.3",
|
||||
@ -90,6 +92,6 @@
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"classnames": "^2.2.6",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"react-cornerstone-viewport": "^0.1.16"
|
||||
"react-cornerstone-viewport": "^0.1.20"
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { ToolbarSection } from 'react-viewerbase';
|
||||
import OHIF from 'ohif-core'
|
||||
|
||||
const { setToolActive } = OHIF.redux.actions;
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const activeButton = state.tools.buttons.find(tool => tool.active === true);
|
||||
|
||||
return {
|
||||
buttons: state.tools.buttons,
|
||||
activeCommand: activeButton && activeButton.command
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
setToolActive: tool => {
|
||||
dispatch(setToolActive(tool.command))
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedToolbarSection = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ToolbarSection);
|
||||
|
||||
export default ConnectedToolbarSection;
|
||||
@ -1,5 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import OHIFCornerstoneViewport from './OHIFCornerstoneViewport.js';
|
||||
import ToolbarModule from './ToolbarModule.js';
|
||||
|
||||
/**
|
||||
* Pass in 'children' to a React component. The purpose of this is to
|
||||
@ -48,6 +49,6 @@ export default class OHIFCornerstoneExtension {
|
||||
}
|
||||
|
||||
getToolbarModule() {
|
||||
return null;
|
||||
return ToolbarModule;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ConnectedToolbarSection from './ConnectedToolbarSection';
|
||||
import { ToolbarButton } from 'react-viewerbase';
|
||||
import ConnectedCineDialog from './ConnectedCineDialog';
|
||||
|
||||
class ToolbarModule extends Component {
|
||||
state = {
|
||||
cineDialogOpen: false
|
||||
}
|
||||
|
||||
onClickCineToolbarButton = () => {
|
||||
this.setState({
|
||||
cineDialogOpen: !this.state.cineDialogOpen
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const cineDialogContainerStyle = {
|
||||
display: this.state.cineDialogOpen ? 'inline-block' : 'none'
|
||||
};
|
||||
|
||||
return (<div className="ToolbarModule">
|
||||
<ConnectedToolbarSection />
|
||||
<ToolbarButton
|
||||
active={this.state.cineDialogOpen}
|
||||
onClick={this.onClickCineToolbarButton}
|
||||
text={'CINE'}
|
||||
iconClasses={'fab fa-youtube'}
|
||||
/>
|
||||
<div className="CineDialogContainer" style={cineDialogContainerStyle}>
|
||||
<ConnectedCineDialog />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ToolbarModule;
|
||||
@ -3248,6 +3248,11 @@ lodash.camelcase@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
|
||||
|
||||
lodash.clonedeep@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
|
||||
|
||||
lodash.debounce@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
@ -4413,10 +4418,10 @@ randomfill@^1.0.3:
|
||||
randombytes "^2.0.5"
|
||||
safe-buffer "^5.1.0"
|
||||
|
||||
react-cornerstone-viewport@^0.1.16:
|
||||
version "0.1.16"
|
||||
resolved "https://registry.yarnpkg.com/react-cornerstone-viewport/-/react-cornerstone-viewport-0.1.16.tgz#b1db13a3160ee10ffa9bfd91a6a0247f008170e2"
|
||||
integrity sha512-hMEWoA3oDuurJ0AWZDH/hw1jPD7yY3EbaguE0CFusXdHsclCa7GjZXZb9EPqiAw8bF8vBIty7s96dwkqSFSLdw==
|
||||
react-cornerstone-viewport@^0.1.20:
|
||||
version "0.1.20"
|
||||
resolved "https://registry.yarnpkg.com/react-cornerstone-viewport/-/react-cornerstone-viewport-0.1.20.tgz#90e369a48e3f47dd5da69d42f0c8ee7e87e81543"
|
||||
integrity sha512-SbaSjCAVFpQoUUXZ6d5F5QwKrP66zRJ4mN7JXPGyiL6+/m0jGkaBVci6pftkth66Lu5HRlCZUS8nh0plONPUtA==
|
||||
dependencies:
|
||||
lodash.debounce "^4.0.8"
|
||||
moment "^2.23.0"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ohif-dicom-pdf-extension",
|
||||
"version": "0.0.5",
|
||||
"version": "0.0.6",
|
||||
"description": "OHIF extension for Dicom PDF",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@ -20,7 +20,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"dicom-parser": "^1.8.3",
|
||||
"ohif-core": "^0.2.6",
|
||||
"ohif-core": "^0.3.4",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^15.0.0 || ^16.0.0",
|
||||
"react-dom": "^15.0.0 || ^16.0.0"
|
||||
|
||||
@ -17,11 +17,11 @@ export default class OHIFDicomPDFExtension {
|
||||
return OHIFDicomPDFSopClassHandler;
|
||||
}
|
||||
|
||||
getPanelModuleDefinition() {
|
||||
getPanelModule() {
|
||||
return null;
|
||||
}
|
||||
|
||||
getToolbarModuleDefinition() {
|
||||
getToolbarModule() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3173,11 +3173,6 @@ detect-port-alt@1.1.6:
|
||||
address "^1.0.1"
|
||||
debug "^2.6.0"
|
||||
|
||||
dicom-parser@^1.8.3:
|
||||
version "1.8.3"
|
||||
resolved "https://registry.yarnpkg.com/dicom-parser/-/dicom-parser-1.8.3.tgz#6e4b862898112304db30143147562011c1ce6a4d"
|
||||
integrity sha512-CMeUr+jea7Ml70N+/Z5Pd2MYtvLp6IU+TnvdLe6VRVKzZuTeYLYyuAQa9R+sFK4v4N39hig+hKHN+Wfi9sQ6GA==
|
||||
|
||||
diff@^3.2.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
|
||||
|
||||
14
Packages-react/extensions/ohif-vtk-extension/.babelrc
Normal file
14
Packages-react/extensions/ohif-vtk-extension/.babelrc
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"presets": [
|
||||
["@babel/preset-env", {
|
||||
"targets": {
|
||||
"ie": "11"
|
||||
}
|
||||
}],
|
||||
"@babel/preset-react"
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-transform-runtime"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
16
Packages-react/extensions/ohif-vtk-extension/.eslintrc
Normal file
16
Packages-react/extensions/ohif-vtk-extension/.eslintrc
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": [
|
||||
"react-app",
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended"
|
||||
],
|
||||
"parser": "babel-eslint",
|
||||
"env": {
|
||||
"jest": true
|
||||
},
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect",
|
||||
},
|
||||
},
|
||||
}
|
||||
25
Packages-react/extensions/ohif-vtk-extension/.gitignore
vendored
Normal file
25
Packages-react/extensions/ohif-vtk-extension/.gitignore
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
|
||||
# builds
|
||||
build
|
||||
dist
|
||||
.rpt2_cache
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.idea
|
||||
|
||||
yalc.lock
|
||||
3
Packages-react/extensions/ohif-vtk-extension/.prettierrc
Normal file
3
Packages-react/extensions/ohif-vtk-extension/.prettierrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"singleQuote": true
|
||||
}
|
||||
4
Packages-react/extensions/ohif-vtk-extension/.travis.yml
Normal file
4
Packages-react/extensions/ohif-vtk-extension/.travis.yml
Normal file
@ -0,0 +1,4 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 9
|
||||
- 8
|
||||
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Open Health Imaging Foundation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@ -0,0 +1,31 @@
|
||||
# react-vtkjs-viewport
|
||||
|
||||
> VTK.js image viewport component for React
|
||||
|
||||
[](https://www.npmjs.com/package/react-vtkjs-viewport)
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install --save react-vtkjs-viewport
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```jsx
|
||||
import React, { Component } from 'react'
|
||||
|
||||
import CornerstoneViewport from 'react-cornerstone-viewport'
|
||||
|
||||
class Example extends Component {
|
||||
render () {
|
||||
return (
|
||||
<CornerstoneViewport />
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT © [OHIF](https://github.com/OHIF)
|
||||
@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "react-vtkjs-viewport",
|
||||
"version": "0.0.6-76b678ec",
|
||||
"description": "VTK.js image viewport component for React",
|
||||
"author": "OHIF Contributors",
|
||||
"license": "MIT",
|
||||
"repository": "OHIF/react-vtkjs-viewport",
|
||||
"main": "dist/index.js",
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --progress --colors --mode development",
|
||||
"build:release": "webpack --progress --colors --mode production",
|
||||
"start": "webpack --watch --progress --colors --mode development",
|
||||
"prepare": "npm run build:release",
|
||||
"predeploy": "cd example && npm install && npm run build:release",
|
||||
"prepublishOnly": "npm run build:release",
|
||||
"deploy": "gh-pages -d example/build",
|
||||
"generateStaticSite": "./generateStaticSite.sh"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^15.0.0 || ^16.0.0",
|
||||
"react-dom": "^15.0.0 || ^16.0.0"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"src/**/*.{js,jsx,json,css}": [
|
||||
"prettier --single-quote --write",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not ie <= 11",
|
||||
"not op_mini all"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"dependencies": {
|
||||
"cornerstone-core": "^2.2.8",
|
||||
"cornerstone-math": "^0.1.8",
|
||||
"vtk.js": "^8.3.11"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
76b678ec6a9c889ca68231a62fd71346
|
||||
21
Packages-react/extensions/ohif-vtk-extension/LICENSE
Normal file
21
Packages-react/extensions/ohif-vtk-extension/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Open Health Imaging Foundation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
95
Packages-react/extensions/ohif-vtk-extension/package.json
Normal file
95
Packages-react/extensions/ohif-vtk-extension/package.json
Normal file
@ -0,0 +1,95 @@
|
||||
{
|
||||
"name": "ohif-vtk-extension",
|
||||
"version": "0.0.1",
|
||||
"description": "OHIF extension for VTK.js",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
"repository": "OHIF/Viewers",
|
||||
"main": "dist/index.umd.js",
|
||||
"module": "dist/index.es.js",
|
||||
"jsnext:main": "dist/index.es.js",
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"prepublishOnly": "npm run build",
|
||||
"start": "rollup -c -w",
|
||||
"lint": "eslint -c .eslintrc --fix src && prettier --single-quote --write src/**/*.{js,jsx,json,css}"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"cornerstone-core": "^2.2.8",
|
||||
"cornerstone-math": "^0.1.8",
|
||||
"cornerstone-tools": "^3.1.0",
|
||||
"cornerstone-wado-image-loader": "^2.2.3",
|
||||
"dcmjs": "^0.3.6",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"hammerjs": "^2.0.8",
|
||||
"ohif-core": "^0.3.3",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^15.0.0 || ^16.0.0",
|
||||
"react-dom": "^15.0.0 || ^16.0.0",
|
||||
"react-redux": "^6.0.0",
|
||||
"react-resize-detector": "^3.4.0",
|
||||
"redux": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.2.2",
|
||||
"@babel/plugin-external-helpers": "^7.2.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.2.3",
|
||||
"@babel/plugin-transform-runtime": "^7.2.0",
|
||||
"@babel/preset-env": "^7.2.3",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"cross-env": "^5.2.0",
|
||||
"eslint": "5.13.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"eslint-plugin-node": "^8.0.0",
|
||||
"eslint-plugin-promise": "^4.0.1",
|
||||
"eslint-plugin-react": "^7.11.1",
|
||||
"gh-pages": "^2.0.1",
|
||||
"husky": "^1.3.1",
|
||||
"lint-staged": "^8.1.0",
|
||||
"prettier": "^1.15.3",
|
||||
"react": "^16.6.3",
|
||||
"react-dom": "^16.6.3",
|
||||
"react-viewerbase": "^0.2.10",
|
||||
"rollup": "^1.1.2",
|
||||
"rollup-plugin-babel": "^4.2.0",
|
||||
"rollup-plugin-commonjs": "^9.2.0",
|
||||
"rollup-plugin-node-builtins": "^2.1.2",
|
||||
"rollup-plugin-node-resolve": "^4.0.0",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.0",
|
||||
"rollup-plugin-postcss": "^2.0.3",
|
||||
"rollup-plugin-url": "^2.1.0",
|
||||
"stylelint": "^9.9.0",
|
||||
"stylelint-config-recommended": "^2.1.0",
|
||||
"stylus": "^0.54.5"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"src/**/*.{js,jsx,json,css}": [
|
||||
"prettier --single-quote --write",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not ie <= 11",
|
||||
"not op_mini all"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"classnames": "^2.2.6",
|
||||
"react-vtkjs-viewport": "file:.yalc/react-vtkjs-viewport"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
import babel from 'rollup-plugin-babel'
|
||||
import commonjs from 'rollup-plugin-commonjs'
|
||||
import external from 'rollup-plugin-peer-deps-external'
|
||||
import postcss from 'rollup-plugin-postcss'
|
||||
import resolve from 'rollup-plugin-node-resolve'
|
||||
import url from 'rollup-plugin-url'
|
||||
import pkg from './package.json'
|
||||
// Deal with https://github.com/rollup/rollup-plugin-commonjs/issues/297
|
||||
import builtins from 'rollup-plugin-node-builtins';
|
||||
|
||||
const globals = {
|
||||
'react': 'React',
|
||||
'react-dom': 'ReactDOM',
|
||||
'react-redux': 'ReactRedux',
|
||||
'react-resize-detector': 'ReactResizeDetector',
|
||||
'prop-types': 'PropTypes',
|
||||
'cornerstone-core': 'cornerstone',
|
||||
'cornerstone-wado-image-loader': 'cornerstoneWADOImageLoader',
|
||||
'cornerstone-math': 'cornerstoneMath',
|
||||
'cornerstone-tools': 'cornerstoneTools',
|
||||
'dcmjs': 'dcmjs',
|
||||
'dicom-parser': 'dicomParser',
|
||||
'ohif-core': 'OHIF',
|
||||
'hammerjs': 'Hammer'
|
||||
};
|
||||
|
||||
export default {
|
||||
input: 'src/index.js',
|
||||
output: [
|
||||
{
|
||||
file: pkg.main,
|
||||
format: 'umd',
|
||||
name: 'ohif-vtk-extension',
|
||||
sourcemap: true,
|
||||
globals
|
||||
},
|
||||
{
|
||||
file: pkg.module,
|
||||
format: 'es',
|
||||
sourcemap: true,
|
||||
globals
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
builtins(),
|
||||
external(),
|
||||
postcss({
|
||||
modules: false
|
||||
}),
|
||||
url(),
|
||||
babel({
|
||||
exclude: 'node_modules/**',
|
||||
externalHelpers: true,
|
||||
runtimeHelpers: true
|
||||
}),
|
||||
resolve(),
|
||||
commonjs({
|
||||
include: ['node_modules/**', '.yalc/**'],
|
||||
namedExports: {
|
||||
'.yalc/react-vtkjs-viewport/dist/index.js': [
|
||||
'getImageData',
|
||||
'loadImageData',
|
||||
'VTKViewport',
|
||||
'VTKMPRViewport',
|
||||
]
|
||||
}
|
||||
})
|
||||
],
|
||||
external: Object.keys(pkg.peerDependencies || {}),
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { ToolbarSection } from 'react-viewerbase';
|
||||
import OHIF from 'ohif-core'
|
||||
|
||||
const { setToolActive } = OHIF.redux.actions;
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const activeButton = state.tools.buttons.find(tool => tool.active === true);
|
||||
|
||||
return {
|
||||
buttons: [ {
|
||||
command: 'Rotate',
|
||||
type: 'tool',
|
||||
text: 'Rotate',
|
||||
iconClasses: 'fa fa-rotate',
|
||||
//svgUrl: `${Icons}#icon-tools-stack-scroll`,
|
||||
active: true
|
||||
}],
|
||||
activeCommand: 'Rotate'
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
setToolActive: tool => {
|
||||
//dispatch(setToolActive(tool.command))
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedToolbarSection = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ToolbarSection);
|
||||
|
||||
export default ConnectedToolbarSection;
|
||||
@ -0,0 +1,61 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { VTKMPRViewport } from 'react-vtkjs-viewport';
|
||||
import OHIF from 'ohif-core';
|
||||
|
||||
const {
|
||||
setViewportActive,
|
||||
setViewportSpecificData,
|
||||
clearViewportSpecificData
|
||||
} = OHIF.redux.actions;
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const activeButton = state.tools.buttons.find(tool => tool.active === true);
|
||||
let dataFromStore;
|
||||
|
||||
if (state.extensions && state.extensions.vtk) {
|
||||
dataFromStore = state.extensions.vtk;
|
||||
}
|
||||
|
||||
// If this is the active viewport, enable prefetching.
|
||||
const { viewportIndex } = ownProps; //.viewportData;
|
||||
const isActive = viewportIndex === state.viewports.activeViewportIndex;
|
||||
const viewportSpecificData =
|
||||
state.viewports.viewportSpecificData[viewportIndex] || {};
|
||||
|
||||
const viewportLayout = state.viewports.layout.viewports[viewportIndex];
|
||||
const pluginDetails = viewportLayout.vtk || {};
|
||||
|
||||
return {
|
||||
layout: state.viewports.layout,
|
||||
isActive,
|
||||
...pluginDetails,
|
||||
activeTool: activeButton && activeButton.command,
|
||||
...dataFromStore,
|
||||
enableStackPrefetch: isActive,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, ownProps) => {
|
||||
const { viewportIndex } = ownProps;
|
||||
|
||||
return {
|
||||
setViewportActive: () => {
|
||||
dispatch(setViewportActive(viewportIndex));
|
||||
},
|
||||
|
||||
setViewportSpecificData: data => {
|
||||
dispatch(setViewportSpecificData(viewportIndex, data));
|
||||
},
|
||||
|
||||
clearViewportSpecificData: () => {
|
||||
dispatch(clearViewportSpecificData(viewportIndex));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedVTKViewport = connect(
|
||||
mapStateToProps,
|
||||
//mapDispatchToProps
|
||||
)(VTKMPRViewport);
|
||||
|
||||
export default ConnectedVTKViewport;
|
||||
@ -0,0 +1,17 @@
|
||||
.imageViewerLoadingIndicator {
|
||||
color: #91B9CD;
|
||||
}
|
||||
|
||||
.loadingIndicator {
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
font-size: 18px;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
|
||||
/* Necessary for click-through to cornerstone element below */
|
||||
pointer-events: none;
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import './LoadingIndicator.css';
|
||||
|
||||
class LoadingIndicator extends PureComponent {
|
||||
static propTypes = {
|
||||
percentComplete: PropTypes.number.isRequired,
|
||||
error: PropTypes.object
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
percentComplete: 0,
|
||||
error: null
|
||||
};
|
||||
|
||||
render() {
|
||||
let percComplete;
|
||||
if (this.props.percentComplete && this.props.percentComplete !== 100) {
|
||||
percComplete = `${this.props.percentComplete}%`;
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{this.props.error ? (
|
||||
<div className="imageViewerErrorLoadingIndicator loadingIndicator">
|
||||
<div className="indicatorContents">
|
||||
<h4>Error Loading Image</h4>
|
||||
<p className="description">An error has occurred.</p>
|
||||
<p className="details">{this.props.error.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="imageViewerLoadingIndicator loadingIndicator">
|
||||
<div className="indicatorContents">
|
||||
<p>
|
||||
Loading... <i className="fa fa-spin fa-circle-o-notch fa-fw" />{' '}
|
||||
{percComplete}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default LoadingIndicator;
|
||||
@ -0,0 +1,54 @@
|
||||
import React, { Component } from 'react';
|
||||
import OHIFVTKViewport from './OHIFVTKViewport.js';
|
||||
import ToolbarModule from './ToolbarModule.js';
|
||||
|
||||
/**
|
||||
* Pass in 'children' to a React component. The purpose of this is to
|
||||
* allow end users of this extension to pass in components which will
|
||||
* be rendered on top of the base components.
|
||||
*
|
||||
* @param WrappedComponent
|
||||
* @param children
|
||||
* @return {function(*): *}
|
||||
*/
|
||||
function withChildren(WrappedComponent, children) {
|
||||
return function(props) {
|
||||
return <WrappedComponent children={children} { ...props } />;
|
||||
};
|
||||
}
|
||||
|
||||
// Note: If you are authoring extensions which use stateful libraries (e.g. cornerstone-core, react-redux) as peerDependencies and are also duplicated at the application level, try using 'yalc' to link it to the application, rather than yarn link. This can help fix 'module not found' issues.
|
||||
// https://github.com/whitecolor/yalc
|
||||
|
||||
export default class OHIFVTKExtension {
|
||||
constructor(children) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension ID is a unique id, might be used for namespacing extension specific redux actions/reducers (?)
|
||||
*/
|
||||
getExtensionId() {
|
||||
return 'vtk';
|
||||
}
|
||||
|
||||
getViewportModule() {
|
||||
if (this.children && this.children.viewport) {
|
||||
return withChildren(OHIFVTKViewport, this.children.viewport);
|
||||
}
|
||||
|
||||
return OHIFVTKViewport;
|
||||
}
|
||||
|
||||
getSopClassHandler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
getPanelModule() {
|
||||
return null;
|
||||
}
|
||||
|
||||
getToolbarModule() {
|
||||
return ToolbarModule;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,258 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import OHIF from 'ohif-core';
|
||||
import ConnectedVTKViewport from './ConnectedVTKViewport';
|
||||
import cornerstone from 'cornerstone-core';
|
||||
import handleSegmentationStorage from './handleSegmentationStorage.js';
|
||||
import { getImageData, loadImageData } from 'react-vtkjs-viewport';
|
||||
import LoadingIndicator from './LoadingIndicator.js';
|
||||
|
||||
const { StackManager } = OHIF.utils;
|
||||
|
||||
// Metadata configuration
|
||||
const metadataProvider = new OHIF.cornerstone.MetadataProvider();
|
||||
|
||||
cornerstone.metaData.addProvider(
|
||||
metadataProvider.provider.bind(metadataProvider)
|
||||
);
|
||||
|
||||
StackManager.setMetadataProvider(metadataProvider);
|
||||
|
||||
const SOP_CLASSES = {
|
||||
SEGMENTATION_STORAGE: '1.2.840.10008.5.1.4.1.1.66.4'
|
||||
};
|
||||
|
||||
const specialCaseHandlers = {};
|
||||
specialCaseHandlers[
|
||||
SOP_CLASSES.SEGMENTATION_STORAGE
|
||||
] = handleSegmentationStorage;
|
||||
|
||||
class OHIFVTKViewport extends Component {
|
||||
state = {
|
||||
viewportData: null
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
studies: PropTypes.object,
|
||||
displaySet: PropTypes.object,
|
||||
viewportIndex: PropTypes.number,
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
static id = 'OHIFCornerstoneViewport';
|
||||
|
||||
static init() {
|
||||
console.log('OHIFCornerstoneViewport init()');
|
||||
}
|
||||
|
||||
static destroy() {
|
||||
console.log('OHIFCornerstoneViewport destroy()');
|
||||
StackManager.clearStacks();
|
||||
}
|
||||
|
||||
static getCornerstoneStack(
|
||||
studies,
|
||||
studyInstanceUid,
|
||||
displaySetInstanceUid,
|
||||
sopInstanceUid,
|
||||
frameIndex
|
||||
) {
|
||||
// Create shortcut to displaySet
|
||||
const study = studies.find(
|
||||
study => study.studyInstanceUid === studyInstanceUid
|
||||
);
|
||||
|
||||
const displaySet = study.displaySets.find(set => {
|
||||
return set.displaySetInstanceUid === displaySetInstanceUid;
|
||||
});
|
||||
|
||||
// Get stack from Stack Manager
|
||||
const storedStack = StackManager.findOrCreateStack(study, displaySet);
|
||||
|
||||
// Clone the stack here so we don't mutate it
|
||||
const stack = Object.assign({}, storedStack);
|
||||
|
||||
if (frameIndex !== undefined) {
|
||||
stack.currentImageIdIndex = frameIndex;
|
||||
} else if (sopInstanceUid) {
|
||||
const index = stack.imageIds.findIndex(imageId => {
|
||||
const sopCommonModule = cornerstone.metaData.get(
|
||||
'sopCommonModule',
|
||||
imageId
|
||||
);
|
||||
if (!sopCommonModule) {
|
||||
return;
|
||||
}
|
||||
|
||||
return sopCommonModule.sopInstanceUID === sopInstanceUid;
|
||||
});
|
||||
|
||||
if (index > -1) {
|
||||
stack.currentImageIdIndex = index;
|
||||
}
|
||||
} else {
|
||||
stack.currentImageIdIndex = 0;
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
static getViewportData = (
|
||||
studies,
|
||||
studyInstanceUid,
|
||||
displaySetInstanceUid,
|
||||
sopInstanceUid,
|
||||
frameIndex
|
||||
) => {
|
||||
return OHIFVTKViewport.getCornerstoneStack(
|
||||
studies,
|
||||
studyInstanceUid,
|
||||
displaySetInstanceUid,
|
||||
sopInstanceUid,
|
||||
frameIndex
|
||||
);
|
||||
};
|
||||
|
||||
getViewportData = (
|
||||
studies,
|
||||
studyInstanceUid,
|
||||
displaySetInstanceUid,
|
||||
sopClassUid,
|
||||
sopInstanceUid,
|
||||
frameIndex
|
||||
) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const stack = OHIFVTKViewport.getViewportData(
|
||||
studies,
|
||||
studyInstanceUid,
|
||||
displaySetInstanceUid,
|
||||
sopClassUid,
|
||||
sopInstanceUid,
|
||||
frameIndex
|
||||
);
|
||||
|
||||
switch (sopClassUid) {
|
||||
case SOP_CLASSES.SEGMENTATION_STORAGE:
|
||||
throw new Error("Not yet implemented");
|
||||
|
||||
const data = handleSegmentationStorage(stack.imageIds, displaySetInstanceUid, cornerstone);
|
||||
const imageDataObject = data.referenceDataObject;
|
||||
const labelmapDataObject = data.labelmapDataObject;
|
||||
|
||||
const doneLoadingCallback = () => {
|
||||
resolve({
|
||||
data: imageDataObject.vtkImageData,
|
||||
labelmap: labelmapDataObject
|
||||
});
|
||||
};
|
||||
|
||||
const callbacks = [
|
||||
doneLoadingCallback
|
||||
];
|
||||
|
||||
loadImageData(imageDataObject, callbacks, cornerstone);
|
||||
|
||||
break;
|
||||
default:
|
||||
const imageDataObject = getImageData(stack.imageIds, displaySetInstanceUid, cornerstone);
|
||||
const doneLoadingCallback = () => {
|
||||
resolve({
|
||||
data: imageDataObject.vtkImageData,
|
||||
});
|
||||
};
|
||||
|
||||
const callbacks = [
|
||||
doneLoadingCallback
|
||||
];
|
||||
|
||||
loadImageData(imageDataObject, callbacks, cornerstone);
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
setStateFromProps() {
|
||||
const { studies, displaySet } = this.props.viewportData;
|
||||
const {
|
||||
studyInstanceUid,
|
||||
displaySetInstanceUid,
|
||||
sopClassUids,
|
||||
sopInstanceUid,
|
||||
frameIndex
|
||||
} = displaySet;
|
||||
|
||||
if (sopClassUids.length > 1) {
|
||||
console.warn(
|
||||
'More than one SOPClassUid in the same series is not yet supported.'
|
||||
);
|
||||
}
|
||||
|
||||
const sopClassUid = sopClassUids[0];
|
||||
|
||||
this.getViewportData(
|
||||
studies,
|
||||
studyInstanceUid,
|
||||
displaySetInstanceUid,
|
||||
sopClassUid,
|
||||
sopInstanceUid,
|
||||
frameIndex
|
||||
).then(({ data, labelmap })=> {
|
||||
this.setState({
|
||||
viewportData: data,
|
||||
labelmap
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setStateFromProps();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { studies, displaySet } = this.props.viewportData;
|
||||
const prevDisplaySet = prevProps.viewportData.displaySet;
|
||||
|
||||
if (
|
||||
displaySet.displaySetInstanceUid !==
|
||||
prevDisplaySet.displaySetInstanceUid ||
|
||||
displaySet.sopInstanceUid !== prevDisplaySet.sopInstanceUid ||
|
||||
displaySet.frameIndex !== prevDisplaySet.frameIndex
|
||||
) {
|
||||
this.setStateFromProps();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let childrenWithProps = null;
|
||||
|
||||
// TODO: Does it make more sense to use Context?
|
||||
if (this.props.children && this.props.children.length) {
|
||||
childrenWithProps = this.props.children.map((child, index) => {
|
||||
return React.cloneElement(child, {
|
||||
viewportIndex: this.props.viewportIndex,
|
||||
key: index
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const style = { width: '100%', height: '100%', position: 'relative' };
|
||||
|
||||
return (
|
||||
<>
|
||||
{this.state.viewportData ? (
|
||||
<ConnectedVTKViewport
|
||||
data={this.state.viewportData}
|
||||
labelmap={this.state.labelmap}
|
||||
viewportIndex={this.props.viewportIndex}
|
||||
/>
|
||||
) : <div style={style}>
|
||||
<LoadingIndicator/>
|
||||
</div>}
|
||||
{childrenWithProps}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default OHIFVTKViewport;
|
||||
@ -0,0 +1,15 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ConnectedToolbarSection from './ConnectedToolbarSection';
|
||||
|
||||
class ToolbarModule extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="ToolbarModule">
|
||||
<ConnectedToolbarSection />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ToolbarModule;
|
||||
@ -0,0 +1,123 @@
|
||||
import OHIF from 'ohif-core';
|
||||
import cornerstone from 'cornerstone-core';
|
||||
import cornerstoneTools from 'cornerstone-tools';
|
||||
import * as dcmjs from 'dcmjs';
|
||||
|
||||
const { StackManager } = OHIF.utils;
|
||||
|
||||
function getDisplaySet(studies, studyInstanceUid, displaySetInstanceUid) {
|
||||
const study = studies.find(
|
||||
study => study.studyInstanceUid === studyInstanceUid
|
||||
);
|
||||
|
||||
const displaySet = study.displaySets.find(set => {
|
||||
return set.displaySetInstanceUid === displaySetInstanceUid;
|
||||
});
|
||||
|
||||
return displaySet;
|
||||
}
|
||||
|
||||
function getDisplaySetsBySeries(studies, studyInstanceUid, seriesInstanceUid) {
|
||||
const study = studies.find(
|
||||
study => study.studyInstanceUid === studyInstanceUid
|
||||
);
|
||||
|
||||
return study.displaySets.filter(set => {
|
||||
return set.seriesInstanceUid === seriesInstanceUid;
|
||||
});
|
||||
}
|
||||
|
||||
function getCornerstoneStack(studies, studyInstanceUid, displaySetInstanceUid) {
|
||||
const study = studies.find(
|
||||
study => study.studyInstanceUid === studyInstanceUid
|
||||
);
|
||||
|
||||
// Create shortcut to displaySet
|
||||
const displaySet = getDisplaySet(
|
||||
studies,
|
||||
studyInstanceUid,
|
||||
displaySetInstanceUid
|
||||
);
|
||||
|
||||
// Get stack from Stack Manager
|
||||
const stack = StackManager.findOrCreateStack(study, displaySet);
|
||||
|
||||
// Clone the stack here so we don't mutate it later
|
||||
const stackClone = Object.assign({}, stack);
|
||||
stackClone.currentImageIdIndex = 0;
|
||||
|
||||
return stackClone;
|
||||
}
|
||||
|
||||
function retrieveDicomData(wadoUri) {
|
||||
// TODO: Authorization header depends on the server. If we ever have multiple servers
|
||||
// we will need to figure out how / when to pass this information in.
|
||||
return fetch(wadoUri, {
|
||||
headers: OHIF.DICOMWeb.getAuthorizationHeader()
|
||||
}).then(response => response.arrayBuffer());
|
||||
}
|
||||
|
||||
async function handleSegmentationStorage(
|
||||
studies,
|
||||
studyInstanceUid,
|
||||
displaySetInstanceUid
|
||||
) {
|
||||
const study = studies.find(
|
||||
study => study.studyInstanceUid === studyInstanceUid
|
||||
);
|
||||
const displaySet = getDisplaySet(
|
||||
studies,
|
||||
studyInstanceUid,
|
||||
displaySetInstanceUid
|
||||
);
|
||||
const segWadoUri = displaySet.images[0].getData().wadouri;
|
||||
const arrayBuffer = await retrieveDicomData(segWadoUri);
|
||||
const dicomData = dcmjs.data.DicomMessage.readFile(arrayBuffer);
|
||||
const dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(
|
||||
dicomData.dict
|
||||
);
|
||||
|
||||
const segments = dcmjs.adapters.VTKjs.Segmentation.generateSegments(dataset);
|
||||
|
||||
dataset._meta = dcmjs.data.DicomMetaDictionary.namifyDataset(dicomData.meta);
|
||||
|
||||
const seriesInstanceUid = dataset.ReferencedSeriesSequence.SeriesInstanceUID;
|
||||
const displaySets = getDisplaySetsBySeries(
|
||||
studies,
|
||||
studyInstanceUid,
|
||||
seriesInstanceUid
|
||||
);
|
||||
|
||||
if (displaySets.length > 1) {
|
||||
console.warn(
|
||||
'More than one display set with the same seriesInstanceUid. This is not supported yet...'
|
||||
);
|
||||
}
|
||||
|
||||
const referenceDisplaySet = displaySets[0];
|
||||
const imageIds = referenceDisplaySet.images.map(image => image.getImageId());
|
||||
|
||||
if (!results) {
|
||||
throw new Error('Fractional segmentations are not supported');
|
||||
}
|
||||
|
||||
const cachedStack = StackManager.findOrCreateStack(
|
||||
study,
|
||||
referenceDisplaySet
|
||||
);
|
||||
const stack = Object.assign({}, cachedStack);
|
||||
stack.currentImageIdIndex = 0;
|
||||
|
||||
return {
|
||||
referenceDataObject,
|
||||
labelmapDataObject
|
||||
}
|
||||
|
||||
return {
|
||||
studyInstanceUid,
|
||||
displaySetInstanceUid,
|
||||
stack
|
||||
};
|
||||
}
|
||||
|
||||
export default handleSegmentationStorage;
|
||||
@ -0,0 +1,3 @@
|
||||
import OHIFVTKExtension from './OHIFVTKExtension.js';
|
||||
|
||||
export default OHIFVTKExtension;
|
||||
8949
Packages-react/extensions/ohif-vtk-extension/yarn.lock
Normal file
8949
Packages-react/extensions/ohif-vtk-extension/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@ -1 +1 @@
|
||||
Subproject commit 10701c5425c58ccfca7d8758a1698f438bc197e9
|
||||
Subproject commit a728166da104670b9d62ba4cd8ec4eef645ff29e
|
||||
5
Packages-react/ohif-viewer/.gitignore
vendored
5
Packages-react/ohif-viewer/.gitignore
vendored
@ -4,4 +4,7 @@ node_modules
|
||||
yarn.lock
|
||||
yarn-error.log
|
||||
src/sha.js
|
||||
src/version.js
|
||||
src/version.js
|
||||
|
||||
.yalc
|
||||
yalc.lock
|
||||
@ -106,11 +106,11 @@
|
||||
"hammerjs": "^2.0.8",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"moment": "^2.24.0",
|
||||
"ohif-core": "^0.3.3",
|
||||
"ohif-cornerstone-extension": "0.0.17",
|
||||
"ohif-core": "^0.3.4",
|
||||
"ohif-cornerstone-extension": "^0.0.20",
|
||||
"ohif-dicom-html-extension": "^0.0.2",
|
||||
"ohif-dicom-microscopy-extension": "^0.0.5",
|
||||
"ohif-dicom-pdf-extension": "^0.0.5",
|
||||
"ohif-dicom-pdf-extension": "^0.0.6",
|
||||
"oidc-client": "^1.6.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-bootstrap-modal": "^4.2.0",
|
||||
|
||||
@ -9,6 +9,7 @@ import ui from './redux/ui.js';
|
||||
import OHIFStandaloneViewer from './OHIFStandaloneViewer';
|
||||
import WhiteLabellingContext from './WhiteLabellingContext';
|
||||
import OHIFCornerstoneExtension from 'ohif-cornerstone-extension';
|
||||
//import OHIFVTKExtension from 'ohif-vtk-extension';
|
||||
import OHIFDicomPDFExtension from 'ohif-dicom-pdf-extension';
|
||||
import OHIFDicomHtmlExtension from 'ohif-dicom-html-extension';
|
||||
import OHIFDicomMicroscopyExtension from 'ohif-dicom-microscopy-extension';
|
||||
@ -146,6 +147,7 @@ store.dispatch(toolAction);
|
||||
/** TODO: extensions should be passed in as prop as soon as we have the extensions as separate packages and then registered by ExtensionsManager */
|
||||
const extensions = [
|
||||
new OHIFCornerstoneExtension(),
|
||||
//new OHIFVTKExtension(),
|
||||
new OHIFDicomPDFExtension(),
|
||||
new OHIFDicomHtmlExtension(),
|
||||
new OHIFDicomMicroscopyExtension()
|
||||
|
||||
@ -0,0 +1,130 @@
|
||||
import { connect } from 'react-redux';
|
||||
import PluginSwitch from './PluginSwitch.js';
|
||||
import OHIF from 'ohif-core'
|
||||
|
||||
const { setLayout } = OHIF.redux.actions;
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const { activeViewportIndex, layout } = state.viewports;
|
||||
|
||||
return {
|
||||
activeViewportIndex,
|
||||
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, layout } = propsFromState;
|
||||
const { setLayout } = propsFromDispatch;
|
||||
|
||||
// TODO: Do not display certain options if the current display set
|
||||
// cannot be displayed using these view types
|
||||
const options = [
|
||||
{
|
||||
title: 'Original Acquisition',
|
||||
onClick: (click) => {
|
||||
console.warn('Original Acquisition');
|
||||
|
||||
const layoutData = setSingleLayoutData(layout.viewports, activeViewportIndex, { plugin: 'cornerstone'});
|
||||
|
||||
setLayout({ viewports: layoutData });
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Axial',
|
||||
onClick: (click) => {
|
||||
console.warn('Axial');
|
||||
const data = {
|
||||
plugin: 'vtk',
|
||||
vtk: {
|
||||
mode: 'mpr',
|
||||
sliceNormal: [0, 0, 1]
|
||||
}
|
||||
};
|
||||
|
||||
const layoutData = setSingleLayoutData(layout.viewports, activeViewportIndex, data);
|
||||
|
||||
setLayout({ viewports: layoutData });
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Sagittal',
|
||||
onClick: (click) => {
|
||||
console.warn('Sagittal');
|
||||
const data = {
|
||||
plugin: 'vtk',
|
||||
vtk: {
|
||||
mode: 'mpr',
|
||||
sliceNormal: [1, 0, 0]
|
||||
}
|
||||
};
|
||||
|
||||
const layoutData = setSingleLayoutData(layout.viewports, activeViewportIndex, data);
|
||||
|
||||
setLayout({ viewports: layoutData });
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Coronal',
|
||||
onClick: (click) => {
|
||||
console.warn('Coronal');
|
||||
const data = {
|
||||
plugin: 'vtk',
|
||||
vtk: {
|
||||
mode: 'mpr',
|
||||
sliceNormal: [0, 1, 0]
|
||||
}
|
||||
};
|
||||
|
||||
const layoutData = setSingleLayoutData(layout.viewports, activeViewportIndex, data);
|
||||
|
||||
setLayout({ viewports: layoutData });
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '3D Perspective',
|
||||
onClick: (click) => {
|
||||
console.warn('3D Perspective');
|
||||
const data = {
|
||||
plugin: 'vtk',
|
||||
vtk: {
|
||||
mode: '3d',
|
||||
}
|
||||
};
|
||||
|
||||
const layoutData = setSingleLayoutData(layout.viewports, activeViewportIndex, data);
|
||||
|
||||
setLayout({ viewports: layoutData });
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
return {
|
||||
options,
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedPluginSwitch = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
mergeProps
|
||||
)(PluginSwitch);
|
||||
|
||||
export default ConnectedPluginSwitch;
|
||||
@ -2,8 +2,17 @@ import { connect } from 'react-redux';
|
||||
import ToolbarRow from './ToolbarRow';
|
||||
import { setLeftSidebarOpen, setRightSidebarOpen } from '../redux/actions.js';
|
||||
|
||||
const defaultPlugin = 'cornerstone';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const { layout, viewportSpecificData, activeViewportIndex } = state.viewports;
|
||||
const pluginInLayout = layout.viewports[activeViewportIndex] && layout.viewports[activeViewportIndex].plugin;
|
||||
const pluginInViewportData = viewportSpecificData[activeViewportIndex] && viewportSpecificData[activeViewportIndex].plugin;
|
||||
const pluginInActiveViewport = pluginInLayout || pluginInViewportData || defaultPlugin;
|
||||
// const extensionData = state.extensions[pluginInActiveViewport];
|
||||
|
||||
return {
|
||||
pluginId: pluginInActiveViewport,
|
||||
leftSidebarOpen: state.ui.leftSidebarOpen,
|
||||
rightSidebarOpen: state.ui.rightSidebarOpen
|
||||
};
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Dropdown } from 'react-viewerbase';
|
||||
|
||||
class PluginSwitch extends Component {
|
||||
static propTypes = {
|
||||
options: PropTypes.array,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="PluginSwitch">
|
||||
{this.props.options && <Dropdown title={"View"} list={this.props.options}/>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PluginSwitch;
|
||||
@ -1,23 +1,20 @@
|
||||
import React, { Component } from 'react';
|
||||
import ConnectedToolbarSection from './ConnectedToolbarSection';
|
||||
import ConnectedLayoutButton from './ConnectedLayoutButton';
|
||||
import ConnectedCineDialog from './ConnectedCineDialog.js';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ToolbarButton, RoundedButtonGroup } from 'react-viewerbase';
|
||||
import OHIF from 'ohif-core';
|
||||
import { RoundedButtonGroup } from 'react-viewerbase';
|
||||
import ConnectedLayoutButton from './ConnectedLayoutButton';
|
||||
///import ConnectedPluginSwitch from './ConnectedPluginSwitch.js';
|
||||
import './ToolbarRow.css';
|
||||
|
||||
const Icons = 'icons.svg';
|
||||
|
||||
class ToolbarRow extends Component {
|
||||
state = {
|
||||
cineDialogOpen: false
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
leftSidebarOpen: PropTypes.bool.isRequired,
|
||||
rightSidebarOpen: PropTypes.bool.isRequired,
|
||||
setLeftSidebarOpen: PropTypes.func,
|
||||
setRightSidebarOpen: PropTypes.func
|
||||
setRightSidebarOpen: PropTypes.func,
|
||||
pluginId: PropTypes.string
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
@ -33,12 +30,6 @@ class ToolbarRow extends Component {
|
||||
this.props.setRightSidebarOpen(!!value);
|
||||
};
|
||||
|
||||
onClickCineToolbarButton = () => {
|
||||
this.setState({
|
||||
cineDialogOpen: !this.state.cineDialogOpen
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const leftSidebarToggle = [
|
||||
{
|
||||
@ -68,9 +59,23 @@ class ToolbarRow extends Component {
|
||||
? rightSidebarToggle[0].value
|
||||
: null;
|
||||
|
||||
const cineDialogContainerStyle = {
|
||||
display: this.state.cineDialogOpen ? 'inline-block' : 'none'
|
||||
};
|
||||
const currentPluginId = this.props.pluginId;
|
||||
|
||||
const { PLUGIN_TYPES, availablePlugins } = OHIF.plugins;
|
||||
const plugin = availablePlugins.find(entry => {
|
||||
return (
|
||||
entry.type === PLUGIN_TYPES.TOOLBAR &&
|
||||
entry.id === currentPluginId
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
let pluginComp;
|
||||
if (plugin) {
|
||||
const PluginComponent = plugin.component;
|
||||
|
||||
pluginComp = <PluginComponent/>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ToolbarRow">
|
||||
@ -81,17 +86,9 @@ class ToolbarRow extends Component {
|
||||
onValueChanged={this.onLeftSidebarValueChanged}
|
||||
/>
|
||||
</div>
|
||||
<ConnectedToolbarSection />
|
||||
{ pluginComp }
|
||||
<ConnectedLayoutButton />
|
||||
<ToolbarButton
|
||||
active={this.state.cineDialogOpen}
|
||||
onClick={this.onClickCineToolbarButton}
|
||||
text={'CINE'}
|
||||
iconClasses={'fab fa-youtube'}
|
||||
/>
|
||||
<div className="CineDialogContainer" style={cineDialogContainerStyle}>
|
||||
<ConnectedCineDialog />
|
||||
</div>
|
||||
{/*<ConnectedPluginSwitch/>*/}
|
||||
<div className="pull-right m-t-1 rm-x-1" style={{ marginLeft: 'auto' }}>
|
||||
<RoundedButtonGroup
|
||||
options={rightSidebarToggle}
|
||||
|
||||
@ -1 +1 @@
|
||||
export default '6f8b9ae5932e23a1b2031ad173d9a87121e9eae8';
|
||||
export default '416ecb659362a0ebf5449109186c55511421cc33';
|
||||
|
||||
@ -7811,10 +7811,10 @@ octal@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/octal/-/octal-1.0.0.tgz#63e7162a68efbeb9e213588d58e989d1e5c4530b"
|
||||
integrity sha1-Y+cWKmjvvrniE1iNWOmJ0eXEUws=
|
||||
|
||||
ohif-core@^0.3.3:
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/ohif-core/-/ohif-core-0.3.3.tgz#6067b31dfdd7c91541aa4d5cf1ad617038147640"
|
||||
integrity sha512-uE1EzMrSE+HZIvCBysEvnIwZfb3M5HTLnDGh9NEurBmTOYjD0NIHVoMimjNbxINoNQUBUpOUdJbXAuUk2YOuZg==
|
||||
ohif-core@^0.3.4:
|
||||
version "0.3.4"
|
||||
resolved "https://registry.yarnpkg.com/ohif-core/-/ohif-core-0.3.4.tgz#0dbed1f7edbd1cd9a826157fba6937171633fb7c"
|
||||
integrity sha512-qK0fnQ6Yh7cYcQQN6D3csYGtRxVNxJOyT6yxmgQIdAEoK87oPmmApZL8jxMySPrGgF5RqPFqplPTrxrKh82tOw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.2.0"
|
||||
dicomweb-client "^0.4.2"
|
||||
@ -7825,15 +7825,15 @@ ohif-core@^0.3.3:
|
||||
lodash.merge "^4.6.1"
|
||||
validate.js "^0.12.0"
|
||||
|
||||
ohif-cornerstone-extension@0.0.17:
|
||||
version "0.0.17"
|
||||
resolved "https://registry.yarnpkg.com/ohif-cornerstone-extension/-/ohif-cornerstone-extension-0.0.17.tgz#58c182d3227d328c5a17966b5e7c40b513920704"
|
||||
integrity sha512-tT6rbirsCyMDgYPzJXjNhk7zT9KN/mJaKPfp3TVcNIgN1EAARQROU/5shaLUa6DA8M3QDQyKVIVKu+39i6ijVg==
|
||||
ohif-cornerstone-extension@^0.0.20:
|
||||
version "0.0.20"
|
||||
resolved "https://registry.yarnpkg.com/ohif-cornerstone-extension/-/ohif-cornerstone-extension-0.0.20.tgz#831da61160338ba30b09d6454876d3d7b318445b"
|
||||
integrity sha512-m/qmBFcV3vJ6+ma0UHXHqMN0Nz1Zw9I47T6zgnvz7ZwxJ3h8aQfUjVPGtRcuB2snna4c4NmEHaxoEGRR0bFdIg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.2.0"
|
||||
classnames "^2.2.6"
|
||||
lodash.throttle "^4.1.1"
|
||||
react-cornerstone-viewport "^0.1.16"
|
||||
react-cornerstone-viewport "^0.1.20"
|
||||
|
||||
ohif-dicom-html-extension@^0.0.2:
|
||||
version "0.0.2"
|
||||
@ -7851,10 +7851,10 @@ ohif-dicom-microscopy-extension@^0.0.5:
|
||||
classnames "^2.2.6"
|
||||
dicom-microscopy-viewer "^0.2.0"
|
||||
|
||||
ohif-dicom-pdf-extension@^0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/ohif-dicom-pdf-extension/-/ohif-dicom-pdf-extension-0.0.5.tgz#8d2b453aa9d1df736f5c54818f7ee682f60f4c32"
|
||||
integrity sha512-YlMgh25hJ+p9e/Uzgg0Wx3deutUKaPd1t/PtL8gIHD+3/k3hgmTsz8nYsQ7xKGSXGpl56d/r9PrRpKF9n8nLSw==
|
||||
ohif-dicom-pdf-extension@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/ohif-dicom-pdf-extension/-/ohif-dicom-pdf-extension-0.0.6.tgz#5c1c1bf955d160dda01c36c4ed899d8e65384d63"
|
||||
integrity sha512-MRBDnC78itsos3c8QMKjgaFp8tmXyGIq5qVLREr//osqCYirhWQbCFJv73eYR5+bRCdJfUMMpvnDSChFIhcT6A==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.2.0"
|
||||
classnames "^2.2.6"
|
||||
@ -9440,10 +9440,10 @@ react-bootstrap-modal@^4.2.0:
|
||||
react-overlays "^0.8.0"
|
||||
react-transition-group "^2.0.0"
|
||||
|
||||
react-cornerstone-viewport@^0.1.16:
|
||||
version "0.1.16"
|
||||
resolved "https://registry.yarnpkg.com/react-cornerstone-viewport/-/react-cornerstone-viewport-0.1.16.tgz#b1db13a3160ee10ffa9bfd91a6a0247f008170e2"
|
||||
integrity sha512-hMEWoA3oDuurJ0AWZDH/hw1jPD7yY3EbaguE0CFusXdHsclCa7GjZXZb9EPqiAw8bF8vBIty7s96dwkqSFSLdw==
|
||||
react-cornerstone-viewport@^0.1.20:
|
||||
version "0.1.20"
|
||||
resolved "https://registry.yarnpkg.com/react-cornerstone-viewport/-/react-cornerstone-viewport-0.1.20.tgz#90e369a48e3f47dd5da69d42f0c8ee7e87e81543"
|
||||
integrity sha512-SbaSjCAVFpQoUUXZ6d5F5QwKrP66zRJ4mN7JXPGyiL6+/m0jGkaBVci6pftkth66Lu5HRlCZUS8nh0plONPUtA==
|
||||
dependencies:
|
||||
lodash.debounce "^4.0.8"
|
||||
moment "^2.23.0"
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 3773fd4899eb8faf24a128f6a4a43f6e6e5762ee
|
||||
Subproject commit 05f58a4be2d7f90671d71a2c5cf96a2f08bb219d
|
||||
@ -1 +1 @@
|
||||
Subproject commit 6294f3c78f085b7501136964e194cc82e995b15d
|
||||
Subproject commit 3fe82ecec15dc3e1843a00b0d88da8f3f7e161c4
|
||||
1
Packages-react/react-vtkjs-viewport
Submodule
1
Packages-react/react-vtkjs-viewport
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 8d1a0b11e5e565f779f12082d24ca8f9daa0b051
|
||||
Loading…
Reference in New Issue
Block a user