2018-11-30 17:40:01 +01:00
|
|
|
import { Component } from 'react';
|
|
|
|
|
import React from 'react';
|
|
|
|
|
import PropTypes from 'prop-types';
|
2018-12-14 14:38:36 +01:00
|
|
|
import { OHIF } from 'ohif-core';
|
2018-12-06 16:09:31 +01:00
|
|
|
import { cornerstone, cornerstoneTools } from 'meteor/ohif:cornerstone';
|
|
|
|
|
import ConnectedCornerstoneViewport from '../ConnectedCornerstoneViewport.js';
|
2018-11-30 17:40:01 +01:00
|
|
|
import './GridLayout.styl';
|
2018-12-06 13:10:46 +01:00
|
|
|
import StackManager from '../../../lib/StackManager.js';
|
2018-11-30 17:40:01 +01:00
|
|
|
|
|
|
|
|
const TOP_CLASS = 'top';
|
|
|
|
|
const BOTTOM_CLASS = 'bottom';
|
|
|
|
|
const MIDDLE_CLASS = 'middle';
|
|
|
|
|
|
2018-12-06 13:10:46 +01:00
|
|
|
function getCornerstoneStack(viewportData) {
|
|
|
|
|
const {
|
|
|
|
|
displaySetInstanceUid,
|
|
|
|
|
studyInstanceUid,
|
|
|
|
|
} = viewportData;
|
|
|
|
|
|
|
|
|
|
// Create shortcut to displaySet
|
|
|
|
|
const study = OHIF.viewer.Studies.findBy({
|
|
|
|
|
studyInstanceUid,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const displaySet = study.displaySets.find((set) => {
|
|
|
|
|
return set.displaySetInstanceUid === displaySetInstanceUid;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Get stack from Stack Manager
|
|
|
|
|
const stack = StackManager.findOrCreateStack(study, displaySet);
|
|
|
|
|
stack.currentImageIdIndex = 0;
|
|
|
|
|
|
|
|
|
|
return stack;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-30 17:40:01 +01:00
|
|
|
class GridLayout extends Component {
|
|
|
|
|
constructor(props) {
|
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
|
|
this.getClass = this.getClass.bind(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get class for each viewport, so each app
|
|
|
|
|
// using ohif-viewerbase can style on their own
|
|
|
|
|
getClass(index) {
|
|
|
|
|
const { rows, columns } = this.props;
|
|
|
|
|
|
|
|
|
|
if (rows === 1) {
|
|
|
|
|
return `${TOP_CLASS} ${BOTTOM_CLASS}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const actualRow = Math.floor(index / columns);
|
|
|
|
|
|
|
|
|
|
if ( actualRow === 0 ) {
|
|
|
|
|
return TOP_CLASS;
|
|
|
|
|
}
|
|
|
|
|
if ( actualRow + 1 === rows ) {
|
|
|
|
|
return BOTTOM_CLASS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return MIDDLE_CLASS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getActiveClass(index) {
|
2018-12-06 16:09:31 +01:00
|
|
|
if (this.props.activeViewportIndex === index) {
|
2018-11-30 17:40:01 +01:00
|
|
|
return 'active';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return ''
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
|
// Get the height percentage for each viewport
|
|
|
|
|
const rows = this.props.rows || 1;
|
|
|
|
|
const height = 100 / rows;
|
|
|
|
|
|
|
|
|
|
// Get the width percentage for each viewport
|
|
|
|
|
const columns = this.props.columns || 1;
|
|
|
|
|
const width = 100 / columns;
|
|
|
|
|
|
|
|
|
|
let viewportData = this.props.viewportData;
|
|
|
|
|
const numViewports = rows * columns;
|
|
|
|
|
const numViewportsWithData = viewportData.length;
|
|
|
|
|
|
|
|
|
|
// Check if the viewportData length is different from the given
|
|
|
|
|
if (numViewportsWithData < numViewports) {
|
|
|
|
|
// Add the missing viewports
|
|
|
|
|
const difference = numViewports - numViewportsWithData;
|
|
|
|
|
for (let i = 0; i < difference; i++) {
|
|
|
|
|
viewportData.push({
|
|
|
|
|
viewportIndex: numViewportsWithData + i + 1,
|
|
|
|
|
rows,
|
|
|
|
|
columns
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} else if (numViewportsWithData > numViewports) {
|
|
|
|
|
// Remove the additional viewports
|
|
|
|
|
viewportData = viewportData.slice(0, numViewports);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-30 20:28:15 +01:00
|
|
|
const viewports = viewportData.map((data, index) => {
|
|
|
|
|
const className = `viewportContainer ${this.getClass(index)} ${this.getActiveClass(index)}`;
|
2018-12-06 13:10:46 +01:00
|
|
|
|
2018-12-03 23:56:29 +01:00
|
|
|
// TODO[react]: Not sure why I needed to do this. Looks like
|
|
|
|
|
// empty viewports aren't provided with a viewportIndex normally?
|
|
|
|
|
data.viewportIndex = index;
|
2018-11-30 17:40:01 +01:00
|
|
|
|
|
|
|
|
const styles = {
|
|
|
|
|
height: `${height}%`,
|
|
|
|
|
width: `${width}%`,
|
|
|
|
|
};
|
|
|
|
|
|
2018-12-06 13:10:46 +01:00
|
|
|
const cornerstoneViewport = (data) => {
|
|
|
|
|
const stack = getCornerstoneStack(data)
|
|
|
|
|
const viewportData = {
|
|
|
|
|
stack,
|
|
|
|
|
...data
|
|
|
|
|
};
|
|
|
|
|
|
2018-12-06 16:09:31 +01:00
|
|
|
return (<ConnectedCornerstoneViewport
|
2018-12-06 13:10:46 +01:00
|
|
|
viewportData={viewportData}
|
|
|
|
|
cornerstone={cornerstone}
|
|
|
|
|
cornerstoneTools={cornerstoneTools}
|
|
|
|
|
/>);
|
|
|
|
|
};
|
2018-11-30 17:40:01 +01:00
|
|
|
|
2018-11-30 20:28:15 +01:00
|
|
|
const pluginViewport = (data) => (
|
|
|
|
|
<div className={`viewport-plugin-${data.plugin}`} style="height:100%; width: 100%">
|
2018-11-30 17:40:01 +01:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
|
2018-12-06 13:10:46 +01:00
|
|
|
let contents;
|
2018-12-03 23:56:29 +01:00
|
|
|
if (!data.studyInstanceUid || !data.displaySetInstanceUid) {
|
|
|
|
|
contents = (
|
|
|
|
|
<div className="CornerstoneViewport">
|
|
|
|
|
<div className="viewportInstructions">
|
|
|
|
|
Please drag a stack here to view images.
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
} else if (data.plugin === 'cornerstone') {
|
|
|
|
|
contents = cornerstoneViewport(data);
|
|
|
|
|
} else {
|
|
|
|
|
contents = pluginViewport(data);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-30 17:40:01 +01:00
|
|
|
return (
|
2018-11-30 20:28:15 +01:00
|
|
|
<div key={index} className={className} style={styles}>
|
2018-12-03 23:56:29 +01:00
|
|
|
{contents}
|
|
|
|
|
{/*{>seriesQuickSwitch (clone this viewport=viewport viewportIndex=@index)}*/}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
});
|
2018-11-30 17:40:01 +01:00
|
|
|
|
2018-11-30 20:28:15 +01:00
|
|
|
const layoutClass = `layout-${rows}-${columns}`;
|
|
|
|
|
|
2018-11-30 17:40:01 +01:00
|
|
|
return (
|
2018-11-30 21:23:59 +01:00
|
|
|
<div id='imageViewerViewports' className={layoutClass}>
|
2018-11-30 20:28:15 +01:00
|
|
|
{ viewports }
|
2018-11-30 17:40:01 +01:00
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default GridLayout;
|