197 lines
7.0 KiB
TypeScript
197 lines
7.0 KiB
TypeScript
import { id } from './id';
|
|
import { hotkeys } from '@ohif/core';
|
|
import initWorkflowSteps from './initWorkflowSteps';
|
|
import initToolGroups from './initToolGroups';
|
|
import toolbarButtons from './toolbarButtons';
|
|
import segmentationButtons from './segmentationButtons';
|
|
|
|
const extensionDependencies = {
|
|
'@ohif/extension-default': '3.7.0-beta.76',
|
|
'@ohif/extension-cornerstone': '3.7.0-beta.76',
|
|
'@ohif/extension-cornerstone-dynamic-volume': '3.7.0-beta.76',
|
|
'@ohif/extension-cornerstone-dicom-seg': '3.7.0-beta.76',
|
|
'@ohif/extension-tmtv': '3.7.0-beta.76',
|
|
};
|
|
|
|
const ohif = {
|
|
layout: '@ohif/extension-default.layoutTemplateModule.viewerLayout',
|
|
defaultSopClassHandler: '@ohif/extension-default.sopClassHandlerModule.stack',
|
|
chartSopClassHandler: '@ohif/extension-default.sopClassHandlerModule.chart',
|
|
hangingProtocol: '@ohif/extension-default.hangingProtocolModule.default',
|
|
leftPanel: '@ohif/extension-default.panelModule.seriesList',
|
|
rightPanel: '@ohif/extension-default.panelModule.measure',
|
|
chartViewport: '@ohif/extension-default.viewportModule.chartViewport',
|
|
};
|
|
|
|
const dynamicVolume = {
|
|
leftPanel: '@ohif/extension-cornerstone-dynamic-volume.panelModule.dynamic-volume',
|
|
};
|
|
|
|
const cornerstone = {
|
|
viewport: '@ohif/extension-cornerstone.viewportModule.cornerstone',
|
|
activeViewportWindowLevel: '@ohif/extension-cornerstone.panelModule.activeViewportWindowLevel',
|
|
};
|
|
|
|
function modeFactory({ modeConfiguration }) {
|
|
return {
|
|
id,
|
|
routeName: 'dynamic-volume',
|
|
displayName: 'Preclinical 4D',
|
|
onModeEnter: function ({ servicesManager, extensionManager, commandsManager }: withAppTypes) {
|
|
const {
|
|
measurementService,
|
|
toolbarService,
|
|
cineService,
|
|
cornerstoneViewportService,
|
|
toolGroupService,
|
|
customizationService,
|
|
viewportGridService,
|
|
} = servicesManager.services;
|
|
|
|
const utilityModule = extensionManager.getModuleEntry(
|
|
'@ohif/extension-cornerstone.utilityModule.tools'
|
|
);
|
|
|
|
const { toolNames, Enums } = utilityModule.exports;
|
|
|
|
measurementService.clearMeasurements();
|
|
initToolGroups({ toolNames, Enums, toolGroupService, commandsManager, servicesManager });
|
|
|
|
toolbarService.addButtons([...toolbarButtons, ...segmentationButtons]);
|
|
toolbarService.createButtonSection('secondary', ['ProgressDropdown']);
|
|
|
|
// the primary button section is created in the workflow steps
|
|
// specific to the step
|
|
customizationService.addModeCustomizations([
|
|
{
|
|
id: 'PanelSegmentation.tableMode',
|
|
mode: 'expanded',
|
|
},
|
|
{
|
|
id: 'PanelSegmentation.onSegmentationAdd',
|
|
onSegmentationAdd: () => {
|
|
commandsManager.run('createNewLabelMapForDynamicVolume');
|
|
},
|
|
},
|
|
{
|
|
id: 'PanelSegmentation.showAddSegment',
|
|
showAddSegment: false,
|
|
},
|
|
{
|
|
id: 'PanelSegmentation.readableText',
|
|
// remove following if you are not interested in that stats
|
|
readableText: {
|
|
lesionStats: 'Lesion Statistics',
|
|
minValue: 'Minimum Value',
|
|
maxValue: 'Maximum Value',
|
|
meanValue: 'Mean Value',
|
|
volume: 'Volume',
|
|
suvPeak: 'SUV Peak',
|
|
suvMax: 'Maximum SUV',
|
|
suvMaxIJK: 'SUV Max IJK',
|
|
},
|
|
},
|
|
]);
|
|
|
|
// Auto play the clip initially when the volumes are loaded
|
|
const { unsubscribe } = cornerstoneViewportService.subscribe(
|
|
cornerstoneViewportService.EVENTS.VIEWPORT_VOLUMES_CHANGED,
|
|
() => {
|
|
const viewportId = viewportGridService.getActiveViewportId();
|
|
const csViewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
|
cineService.playClip(csViewport.element, { viewportId });
|
|
// cineService.setIsCineEnabled(true);
|
|
|
|
unsubscribe();
|
|
}
|
|
);
|
|
},
|
|
onSetupRouteComplete: ({ servicesManager }: withAppTypes) => {
|
|
// This needs to run after hanging protocol matching process because
|
|
// it may change the protocol/stage based on workflow stage settings
|
|
initWorkflowSteps({ servicesManager });
|
|
},
|
|
onModeExit: ({ servicesManager }: withAppTypes) => {
|
|
const {
|
|
toolGroupService,
|
|
syncGroupService,
|
|
segmentationService,
|
|
cornerstoneViewportService,
|
|
} = servicesManager.services;
|
|
|
|
toolGroupService.destroy();
|
|
syncGroupService.destroy();
|
|
segmentationService.destroy();
|
|
cornerstoneViewportService.destroy();
|
|
},
|
|
get validationTags() {
|
|
return {
|
|
study: [],
|
|
series: [],
|
|
};
|
|
},
|
|
isValidMode: ({ modalities, study }) => {
|
|
// Todo: we need to find a better way to validate the mode
|
|
return {
|
|
valid: study.mrn === 'M1',
|
|
description: 'This mode is only available for 4D PET/CT studies.',
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Mode Routes are used to define the mode's behavior. A list of Mode Route
|
|
* that includes the mode's path and the layout to be used. The layout will
|
|
* include the components that are used in the layout. For instance, if the
|
|
* default layoutTemplate is used (id: '@ohif/extension-default.layoutTemplateModule.viewerLayout')
|
|
* it will include the leftPanels, rightPanels, and viewports. However, if
|
|
* you define another layoutTemplate that includes a Footer for instance,
|
|
* you should provide the Footer component here too. Note: We use Strings
|
|
* to reference the component's ID as they are registered in the internal
|
|
* ExtensionManager. The template for the string is:
|
|
* `${extensionId}.{moduleType}.${componentId}`.
|
|
*/
|
|
routes: [
|
|
{
|
|
path: 'preclinical-4d',
|
|
layoutTemplate: ({ location, servicesManager }) => {
|
|
return {
|
|
id: ohif.layout,
|
|
props: {
|
|
leftPanels: [[dynamicVolume.leftPanel, cornerstone.activeViewportWindowLevel]],
|
|
rightPanels: [],
|
|
rightPanelClosed: true,
|
|
viewports: [
|
|
{
|
|
namespace: cornerstone.viewport,
|
|
displaySetsToDisplay: [ohif.defaultSopClassHandler],
|
|
},
|
|
{
|
|
namespace: ohif.chartViewport,
|
|
displaySetsToDisplay: [ohif.chartSopClassHandler],
|
|
},
|
|
],
|
|
},
|
|
};
|
|
},
|
|
},
|
|
],
|
|
extensions: extensionDependencies,
|
|
// Default protocol gets self-registered by default in the init
|
|
hangingProtocol: 'default4D',
|
|
// Order is important in sop class handlers when two handlers both use
|
|
// the same sop class under different situations. In that case, the more
|
|
// general handler needs to come last. For this case, the dicomvideo must
|
|
// come first to remove video transfer syntax before ohif uses images
|
|
sopClassHandlers: [ohif.chartSopClassHandler, ohif.defaultSopClassHandler],
|
|
hotkeys: [...hotkeys.defaults.hotkeyBindings],
|
|
};
|
|
}
|
|
|
|
const mode = {
|
|
id,
|
|
modeFactory,
|
|
extensionDependencies,
|
|
};
|
|
|
|
export default mode;
|