add new viewer folder
This commit is contained in:
parent
d541c23117
commit
fc5bd73c1e
2164
OHIFViewer-react/README.md
Normal file
2164
OHIFViewer-react/README.md
Normal file
File diff suppressed because it is too large
Load Diff
40
OHIFViewer-react/package.json
Normal file
40
OHIFViewer-react/package.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "react-cornerstone-viewport-example",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"cornerstone-core": "2.2.8",
|
||||
"cornerstone-math": "0.1.7",
|
||||
"cornerstone-tools": "3.0.0-b.1471",
|
||||
"cornerstone-wado-image-loader": "2.2.3",
|
||||
"dicom-parser": "1.8.3",
|
||||
"hammerjs": "^2.0.8",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"moment": "^2.22.2",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.4.1",
|
||||
"react-cornerstone-viewport": "^0.1.1",
|
||||
"react-dom": "^16.4.1",
|
||||
"react-scripts": "^2.1.1",
|
||||
"react-viewerbase": "^0.1.2",
|
||||
"ohif-core": "link:/Users/Erik/Projects/OHIF/ohif-core"
|
||||
},
|
||||
"scripts": {
|
||||
"copy:webworkers": "cp node_modules/cornerstone-wado-image-loader/dist/*.min.js* public",
|
||||
"version": "node -p -e \"'export default \\'' + require('./package.json').version + '\\';'\" > src/version.js",
|
||||
"sha": "echo \"export default '\"$(git rev-parse HEAD)\"';\" > src/sha.js",
|
||||
"details": "npm run version && npm run sha",
|
||||
"prep": "npm run details && npm run copy:webworkers",
|
||||
"start": "npm run prep && react-scripts start",
|
||||
"build": "npm run prep && react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not ie <= 11",
|
||||
"not op_mini all"
|
||||
]
|
||||
}
|
||||
3
OHIFViewer-react/public/cornerstoneWADOImageLoader.min.js
vendored
Normal file
3
OHIFViewer-react/public/cornerstoneWADOImageLoader.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
OHIFViewer-react/public/cornerstoneWADOImageLoaderCodecs.min.js
vendored
Normal file
4
OHIFViewer-react/public/cornerstoneWADOImageLoaderCodecs.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3
OHIFViewer-react/public/cornerstoneWADOImageLoaderWebWorker.min.js
vendored
Normal file
3
OHIFViewer-react/public/cornerstoneWADOImageLoaderWebWorker.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
23
OHIFViewer-react/public/index.html
Normal file
23
OHIFViewer-react/public/index.html
Normal file
@ -0,0 +1,23 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
|
||||
<title>react-cornerstone-viewport</title>
|
||||
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
8
OHIFViewer-react/public/manifest.json
Normal file
8
OHIFViewer-react/public/manifest.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"short_name": "react-cornerstone-viewport",
|
||||
"name": "react-cornerstone-viewport",
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
16
OHIFViewer-react/src/App.css
Normal file
16
OHIFViewer-react/src/App.css
Normal file
@ -0,0 +1,16 @@
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
background-color: black;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
83
OHIFViewer-react/src/App.js
Normal file
83
OHIFViewer-react/src/App.js
Normal file
@ -0,0 +1,83 @@
|
||||
import React, { Component } from 'react';
|
||||
import { withRouter } from 'react-router';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
import { OHIF } from 'ohif-core';
|
||||
import ViewerRouting from "./ViewerRouting.js";
|
||||
import IHEInvokeImageDisplay from './IHEInvokeImageDisplay.js';
|
||||
import './App.css';
|
||||
|
||||
const reload = () => window.location.reload();
|
||||
const Studylist = OHIF.studylist.components.StudyList;
|
||||
|
||||
function setContext(context) {
|
||||
/*Rollbar.configure({
|
||||
payload: {
|
||||
context
|
||||
}
|
||||
});*/
|
||||
console.log(context);
|
||||
}
|
||||
|
||||
class App extends Component {
|
||||
componentDidMount() {
|
||||
// Temporary until the rest of the UI is in React
|
||||
window.router = {
|
||||
history: this.props.history
|
||||
};
|
||||
|
||||
this.unlisten = this.props.history.listen((location, action) => {
|
||||
setContext(window.location.pathname);
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unlisten();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path="/studylist"
|
||||
component={Studylist}
|
||||
/*auth={this.props.auth}*/
|
||||
store={this.props.store}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/"
|
||||
component={Studylist}
|
||||
/*auth={this.props.auth}*/
|
||||
store={this.props.store}
|
||||
/>
|
||||
<Route
|
||||
path="/viewer/:studyInstanceUids"
|
||||
component={ViewerRouting}
|
||||
/*auth={this.props.auth}*/
|
||||
store={this.props.store}
|
||||
/>
|
||||
<Route
|
||||
path="/study/:studyInstanceUid/series/:seriesInstanceUids"
|
||||
component={ViewerRouting}
|
||||
/*auth={this.props.auth}*/
|
||||
store={this.props.store}
|
||||
/>
|
||||
<Route
|
||||
path="/IHEInvokeImageDisplay"
|
||||
component={IHEInvokeImageDisplay}
|
||||
/*auth={this.props.auth}*/
|
||||
store={this.props.store}
|
||||
/>
|
||||
|
||||
{/*<Route path="/silent-refresh.html" onEnter={reload} />
|
||||
<Route path="/logout-redirect.html" onEnter={reload} />*/}
|
||||
<Route render={() =>
|
||||
<div> Sorry, this page does not exist. </div>}
|
||||
/>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(App);
|
||||
33
OHIFViewer-react/src/IHEInvokeImageDisplay.js
Normal file
33
OHIFViewer-react/src/IHEInvokeImageDisplay.js
Normal file
@ -0,0 +1,33 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import ViewerFromStudyData from "./ViewerFromStudyData.js";
|
||||
|
||||
function IHEInvokeImageDisplay({ match }) {
|
||||
const requestType = match.params.query.requestType;
|
||||
|
||||
let studyInstanceUids;
|
||||
let displayStudyList = false;
|
||||
if (requestType === "STUDY") {
|
||||
studyInstanceUids = match.params.query.studyUID.split(';');
|
||||
} else if (requestType === "STUDYBASE64") {
|
||||
const uids = this.params.query.studyUID;
|
||||
const decodedData = window.atob(uids);
|
||||
studyInstanceUids = decodedData.split(';');
|
||||
} else if (requestType === "PATIENT") {
|
||||
const patientUids = this.params.query.patientID.split(';');
|
||||
displayStudyList = true
|
||||
} else {
|
||||
displayStudyList = true
|
||||
}
|
||||
|
||||
if (displayStudyList) {
|
||||
//return (<StudyList/>);
|
||||
return ('');
|
||||
}
|
||||
|
||||
return (
|
||||
<ViewerFromStudyData studyInstanceUids={studyInstanceUids}/>
|
||||
);
|
||||
}
|
||||
|
||||
export default IHEInvokeImageDisplay;
|
||||
102
OHIFViewer-react/src/ViewerFromStudyData.js
Normal file
102
OHIFViewer-react/src/ViewerFromStudyData.js
Normal file
@ -0,0 +1,102 @@
|
||||
import React, {Component} from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Viewer from "./viewer/viewer.js";
|
||||
import { OHIF } from 'ohif-core';
|
||||
|
||||
// TODO: Move to react-viewerbase
|
||||
|
||||
function createDisplaySets(studies) {
|
||||
// Define the OHIF.viewer.data global object
|
||||
// TODO: Save all data that is currently in OHIF.viewer in redux instead
|
||||
OHIF.viewer.data = OHIF.viewer.data || {};
|
||||
|
||||
// @TypeSafeStudies
|
||||
// Clears OHIF.viewer.Studies collection
|
||||
OHIF.viewer.Studies.removeAll();
|
||||
|
||||
// @TypeSafeStudies
|
||||
// Clears OHIF.viewer.StudyMetadataList collection
|
||||
OHIF.viewer.StudyMetadataList.removeAll();
|
||||
|
||||
OHIF.viewer.data.studyInstanceUids = [];
|
||||
|
||||
const updatedStudies = studies.map(study => {
|
||||
const studyMetadata = new OHIF.metadata.OHIFStudyMetadata(study, study.studyInstanceUid);
|
||||
let displaySets = study.displaySets;
|
||||
|
||||
if (!study.displaySets) {
|
||||
displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(studyMetadata);
|
||||
study.displaySets = displaySets;
|
||||
}
|
||||
|
||||
studyMetadata.setDisplaySets(displaySets);
|
||||
|
||||
study.selected = true;
|
||||
OHIF.viewer.Studies.insert(study);
|
||||
OHIF.viewer.StudyMetadataList.insert(studyMetadata);
|
||||
OHIF.viewer.data.studyInstanceUids.push(study.studyInstanceUid);
|
||||
|
||||
// Updates WADO-RS metaDataManager
|
||||
OHIF.viewerbase.updateMetaDataManager(study);
|
||||
|
||||
return study;
|
||||
});
|
||||
|
||||
return updatedStudies;
|
||||
}
|
||||
|
||||
class ViewerFromStudyData extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
studies: null,
|
||||
error: null
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// TODO: Avoid using timepoints here
|
||||
//const params = { studyInstanceUids, seriesInstanceUids, timepointId, timepointsFilter={} };
|
||||
const params = {
|
||||
studyInstanceUids: this.props.studyInstanceUids,
|
||||
seriesInstanceUids: this.props.seriesInstanceUids,
|
||||
}
|
||||
const promise = OHIF.viewerbase.prepareViewerData(params);
|
||||
|
||||
// Render the viewer when the data is ready
|
||||
promise.then(({ studies, viewerData }) => {
|
||||
OHIF.viewer.data = viewerData;
|
||||
|
||||
const updatedStudies = createDisplaySets(studies);
|
||||
|
||||
this.setState({
|
||||
studies: updatedStudies,
|
||||
});
|
||||
}).catch(error => {
|
||||
this.setState({
|
||||
error,
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.error) {
|
||||
return (<div>Error: {JSON.stringify(this.state.error)}</div>);
|
||||
} else if (!this.state.studies) {
|
||||
return (<div>Loading...</div>);
|
||||
}
|
||||
|
||||
return (
|
||||
<Viewer studies={this.state.studies}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ViewerFromStudyData.propTypes = {
|
||||
studyInstanceUids: PropTypes.array.isRequired,
|
||||
seriesInstanceUids: PropTypes.array
|
||||
};
|
||||
|
||||
export default ViewerFromStudyData;
|
||||
34
OHIFViewer-react/src/ViewerRouting.js
Normal file
34
OHIFViewer-react/src/ViewerRouting.js
Normal file
@ -0,0 +1,34 @@
|
||||
import React, {Component} from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import ViewerFromStudyData from "./ViewerFromStudyData.js";
|
||||
|
||||
// TODO: Move to react-viewerbase
|
||||
|
||||
function ViewerRouting({ match }) {
|
||||
const { studyInstanceUids, seriesInstanceUids } = match.params;
|
||||
|
||||
let studyUIDs;
|
||||
let seriesUIDs;
|
||||
|
||||
if (studyInstanceUids && !seriesInstanceUids) {
|
||||
studyUIDs = studyInstanceUids.split(';');
|
||||
} else if (studyInstanceUids && seriesInstanceUids) {
|
||||
studyUIDs = [match.params.studyInstanceUid];
|
||||
seriesUIDs = match.params.seriesInstanceUids.split(';');
|
||||
}
|
||||
|
||||
return (
|
||||
<ViewerFromStudyData studyInstanceUids={studyUIDs} seriesInstanceUids={seriesUIDs}/>
|
||||
);
|
||||
}
|
||||
|
||||
ViewerRouting.propTypes = {
|
||||
match: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
studyInstanceUids: PropTypes.string.isRequired,
|
||||
seriesInstanceUids: PropTypes.string
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
export default ViewerRouting;
|
||||
37
OHIFViewer-react/src/config.js
Normal file
37
OHIFViewer-react/src/config.js
Normal file
@ -0,0 +1,37 @@
|
||||
import { OHIF } from 'ohif-core';
|
||||
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
|
||||
import sha from './sha.js';
|
||||
import version from './version.js';
|
||||
|
||||
OHIF.info = {
|
||||
sha,
|
||||
version
|
||||
};
|
||||
|
||||
|
||||
const maxWebWorkers = Math.max(navigator.hardwareConcurrency - 1, 1);
|
||||
const config = {
|
||||
maxWebWorkers,
|
||||
startWebWorkersOnDemand: true,
|
||||
webWorkerPath: OHIF.utils.absoluteUrl('packages/ohif_cornerstone/public/js/cornerstoneWADOImageLoaderWebWorker.es5.js'),
|
||||
taskConfiguration: {
|
||||
decodeTask: {
|
||||
loadCodecsOnStartup: true,
|
||||
initializeCodecsOnStartup: false,
|
||||
codecsPath: OHIF.utils.absoluteUrl('packages/ohif_cornerstone/public/js/cornerstoneWADOImageLoaderCodecs.es5.js'),
|
||||
usePDFJS: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
|
||||
|
||||
cornerstoneWADOImageLoader.configure({
|
||||
beforeSend: function(xhr) {
|
||||
const headers = OHIF.DICOMWeb.getAuthorizationHeader();
|
||||
|
||||
if (headers.Authorization) {
|
||||
xhr.setRequestHeader("Authorization", headers.Authorization);
|
||||
}
|
||||
}
|
||||
});
|
||||
169
OHIFViewer-react/src/flexboxLayout/flexboxLayout.js
Normal file
169
OHIFViewer-react/src/flexboxLayout/flexboxLayout.js
Normal file
@ -0,0 +1,169 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { OHIF } from 'ohif-core';
|
||||
import { StudyBrowser } from 'react-viewerbase';
|
||||
import cornerstone from 'cornerstone-core';
|
||||
|
||||
/**
|
||||
* Asynchronous wrapper around Cornerstone's renderToCanvas method.
|
||||
*
|
||||
* @param {HTMLElement} canvasElement An HTML <canvas> element
|
||||
* @param {Image} image A Cornerstone Image
|
||||
*
|
||||
* @return {Promise} A promise tracking the progress of the rendering. Resolves empty.
|
||||
*/
|
||||
function renderAsync(canvasElement, image) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
cornerstone.renderToCanvas(canvasElement, image);
|
||||
resolve();
|
||||
} catch(error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Define a handler for success on image load
|
||||
const loadSuccess = function(image, studyInstanceUid, displaySetInstanceUid) {
|
||||
// This is an off-screen canvas. It's used to get dataURL images by using
|
||||
// cornerstone.renderToCanvas function.
|
||||
const canvasElement = document.createElement('canvas');
|
||||
canvasElement.width = 193;
|
||||
canvasElement.height = 123;
|
||||
|
||||
// Render the image to canvas to be able to get its dataURL
|
||||
renderAsync(canvasElement, image).then(() => {
|
||||
const studies = this.state.studiesForBrowser;
|
||||
const study = studies.find(study => study.studyInstanceUid === studyInstanceUid);
|
||||
const thumbnail = study.thumbnails.find(t => t.displaySetInstanceUid === displaySetInstanceUid);
|
||||
|
||||
thumbnail.imageSrc = canvasElement.toDataURL('image/jpeg', 1);
|
||||
|
||||
this.setState({
|
||||
studiesForBrowser: studies
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Define a handler for error on image load
|
||||
const loadError = function(error, studyInstanceUid, displaySetInstanceUid) {
|
||||
const studies = this.state.studiesForBrowser;
|
||||
const study = studies.find(study => study.studyInstanceUid === studyInstanceUid);
|
||||
const thumbnail = study.thumbnails.find(t => t.displaySetInstanceUid === displaySetInstanceUid);
|
||||
|
||||
thumbnail.error = error;
|
||||
|
||||
this.setState({
|
||||
studiesForBrowser: studies
|
||||
});
|
||||
};
|
||||
|
||||
class FlexboxLayout extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
leftSidebarOpen: true,
|
||||
rightSidebarOpen: false,
|
||||
studiesForBrowser: this.getStudiesForBrowser(),
|
||||
};
|
||||
|
||||
this.getStudiesForBrowser = this.getStudiesForBrowser.bind(this);
|
||||
this.getThumbnailsFromImageIds = this.getThumbnailsFromImageIds.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getThumbnailsFromImageIds();
|
||||
}
|
||||
|
||||
getThumbnailsFromImageIds() {
|
||||
const studyThumbnails = this.state.studiesForBrowser.forEach(function (study) {
|
||||
const { studyInstanceUid } = study;
|
||||
|
||||
study.thumbnails.forEach(function (displaySet) {
|
||||
const imageId = displaySet.imageId;
|
||||
const {displaySetInstanceUid, seriesDescription, seriesNumber, instanceNumber, numImageFrames} = displaySet;
|
||||
|
||||
cornerstone.loadAndCacheImage(imageId).then((image) => {
|
||||
loadSuccess.call(this, image, studyInstanceUid, displaySetInstanceUid);
|
||||
}, error => {
|
||||
loadError.call(this, error, studyInstanceUid, displaySetInstanceUid);
|
||||
});
|
||||
}, this);
|
||||
}, this);
|
||||
|
||||
}
|
||||
|
||||
getStudiesForBrowser() {
|
||||
// @TypeSafeStudies
|
||||
const studies = OHIF.viewer.Studies.findAllBy({
|
||||
selected: true
|
||||
});
|
||||
|
||||
|
||||
// TODO[react]:
|
||||
// - Add sorting of display sets
|
||||
// - Pass in which display set is active from Redux
|
||||
// - Pass in errors and stack loading progress from Redux
|
||||
// - Add useMiddleSeriesInstanceAsThumbnail
|
||||
// - Add showStackLoadingProgressBar option
|
||||
return studies.map((study) => {
|
||||
const { studyInstanceUid } = study;
|
||||
|
||||
const thumbnails = study.displaySets.map((displaySet) => {
|
||||
const active = false;
|
||||
const stackPercentComplete = 0;
|
||||
const { displaySetInstanceUid, seriesDescription, seriesNumber, instanceNumber, numImageFrames } = displaySet;
|
||||
const imageId = displaySet.images[0].getImageId();
|
||||
return {
|
||||
imageSrc: '',
|
||||
imageId,
|
||||
displaySetInstanceUid,
|
||||
seriesDescription,
|
||||
seriesNumber,
|
||||
instanceNumber,
|
||||
numImageFrames,
|
||||
active,
|
||||
stackPercentComplete
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
studyInstanceUid,
|
||||
thumbnails
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let mainContentClassName = "mainContent"
|
||||
if (this.state.leftSidebarOpen) {
|
||||
mainContentClassName += ' sidebar-left-open';
|
||||
}
|
||||
|
||||
if (this.state.rightSidebarOpen) {
|
||||
mainContentClassName += ' sidebar-right-open';
|
||||
}
|
||||
|
||||
// TODO[react]: Add measurementLightTable
|
||||
return (
|
||||
<div className="viewerSection">
|
||||
<div className={this.state.leftSidebarOpen ? "sidebarMenu sidebar-left sidebar-open" : "sidebarMenu sidebar-left"}>
|
||||
<StudyBrowser studies={this.state.studiesForBrowser}/>
|
||||
</div>
|
||||
<div className={mainContentClassName}>
|
||||
{/* TODO: Needs to be moved from Meteor package to react-viewerbase: <ViewerMain studies={this.props.studies}/>*/}
|
||||
</div>
|
||||
<div className={this.state.rightSidebarOpen ? "sidebarMenu sidebar-right sidebar-open" : "sidebarMenu sidebar-right"}>
|
||||
{/*{{> measurementLightTable (clone this)}}*/}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FlexboxLayout.propTypes = {
|
||||
studies: PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
export default FlexboxLayout;
|
||||
65
OHIFViewer-react/src/flexboxLayout/flexboxLayout.styl
Normal file
65
OHIFViewer-react/src/flexboxLayout/flexboxLayout.styl
Normal file
@ -0,0 +1,65 @@
|
||||
.viewerSection
|
||||
display: flex
|
||||
flex: 1
|
||||
flex-flow: row nowrap
|
||||
align-items: stretch
|
||||
height: 'calc(100% - %s)' % ($toolbarHeight)
|
||||
width: 100%
|
||||
|
||||
.sidebarMenu
|
||||
height: 100%
|
||||
// required transformation to make inner fixed elements relative to this one
|
||||
transform(scale(1))
|
||||
transition($sidebarTransition)
|
||||
|
||||
.sidebar-option
|
||||
height: 100%
|
||||
max-width: inherit
|
||||
position: absolute
|
||||
transform(translateX(100%))
|
||||
transition($sidebarTransition)
|
||||
width: 100%
|
||||
|
||||
&.active
|
||||
transform(translateX(0%))
|
||||
|
||||
.sidebar-left
|
||||
theme('border-right', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
flex: 1
|
||||
margin-left: - $studiesSidebarMenuWidth
|
||||
max-width: $studiesSidebarMenuWidth
|
||||
order: 1
|
||||
|
||||
&.sidebar-open
|
||||
margin-left: 0
|
||||
|
||||
.mainContent
|
||||
flex: 1
|
||||
height: 100%
|
||||
order: 2
|
||||
overflow: hidden
|
||||
transition($sidebarTransition)
|
||||
width: 100%
|
||||
|
||||
.sidebar-right
|
||||
flex: 1
|
||||
margin-right: - $rightSidebarMenuWidth
|
||||
max-width: $rightSidebarMenuWidth
|
||||
order: 3
|
||||
position: relative
|
||||
|
||||
&[data-timepoints="3"]
|
||||
margin-right: - ($rightSidebarMenuWidth + 135.5px)
|
||||
max-width: $rightSidebarMenuWidth + 135.5px
|
||||
|
||||
&[data-timepoints="4"]
|
||||
margin-right: - ($rightSidebarMenuWidth + 270px)
|
||||
max-width: $rightSidebarMenuWidth + 270px
|
||||
|
||||
&.sidebar-open
|
||||
margin-right: 0
|
||||
|
||||
.studiesListedChanger
|
||||
theme('border-bottom', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
padding: 20px 10px
|
||||
text-align: center
|
||||
15
OHIFViewer-react/src/head.html
Normal file
15
OHIFViewer-react/src/head.html
Normal file
@ -0,0 +1,15 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>OHIF Viewer</title>
|
||||
<meta name="description" content="Open Health Imaging Foundation DICOM Viewer">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<link rel="shortcut icon" type="image/png" href="/images/logo.png" sizes="16x16 32x32 64x64">
|
||||
<!--Best display for mobile devices-->
|
||||
<meta http-equiv="cleartype" content="on">
|
||||
<meta name="MobileOptimized" content="320">
|
||||
<meta name="HandheldFriendly" content="True">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
22
OHIFViewer-react/src/index.js
Normal file
22
OHIFViewer-react/src/index.js
Normal file
@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import { createStore } from 'redux';
|
||||
import App from './App.js';
|
||||
import { OHIF } from 'ohif-core';
|
||||
import './config';
|
||||
|
||||
const store = createStore(OHIF.redux.combinedReducer);
|
||||
|
||||
// TODO[react] Use a provider when the whole tree is React
|
||||
window.store = store;
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<App store={store}/>
|
||||
</BrowserRouter>
|
||||
</Provider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
3
OHIFViewer-react/src/log.js
Normal file
3
OHIFViewer-react/src/log.js
Normal file
@ -0,0 +1,3 @@
|
||||
import loglevel from 'loglevel';
|
||||
log = loglevel.getLogger('OHIFViewer');
|
||||
log.setLevel('info');
|
||||
1
OHIFViewer-react/src/sha.js
Normal file
1
OHIFViewer-react/src/sha.js
Normal file
@ -0,0 +1 @@
|
||||
export default '7b66dec163174eae2f6aca133f740529c8b4d08c';
|
||||
1
OHIFViewer-react/src/version.js
Normal file
1
OHIFViewer-react/src/version.js
Normal file
@ -0,0 +1 @@
|
||||
export default '0.0.0';
|
||||
99
OHIFViewer-react/src/viewer/viewer.js
Normal file
99
OHIFViewer-react/src/viewer/viewer.js
Normal file
@ -0,0 +1,99 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cornerstone from 'cornerstone-core';
|
||||
import cornerstoneTools from 'cornerstone-tools';
|
||||
import { OHIF } from 'ohif-core';
|
||||
import { CineDialog } from 'react-viewerbase';
|
||||
import FlexboxLayout from '../flexboxLayout/flexboxLayout.js';
|
||||
|
||||
/**
|
||||
* Inits OHIF Hanging Protocol's onReady.
|
||||
* It waits for OHIF Hanging Protocol to be ready to instantiate the ProtocolEngine
|
||||
* Hanging Protocol will use OHIF LayoutManager to render viewports properly
|
||||
*/
|
||||
/*const initHangingProtocol = () => {
|
||||
// When Hanging Protocol is ready
|
||||
HP.ProtocolStore.onReady(() => {
|
||||
|
||||
// Gets all StudyMetadata objects: necessary for Hanging Protocol to access study metadata
|
||||
const studyMetadataList = OHIF.viewer.StudyMetadataList.all();
|
||||
|
||||
// Caches Layout Manager: Hanging Protocol uses it for layout management according to current protocol
|
||||
const layoutManager = OHIF.viewerbase.layoutManager;
|
||||
|
||||
// Instantiate StudyMetadataSource: necessary for Hanging Protocol to get study metadata
|
||||
const studyMetadataSource = new OHIF.studies.classes.OHIFStudyMetadataSource();
|
||||
|
||||
// Get prior studies map
|
||||
const studyPriorsMap = OHIF.studylist.functions.getStudyPriorsMap(studyMetadataList);
|
||||
|
||||
// Creates Protocol Engine object with required arguments
|
||||
const ProtocolEngine = new HP.ProtocolEngine(layoutManager, studyMetadataList, studyPriorsMap, studyMetadataSource);
|
||||
|
||||
// Sets up Hanging Protocol engine
|
||||
HP.setEngine(ProtocolEngine);
|
||||
});
|
||||
};*/
|
||||
|
||||
|
||||
OHIF.viewer.defaultTool = {
|
||||
left: 'wwwc',
|
||||
right: 'zoom',
|
||||
middle: 'pan'
|
||||
};
|
||||
|
||||
OHIF.viewer.refLinesEnabled = true;
|
||||
OHIF.viewer.cine = {
|
||||
framesPerSecond: 24,
|
||||
loop: true
|
||||
};
|
||||
|
||||
const viewportUtils = OHIF.viewerbase.viewportUtils;
|
||||
|
||||
OHIF.viewer.functionList = {
|
||||
toggleCineDialog: viewportUtils.toggleCineDialog,
|
||||
toggleCinePlay: viewportUtils.toggleCinePlay,
|
||||
clearTools: viewportUtils.clearTools,
|
||||
resetViewport: viewportUtils.resetViewport,
|
||||
invert: viewportUtils.invert
|
||||
};
|
||||
|
||||
// Create the synchronizer used to update reference lines
|
||||
OHIF.viewer.updateImageSynchronizer = new cornerstoneTools.Synchronizer('cornerstonenewimage', cornerstoneTools.updateImageSynchronizer);
|
||||
|
||||
OHIF.viewer.metadataProvider = new OHIF.cornerstone.MetadataProvider();
|
||||
|
||||
// Metadata configuration
|
||||
const metadataProvider = OHIF.viewer.metadataProvider;
|
||||
cornerstone.metaData.addProvider(metadataProvider.provider.bind(metadataProvider));
|
||||
|
||||
class Viewer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
leftSidebar: 'studies',
|
||||
rightSidebar: 'measurements',
|
||||
studies: this.props.studies
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<>
|
||||
<div className='viewerDialogs'>
|
||||
{/*<CineDialog/>*/}
|
||||
</div>
|
||||
<div id="viewer" className='Viewer'>
|
||||
{/*<ToolbarSection/>*/}
|
||||
<FlexboxLayout studies={this.state.studies}/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Viewer.propTypes = {
|
||||
studies: PropTypes.array
|
||||
};
|
||||
|
||||
export default Viewer;
|
||||
13
OHIFViewer-react/src/viewer/viewer.styl
Normal file
13
OHIFViewer-react/src/viewer/viewer.styl
Normal file
@ -0,0 +1,13 @@
|
||||
@import "{ohif:viewerbase}/app"
|
||||
|
||||
body
|
||||
background-color: black
|
||||
|
||||
#viewer
|
||||
background-color: black
|
||||
height: 100%
|
||||
width: 100%
|
||||
|
||||
.loadingTextDiv
|
||||
theme('color', '$textSecondaryColor')
|
||||
font-size: 30px
|
||||
10139
OHIFViewer-react/yarn-error.log
Normal file
10139
OHIFViewer-react/yarn-error.log
Normal file
File diff suppressed because it is too large
Load Diff
10103
OHIFViewer-react/yarn.lock
Normal file
10103
OHIFViewer-react/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user