feat: Viewport API + Documentation Page

This commit is contained in:
Rodrigo Antinarelli 2020-04-22 19:00:35 -03:00 committed by James A. Petts
parent 5f9535a74b
commit 12d1ff6bea
6 changed files with 254 additions and 71 deletions

View File

@ -1,38 +1,62 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import { ViewportActionBar, Notification, Button } from '@ohif/ui'; import { ViewportActionBar, Notification, Button } from '@ohif/ui';
const Viewport = ({ const Viewport = ({ viewportIndex, onSeriesChange, studyData, children }) => {
viewportIndex,
onSeriesChange,
studyData,
isTracked,
studyDate,
modality,
currentSeries,
patientInformation,
activeViewportIndex,
children,
}) => {
return ( return (
<div className="flex flex-col h-full"> <div className="flex flex-col h-full relative">
<ViewportActionBar isTracked modality={modality} /> <div className="absolute top-0 left-0 w-full">
<ViewportActionBar
onSeriesChange={onSeriesChange}
studyData={studyData}
/>
{/* TODO: NOTIFICATION API DEFINITION - OHIF-112 */} {/* TODO: NOTIFICATION API DEFINITION - OHIF-112 */}
<Notification <Notification
text="Track all measurement for this series?" text="Track all measurement for this series?"
type="info" type="info"
actionButtons={ actionButtons={
<div> <div>
<Button>No</Button> <Button>No</Button>
<Button className="ml-2">No, do not ask again</Button> <Button className="ml-2">No, do not ask again</Button>
<Button className="ml-2" color="primary"> <Button className="ml-2" color="primary">
Yes Yes
</Button> </Button>
</div> </div>
} }
/> />
</div>
{/* STUDY IMAGE */}
<div className="w-full h-full" id={`viewport-${viewportIndex}`}>
{children}
</div>
</div> </div>
); );
}; };
Viewport.propTypes = {
viewportIndex: PropTypes.number.isRequired,
onSeriesChange: PropTypes.func.isRequired,
studyData: PropTypes.shape({
label: PropTypes.string.isRequired,
isTracked: PropTypes.bool.isRequired,
isLocked: PropTypes.bool.isRequired,
studyDate: PropTypes.string.isRequired,
currentSeries: PropTypes.number.isRequired,
seriesDescription: PropTypes.string.isRequired,
modality: PropTypes.string.isRequired,
patientInformation: PropTypes.shape({
patientName: PropTypes.string.isRequired,
patientSex: PropTypes.string.isRequired,
patientAge: PropTypes.string.isRequired,
MRN: PropTypes.string.isRequired,
thickness: PropTypes.string.isRequired,
spacing: PropTypes.string.isRequired,
scanner: PropTypes.string.isRequired,
}),
}).isRequired,
children: PropTypes.node.isRequired,
};
export default Viewport; export default Viewport;

View File

