* Filter segs and fetch correct metadata. * Initiate seg loading logic on series load into viewport. Need to write. * Automatic consumption of SEG functional. * Pull in master. * Fix issues after pulling in master. * Clean up old segmentation handlers. * WIP * WIP * Poppulate viewport with metadata. * Show hide/segmentation in react-vtkjs-viewport. * feat: 🎸 View segmentations in vtkjs viewport * Filter segs and fetch correct metadata. * Initiate seg loading logic on series load into viewport. Need to write. * Automatic consumption of SEG functional. * Pull in master. * Fix issues after pulling in master. * Clean up old segmentation handlers. * WIP * WIP * Poppulate viewport with metadata. * Show hide/segmentation in react-vtkjs-viewport. * feat: 🎸 View segmentations in vtkjs viewport * Rebase on master. * format format format * add basic extension parts * Updated yarn lock * Fetch derived/referenced displaysets in sidepanel * Add buttons, expose seriesDescription, write notes for Danny. * Add growcut tool extention. -> Move to a seperate repo. * Change some text fields. * expose dialog provider * hide draggable area * No pointer events for now; need to revisit * Don't filter seg from the outset for now * fiddling about * fix path to series data * fix logic to determine next available labelmapindex * Ability to swtich between labelmaps * Return a promise so we can make sure our labelmap is loaded before pulling metadata * Better UI to toggle labelmaps * Fix accidental untoggle of active labelmap for ui * Remove brush tool from cornerstone extension * Add cstools in preInit for seg extension * Add buttons for seg magic * Hide the measurements panel for now * Slightly better seg/scissor icons * Add eraser * ability to switch segments * seg color / switcher * Fix vtk labelmap cache. * sidepanel should scroll if there's overflow * Use a fancier range slider * Slightly prettier buttons * Push in progress * A bit more reactive; handle no-meta * Update to vtk.js 11.14.0 and react-vtkjs-viewport 0.6.0 * chore: kickstart preview * Fix conflict issues * Refactor panel * Isolate increment functions * Wip segment table * Hide selector and add scroll to segmentation * Increase width of segment description * Hide not used items * Add new select for segmentations * Align ui * Fix default segmentation * Fix broken import test * Get measurements panel back and add spacing to grouped buttons * Hide brush and selector and refresh when switching segmentations * Add pointer events back and fix broken tests for measurement table * Update segment list when switching humbnails * CR Update: Minor UI adjustments * CR Update: Set active segment * Move components to components folder * Add new settings ui * Integrate configuration * Improve styles * Float numbers * Improve css * Refresh settings menu if side panel changed * Fix settings rendering logic and remove comments * Extract components * Remove not used tools * Remove non used extension * Use style variables and remove comments * Remove non used dep from lock * Remove tools * Remove segmentation from toolbar * Add todo and brushradius from config * Fix packagejson growcut import * Remove webpack config already defined in parent * Update package json description * Change component name to british english to us * Improve prop types * Rename cornerstone label map event * Scope css * Extract and add doc to helper * Update jsdocs for getDerivedDatasets * Add proptypes and cr updates * Update tablistitem proptypes * config is readonly, rollback destructuring * Remove event for side panel * Add jsdocs for util * Extract getimageid to studymetada * Use ohif log instead of console * Remove specific style from side panel * Fix default props for brush radius * Descructure configuration props from settings component to avoid invalid props * Update proptypes to be required (settings) * Update readme * Remove commandsmodule * Get configuration module inside the component * Set selected segment * Rename extension and use modality to filter * Fix for failing tests (#1423) * hello world * Finish rebase for Igor. * Re-fix cornerstoneTools version that got messed up in merge. * Fix reactivity of isDisabled, write implementation for the SEG panel. * Nuke yarn.lock to stack CST to 4.12.0 * Remove debugger statements. * fix: bump cornerstone-tools version to address toFixed issue * test: force tests for MISTER^MR to navigate to study directly * test: remove eraser tool test * test: count is off by one * test: don't save SR state for the time being * test: disable more tests Co-authored-by: James A. Petts <jamesapetts@gmail.com> Co-authored-by: dannyrb <danny.ri.brown@gmail.com> Co-authored-by: igoroctaviano] <igoroctaviano@users.noreply.github.com> Co-authored-by: Mirna Silva <mirna.silva@radicalimaging.com>
239 lines
5.6 KiB
JavaScript
239 lines
5.6 KiB
JavaScript
import React, { Component } from 'react';
|
|
|
|
import ConnectedCornerstoneViewport from './ConnectedCornerstoneViewport';
|
|
import OHIF from '@ohif/core';
|
|
import PropTypes from 'prop-types';
|
|
import cornerstone from 'cornerstone-core';
|
|
|
|
const { StackManager } = OHIF.utils;
|
|
|
|
class OHIFCornerstoneViewport extends Component {
|
|
state = {
|
|
viewportData: null,
|
|
};
|
|
|
|
static defaultProps = {
|
|
customProps: {},
|
|
};
|
|
|
|
static propTypes = {
|
|
studies: PropTypes.object,
|
|
displaySet: PropTypes.object,
|
|
viewportIndex: PropTypes.number,
|
|
children: PropTypes.node,
|
|
customProps: PropTypes.object,
|
|
};
|
|
|
|
static id = 'OHIFCornerstoneViewport';
|
|
|
|
static init() {
|
|
console.log('OHIFCornerstoneViewport init()');
|
|
}
|
|
|
|
static destroy() {
|
|
console.log('OHIFCornerstoneViewport destroy()');
|
|
StackManager.clearStacks();
|
|
}
|
|
|
|
/**
|
|
* Obtain the CornerstoneTools Stack for the specified display set.
|
|
*
|
|
* @param {Object[]} studies
|
|
* @param {String} StudyInstanceUID
|
|
* @param {String} displaySetInstanceUID
|
|
* @param {String} [SOPInstanceUID]
|
|
* @param {Number} [frameIndex=1]
|
|
* @return {Object} CornerstoneTools Stack
|
|
*/
|
|
static getCornerstoneStack(
|
|
studies,
|
|
StudyInstanceUID,
|
|
displaySetInstanceUID,
|
|
SOPInstanceUID,
|
|
frameIndex = 0
|
|
) {
|
|
if (!studies || !studies.length) {
|
|
throw new Error('Studies not provided.');
|
|
}
|
|
|
|
if (!StudyInstanceUID) {
|
|
throw new Error('StudyInstanceUID not provided.');
|
|
}
|
|
|
|
if (!displaySetInstanceUID) {
|
|
throw new Error('StudyInstanceUID not provided.');
|
|
}
|
|
|
|
// Create shortcut to displaySet
|
|
const study = studies.find(
|
|
study => study.StudyInstanceUID === StudyInstanceUID
|
|
);
|
|
|
|
if (!study) {
|
|
throw new Error('Study not found.');
|
|
}
|
|
|
|
const displaySet = study.displaySets.find(set => {
|
|
return set.displaySetInstanceUID === displaySetInstanceUID;
|
|
});
|
|
|
|
if (!displaySet) {
|
|
throw new Error('Display Set not found.');
|
|
}
|
|
|
|
// 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);
|
|
stack.currentImageIdIndex = frameIndex;
|
|
|
|
if (SOPInstanceUID) {
|
|
const index = stack.imageIds.findIndex(imageId => {
|
|
const imageIdSOPInstanceUID = cornerstone.metaData.get(
|
|
'SOPInstanceUID',
|
|
imageId
|
|
);
|
|
|
|
return imageIdSOPInstanceUID === SOPInstanceUID;
|
|
});
|
|
|
|
if (index > -1) {
|
|
stack.currentImageIdIndex = index;
|
|
} else {
|
|
console.warn(
|
|
'SOPInstanceUID provided was not found in specified DisplaySet'
|
|
);
|
|
}
|
|
}
|
|
|
|
return stack;
|
|
}
|
|
|
|
getViewportData = async (
|
|
studies,
|
|
StudyInstanceUID,
|
|
displaySetInstanceUID,
|
|
SOPInstanceUID,
|
|
frameIndex
|
|
) => {
|
|
let viewportData;
|
|
|
|
const stack = OHIFCornerstoneViewport.getCornerstoneStack(
|
|
studies,
|
|
StudyInstanceUID,
|
|
displaySetInstanceUID,
|
|
SOPInstanceUID,
|
|
frameIndex
|
|
);
|
|
|
|
viewportData = {
|
|
StudyInstanceUID,
|
|
displaySetInstanceUID,
|
|
stack,
|
|
};
|
|
|
|
return viewportData;
|
|
};
|
|
|
|
setStateFromProps() {
|
|
const { studies, displaySet } = this.props.viewportData;
|
|
const {
|
|
StudyInstanceUID,
|
|
displaySetInstanceUID,
|
|
sopClassUIDs,
|
|
SOPInstanceUID,
|
|
frameIndex,
|
|
} = displaySet;
|
|
|
|
if (!StudyInstanceUID || !displaySetInstanceUID) {
|
|
return;
|
|
}
|
|
|
|
if (sopClassUIDs && sopClassUIDs.length > 1) {
|
|
console.warn(
|
|
'More than one SOPClassUID in the same series is not yet supported.'
|
|
);
|
|
}
|
|
|
|
this.getViewportData(
|
|
studies,
|
|
StudyInstanceUID,
|
|
displaySetInstanceUID,
|
|
SOPInstanceUID,
|
|
frameIndex
|
|
).then(viewportData => {
|
|
this.setState({
|
|
viewportData,
|
|
});
|
|
});
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.setStateFromProps();
|
|
}
|
|
|
|
componentDidUpdate(prevProps) {
|
|
const { 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;
|
|
|
|
if (!this.state.viewportData) {
|
|
return null;
|
|
}
|
|
const { viewportIndex } = this.props;
|
|
const {
|
|
imageIds,
|
|
currentImageIdIndex,
|
|
// If this comes from the instance, would be a better default
|
|
// `FrameTime` in the instance
|
|
// frameRate = 0,
|
|
} = this.state.viewportData.stack;
|
|
|
|
// 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 (
|
|
child &&
|
|
React.cloneElement(child, {
|
|
viewportIndex: this.props.viewportIndex,
|
|
key: index,
|
|
})
|
|
);
|
|
});
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<ConnectedCornerstoneViewport
|
|
viewportIndex={viewportIndex}
|
|
imageIds={imageIds}
|
|
imageIdIndex={currentImageIdIndex}
|
|
// ~~ Connected (From REDUX)
|
|
// frameRate={frameRate}
|
|
// isPlaying={false}
|
|
// isStackPrefetchEnabled={true}
|
|
// onElementEnabled={() => {}}
|
|
// setViewportActive{() => {}}
|
|
{...this.props.customProps}
|
|
/>
|
|
{childrenWithProps}
|
|
</>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default OHIFCornerstoneViewport;
|