feat(customization): new customization service api (#4688)
This commit is contained in:
1 parent
fab52808cb
commit
55ad8efbab
124 files changed
+4261
-2517
No files matched your search
@@ -47,80 +47,6 @@ const OverlayItemComponents = {
|
||||
'ohif.overlayItem.instanceNumber': InstanceNumberOverlayItem,
|
||||
};
|
||||
|
||||
const studyDateItem = {
|
||||
id: 'StudyDate',
|
||||
customizationType: 'ohif.overlayItem',
|
||||
label: '',
|
||||
title: 'Study date',
|
||||
condition: ({ referenceInstance }) => referenceInstance?.StudyDate,
|
||||
contentF: ({ referenceInstance, formatters: { formatDate } }) =>
|
||||
formatDate(referenceInstance.StudyDate),
|
||||
};
|
||||
|
||||
const seriesDescriptionItem = {
|
||||
id: 'SeriesDescription',
|
||||
customizationType: 'ohif.overlayItem',
|
||||
label: '',
|
||||
title: 'Series description',
|
||||
condition: ({ referenceInstance }) => {
|
||||
return referenceInstance && referenceInstance.SeriesDescription;
|
||||
},
|
||||
contentF: ({ referenceInstance }) => referenceInstance.SeriesDescription,
|
||||
};
|
||||
|
||||
const topLeftItems = {
|
||||
id: 'cornerstoneOverlayTopLeft',
|
||||
items: [studyDateItem, seriesDescriptionItem],
|
||||
};
|
||||
|
||||
const topRightItems = { id: 'cornerstoneOverlayTopRight', items: [] };
|
||||
|
||||
const bottomLeftItems = {
|
||||
id: 'cornerstoneOverlayBottomLeft',
|
||||
items: [
|
||||
{
|
||||
id: 'WindowLevel',
|
||||
customizationType: 'ohif.overlayItem.windowLevel',
|
||||
},
|
||||
{
|
||||
id: 'ZoomLevel',
|
||||
customizationType: 'ohif.overlayItem.zoomLevel',
|
||||
condition: props => {
|
||||
const activeToolName = props.toolGroupService.getActiveToolForViewport(props.viewportId);
|
||||
return activeToolName === 'Zoom';
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const bottomRightItems = {
|
||||
id: 'cornerstoneOverlayBottomRight',
|
||||
items: [
|
||||
{
|
||||
id: 'InstanceNumber',
|
||||
customizationType: 'ohif.overlayItem.instanceNumber',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* The @ohif/cornerstoneOverlay is a default value for a customization
|
||||
* for the cornerstone overlays. The intent is to allow it to be extended
|
||||
* without needing to re-write the individual overlays by using the append
|
||||
* mechanism. Individual attributes can be modified individually without
|
||||
* affecting the other items by using the append as well, with position
|
||||
* based replacement.
|
||||
* This is used as a default in the getCustomizationModule so that it
|
||||
* is available early for additional customization extensions.
|
||||
*/
|
||||
const CornerstoneOverlay = {
|
||||
id: '@ohif/cornerstoneOverlay',
|
||||
topLeftItems,
|
||||
topRightItems,
|
||||
bottomLeftItems,
|
||||
bottomRightItems,
|
||||
};
|
||||
|
||||
/**
|
||||
* Customizable Viewport Overlay
|
||||
*/
|
||||
@@ -143,26 +69,18 @@ function CustomizableViewportOverlay({
|
||||
const [scale, setScale] = useState(1);
|
||||
const { imageIndex } = imageSliceData;
|
||||
|
||||
// The new customization is 'cornerstoneOverlay', with an append or replace
|
||||
// on the individual items rather than defining individual items.
|
||||
const cornerstoneOverlay = customizationService.getCustomization('@ohif/cornerstoneOverlay');
|
||||
|
||||
// Historical usage defined the overlays as separate items due to lack of
|
||||
// append functionality. This code enables the historical usage, but
|
||||
// the recommended functionality is to append to the default values in
|
||||
// cornerstoneOverlay rather than defining individual items.
|
||||
const topLeftCustomization =
|
||||
customizationService.getCustomization('cornerstoneOverlayTopLeft') ||
|
||||
cornerstoneOverlay?.topLeftItems;
|
||||
const topRightCustomization =
|
||||
customizationService.getCustomization('cornerstoneOverlayTopRight') ||
|
||||
cornerstoneOverlay?.topRightItems;
|
||||
const bottomLeftCustomization =
|
||||
customizationService.getCustomization('cornerstoneOverlayBottomLeft') ||
|
||||
cornerstoneOverlay?.bottomLeftItems;
|
||||
const bottomRightCustomization =
|
||||
customizationService.getCustomization('cornerstoneOverlayBottomRight') ||
|
||||
cornerstoneOverlay?.bottomRightItems;
|
||||
const topLeftCustomization = customizationService.getCustomization('viewportOverlay.topLeft');
|
||||
const topRightCustomization = customizationService.getCustomization('viewportOverlay.topRight');
|
||||
const bottomLeftCustomization = customizationService.getCustomization(
|
||||
'viewportOverlay.bottomLeft'
|
||||
);
|
||||
const bottomRightCustomization = customizationService.getCustomization(
|
||||
'viewportOverlay.bottomRight'
|
||||
);
|
||||
|
||||
const instanceNumber = useMemo(
|
||||
() =>
|
||||
@@ -264,8 +182,8 @@ function CustomizableViewportOverlay({
|
||||
return null;
|
||||
}
|
||||
|
||||
const { customizationType } = item;
|
||||
const OverlayItemComponent = OverlayItemComponents[customizationType];
|
||||
const { inheritsFrom } = item;
|
||||
const OverlayItemComponent = OverlayItemComponents[inheritsFrom];
|
||||
|
||||
if (OverlayItemComponent) {
|
||||
return <OverlayItemComponent {...overlayItemProps} />;
|
||||
@@ -293,10 +211,6 @@ function CustomizableViewportOverlay({
|
||||
|
||||
const getContent = useCallback(
|
||||
(customization, keyPrefix) => {
|
||||
if (!customization?.items) {
|
||||
return null;
|
||||
}
|
||||
const { items } = customization;
|
||||
const props = {
|
||||
...displaySetProps,
|
||||
formatters: { formatDate: formatDICOMDate },
|
||||
@@ -309,7 +223,7 @@ function CustomizableViewportOverlay({
|
||||
|
||||
return (
|
||||
<>
|
||||
{items.map((item, index) => (
|
||||
{customization.map((item, index) => (
|
||||
<div key={`${keyPrefix}_${index}`}>
|
||||
{((!item?.condition || item.condition(props)) && _renderOverlayItem(item, props)) ||
|
||||
null}
|
||||
@@ -533,4 +447,4 @@ CustomizableViewportOverlay.propTypes = {
|
||||
|
||||
export default CustomizableViewportOverlay;
|
||||
|
||||
export { CustomizableViewportOverlay, CornerstoneOverlay };
|
||||
export { CustomizableViewportOverlay };
|
||||
@@ -194,7 +194,7 @@ function commandsModule({
|
||||
* on the measurement with a response if not cancelled.
|
||||
*/
|
||||
setMeasurementLabel: ({ uid }) => {
|
||||
const labelConfig = customizationService.get('measurementLabels');
|
||||
const labelConfig = customizationService.getCustomization('measurementLabels');
|
||||
const measurement = measurementService.getMeasurement(uid);
|
||||
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig).then(
|
||||
(val: Map<any, any>) => {
|
||||
@@ -311,7 +311,7 @@ function commandsModule({
|
||||
},
|
||||
|
||||
renameMeasurement: ({ uid }) => {
|
||||
const labelConfig = customizationService.get('measurementLabels');
|
||||
const labelConfig = customizationService.getCustomization('measurementLabels');
|
||||
const measurement = measurementService.getMeasurement(uid);
|
||||
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig).then(val => {
|
||||
measurementService.update(
|
||||
@@ -362,7 +362,7 @@ function commandsModule({
|
||||
viewportGridService.setActiveViewportId(viewportId);
|
||||
},
|
||||
arrowTextCallback: ({ callback, data, uid }) => {
|
||||
const labelConfig = customizationService.get('measurementLabels');
|
||||
const labelConfig = customizationService.getCustomization('measurementLabels');
|
||||
callLabelAutocompleteDialog(uiDialogService, callback, {}, labelConfig);
|
||||
},
|
||||
toggleCine: () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useEffect, useState, useRef } from 'react';
|
||||
import { CinePlayer, useCine } from '@ohif/ui';
|
||||
import { useCine } from '@ohif/ui';
|
||||
import { Enums, eventTarget, cache } from '@cornerstonejs/core';
|
||||
import { useAppConfig } from '@state';
|
||||
|
||||
@@ -160,8 +160,7 @@ function RenderCinePlayer({
|
||||
dynamicInfo: dynamicInfoProp,
|
||||
customizationService,
|
||||
}) {
|
||||
const { component: CinePlayerComponent = CinePlayer } =
|
||||
customizationService.get('cinePlayer') ?? {};
|
||||
const CinePlayerComponent = customizationService.getCustomization('cinePlayer');
|
||||
|
||||
const [dynamicInfo, setDynamicInfo] = useState(dynamicInfoProp);
|
||||
|
||||
|
||||
+12
-12
@@ -2,21 +2,21 @@
|
||||
// configured via the customization service.
|
||||
const defaultWindowLevelPresets = {
|
||||
CT: [
|
||||
{ description: 'Soft tissue', window: '400', level: '40' },
|
||||
{ description: 'Lung', window: '1500', level: '-600' },
|
||||
{ description: 'Liver', window: '150', level: '90' },
|
||||
{ description: 'Bone', window: '2500', level: '480' },
|
||||
{ description: 'Brain', window: '80', level: '40' },
|
||||
{ id: 'ct-soft-tissue', description: 'Soft tissue', window: '400', level: '40' },
|
||||
{ id: 'ct-lung', description: 'Lung', window: '1500', level: '-600' },
|
||||
{ id: 'ct-liver', description: 'Liver', window: '150', level: '90' },
|
||||
{ id: 'ct-bone', description: 'Bone', window: '2500', level: '480' },
|
||||
{ id: 'ct-brain', description: 'Brain', window: '80', level: '40' },
|
||||
],
|
||||
|
||||
PT: [
|
||||
{ description: 'Default', window: '5', level: '2.5' },
|
||||
{ description: 'SUV', window: '0', level: '3' },
|
||||
{ description: 'SUV', window: '0', level: '5' },
|
||||
{ description: 'SUV', window: '0', level: '7' },
|
||||
{ description: 'SUV', window: '0', level: '8' },
|
||||
{ description: 'SUV', window: '0', level: '10' },
|
||||
{ description: 'SUV', window: '0', level: '15' },
|
||||
{ id: 'pt-default', description: 'Default', window: '5', level: '2.5' },
|
||||
{ id: 'pt-suv-3', description: 'SUV', window: '0', level: '3' },
|
||||
{ id: 'pt-suv-5', description: 'SUV', window: '0', level: '5' },
|
||||
{ id: 'pt-suv-7', description: 'SUV', window: '0', level: '7' },
|
||||
{ id: 'pt-suv-8', description: 'SUV', window: '0', level: '8' },
|
||||
{ id: 'pt-suv-10', description: 'SUV', window: '0', level: '10' },
|
||||
{ id: 'pt-suv-15', description: 'SUV', window: '0', level: '15' },
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
+4
-5
@@ -16,11 +16,10 @@ export function getWindowLevelActionMenu({
|
||||
}>): ReactNode {
|
||||
const { customizationService } = servicesManager.services;
|
||||
|
||||
const { presets } = customizationService.get('cornerstone.windowLevelPresets');
|
||||
const colorbarProperties = customizationService.get('cornerstone.colorbar');
|
||||
const { volumeRenderingPresets, volumeRenderingQualityRange } = customizationService.get(
|
||||
'cornerstone.3dVolumeRendering'
|
||||
);
|
||||
const presets = customizationService.getCustomization('cornerstone.windowLevelPresets');
|
||||
const colorbarProperties = customizationService.getCustomization('cornerstone.colorbar');
|
||||
const { volumeRenderingPresets, volumeRenderingQualityRange } =
|
||||
customizationService.getCustomization('cornerstone.3dVolumeRendering');
|
||||
|
||||
const displaySetPresets = displaySets
|
||||
.filter(displaySet => presets[displaySet.Modality])
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { colormaps } from '../utils/colormaps';
|
||||
|
||||
const DefaultColormap = 'Grayscale';
|
||||
|
||||
export default {
|
||||
'cornerstone.colorbar': {
|
||||
width: '16px',
|
||||
colorbarTickPosition: 'left',
|
||||
colormaps,
|
||||
colorbarContainerPosition: 'right',
|
||||
colorbarInitialColormap: DefaultColormap,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
export default {
|
||||
'layoutSelector.advancedPresetGenerator': ({
|
||||
servicesManager,
|
||||
}: {
|
||||
servicesManager: AppTypes.ServicesManager;
|
||||
}) => {
|
||||
const _areSelectorsValid = (
|
||||
hp: AppTypes.HangingProtocol.Protocol,
|
||||
displaySets: AppTypes.DisplaySet[],
|
||||
hangingProtocolService: AppTypes.HangingProtocolService
|
||||
) => {
|
||||
if (!hp.displaySetSelectors || Object.values(hp.displaySetSelectors).length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return hangingProtocolService.areRequiredSelectorsValid(
|
||||
Object.values(hp.displaySetSelectors),
|
||||
displaySets[0]
|
||||
);
|
||||
};
|
||||
|
||||
const generateAdvancedPresets = ({
|
||||
servicesManager,
|
||||
}: {
|
||||
servicesManager: AppTypes.ServicesManager;
|
||||
}) => {
|
||||
const { hangingProtocolService, viewportGridService, displaySetService } =
|
||||
servicesManager.services;
|
||||
|
||||
const hangingProtocols = Array.from(hangingProtocolService.protocols.values());
|
||||
|
||||
const viewportId = viewportGridService.getActiveViewportId();
|
||||
|
||||
if (!viewportId) {
|
||||
return [];
|
||||
}
|
||||
const displaySetInsaneUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
|
||||
|
||||
if (!displaySetInsaneUIDs) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const displaySets = displaySetInsaneUIDs.map(uid =>
|
||||
displaySetService.getDisplaySetByUID(uid)
|
||||
);
|
||||
|
||||
return hangingProtocols
|
||||
.map(hp => {
|
||||
if (!hp.isPreset) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const areValid = _areSelectorsValid(hp, displaySets, hangingProtocolService);
|
||||
|
||||
return {
|
||||
icon: hp.icon,
|
||||
title: hp.name,
|
||||
commandOptions: {
|
||||
protocolId: hp.id,
|
||||
},
|
||||
disabled: !areValid,
|
||||
};
|
||||
})
|
||||
.filter(preset => preset !== null);
|
||||
};
|
||||
|
||||
return generateAdvancedPresets({ servicesManager });
|
||||
},
|
||||
'layoutSelector.commonPresets': [
|
||||
{
|
||||
icon: 'layout-common-1x1',
|
||||
commandOptions: {
|
||||
numRows: 1,
|
||||
numCols: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'layout-common-1x2',
|
||||
commandOptions: {
|
||||
numRows: 1,
|
||||
numCols: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'layout-common-2x2',
|
||||
commandOptions: {
|
||||
numRows: 2,
|
||||
numCols: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'layout-common-2x3',
|
||||
commandOptions: {
|
||||
numRows: 2,
|
||||
numCols: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,124 @@
|
||||
export default {
|
||||
'cornerstone.measurements': {
|
||||
Angle: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
CobbAngle: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
ArrowAnnotate: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
RectangleROi: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
CircleROI: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
EllipticalROI: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
Bidirectional: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
Length: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
LivewireContour: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
SplineROI: {
|
||||
displayText: [
|
||||
{
|
||||
displayName: 'Areas',
|
||||
value: 'area',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
value: 'areaUnits',
|
||||
for: ['area'],
|
||||
type: 'unit',
|
||||
},
|
||||
],
|
||||
report: [
|
||||
{
|
||||
displayName: 'Area',
|
||||
value: 'area',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
displayName: 'Unit',
|
||||
value: 'areaUnits',
|
||||
type: 'value',
|
||||
},
|
||||
],
|
||||
},
|
||||
PlanarFreehandROI: {
|
||||
displayTextOpen: [
|
||||
{
|
||||
displayName: 'Length',
|
||||
value: 'length',
|
||||
type: 'value',
|
||||
},
|
||||
],
|
||||
displayText: [
|
||||
{
|
||||
displayName: 'Mean',
|
||||
value: 'mean',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
displayName: 'Max',
|
||||
value: 'max',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
displayName: 'Area',
|
||||
value: 'area',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
value: 'pixelValueUnits',
|
||||
for: ['mean', 'max'],
|
||||
type: 'unit',
|
||||
},
|
||||
{
|
||||
value: 'areaUnits',
|
||||
for: ['area'],
|
||||
type: 'unit',
|
||||
},
|
||||
],
|
||||
report: [
|
||||
{
|
||||
displayName: 'Mean',
|
||||
value: 'mean',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
displayName: 'Max',
|
||||
value: 'max',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
displayName: 'Area',
|
||||
value: 'area',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
displayName: 'Unit',
|
||||
value: 'unit',
|
||||
type: 'value',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
import { CinePlayer } from '@ohif/ui';
|
||||
import DicomUpload from '../components/DicomUpload/DicomUpload';
|
||||
|
||||
export default {
|
||||
cinePlayer: CinePlayer,
|
||||
autoCineModalities: ['OT', 'US'],
|
||||
'panelMeasurement.disableEditing': false,
|
||||
onBeforeSRAddMeasurement: ({ measurement, StudyInstanceUID, SeriesInstanceUID }) => {
|
||||
return measurement;
|
||||
},
|
||||
onBeforeDicomStore: ({ dicomDict, measurementData, naturalizedReport }) => {
|
||||
return dicomDict;
|
||||
},
|
||||
dicomUploadComponent: DicomUpload,
|
||||
codingValues: {},
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
Icons,
|
||||
} from '@ohif/ui-next';
|
||||
|
||||
export default function getSegmentationPanelCustomization({ commandsManager, servicesManager }) {
|
||||
return {
|
||||
'panelSegmentation.customDropdownMenuContent': ({
|
||||
activeSegmentation,
|
||||
onSegmentationAdd,
|
||||
onSegmentationRemoveFromViewport,
|
||||
onSegmentationEdit,
|
||||
onSegmentationDelete,
|
||||
allowExport,
|
||||
storeSegmentation,
|
||||
onSegmentationDownload,
|
||||
onSegmentationDownloadRTSS,
|
||||
t,
|
||||
}) => (
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem onClick={() => onSegmentationAdd(activeSegmentation.segmentationId)}>
|
||||
<Icons.Add className="text-foreground" />
|
||||
<span className="pl-2">{t('Create New Segmentation')}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuLabel>{t('Manage Current Segmentation')}</DropdownMenuLabel>
|
||||
<DropdownMenuItem
|
||||
onClick={() => onSegmentationRemoveFromViewport(activeSegmentation.segmentationId)}
|
||||
>
|
||||
<Icons.Series className="text-foreground" />
|
||||
<span className="pl-2">{t('Remove from Viewport')}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => onSegmentationEdit(activeSegmentation.segmentationId)}>
|
||||
<Icons.Rename className="text-foreground" />
|
||||
<span className="pl-2">{t('Rename')}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger
|
||||
disabled={!allowExport}
|
||||
className="pl-1"
|
||||
>
|
||||
<Icons.Export className="text-foreground" />
|
||||
<span className="pl-2">{t('Export & Download')}</span>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuItem
|
||||
onClick={() => storeSegmentation(activeSegmentation.segmentationId)}
|
||||
>
|
||||
{t('Export DICOM SEG')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => onSegmentationDownload(activeSegmentation.segmentationId)}
|
||||
>
|
||||
{t('Download DICOM SEG')}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => onSegmentationDelete(activeSegmentation.segmentationId)}>
|
||||
<Icons.Delete className="text-red-600" />
|
||||
<span className="pl-2 text-red-600">{t('Delete')}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
),
|
||||
'panelSegmentation.disableEditing': false,
|
||||
'panelSegmentation.showAddSegment': true,
|
||||
'panelSegmentation.onSegmentationAdd': () => {
|
||||
const { viewportGridService } = servicesManager.services;
|
||||
const viewportId = viewportGridService.getState().activeViewportId;
|
||||
commandsManager.run('createLabelmapForViewport', { viewportId });
|
||||
},
|
||||
'panelSegmentation.tableMode': 'collapsed',
|
||||
'panelSegmentation.readableText': {
|
||||
lesionStats: 'Lesion Statistics',
|
||||
minValue: 'Minimum Value',
|
||||
maxValue: 'Maximum Value',
|
||||
meanValue: 'Mean Value',
|
||||
volume: 'Volume (ml)',
|
||||
suvPeak: 'SUV Peak',
|
||||
suvMax: 'Maximum SUV',
|
||||
suvMaxIJK: 'SUV Max IJK',
|
||||
lesionGlyoclysisStats: 'Lesion Glycolysis',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
export default {
|
||||
cornerstoneViewportClickCommands: {
|
||||
doubleClick: ['toggleOneUp'],
|
||||
button1: ['closeContextMenu'],
|
||||
button3: [
|
||||
{
|
||||
commandName: 'showCornerstoneContextMenu',
|
||||
commandOptions: {
|
||||
requireNearbyToolData: true,
|
||||
menuId: 'measurementsContextMenu',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
export default {
|
||||
'viewportOverlay.topLeft': [
|
||||
{
|
||||
id: 'StudyDate',
|
||||
inheritsFrom: 'ohif.overlayItem',
|
||||
label: '',
|
||||
title: 'Study date',
|
||||
condition: ({ referenceInstance }) => referenceInstance?.StudyDate,
|
||||
contentF: ({ referenceInstance, formatters: { formatDate } }) =>
|
||||
formatDate(referenceInstance.StudyDate),
|
||||
},
|
||||
{
|
||||
id: 'SeriesDescription',
|
||||
inheritsFrom: 'ohif.overlayItem',
|
||||
label: '',
|
||||
title: 'Series description',
|
||||
condition: ({ referenceInstance }) => {
|
||||
return referenceInstance && referenceInstance.SeriesDescription;
|
||||
},
|
||||
contentF: ({ referenceInstance }) => referenceInstance.SeriesDescription,
|
||||
},
|
||||
],
|
||||
'viewportOverlay.topRight': [],
|
||||
'viewportOverlay.bottomLeft': [
|
||||
{
|
||||
id: 'WindowLevel',
|
||||
inheritsFrom: 'ohif.overlayItem.windowLevel',
|
||||
},
|
||||
{
|
||||
id: 'ZoomLevel',
|
||||
inheritsFrom: 'ohif.overlayItem.zoomLevel',
|
||||
condition: props => {
|
||||
const activeToolName = props.toolGroupService.getActiveToolForViewport(props.viewportId);
|
||||
return activeToolName === 'Zoom';
|
||||
},
|
||||
},
|
||||
],
|
||||
'viewportOverlay.bottomRight': [
|
||||
{
|
||||
id: 'InstanceNumber',
|
||||
inheritsFrom: 'ohif.overlayItem.instanceNumber',
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Enums } from '@cornerstonejs/tools';
|
||||
import { toolNames } from '../initCornerstoneTools';
|
||||
|
||||
export default {
|
||||
'cornerstone.overlayViewportTools': {
|
||||
active: [
|
||||
{
|
||||
toolName: toolNames.WindowLevel,
|
||||
bindings: [{ mouseButton: Enums.MouseBindings.Primary }],
|
||||
},
|
||||
{
|
||||
toolName: toolNames.Pan,
|
||||
bindings: [{ mouseButton: Enums.MouseBindings.Auxiliary }],
|
||||
},
|
||||
{
|
||||
toolName: toolNames.Zoom,
|
||||
bindings: [{ mouseButton: Enums.MouseBindings.Secondary }],
|
||||
},
|
||||
{
|
||||
toolName: toolNames.StackScroll,
|
||||
bindings: [{ mouseButton: Enums.MouseBindings.Wheel }],
|
||||
},
|
||||
],
|
||||
enabled: [
|
||||
{
|
||||
toolName: toolNames.PlanarFreehandContourSegmentation,
|
||||
configuration: {
|
||||
displayOnePointAsCrosshairs: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
import { CONSTANTS } from '@cornerstonejs/core';
|
||||
|
||||
const { VIEWPORT_PRESETS } = CONSTANTS;
|
||||
|
||||
export default {
|
||||
'cornerstone.3dVolumeRendering': {
|
||||
volumeRenderingPresets: VIEWPORT_PRESETS,
|
||||
volumeRenderingQualityRange: {
|
||||
min: 1,
|
||||
max: 4,
|
||||
step: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import defaultWindowLevelPresets from '../components/WindowLevelActionMenu/defaultWindowLevelPresets';
|
||||
|
||||
export default {
|
||||
'cornerstone.windowLevelPresets': defaultWindowLevelPresets,
|
||||
};
|
||||
@@ -1,213 +0,0 @@
|
||||
import { Enums } from '@cornerstonejs/tools';
|
||||
import { toolNames } from './initCornerstoneTools';
|
||||
import defaultWindowLevelPresets from './components/WindowLevelActionMenu/defaultWindowLevelPresets';
|
||||
import { colormaps } from './utils/colormaps';
|
||||
import { CONSTANTS } from '@cornerstonejs/core';
|
||||
import { CornerstoneOverlay } from './Viewport/Overlays/CustomizableViewportOverlay';
|
||||
|
||||
const DefaultColormap = 'Grayscale';
|
||||
const { VIEWPORT_PRESETS } = CONSTANTS;
|
||||
|
||||
const tools = {
|
||||
active: [
|
||||
{
|
||||
toolName: toolNames.WindowLevel,
|
||||
bindings: [{ mouseButton: Enums.MouseBindings.Primary }],
|
||||
},
|
||||
{
|
||||
toolName: toolNames.Pan,
|
||||
bindings: [{ mouseButton: Enums.MouseBindings.Auxiliary }],
|
||||
},
|
||||
{
|
||||
toolName: toolNames.Zoom,
|
||||
bindings: [{ mouseButton: Enums.MouseBindings.Secondary }],
|
||||
},
|
||||
{
|
||||
toolName: toolNames.StackScroll,
|
||||
bindings: [{ mouseButton: Enums.MouseBindings.Wheel }],
|
||||
},
|
||||
],
|
||||
enabled: [
|
||||
{
|
||||
toolName: toolNames.PlanarFreehandContourSegmentation,
|
||||
configuration: {
|
||||
displayOnePointAsCrosshairs: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function getCustomizationModule() {
|
||||
return [
|
||||
{
|
||||
name: 'default',
|
||||
value: [
|
||||
CornerstoneOverlay,
|
||||
{
|
||||
id: 'cornerstone.overlayViewportTools',
|
||||
tools,
|
||||
},
|
||||
{
|
||||
id: 'cornerstone.windowLevelPresets',
|
||||
presets: defaultWindowLevelPresets,
|
||||
},
|
||||
{
|
||||
id: 'cornerstone.colorbar',
|
||||
width: '16px',
|
||||
colorbarTickPosition: 'left',
|
||||
colormaps,
|
||||
colorbarContainerPosition: 'right',
|
||||
colorbarInitialColormap: DefaultColormap,
|
||||
},
|
||||
{
|
||||
id: 'cornerstone.3dVolumeRendering',
|
||||
volumeRenderingPresets: VIEWPORT_PRESETS,
|
||||
volumeRenderingQualityRange: {
|
||||
min: 1,
|
||||
max: 4,
|
||||
step: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'cornerstone.measurements',
|
||||
Angle: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
CobbAngle: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
ArrowAnnotate: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
RectangleROi: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
CircleROI: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
EllipticalROI: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
Bidirectional: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
Length: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
LivewireContour: {
|
||||
displayText: [],
|
||||
report: [],
|
||||
},
|
||||
SplineROI: {
|
||||
displayText: [
|
||||
{
|
||||
displayName: 'Area',
|
||||
value: 'area',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
value: 'areaUnits',
|
||||
for: ['area'],
|
||||
type: 'unit',
|
||||
},
|
||||
/**
|
||||
{
|
||||
displayName: 'Modality',
|
||||
value: 'Modality',
|
||||
type: 'value',
|
||||
},
|
||||
*/
|
||||
],
|
||||
report: [
|
||||
{
|
||||
displayName: 'Area',
|
||||
value: 'area',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
displayName: 'Unit',
|
||||
value: 'areaUnits',
|
||||
type: 'value',
|
||||
},
|
||||
],
|
||||
},
|
||||
PlanarFreehandROI: {
|
||||
displayTextOpen: [
|
||||
{
|
||||
displayName: 'Length',
|
||||
value: 'length',
|
||||
type: 'value',
|
||||
},
|
||||
],
|
||||
displayText: [
|
||||
{
|
||||
displayName: 'Mean',
|
||||
value: 'mean',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
displayName: 'Max',
|
||||
value: 'max',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
displayName: 'Area',
|
||||
value: 'area',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
value: 'pixelValueUnits',
|
||||
for: ['mean', 'max' /** 'stdDev **/],
|
||||
type: 'unit',
|
||||
},
|
||||
{
|
||||
value: 'areaUnits',
|
||||
for: ['area'],
|
||||
type: 'unit',
|
||||
},
|
||||
/**
|
||||
{
|
||||
displayName: 'Std Dev',
|
||||
value: 'stdDev',
|
||||
type: 'value',
|
||||
},
|
||||
*/
|
||||
],
|
||||
report: [
|
||||
{
|
||||
displayName: 'Mean',
|
||||
value: 'mean',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
displayName: 'Max',
|
||||
value: 'max',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
displayName: 'Area',
|
||||
value: 'area',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
displayName: 'Unit',
|
||||
value: 'unit',
|
||||
type: 'value',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export default getCustomizationModule;
|
||||
@@ -0,0 +1,32 @@
|
||||
import viewportOverlayCustomization from './customizations/viewportOverlayCustomization';
|
||||
import getSegmentationPanelCustomization from './customizations/segmentationPanelCustomization';
|
||||
import layoutSelectorCustomization from './customizations/layoutSelectorCustomization';
|
||||
import viewportToolsCustomization from './customizations/viewportToolsCustomization';
|
||||
import viewportClickCommandsCustomization from './customizations/viewportClickCommandsCustomization';
|
||||
import measurementsCustomization from './customizations/measurementsCustomization';
|
||||
import volumeRenderingCustomization from './customizations/volumeRenderingCustomization';
|
||||
import colorbarCustomization from './customizations/colorbarCustomization';
|
||||
import windowLevelPresetsCustomization from './customizations/windowLevelPresetsCustomization';
|
||||
import miscCustomization from './customizations/miscCustomization';
|
||||
|
||||
function getCustomizationModule({ commandsManager, servicesManager }) {
|
||||
return [
|
||||
{
|
||||
name: 'default',
|
||||
value: {
|
||||
...viewportOverlayCustomization,
|
||||
...getSegmentationPanelCustomization({ commandsManager, servicesManager }),
|
||||
...layoutSelectorCustomization,
|
||||
...viewportToolsCustomization,
|
||||
...viewportClickCommandsCustomization,
|
||||
...measurementsCustomization,
|
||||
...volumeRenderingCustomization,
|
||||
...colorbarCustomization,
|
||||
...windowLevelPresetsCustomization,
|
||||
...miscCustomization,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export default getCustomizationModule;
|
||||
@@ -12,10 +12,7 @@ function mapSegmentationToDisplay(segmentation, customizationService) {
|
||||
const { label, segments } = segmentation;
|
||||
|
||||
// Get the readable text mapping once
|
||||
const { readableText: readableTextMap } = customizationService.getCustomization(
|
||||
'PanelSegmentation.readableText',
|
||||
{}
|
||||
);
|
||||
const readableTextMap = customizationService.getCustomization('panelSegmentation.readableText');
|
||||
|
||||
// Helper function to recursively map cachedStats to readable display text
|
||||
function mapStatsToDisplay(stats, indent = 0) {
|
||||
|
||||
@@ -7,10 +7,7 @@ function mapSegmentationToDisplay(segmentation, customizationService) {
|
||||
const { label, segments } = segmentation;
|
||||
|
||||
// Get the readable text mapping once
|
||||
const { readableText: readableTextMap } = customizationService.getCustomization(
|
||||
'PanelSegmentation.readableText',
|
||||
{}
|
||||
);
|
||||
const readableTextMap = customizationService.getCustomization('panelSegmentation.readableText');
|
||||
|
||||
// Helper function to recursively map cachedStats to readable display text
|
||||
function mapStatsToDisplay(stats, indent = 0) {
|
||||
|
||||
@@ -160,11 +160,9 @@ const cornerstoneExtension: Types.Extensions.Extension = {
|
||||
ViewportActionCornersProvider
|
||||
);
|
||||
|
||||
const { syncGroupService } = servicesManager.services;
|
||||
const { syncGroupService, customizationService } = servicesManager.services;
|
||||
syncGroupService.registerCustomSynchronizer('frameview', createFrameViewSynchronizer);
|
||||
servicesManager.services.customizationService.setGlobalCustomization('dicomUploadComponent', {
|
||||
component: props => <DicomUpload {...props} />,
|
||||
});
|
||||
|
||||
return init.call(this, props);
|
||||
},
|
||||
getToolbarModule,
|
||||
|
||||
@@ -5,27 +5,6 @@ import { findNearbyToolData } from './utils/findNearbyToolData';
|
||||
|
||||
const cs3DToolsEvents = Enums.Events;
|
||||
|
||||
const DEFAULT_CONTEXT_MENU_CLICKS = {
|
||||
button1: {
|
||||
commands: [
|
||||
{
|
||||
commandName: 'closeContextMenu',
|
||||
},
|
||||
],
|
||||
},
|
||||
button3: {
|
||||
commands: [
|
||||
{
|
||||
commandName: 'showCornerstoneContextMenu',
|
||||
commandOptions: {
|
||||
requireNearbyToolData: true,
|
||||
menuId: 'measurementsContextMenu',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a name, consisting of:
|
||||
* * alt when the alt key is down
|
||||
@@ -60,8 +39,10 @@ function initContextMenu({
|
||||
* defaults on button1 and button2
|
||||
*/
|
||||
const cornerstoneViewportHandleEvent = (name, evt) => {
|
||||
const customizations =
|
||||
customizationService.get('cornerstoneViewportClickCommands') || DEFAULT_CONTEXT_MENU_CLICKS;
|
||||
const customizations = customizationService.getCustomization(
|
||||
'cornerstoneViewportClickCommands'
|
||||
);
|
||||
|
||||
const toRun = customizations[name];
|
||||
|
||||
if (!toRun) {
|
||||
@@ -71,7 +52,7 @@ function initContextMenu({
|
||||
// only find nearbyToolData if required, for the click (which closes the context menu
|
||||
// we don't need to find nearbyToolData)
|
||||
let nearbyToolData = null;
|
||||
if (toRun.commands.some(command => command.commandOptions?.requireNearbyToolData)) {
|
||||
if (toRun.some(command => command.commandOptions?.requireNearbyToolData)) {
|
||||
nearbyToolData = findNearbyToolData(commandsManager, evt);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import { eventTarget, EVENTS } from '@cornerstonejs/core';
|
||||
import { Enums } from '@cornerstonejs/tools';
|
||||
import { CommandsManager, CustomizationService, Types } from '@ohif/core';
|
||||
import { CommandsManager, CustomizationService } from '@ohif/core';
|
||||
import { findNearbyToolData } from './utils/findNearbyToolData';
|
||||
|
||||
const cs3DToolsEvents = Enums.Events;
|
||||
|
||||
const DEFAULT_DOUBLE_CLICK = {
|
||||
doubleClick: {
|
||||
commandName: 'toggleOneUp',
|
||||
commandOptions: {},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a double click event name, consisting of:
|
||||
* * alt when the alt key is down
|
||||
@@ -50,8 +43,9 @@ function initDoubleClick({ customizationService, commandsManager }: initDoubleCl
|
||||
const eventName = getDoubleClickEventName(evt);
|
||||
|
||||
// Allows for the customization of the double click on a viewport.
|
||||
const customizations =
|
||||
customizationService.get('cornerstoneViewportClickCommands') || DEFAULT_DOUBLE_CLICK;
|
||||
const customizations = customizationService.getCustomization(
|
||||
'cornerstoneViewportClickCommands'
|
||||
);
|
||||
|
||||
const toRun = customizations[eventName];
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { utils } from '@ohif/core';
|
||||
import { MeasurementTable } from '@ohif/ui-next';
|
||||
import debounce from 'lodash.debounce';
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
Icons,
|
||||
SegmentationTable,
|
||||
DropdownMenuSubTrigger,
|
||||
} from '@ohif/ui-next';
|
||||
import { SegmentationTable } from '@ohif/ui-next';
|
||||
import { useActiveViewportSegmentationRepresentations } from '../hooks/useActiveViewportSegmentationRepresentations';
|
||||
import { metaData } from '@cornerstonejs/core';
|
||||
|
||||
@@ -19,7 +8,7 @@ export default function PanelSegmentation({
|
||||
commandsManager,
|
||||
children,
|
||||
}: withAppTypes) {
|
||||
const { customizationService, viewportGridService, displaySetService } = servicesManager.services;
|
||||
const { customizationService, displaySetService } = servicesManager.services;
|
||||
|
||||
const { segmentationsWithRepresentations, disabled } =
|
||||
useActiveViewportSegmentationRepresentations({
|
||||
@@ -27,11 +16,6 @@ export default function PanelSegmentation({
|
||||
});
|
||||
|
||||
const handlers = {
|
||||
onSegmentationAdd: async () => {
|
||||
const viewportId = viewportGridService.getState().activeViewportId;
|
||||
commandsManager.run('createLabelmapForViewport', { viewportId });
|
||||
},
|
||||
|
||||
onSegmentationClick: (segmentationId: string) => {
|
||||
commandsManager.run('setActiveSegmentation', { segmentationId });
|
||||
},
|
||||
@@ -125,107 +109,19 @@ export default function PanelSegmentation({
|
||||
},
|
||||
};
|
||||
|
||||
const { mode: SegmentationTableMode } = customizationService.getCustomization(
|
||||
'PanelSegmentation.tableMode',
|
||||
{
|
||||
id: 'default.segmentationTable.mode',
|
||||
mode: 'collapsed',
|
||||
}
|
||||
const segmentationTableMode = customizationService.getCustomization(
|
||||
'panelSegmentation.tableMode'
|
||||
);
|
||||
|
||||
// custom onSegmentationAdd if provided
|
||||
const { onSegmentationAdd } = customizationService.getCustomization(
|
||||
'PanelSegmentation.onSegmentationAdd',
|
||||
{
|
||||
id: 'segmentation.onSegmentationAdd',
|
||||
onSegmentationAdd: handlers.onSegmentationAdd,
|
||||
}
|
||||
const onSegmentationAdd = customizationService.getCustomization(
|
||||
'panelSegmentation.onSegmentationAdd'
|
||||
);
|
||||
|
||||
const { disableEditing } = customizationService.getCustomization(
|
||||
'PanelSegmentation.disableEditing',
|
||||
{
|
||||
id: 'default.disableEditing',
|
||||
disableEditing: false,
|
||||
}
|
||||
);
|
||||
|
||||
const { showAddSegment } = customizationService.getCustomization(
|
||||
'PanelSegmentation.showAddSegment',
|
||||
{
|
||||
id: 'default.showAddSegment',
|
||||
showAddSegment: true,
|
||||
}
|
||||
);
|
||||
|
||||
const CustomDropdownMenuContent = customizationService.getCustomComponent(
|
||||
'PanelSegmentation.CustomDropdownMenuContent',
|
||||
({
|
||||
activeSegmentation,
|
||||
onSegmentationAdd,
|
||||
onSegmentationRemoveFromViewport,
|
||||
onSegmentationEdit,
|
||||
onSegmentationDelete,
|
||||
allowExport,
|
||||
storeSegmentation,
|
||||
onSegmentationDownload,
|
||||
onSegmentationDownloadRTSS,
|
||||
t,
|
||||
}) => {
|
||||
return (
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem onClick={() => onSegmentationAdd(activeSegmentation.segmentationId)}>
|
||||
<Icons.Add className="text-foreground" />
|
||||
<span className="pl-2">{t('Create New Segmentation')}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuLabel>{t('Manage Current Segmentation')}</DropdownMenuLabel>
|
||||
<DropdownMenuItem
|
||||
onClick={() => onSegmentationRemoveFromViewport(activeSegmentation.segmentationId)}
|
||||
>
|
||||
<Icons.Series className="text-foreground" />
|
||||
<span className="pl-2">{t('Remove from Viewport')}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => onSegmentationEdit(activeSegmentation.segmentationId)}>
|
||||
<Icons.Rename className="text-foreground" />
|
||||
<span className="pl-2">{t('Rename')}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger
|
||||
disabled={!allowExport}
|
||||
className="pl-1"
|
||||
>
|
||||
<Icons.Export className="text-foreground" />
|
||||
<span className="pl-2">{t('Export & Download')}</span>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuItem
|
||||
onClick={() => storeSegmentation(activeSegmentation.segmentationId)}
|
||||
>
|
||||
{t('Export DICOM SEG')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => onSegmentationDownload(activeSegmentation.segmentationId)}
|
||||
>
|
||||
{t('Download DICOM SEG')}
|
||||
</DropdownMenuItem>
|
||||
{/* <DropdownMenuItem
|
||||
onClick={() => onSegmentationDownloadRTSS(activeSegmentation.segmentationId)}
|
||||
>
|
||||
{t('Download DICOM RTSTRUCT')}
|
||||
</DropdownMenuItem> */}
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => onSegmentationDelete(activeSegmentation.segmentationId)}>
|
||||
<Icons.Delete className="text-red-600" />
|
||||
<span className="pl-2 text-red-600">{t('Delete')}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
);
|
||||
}
|
||||
const disableEditing = customizationService.getCustomization('panelSegmentation.disableEditing');
|
||||
const showAddSegment = customizationService.getCustomization('panelSegmentation.showAddSegment');
|
||||
const CustomDropdownMenuContent = customizationService.getCustomization(
|
||||
'panelSegmentation.customDropdownMenuContent'
|
||||
);
|
||||
|
||||
const exportOptions = segmentationsWithRepresentations.map(({ segmentation }) => {
|
||||
@@ -272,7 +168,7 @@ export default function PanelSegmentation({
|
||||
<SegmentationTable
|
||||
disabled={disabled}
|
||||
data={segmentationsWithRepresentations}
|
||||
mode={SegmentationTableMode}
|
||||
mode={segmentationTableMode}
|
||||
title="Segmentations"
|
||||
exportOptions={exportOptions}
|
||||
disableEditing={disableEditing}
|
||||
@@ -308,7 +204,7 @@ export default function PanelSegmentation({
|
||||
<SegmentationTable.Config />
|
||||
<SegmentationTable.AddSegmentationRow />
|
||||
|
||||
{SegmentationTableMode === 'collapsed' ? (
|
||||
{segmentationTableMode === 'collapsed' ? (
|
||||
<SegmentationTable.Collapsed>
|
||||
<SegmentationTable.SelectorHeader>
|
||||
<CustomDropdownMenuContent />
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { useEffect, useState, memo } from 'react';
|
||||
|
||||
const MODALITIES_REQUIRING_CINE_AUTO_MOUNT = ['OT', 'US'];
|
||||
|
||||
const ActiveViewportBehavior = memo(
|
||||
({ servicesManager, viewportId }: withAppTypes<{ viewportId: string }>) => {
|
||||
const { displaySetService, cineService, viewportGridService, customizationService } =
|
||||
@@ -41,13 +39,7 @@ const ActiveViewportBehavior = memo(
|
||||
const modalities = displaySets.map(displaySet => displaySet?.Modality);
|
||||
const isDynamicVolume = displaySets.some(displaySet => displaySet?.isDynamicVolume);
|
||||
|
||||
const { modalities: sourceModalities } = customizationService.getModeCustomization(
|
||||
'autoCineModalities',
|
||||
{
|
||||
id: 'autoCineModalities',
|
||||
modalities: MODALITIES_REQUIRING_CINE_AUTO_MOUNT,
|
||||
}
|
||||
);
|
||||
const sourceModalities = customizationService.getCustomization('autoCineModalities');
|
||||
|
||||
const requiresCine = modalities.some(modality => sourceModalities.includes(modality));
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ function getMappedAnnotations(annotation, displaySetService) {
|
||||
* @returns {object} Report's content.
|
||||
*/
|
||||
function getColumnValueReport(annotation, customizationService) {
|
||||
const { PlanarFreehandROI } = customizationService.get('cornerstone.measurements');
|
||||
const { PlanarFreehandROI } = customizationService.getCustomization('cornerstone.measurements');
|
||||
const { report } = PlanarFreehandROI;
|
||||
const columns = [];
|
||||
const values = [];
|
||||
|
||||
@@ -145,7 +145,7 @@ function getMappedAnnotations(annotation, displaySetService) {
|
||||
* @returns {object} Report's content.
|
||||
*/
|
||||
function getColumnValueReport(annotation, customizationService) {
|
||||
const { SplineROI } = customizationService.get('cornerstone.measurements');
|
||||
const { SplineROI } = customizationService.getCustomization('cornerstone.measurements');
|
||||
const { report } = SplineROI;
|
||||
const columns = [];
|
||||
const values = [];
|
||||
|
||||
Reference in new issue
Block a user