diff --git a/extensions/cornerstone/src/OHIFCornerstoneViewport.js b/extensions/cornerstone/src/OHIFCornerstoneViewport.js index 54bf5022e..02156a991 100644 --- a/extensions/cornerstone/src/OHIFCornerstoneViewport.js +++ b/extensions/cornerstone/src/OHIFCornerstoneViewport.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; - -import ConnectedCornerstoneViewport from './ConnectedCornerstoneViewport'; +import CornerstoneViewport from 'react-cornerstone-viewport'; +//import ConnectedCornerstoneViewport from './ConnectedCornerstoneViewport'; import OHIF from '@ohif/core'; import PropTypes from 'prop-types'; import cornerstone from 'cornerstone-core'; @@ -18,9 +18,9 @@ class OHIFCornerstoneViewport extends Component { }; static propTypes = { - studies: PropTypes.object, displaySet: PropTypes.object, viewportIndex: PropTypes.number, + dataSource: PropTypes.object, children: PropTypes.node, customProps: PropTypes.object, }; @@ -39,98 +39,57 @@ class OHIFCornerstoneViewport extends Component { /** * 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] + * @param {Object} displaySet + * @param {Object} dataSource * @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.'); - } + static getCornerstoneStack(displaySet, dataSource) { + const { frameIndex } = displaySet; // Get stack from Stack Manager - const storedStack = StackManager.findOrCreateStack(study, displaySet); + const storedStack = StackManager.findOrCreateStack(displaySet, dataSource); // 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 - ); + // TODO -> Do we ever use this like this? + // if (SOPInstanceUID) { + // const index = stack.imageIds.findIndex(imageId => { + // const imageIdSOPInstanceUID = cornerstone.metaData.get( + // 'SOPInstanceUID', + // imageId + // ); - return imageIdSOPInstanceUID === SOPInstanceUID; - }); + // return imageIdSOPInstanceUID === SOPInstanceUID; + // }); - if (index > -1) { - stack.currentImageIdIndex = index; - } else { - console.warn( - 'SOPInstanceUID provided was not found in specified DisplaySet' - ); - } - } + // 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 - ) => { + getViewportData = async displaySet => { let viewportData; + const { dataSource } = this.props; + const stack = OHIFCornerstoneViewport.getCornerstoneStack( - studies, - StudyInstanceUID, - displaySetInstanceUID, - SOPInstanceUID, - frameIndex + displaySet, + dataSource ); viewportData = { - StudyInstanceUID, - displaySetInstanceUID, + StudyInstanceUID: displaySet.StudyInstanceUID, + displaySetInstanceUID: displaySet.displaySetInstanceUID, stack, }; @@ -138,32 +97,24 @@ class OHIFCornerstoneViewport extends Component { }; setStateFromProps() { - const { studies, displaySet } = this.props.viewportData; + const { displaySet } = this.props; const { StudyInstanceUID, displaySetInstanceUID, - sopClassUIDs, - SOPInstanceUID, - frameIndex, + sopClassUids, } = displaySet; if (!StudyInstanceUID || !displaySetInstanceUID) { return; } - if (sopClassUIDs && sopClassUIDs.length > 1) { + 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.getViewportData(displaySet).then(viewportData => { this.setState({ viewportData, }); @@ -175,8 +126,8 @@ class OHIFCornerstoneViewport extends Component { } componentDidUpdate(prevProps) { - const { displaySet } = this.props.viewportData; - const prevDisplaySet = prevProps.viewportData.displaySet; + const { displaySet } = this.props; + const prevDisplaySet = prevProps.displaySet; if ( displaySet.displaySetInstanceUID !== @@ -232,9 +183,11 @@ class OHIFCornerstoneViewport extends Component { 700 ); + // TODO -> We may still want a wrapped component to define all the measurement api stuff. + return ( <> - {}} // setViewportActive{() => {}} {...this.props.customProps} + /> */} + {childrenWithProps} diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js index f609a2d3e..20ffe125a 100644 --- a/extensions/default/src/DicomWebDataSource/index.js +++ b/extensions/default/src/DicomWebDataSource/index.js @@ -130,9 +130,9 @@ function createDicomWebApi(dicomWebConfig) { }, }, }, - getImageIdsForDisplaySet(displaySetInstanceUid) { + getImageIdsForDisplaySet(displaySetInstanceUID) { const displaySet = displaySetManager.getDisplaySetByUID( - displaySetInstanceUid + displaySetInstanceUID ); const images = displaySet.images; diff --git a/extensions/default/src/ViewerLayout/index.jsx b/extensions/default/src/ViewerLayout/index.jsx index 6bec8f7a2..cc2ee7409 100644 --- a/extensions/default/src/ViewerLayout/index.jsx +++ b/extensions/default/src/ViewerLayout/index.jsx @@ -1,8 +1,9 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { SidePanel, Toolbar } from '@ohif/ui'; // import Header from './Header.jsx'; +import { displaySetManager } from '@ohif/core'; function ViewerLayout({ // From Extension Module Params @@ -11,7 +12,8 @@ function ViewerLayout({ leftPanels, rightPanels, toolBarLayout, - displaySetInstanceUids, + viewports, + displaySetInstanceUIDs, ViewportGrid, }) { /** @@ -28,6 +30,17 @@ function ViewerLayout({ }; }, []); + // TODO -> Need some way of selecting which displaySets hit the viewports. + const [viewportData, setViewportData] = useState([]); + + console.log(displaySetInstanceUIDs); + + useEffect(() => { + setViewportData([ + displaySetManager.getDisplaySetByUID(displaySetInstanceUIDs[0]), + ]); + }, [displaySetInstanceUIDs]); + const getPanelData = id => { const entry = extensionManager.getModuleEntry(id); // TODO, not sure why sidepanel content has to be JSX, and not a children prop? @@ -42,11 +55,22 @@ function ViewerLayout({ }; }; + const getViewportComponentData = viewportComponent => { + const entry = extensionManager.getModuleEntry(viewportComponent.namespace); + + return { + component: entry.component, + displaySetsToDisplay: viewportComponent.displaySetsToDisplay, + }; + }; + const leftPanelComponents = leftPanels.map(getPanelData); const rightPanelComponents = rightPanels.map(getPanelData); - console.warn(displaySetInstanceUids); - console.warn(toolBarLayout); + const viewportComponents = viewports.map(getViewportComponentData); + + console.log(displaySetInstanceUIDs); + console.log(toolBarLayout); const [primaryToolBarLayout, secondaryToolBarLayout] = toolBarLayout; @@ -72,7 +96,10 @@ function ViewerLayout({
- + {/* viewportContents={[ { - if (!viewModel.displaySetInstanceUids.length) { + if (!viewModel.displaySetInstanceUIDs.length) { return; } @@ -57,7 +57,7 @@ function StudyBrowserPanel({ getDataSources, commandsManager }) { const { cornerstone, cornerstoneTools } = command.commandFn(); - viewModel.displaySetInstanceUids.forEach(uid => { + viewModel.displaySetInstanceUIDs.forEach(uid => { const imageIds = dataSource.getImageIdsForDisplaySet(uid); const imageId = imageIds[Math.floor(imageIds.length / 2)]; @@ -68,7 +68,7 @@ function StudyBrowserPanel({ getDataSources, commandsManager }) { }); }); - const displaySets = viewModel.displaySetInstanceUids.map( + const displaySets = viewModel.displaySetInstanceUIDs.map( displaySetManager.getDisplaySetByUID ); @@ -98,7 +98,7 @@ function StudyBrowserPanel({ getDataSources, commandsManager }) { const studiesFromInstanceData = {}; displaySets.forEach(ds => { const displaySet = { - displaySetInstanceUid: ds.displaySetInstanceUid, + displaySetInstanceUID: ds.displaySetInstanceUID, description: ds.SeriesDescription, seriesNumber: ds.SeriesNumber, modality: ds.Modality, @@ -107,7 +107,7 @@ function StudyBrowserPanel({ getDataSources, commandsManager }) { }; const displaySetViewportData = viewportData.find( - a => a.displaySetInstanceUid === ds.displaySetInstanceUid + a => a.displaySetInstanceUID === ds.displaySetInstanceUID ); if (displaySetViewportData) { @@ -192,11 +192,11 @@ function StudyBrowserPanel({ getDataSources, commandsManager }) { }); return () => (isSubscribed = false); - }, [viewModel.displaySetInstanceUids]); + }, [viewModel.displaySetInstanceUIDs]); studyData.forEach(study => { study.displaySets.forEach(ds => { - ds.imageSrc = thumbnailImageSrcMap.get(ds.displaySetInstanceUid); + ds.imageSrc = thumbnailImageSrcMap.get(ds.displaySetInstanceUID); }); }); diff --git a/extensions/default/src/getSopClassHandlerModule.js b/extensions/default/src/getSopClassHandlerModule.js index b700a3ef1..59e2a3db8 100644 --- a/extensions/default/src/getSopClassHandlerModule.js +++ b/extensions/default/src/getSopClassHandlerModule.js @@ -15,7 +15,7 @@ const makeDisplaySet = instances => { // set appropriate attributes to image set... imageSet.setAttributes({ - displaySetInstanceUid: imageSet.uid, // create a local alias for the imageSet UID + displaySetInstanceUID: imageSet.uid, // create a local alias for the imageSet UID SeriesDate: instance.SeriesDate, SeriesTime: instance.SeriesTime, SeriesInstanceUID: instance.SeriesInstanceUID, diff --git a/modes/example/src/index.js b/modes/example/src/index.js index 81f3c2de4..8f8da7529 100644 --- a/modes/example/src/index.js +++ b/modes/example/src/index.js @@ -74,8 +74,7 @@ export default function mode({ modeConfiguration }) { rightPanels: ['org.ohif.default.panelModule.measure'], viewports: [ { - namespace: - 'org.ohif.cornerstone.viewportModule.OHIFCornerstoneViewport', + namespace: 'org.ohif.cornerstone.viewportModule.cornerstone', displaySetsToDisplay: [ 'org.ohif.default.sopClassHandlerModule.stack', ], diff --git a/platform/core/src/ViewModelContext.js b/platform/core/src/ViewModelContext.js index ea5ec0bc6..b2af0dc51 100644 --- a/platform/core/src/ViewModelContext.js +++ b/platform/core/src/ViewModelContext.js @@ -3,7 +3,7 @@ import React, { Component, useContext } from 'react'; /// TODO MAKE THIS PRETTY DANNY const ViewModelContext = React.createContext({ - displaySetInstanceUids: [], + displaySetInstanceUIDs: [], setDisplaySetInstanceUids: () => {}, toolBarLayout: [], setToolBarLayout: () => {}, @@ -13,12 +13,12 @@ ViewModelContext.displayName = 'ViewModelContext'; class ViewModelProvider extends Component { state = { - displaySetInstanceUids: [], + displaySetInstanceUIDs: [], }; render() { - const setDisplaySetInstanceUids = displaySetInstanceUids => { - this.setState({ displaySetInstanceUids }); + const setDisplaySetInstanceUids = displaySetInstanceUIDs => { + this.setState({ displaySetInstanceUIDs }); }; const setToolBarLayout = toolBarLayout => { @@ -28,7 +28,7 @@ class ViewModelProvider extends Component { return ( { this.displaySets.push(displaySet); - addedDisplaySetUids.push(displaySet.displaySetInstanceUid); + addedDisplaySetUids.push(displaySet.displaySetInstanceUID); }); return addedDisplaySetUids; @@ -39,9 +39,9 @@ class DisplaySetManager { ); }; - getDisplaySetByUID = displaySetInstanceUid => { + getDisplaySetByUID = displaySetInstanceUID => { return this.displaySets.find( - displaySet => displaySet.displaySetInstanceUid === displaySetInstanceUid + displaySet => displaySet.displaySetInstanceUID === displaySetInstanceUID ); }; @@ -71,7 +71,7 @@ class DisplaySetManager { if (cachedDisplaySets.length) { addedDisplaySetUids = cachedDisplaySets.map( - displaySet => displaySet.displaySetInstanceUid + displaySet => displaySet.displaySetInstanceUID ); } else { const displaySets = handler.getDisplaySetsFromSeries(instances); @@ -79,12 +79,12 @@ class DisplaySetManager { addedDisplaySetUids = this._addDisplaySets(displaySets); } - this.displaySetInstanceUids = [ + this.displaySetInstanceUIDs = [ ...addedDisplaySetUids, - ...this.displaySetInstanceUids, + ...this.displaySetInstanceUIDs, ]; - this.setDisplaySetInstanceUids(this.displaySetInstanceUids); + this.setDisplaySetInstanceUids(this.displaySetInstanceUIDs); } } }; diff --git a/platform/core/src/extensions/ExtensionManager.js b/platform/core/src/extensions/ExtensionManager.js index 0e91754f4..a0492a69d 100644 --- a/platform/core/src/extensions/ExtensionManager.js +++ b/platform/core/src/extensions/ExtensionManager.js @@ -105,9 +105,9 @@ export default class ExtensionManager { this._initToolBarModule(extensionModule, extensionId); break; + case MODULE_TYPES.VIEWPORT: case MODULE_TYPES.PANEL: case MODULE_TYPES.SOP_CLASS_HANDLER: - case MODULE_TYPES.VIEWPORT: case MODULE_TYPES.CONTEXT: case MODULE_TYPES.LAYOUT_TEMPLATE: // Default for most extension points, @@ -118,6 +118,7 @@ export default class ExtensionManager { `${extensionId}.${moduleType}.${element.name}` ] = element; }); + break; } this.modules[moduleType].push({ diff --git a/platform/core/src/utils/StackManager.js b/platform/core/src/utils/StackManager.js index 49d8b0059..a4bac499f 100644 --- a/platform/core/src/utils/StackManager.js +++ b/platform/core/src/utils/StackManager.js @@ -11,79 +11,37 @@ const stackUpdatedCallbacks = []; * Cornerstone meta data provider. This will be used to fill information * into the viewport overlays, and to calculate reference lines and orientation markers * @param {Object} stackMap stackMap object - * @param {Object} study Study object * @param {Object} displaySet The set of images to make the stack from * @return {Array} Array with image IDs */ -function createAndAddStack(stackMap, study, displaySet, stackUpdatedCallbacks) { - const images = displaySet.images; +function createAndAddStack( + stackMap, + displaySet, + dataSource, + stackUpdatedCallbacks +) { + const { + images, + displaySetInstanceUID, + StudyInstanceUID, + frameRate, + isClip, + } = displaySet; if (!images) { return; } - const numImages = images.length; - const imageIds = []; - let imageId; - - displaySet.images.forEach((instance, imageIndex) => { - const image = instance.getData(); - const metaData = { - instance: image, // in this context, instance will be the data of the InstanceMetadata object... - series: displaySet, // TODO: Check this - study, - numImages, - imageIndex: imageIndex + 1, - }; - - const naturalizedInstance = instance.getData().metadata; - const NumberOfFrames = naturalizedInstance.NumberOfFrames; - - if (NumberOfFrames > 1) { - for (let i = 0; i < NumberOfFrames; i++) { - metaData.frameNumber = i; - imageId = getImageId(image, i); - imageIds.push(imageId); - - const { - StudyInstanceUID, - SeriesInstanceUID, - SOPInstanceUID, - } = instance.getData().metadata; - - metadataProvider.addImageIdToUIDs(imageId, { - StudyInstanceUID, - SeriesInstanceUID, - SOPInstanceUID, - }); - } - } else { - metaData.frameNumber = 1; - imageId = getImageId(image); - imageIds.push(imageId); - - const { - StudyInstanceUID, - SeriesInstanceUID, - SOPInstanceUID, - } = naturalizedInstance; - - metadataProvider.addImageIdToUIDs(imageId, { - StudyInstanceUID, - SeriesInstanceUID, - SOPInstanceUID, - }); - } - }); + const imageIds = dataSource.getImageIdsForDisplaySet(displaySetInstanceUID); const stack = { - StudyInstanceUID: study.StudyInstanceUID, - displaySetInstanceUID: displaySet.displaySetInstanceUID, + StudyInstanceUID, + displaySetInstanceUID, imageIds, - frameRate: displaySet.frameRate, - isClip: displaySet.isClip, + frameRate, + isClip, }; - stackMap[displaySet.displaySetInstanceUID] = stack; + stackMap[displaySetInstanceUID] = stack; return stack; } @@ -106,15 +64,14 @@ const StackManager = { }, /** * Create a stack from an image set, as well as add in the metadata on a per image bases. - * @param study The study who's metadata will be added * @param displaySet The set of images to make the stack from * @return {Array} Array with image IDs */ - makeAndAddStack(study, displaySet) { + makeAndAddStack(displaySet, dataSource) { return configuration.createAndAddStack( stackMap, - study, displaySet, + dataSource, stackUpdatedCallbacks ); }, @@ -128,15 +85,14 @@ const StackManager = { }, /** * Find a stack or reate one if it has not been created yet - * @param study The study who's metadata will be added * @param displaySet The set of images to make the stack from * @return {Array} Array with image IDs */ - findOrCreateStack(study, displaySet) { + findOrCreateStack(displaySet, dataSource) { let stack = this.findStack(displaySet.displaySetInstanceUID); if (!stack || !stack.imageIds) { - stack = this.makeAndAddStack(study, displaySet); + stack = this.makeAndAddStack(displaySet, dataSource); } return stack; diff --git a/platform/core/src/utils/loadAndCacheDerivedDisplaySets.js b/platform/core/src/utils/loadAndCacheDerivedDisplaySets.js index 3ce929ca5..24a30418e 100644 --- a/platform/core/src/utils/loadAndCacheDerivedDisplaySets.js +++ b/platform/core/src/utils/loadAndCacheDerivedDisplaySets.js @@ -30,7 +30,7 @@ import studyMetadataManager from './studyMetadataManager'; * Factory function to load and cache derived display sets. * * @param {object} referencedDisplaySet Display set - * @param {string} referencedDisplaySet.displaySetInstanceUid Display set instance uid + * @param {string} referencedDisplaySet.displaySetInstanceUID Display set instance uid * @param {string} referencedDisplaySet.seriesDate * @param {string} referencedDisplaySet.seriesTime * @param {string} referencedDisplaySet.seriesInstanceUid diff --git a/platform/ui/src/components/StudyBrowser/StudyBrowser.jsx b/platform/ui/src/components/StudyBrowser/StudyBrowser.jsx index 625d90aa7..e04144951 100644 --- a/platform/ui/src/components/StudyBrowser/StudyBrowser.jsx +++ b/platform/ui/src/components/StudyBrowser/StudyBrowser.jsx @@ -7,13 +7,13 @@ import { ButtonGroup, Button, StudyItem, ThumbnailList } from '@ohif/ui'; const buttonClasses = 'text-white text-base border-none bg-black p-2 min-w-18'; const activeButtonClasses = 'bg-primary-main'; -const getInitialActiveTab = (tabs) => { +const getInitialActiveTab = tabs => { return tabs && tabs[0] && tabs[0].name; }; -const getTrackedSeries = (displaySets) => { +const getTrackedSeries = displaySets => { let trackedSeries = 0; - displaySets.forEach((displaySet) => { + displaySets.forEach(displaySet => { if (displaySet.isTracked) { trackedSeries++; } @@ -28,7 +28,7 @@ const StudyBrowser = ({ tabs, onClickStudy, onClickThumbnail }) => { const [thumbnailActive, setThumbnailActive] = useState(null); const getTabContent = () => { - const tabData = tabs.find((tab) => tab.name === tabActive); + const tabData = tabs.find(tab => tab.name === tabActive); if (!tabData || !tabData.studies || !Array.isArray(tabData.studies)) { return; @@ -65,17 +65,16 @@ const StudyBrowser = ({ tabs, onClickStudy, onClickThumbnail }) => { { - setThumbnailActive( - thumbnailId === thumbnailActive ? null : thumbnailId - ) + onThumbnailClick={thumbnailId => { + setThumbnailActive( + thumbnailId === thumbnailActive ? null : thumbnailId + ); - if (onClickThumbnail) { - // TODO: what is thumbnailId? Should pass display set instead - onClickThumbnail(thumbnailId); - } + if (onClickThumbnail) { + // TODO: what is thumbnailId? Should pass display set instead + onClickThumbnail(thumbnailId); } - } + }} /> )} @@ -92,7 +91,7 @@ const StudyBrowser = ({ tabs, onClickStudy, onClickThumbnail }) => { color="inherit" className="border border-secondary-light rounded-md" > - {tabs.map((tab) => { + {tabs.map(tab => { const { name, label } = tab; const isActive = tabActive === name; return ( @@ -137,7 +136,7 @@ StudyBrowser.propTypes = { description: PropTypes.string, displaySets: PropTypes.arrayOf( PropTypes.shape({ - displaySetInstanceUid: PropTypes.string.isRequired, + displaySetInstanceUID: PropTypes.string.isRequired, imageSrc: PropTypes.string, imageAltText: PropTypes.string, seriesDate: PropTypes.string, diff --git a/platform/ui/src/components/StudyBrowser/StudyBrowser.mdx b/platform/ui/src/components/StudyBrowser/StudyBrowser.mdx index 1e5c18648..3cfea8a5c 100644 --- a/platform/ui/src/components/StudyBrowser/StudyBrowser.mdx +++ b/platform/ui/src/components/StudyBrowser/StudyBrowser.mdx @@ -27,7 +27,7 @@ import { StudyBrowser } from '@ohif/ui'; modalities: 'CT,SR', displaySets: [ { - displaySetInstanceUid: 'f69f6asdasd48c-223e-db7f-c4af-b8906641a66e', + displaySetInstanceUID: 'f69f6asdasd48c-223e-db7f-c4af-b8906641a66e', description: 'Multiple line image series description lorem sit', seriesNumber: 1, numInstances: 68, @@ -36,7 +36,7 @@ import { StudyBrowser } from '@ohif/ui'; isTracked: true, }, { - displaySetInstanceUid: 'f69f648c-223e-db7f-c4asdasdaf-b8906641a66e', + displaySetInstanceUID: 'f69f648c-223e-db7f-c4asdasdaf-b8906641a66e', description: 'Multiple line image series description lorem sit', seriesNumber: 1, numInstances: 68, @@ -44,14 +44,14 @@ import { StudyBrowser } from '@ohif/ui'; viewportIdentificator: 'B', }, { - displaySetInstanceUid: 'f69f648c-223e-dasdasdb7f-c4af-b8906641a66e', + displaySetInstanceUID: 'f69f648c-223e-dasdasdb7f-c4af-b8906641a66e', description: 'Multiple line image series description lorem sit', seriesNumber: 1, numInstances: 68, componentType: 'thumbnailTracked', }, { - displaySetInstanceUid: 'f69f648c-223e-db7f-c4afas-b8906asd641a66e', + displaySetInstanceUID: 'f69f648c-223e-db7f-c4afas-b8906asd641a66e', description: 'Multiple line description lorem ipsum dolor sit amet', modality: 'SR', componentType: 'thumbnailNoImage', @@ -67,7 +67,7 @@ import { StudyBrowser } from '@ohif/ui'; modalities: 'CT', displaySets: [ { - displaySetInstanceUid: 'f69f648c-223e-db7f-c4af-b8906641a66e', + displaySetInstanceUID: 'f69f648c-223e-db7f-c4af-b8906641a66e', description: 'Multiple line image series description lorem sit', seriesNumber: 1, numInstances: 68, diff --git a/platform/ui/src/components/ThumbnailList/ThumbnailList.jsx b/platform/ui/src/components/ThumbnailList/ThumbnailList.jsx index 06a980c39..15416ecd5 100644 --- a/platform/ui/src/components/ThumbnailList/ThumbnailList.jsx +++ b/platform/ui/src/components/ThumbnailList/ThumbnailList.jsx @@ -8,7 +8,7 @@ const ThumbnailList = ({ thumbnails, thumbnailActive, onThumbnailClick }) => {
{thumbnails.map( ({ - displaySetInstanceUid, + displaySetInstanceUID, description, seriesNumber, numInstances, @@ -20,13 +20,13 @@ const ThumbnailList = ({ thumbnails, thumbnailActive, onThumbnailClick }) => { imageSrc, imageAltText, }) => { - const isActive = thumbnailActive === displaySetInstanceUid; + const isActive = thumbnailActive === displaySetInstanceUID; switch (componentType) { case 'thumbnail': return ( { imageAltText={imageAltText} viewportIdentificator={viewportIdentificator} isActive={isActive} - onClick={() => onThumbnailClick(displaySetInstanceUid)} + onClick={() => onThumbnailClick(displaySetInstanceUID)} /> ); case 'thumbnailNoImage': return ( onThumbnailClick(displaySetInstanceUid)} + onClick={() => onThumbnailClick(displaySetInstanceUID)} /> ); case 'thumbnailTracked': return ( { viewportIdentificator={viewportIdentificator} isTracked={isTracked} isActive={isActive} - onClick={() => onThumbnailClick(displaySetInstanceUid)} + onClick={() => onThumbnailClick(displaySetInstanceUID)} /> ); default: @@ -74,7 +74,7 @@ const ThumbnailList = ({ thumbnails, thumbnailActive, onThumbnailClick }) => { ThumbnailList.propTypes = { thumbnails: PropTypes.arrayOf( PropTypes.shape({ - displaySetInstanceUid: PropTypes.string.isRequired, + displaySetInstanceUID: PropTypes.string.isRequired, imageSrc: PropTypes.string, imageAltText: PropTypes.string, seriesDate: PropTypes.string, diff --git a/platform/ui/src/views/Viewer/studyBrowserMockData.js b/platform/ui/src/views/Viewer/studyBrowserMockData.js index 78083af30..b6aebf6d8 100644 --- a/platform/ui/src/views/Viewer/studyBrowserMockData.js +++ b/platform/ui/src/views/Viewer/studyBrowserMockData.js @@ -6,7 +6,7 @@ const studyWithSR = { modalities: 'CT,SR', displaySets: [ { - displaySetInstanceUid: 'f69f6asdasd48c-223e-db7f-c4af-b8906641a66e', + displaySetInstanceUID: 'f69f6asdasd48c-223e-db7f-c4af-b8906641a66e', description: 'Multiple line image series description lorem sit', seriesNumber: 1, numInstances: 68, @@ -15,7 +15,7 @@ const studyWithSR = { isTracked: true, }, { - displaySetInstanceUid: 'f69f648c-223e-db7f-c4asdasdaf-b8906641a66e', + displaySetInstanceUID: 'f69f648c-223e-db7f-c4asdasdaf-b8906641a66e', description: 'Multiple line image series description lorem sit', seriesNumber: 1, numInstances: 68, @@ -23,14 +23,14 @@ const studyWithSR = { viewportIdentificator: 'B', }, { - displaySetInstanceUid: 'f69f648c-223e-dasdasdb7f-c4af-b8906641a66e', + displaySetInstanceUID: 'f69f648c-223e-dasdasdb7f-c4af-b8906641a66e', description: 'Multiple line image series description lorem sit', seriesNumber: 1, numInstances: 68, componentType: 'thumbnailTracked', }, { - displaySetInstanceUid: 'f69f648c-223e-db7f-c4afas-b8906asd641a66e', + displaySetInstanceUID: 'f69f648c-223e-db7f-c4afas-b8906asd641a66e', description: 'Multiple line description lorem ipsum dolor sit amet', modality: 'SR', componentType: 'thumbnailNoImage', @@ -47,7 +47,7 @@ const studySimple = { modalities: 'CT', displaySets: [ { - displaySetInstanceUid: 'f69f648c-223e-db7f-c4af-b8906641a66e', + displaySetInstanceUID: 'f69f648c-223e-db7f-c4af-b8906641a66e', description: 'Multiple line image series description lorem sit', seriesNumber: 1, numInstances: 68, diff --git a/platform/viewer/src/components/ViewportGrid.jsx b/platform/viewer/src/components/ViewportGrid.jsx index 527dc4b3d..e4defdc4f 100644 --- a/platform/viewer/src/components/ViewportGrid.jsx +++ b/platform/viewer/src/components/ViewportGrid.jsx @@ -8,7 +8,12 @@ import { ViewportGrid, ViewportPane } from '@ohif/ui'; // import EmptyViewport from './EmptyViewport.js'; function ViewerViewportGrid(props) { - const { activeViewportIndex, displaySets, children } = props; + const { + activeViewportIndex, + viewportData, + viewportComponents, + dataSource, + } = props; // From ViewportGridService and/or ContextProvider const [viewportGrid, setViewportGrid] = useState({ @@ -35,8 +40,20 @@ function ViewerViewportGrid(props) { const getViewportPanes = () => viewportGrid.viewports.map((viewport, viewportIndex) => { - const someId = viewport.displaySetId; - // const displaySet = displaySets[someId]; + const displaySet = viewportData[viewportIndex]; + + if (!displaySet) { + return ( + { + /* setDisplaySet for Viewport */ + }} + isActive={activeViewportIndex === viewportIndex} + > + ); + } // if (!displaySet) { // // TODO: Empty Viewport @@ -48,14 +65,12 @@ function ViewerViewportGrid(props) { // ? displaySet.plugin // : layout.plugin; - // const ViewportComponent = _getViewportComponent( - // data, // Why do we pass this as `ViewportData`, when that's not really what it is? - // viewportIndex, - // children, + // TODO -> Need way for other viewport e.g. vtk to be used. - // pluginName, - // defaultPluginName - // ); + const ViewportComponent = _getViewportComponent( + displaySet, + viewportComponents + ); return ( - {/* {ViewportComponent} */} + ); }); const ViewportPanes = React.useMemo(getViewportPanes, [ - children, + viewportComponents, activeViewportIndex, ]); @@ -86,16 +105,30 @@ function ViewerViewportGrid(props) { ViewerViewportGrid.propTypes = { // viewports: PropTypes.array.isRequired, activeViewportIndex: PropTypes.number.isRequired, - children: PropTypes.node, + viewportComponents: PropTypes.array.isRequired, // numRows: PropTypes.number.isRequired, // numColumns: PropTypes.number.isRequired, }; ViewerViewportGrid.defaultProps = { - // viewports: [], // numRows: 1, // numColumns: 1, + viewportData: [], + viewportComponents: [], activeViewportIndex: 0, }; +function _getViewportComponent(displaySet, viewportComponents) { + const { SOPClassHandlerId } = displaySet; + + for (let i = 0; i < viewportComponents.length; i++) { + if ( + viewportComponents[i].displaySetsToDisplay.includes(SOPClassHandlerId) + ) { + const { component } = viewportComponents[i]; + return component; + } + } +} + export default ViewerViewportGrid; diff --git a/platform/viewer/src/routes/ModeRoute.js b/platform/viewer/src/routes/ModeRoute.js index 871323999..c47dfb9f5 100644 --- a/platform/viewer/src/routes/ModeRoute.js +++ b/platform/viewer/src/routes/ModeRoute.js @@ -17,7 +17,7 @@ export default function ModeRoute({ const { toolBarLayout, setToolBarLayout, - displaySetInstanceUids, + displaySetInstanceUIDs, setDisplaySetInstanceUids, } = useViewModel(); @@ -38,7 +38,7 @@ export default function ModeRoute({ const createDisplaySets = useCallback(() => { // Add SOPClassHandlers to a new SOPClassManager. displaySetManager.init(extensionManager, sopClassHandlers, { - displaySetInstanceUids, + displaySetInstanceUIDs, setDisplaySetInstanceUids, }); @@ -49,7 +49,7 @@ export default function ModeRoute({ queryParams, displaySetManager.makeDisplaySets ); - }, [displaySetInstanceUids, location]); + }, [displaySetInstanceUIDs, location]); useEffect(() => { createDisplaySets(); @@ -84,6 +84,10 @@ export default function ModeRoute({ const CombinedContextProvider = ({ children }) => Compose({ components: contextModuleProviders, children }); + function ViewportGridWithDataSource(props) { + return ViewportGrid({ ...props, dataSource }); + } + return ( {/* TODO: extensionManager is already provided to the extension module. @@ -92,9 +96,9 @@ export default function ModeRoute({