@ -10,7 +10,41 @@ const classes = {
row: 'flex flex-col ml-4', row: 'flex flex-col ml-4',
}; };
const ViewportActionBar = ({ isTracked, isLocked, modality }) => { // isTracked: true,
// studyDate: '07-Sep-2010',
// currentSeries: 1,
// modality: 'CT',
// patientInformation: {
// patientName: 'Smith, Jane',
// patientSex: 'F',
// patientAge: '59',
// MRN: '10000001',
// thickness: '5.0mm',
// spacing: '1.25mm',
// scanner: 'Aquilion',
const ViewportActionBar = ({ studyData, onSeriesChange }) => {
const {
label,
isTracked,
isLocked,
modality,
studyDate,
currentSeries,
seriesDescription,
patientInformation,
} = studyData;
const {
patientName,
patientSex,
patientAge,
MRN,
thickness,
spacing,
scanner,
} = patientInformation;
const renderIconStatus = () => { const renderIconStatus = () => {
if (modality === 'SR') { if (modality === 'SR') {
return ( return (
@ -73,28 +107,36 @@ const ViewportActionBar = ({ isTracked, isLocked, modality }) => {
<div className="flex flex-grow"> <div className="flex flex-grow">
<div className="flex items-center"> <div className="flex items-center">
{renderIconStatus()} {renderIconStatus()}
<span className="text-large text-white ml-2">A</span> <span className="text-large text-white ml-2">{label}</span>
</div> </div>
<div className="flex flex-col justify-start ml-4"> <div className="flex flex-col justify-start ml-4">
<div className="flex"> <div className="flex">
<span className="text-base text-white">07-Sep-2010</span> <span className="text-base text-white">{studyDate}</span>
<span className="border-l border-primary-light ml-2 pl-2 text-base text-primary-light"> <span className="border-l border-primary-light ml-2 pl-2 text-base text-primary-light">
S: 1 S: {currentSeries}
</span> </span>
</div> </div>
<div className="flex"> <div className="flex">
<span className="text-base text-primary-light"> <p className="text-base truncate max-w-sm text-primary-light">
Series description lorem ipsum dolor sit... {seriesDescription}
</span> </p>
</div> </div>
</div> </div>
</div> </div>
<div className="ml-2"> <div className="ml-2">
<ButtonGroup> <ButtonGroup>
<Button size="initial" className="py-1 px-2"> <Button
size="initial"
className="py-1 px-2"
onClick={() => onSeriesChange('left')}
>
<Icon name="chevron-left" className="text-white w-4" /> <Icon name="chevron-left" className="text-white w-4" />
</Button> </Button>
<Button size="initial" className="py-1 px-2"> <Button
size="initial"
className="py-1 px-2"
onClick={() => onSeriesChange('right')}
>
<Icon name="chevron-right" className="text-white w-4" /> <Icon name="chevron-right" className="text-white w-4" />
</Button> </Button>
</ButtonGroup> </ButtonGroup>
@ -120,22 +162,24 @@ const ViewportActionBar = ({ isTracked, isLocked, modality }) => {
</div> </div>
<div className="flex flex-col ml-2"> <div className="flex flex-col ml-2">
<span className="text-base font-bold text-white"> <span className="text-base font-bold text-white">
Smith, Jane {patientName}
</span> </span>
<div className="flex mt-4 pb-4 mb-4 border-b border-secondary-main"> <div className="flex mt-4 pb-4 mb-4 border-b border-secondary-main">
<div className={classnames(classes.firstRow)}> <div className={classnames(classes.firstRow)}>
<span className={classnames(classes.infoHeader)}>Sex</span> <span className={classnames(classes.infoHeader)}>Sex</span>
<span className={classnames(classes.infoText)}>F</span> <span className={classnames(classes.infoText)}>
{patientSex}
</span>
</div> </div>
<div className={classnames(classes.row)}> <div className={classnames(classes.row)}>
<span className={classnames(classes.infoHeader)}>Age</span> <span className={classnames(classes.infoHeader)}>Age</span>
<span className={classnames(classes.infoText)}>59</span> <span className={classnames(classes.infoText)}>
{patientAge}
</span>
</div> </div>
<div className={classnames(classes.row)}> <div className={classnames(classes.row)}>
<span className={classnames(classes.infoHeader)}>MRN</span> <span className={classnames(classes.infoHeader)}>MRN</span>
<span className={classnames(classes.infoText)}> <span className={classnames(classes.infoText)}>{MRN}</span>
10000001
</span>
</div> </div>
</div> </div>
<div className="flex"> <div className="flex">
@ -143,14 +187,16 @@ const ViewportActionBar = ({ isTracked, isLocked, modality }) => {
<span className={classnames(classes.infoHeader)}> <span className={classnames(classes.infoHeader)}>
Thickness Thickness
</span> </span>
<span className={classnames(classes.infoText)}>5.00mm</span> <span className={classnames(classes.infoText)}>
{thickness}
</span>
</div> </div>
<div className={classnames(classes.row)}> <div className={classnames(classes.row)}>
<span className={classnames(classes.infoHeader)}> <span className={classnames(classes.infoHeader)}>
Spacing Spacing
</span> </span>
<span className={classnames(classes.infoText)}> <span className={classnames(classes.infoText)}>
1.25 mm {spacing}
</span> </span>
</div> </div>
<div className={classnames(classes.row)}> <div className={classnames(classes.row)}>
@ -158,7 +204,7 @@ const ViewportActionBar = ({ isTracked, isLocked, modality }) => {
Scanner Scanner
</span> </span>
<span className={classnames(classes.infoText)}> <span className={classnames(classes.infoText)}>
Aquilion {scanner}
</span> </span>
</div> </div>
</div> </div>
@ -181,14 +227,26 @@ const ViewportActionBar = ({ isTracked, isLocked, modality }) => {
); );
}; };
ViewportActionBar.defaultProps = {
isLocked: false,
};
ViewportActionBar.propTypes = { ViewportActionBar.propTypes = {
isTracked: PropTypes.bool.isRequired, onSeriesChange: PropTypes.func.isRequired,
isLocked: PropTypes.bool, studyData: PropTypes.shape({
modality: PropTypes.string.isRequired, label: PropTypes.string.isRequired,
isTracked: PropTypes.bool.isRequired,
isLocked: PropTypes.bool.isRequired,
studyDate: PropTypes.string.isRequired,
currentSeries: PropTypes.number.isRequired,
seriesDescription: PropTypes.string.isRequired,
modality: PropTypes.string.isRequired,
patientInformation: PropTypes.shape({
patientName: PropTypes.string.isRequired,
patientSex: PropTypes.string.isRequired,
patientAge: PropTypes.string.isRequired,
MRN: PropTypes.string.isRequired,
thickness: PropTypes.string.isRequired,
spacing: PropTypes.string.isRequired,
scanner: PropTypes.string.isRequired,
}),
}).isRequired,
}; };
export default ViewportActionBar; export default ViewportActionBar;

View File

@ -21,25 +21,109 @@ import { ViewportActionBar } from '@ohif/ui';
<Playground> <Playground>
<div className="p-4 h-64"> <div className="p-4 h-64">
<ViewportActionBar isTracked={true} modality="CT" /> <ViewportActionBar
onSeriesChange={(direction) => alert(`Series ${direction}`)}
studyData={{
label: 'A',
isTracked: true,
isLocked: false,
studyDate: '07-Sep-2010',
currentSeries: 1,
seriesDescription:
'Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit ',
modality: 'CT',
patientInformation: {
patientName: 'Smith, Jane',
patientSex: 'F',
patientAge: '59',
MRN: '10000001',
thickness: '2.0mm',
spacing: '1.25mm',
scanner: 'Aquilion',
},
}}
/>
</div> </div>
</Playground> </Playground>
<Playground> <Playground>
<div className="p-4 h-64"> <div className="p-4 h-64">
<ViewportActionBar isTracked={false} modality="CT" /> <ViewportActionBar
onSeriesChange={(direction) => alert(`Series ${direction}`)}
studyData={{
label: 'A',
isTracked: false,
isLocked: true,
studyDate: '07-Sep-2010',
currentSeries: 1,
seriesDescription:
'Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit ',
modality: 'CT',
patientInformation: {
patientName: 'Smith, Jane',
patientSex: 'F',
patientAge: '59',
MRN: '10000001',
thickness: '2.0mm',
spacing: '1.25mm',
scanner: 'Aquilion',
},
}}
/>
</div> </div>
</Playground> </Playground>
<Playground> <Playground>
<div className="p-4 h-64"> <div className="p-4 h-64">
<ViewportActionBar isTracked={false} isLocked={false} modality="SR" /> <ViewportActionBar
onSeriesChange={(direction) => alert(`Series ${direction}`)}
studyData={{
label: 'A',
isTracked: false,
isLocked: false,
studyDate: '07-Sep-2010',
currentSeries: 1,
seriesDescription:
'Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit ',
modality: 'SR',
patientInformation: {
patientName: 'Smith, Jane',
patientSex: 'F',
patientAge: '59',
MRN: '10000001',
thickness: '2.0mm',
spacing: '1.25mm',
scanner: 'Aquilion',
},
}}
/>
</div> </div>
</Playground> </Playground>
<Playground> <Playground>
<div className="p-4 h-64"> <div className="p-4 h-64">
<ViewportActionBar isTracked={false} isLocked={true} modality="SR" /> <ViewportActionBar
onSeriesChange={(direction) => alert(`Series ${direction}`)}
studyData={{
label: 'A',
isTracked: false,
isLocked: true,
studyDate: '07-Sep-2010',
currentSeries: 1,
seriesDescription:
'Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit ',
modality: 'SR',
patientInformation: {
patientName: 'Smith, Jane',
patientSex: 'F',
patientAge: '59',
MRN: '10000001',
thickness: '2.0mm',
spacing: '1.25mm',
scanner: 'Aquilion',
},
}}
/>
</div> </div>
</Playground> </Playground>

View File

@ -15,6 +15,9 @@ const ViewportGrid = ({ rows, cols, viewportContents }) => {
'border border-secondary-light': !isActive, 'border border-secondary-light': !isActive,
} }
)} )}
onClick={() => {
setActiveViewportIndex(index);
}}
> >
{viewportContent} {viewportContent}
</div> </div>

View File

@ -80,11 +80,15 @@ import { tabs } from './studyBrowserMockData';
viewportContents={[ viewportContents={[
<Viewport <Viewport
viewportIndex={0} viewportIndex={0}
onSeriesChange={() => {}} onSeriesChange={(direction) => alert(`Series ${direction}`)}
studyData={{ studyData={{
isTracked: false, label: 'A',
studyDate: '07-Sep-2010', isTracked: true,
isLocked: false,
studyDate: '07-Sep-2011',
currentSeries: 1, currentSeries: 1,
seriesDescription:
'Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit ',
modality: 'CT', modality: 'CT',
patientInformation: { patientInformation: {
patientName: 'Smith, Jane', patientName: 'Smith, Jane',
@ -96,27 +100,38 @@ import { tabs } from './studyBrowserMockData';
scanner: 'Aquilion', scanner: 'Aquilion',
}, },
}} }}
isTracked={false} >
activeViewportIndex={activeViewportIndex} <div className="flex justify-center items-center h-full">
/>, CONTENT
</div>
</Viewport>,
<Viewport <Viewport
viewportIndex={1} viewportIndex={1}
onSeriesChange={() => {}} onSeriesChange={(direction) => alert(`Series ${direction}`)}
studyData={{ studyData={{
label: 'A',
isTracked: false, isTracked: false,
isLocked: true,
studyDate: '07-Sep-2010', studyDate: '07-Sep-2010',
currentSeries: 1, currentSeries: 2,
modality: 'CT', seriesDescription:
'Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit ',
modality: 'SR',
patientInformation: { patientInformation: {
patientName: 'Smith, Jane', patientName: 'Smith, Jane',
patientSex: 'F', patientSex: 'F',
patientAge: '59', patientAge: '59',
MRN: '10000001', MRN: '10000001',
thickness: '2.0mm',
spacing: '1.25mm',
scanner: 'Aquilion',
}, },
}} }}
isTracked={false} >
activeViewportIndex={activeViewportIndex} <div className="flex justify-center items-center h-full">
/>, CONTENT
</div>
</Viewport>,
]} ]}
setActiveViewportIndex={setActiveViewportIndex} setActiveViewportIndex={setActiveViewportIndex}
activeViewportIndex={activeViewportIndex} activeViewportIndex={activeViewportIndex}

View File

@ -1,5 +1,4 @@
import React, { useState } from 'react'; import React from 'react';
import classnames from 'classnames';
import { Toolbar } from '@ohif/ui'; import { Toolbar } from '@ohif/ui';