feat: separate checks for addWindowLevelActionMenu and addSegmentationOverlay (#4813)
This commit is contained in:
parent
7d67834159
commit
7f0cc0f60e
@ -15,7 +15,6 @@ import type { Types } from '@ohif/core';
|
|||||||
|
|
||||||
import OHIFViewportActionCorners from '../components/OHIFViewportActionCorners';
|
import OHIFViewportActionCorners from '../components/OHIFViewportActionCorners';
|
||||||
import { getWindowLevelActionMenu } from '../components/WindowLevelActionMenu/getWindowLevelActionMenu';
|
import { getWindowLevelActionMenu } from '../components/WindowLevelActionMenu/getWindowLevelActionMenu';
|
||||||
import { useAppConfig } from '@state';
|
|
||||||
import { getViewportDataOverlaySettingsMenu } from '../components/ViewportDataOverlaySettingMenu';
|
import { getViewportDataOverlaySettingsMenu } from '../components/ViewportDataOverlaySettingMenu';
|
||||||
import { getViewportPresentations } from '../utils/presentations/getViewportPresentations';
|
import { getViewportPresentations } from '../utils/presentations/getViewportPresentations';
|
||||||
import { useSynchronizersStore } from '../stores/useSynchronizersStore';
|
import { useSynchronizersStore } from '../stores/useSynchronizersStore';
|
||||||
@ -89,7 +88,6 @@ const OHIFCornerstoneViewport = React.memo(
|
|||||||
const [scrollbarHeight, setScrollbarHeight] = useState('100px');
|
const [scrollbarHeight, setScrollbarHeight] = useState('100px');
|
||||||
const [enabledVPElement, setEnabledVPElement] = useState(null);
|
const [enabledVPElement, setEnabledVPElement] = useState(null);
|
||||||
const elementRef = useRef() as React.MutableRefObject<HTMLDivElement>;
|
const elementRef = useRef() as React.MutableRefObject<HTMLDivElement>;
|
||||||
const [appConfig] = useAppConfig();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
displaySetService,
|
displaySetService,
|
||||||
@ -324,51 +322,52 @@ const OHIFCornerstoneViewport = React.memo(
|
|||||||
|
|
||||||
// Set up the window level action menu in the viewport action corners.
|
// Set up the window level action menu in the viewport action corners.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Doing an === check here because the default config value when not set is true
|
const windowLevelActionMenu = customizationService.getCustomization(
|
||||||
if (appConfig.addWindowLevelActionMenu === false) {
|
'viewportActionMenu.windowLevelActionMenu'
|
||||||
return;
|
);
|
||||||
|
const segmentationOverlay = customizationService.getCustomization(
|
||||||
|
'viewportActionMenu.segmentationOverlay'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (windowLevelActionMenu?.enabled) {
|
||||||
|
viewportActionCornersService.addComponent({
|
||||||
|
viewportId,
|
||||||
|
id: 'windowLevelActionMenu',
|
||||||
|
component: getWindowLevelActionMenu({
|
||||||
|
viewportId,
|
||||||
|
element: elementRef.current,
|
||||||
|
displaySets,
|
||||||
|
servicesManager,
|
||||||
|
commandsManager,
|
||||||
|
location: windowLevelActionMenu.location,
|
||||||
|
verticalDirection: AllInOneMenu.VerticalDirection.TopToBottom,
|
||||||
|
horizontalDirection: AllInOneMenu.HorizontalDirection.RightToLeft,
|
||||||
|
}),
|
||||||
|
location: windowLevelActionMenu.location,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const location = viewportActionCornersService.LOCATIONS.topRight;
|
if (segmentationOverlay?.enabled) {
|
||||||
|
viewportActionCornersService.addComponent({
|
||||||
// TODO: In the future we should consider using the customization service
|
|
||||||
// to determine if and in which corner various action components should go.
|
|
||||||
viewportActionCornersService.addComponent({
|
|
||||||
viewportId,
|
|
||||||
id: 'windowLevelActionMenu',
|
|
||||||
component: getWindowLevelActionMenu({
|
|
||||||
viewportId,
|
viewportId,
|
||||||
element: elementRef.current,
|
id: 'segmentation',
|
||||||
displaySets,
|
component: getViewportDataOverlaySettingsMenu({
|
||||||
servicesManager,
|
viewportId,
|
||||||
commandsManager,
|
element: elementRef.current,
|
||||||
location,
|
displaySets,
|
||||||
verticalDirection: AllInOneMenu.VerticalDirection.TopToBottom,
|
servicesManager,
|
||||||
horizontalDirection: AllInOneMenu.HorizontalDirection.RightToLeft,
|
commandsManager,
|
||||||
}),
|
location: segmentationOverlay.location,
|
||||||
location,
|
}),
|
||||||
});
|
location: segmentationOverlay.location,
|
||||||
|
});
|
||||||
viewportActionCornersService.addComponent({
|
}
|
||||||
viewportId,
|
|
||||||
id: 'segmentation',
|
|
||||||
component: getViewportDataOverlaySettingsMenu({
|
|
||||||
viewportId,
|
|
||||||
element: elementRef.current,
|
|
||||||
displaySets,
|
|
||||||
servicesManager,
|
|
||||||
commandsManager,
|
|
||||||
location,
|
|
||||||
}),
|
|
||||||
location,
|
|
||||||
});
|
|
||||||
}, [
|
}, [
|
||||||
displaySets,
|
displaySets,
|
||||||
viewportId,
|
viewportId,
|
||||||
viewportActionCornersService,
|
viewportActionCornersService,
|
||||||
servicesManager,
|
servicesManager,
|
||||||
commandsManager,
|
commandsManager,
|
||||||
appConfig,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const { ref: resizeRef } = useResizeDetector({
|
const { ref: resizeRef } = useResizeDetector({
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
import viewportActionCornersService from '../services/ViewportActionCornersService/ViewportActionCornersService';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
'viewportActionMenu.windowLevelActionMenu': {
|
||||||
|
enabled: true,
|
||||||
|
location: viewportActionCornersService.LOCATIONS.topRight,
|
||||||
|
},
|
||||||
|
'viewportActionMenu.segmentationOverlay': {
|
||||||
|
enabled: true,
|
||||||
|
location: viewportActionCornersService.LOCATIONS.topRight,
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -9,6 +9,7 @@ import colorbarCustomization from './customizations/colorbarCustomization';
|
|||||||
import windowLevelPresetsCustomization from './customizations/windowLevelPresetsCustomization';
|
import windowLevelPresetsCustomization from './customizations/windowLevelPresetsCustomization';
|
||||||
import miscCustomization from './customizations/miscCustomization';
|
import miscCustomization from './customizations/miscCustomization';
|
||||||
import windowLevelActionMenuCustomization from './customizations/windowLevelActionMenuCustomization';
|
import windowLevelActionMenuCustomization from './customizations/windowLevelActionMenuCustomization';
|
||||||
|
import viewportActionMenuCustomizations from './customizations/viewportActionMenuCustomizations';
|
||||||
|
|
||||||
function getCustomizationModule({ commandsManager, servicesManager }) {
|
function getCustomizationModule({ commandsManager, servicesManager }) {
|
||||||
return [
|
return [
|
||||||
@ -26,6 +27,7 @@ function getCustomizationModule({ commandsManager, servicesManager }) {
|
|||||||
...windowLevelPresetsCustomization,
|
...windowLevelPresetsCustomization,
|
||||||
...miscCustomization,
|
...miscCustomization,
|
||||||
...windowLevelActionMenuCustomization,
|
...windowLevelActionMenuCustomization,
|
||||||
|
...viewportActionMenuCustomizations,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -129,7 +129,6 @@ declare global {
|
|||||||
showStudyList?: boolean;
|
showStudyList?: boolean;
|
||||||
whiteLabeling?: Record<string, unknown>;
|
whiteLabeling?: Record<string, unknown>;
|
||||||
httpErrorHandler?: (error: Error) => void;
|
httpErrorHandler?: (error: Error) => void;
|
||||||
addWindowLevelActionMenu?: boolean;
|
|
||||||
dangerouslyUseDynamicConfig?: {
|
dangerouslyUseDynamicConfig?: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
regex: RegExp;
|
regex: RegExp;
|
||||||
|
|||||||
BIN
platform/docs/docs/assets/img/segmentation-overlay.png
Normal file
BIN
platform/docs/docs/assets/img/segmentation-overlay.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 289 KiB |
@ -207,6 +207,86 @@ customizationService.setCustomizations({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
```
|
||||||
|
**Example: Customizing viewport action Menu**
|
||||||
|
|
||||||
|
**Before (v3.9):**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// In your configuration for global customizations
|
||||||
|
window.config = {
|
||||||
|
// rest of config
|
||||||
|
addWindowLevelActionMenu: true,
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**After (v3.10):**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// you can now handle each action menu item (windowLevelActionMenu and segmentationOverlay) separately
|
||||||
|
|
||||||
|
// cornerstone extension getCustomizationModule
|
||||||
|
function getCustomizationModule() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'default',
|
||||||
|
value: {
|
||||||
|
'viewportActionMenu.windowLevelActionMenu': {
|
||||||
|
enabled: true,
|
||||||
|
location: viewportActionCornersService.LOCATIONS.topRight,
|
||||||
|
},
|
||||||
|
'viewportActionMenu.segmentationOverlay': {
|
||||||
|
enabled: true,
|
||||||
|
location: viewportActionCornersService.LOCATIONS.topRight,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Accessing customizations within your component (e.g., OHIFCornerstoneViewport.tsx)
|
||||||
|
const windowLevelActionMenu = customizationService.getCustomization('viewportActionMenu.windowLevelActionMenu');
|
||||||
|
const segmentationOverlay = customizationService.getCustomization('viewportActionMenu.segmentationOverlay');
|
||||||
|
|
||||||
|
// Modifying customizations at runtime, for example, in your mode's onModeEnter
|
||||||
|
customizationService.setCustomizations({
|
||||||
|
'viewportActionMenu.windowLevelActionMenu': {
|
||||||
|
$set: {
|
||||||
|
enabled: false,
|
||||||
|
location: viewportActionCornersService.LOCATIONS.bottomLeft,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'viewportActionMenu.segmentationOverlay': {
|
||||||
|
$set: {
|
||||||
|
enabled: true,
|
||||||
|
location: viewportActionCornersService.LOCATIONS.topLeft,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Alternatively, setting global customizations via configuration
|
||||||
|
window.config = {
|
||||||
|
// rest of config
|
||||||
|
customizationService: [
|
||||||
|
{
|
||||||
|
'viewportActionMenu.windowLevelActionMenu': {
|
||||||
|
$set: {
|
||||||
|
enabled: false,
|
||||||
|
location: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'viewportActionMenu.segmentationOverlay': {
|
||||||
|
$set: {
|
||||||
|
enabled: true,
|
||||||
|
location: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// rest of config
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
**Note:**
|
**Note:**
|
||||||
|
|
||||||
@ -237,3 +317,5 @@ To keep our customization system consistent, you should be aware of a few key re
|
|||||||
| `cornerstoneOverlayTopRight` | `viewportOverlay.topRight` | Custom overlay items for the top-right corner of the viewport. |
|
| `cornerstoneOverlayTopRight` | `viewportOverlay.topRight` | Custom overlay items for the top-right corner of the viewport. |
|
||||||
| `cornerstoneOverlayBottomLeft` | `viewportOverlay.bottomLeft` | Custom overlay items for the bottom-left corner of the viewport. |
|
| `cornerstoneOverlayBottomLeft` | `viewportOverlay.bottomLeft` | Custom overlay items for the bottom-left corner of the viewport. |
|
||||||
| `cornerstoneOverlayBottomRight` | `viewportOverlay.bottomRight` | Custom overlay items for the bottom-right corner of the viewport. |
|
| `cornerstoneOverlayBottomRight` | `viewportOverlay.bottomRight` | Custom overlay items for the bottom-right corner of the viewport. |
|
||||||
|
| (New) | `viewportActionMenu.windowLevelActionMenu` | Controls the display and the location of the window level action menu in the viewport. |
|
||||||
|
| (New) | `viewportActionMenu.segmentationOverlay` | Controls the display and the location of segmentation overlays in the viewport. |
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import loadingIndicatorProgress from '../../../assets/img/loading-indicator-icon
|
|||||||
import loadingIndicatorPercent from '../../../assets/img/loading-indicator-percent.png';
|
import loadingIndicatorPercent from '../../../assets/img/loading-indicator-percent.png';
|
||||||
import viewportActionCorners from '../../../assets/img/viewport-action-corners.png';
|
import viewportActionCorners from '../../../assets/img/viewport-action-corners.png';
|
||||||
import contextMenu from '../../../assets/img/context-menu.jpg';
|
import contextMenu from '../../../assets/img/context-menu.jpg';
|
||||||
|
import segmentationOverlay from '../../../assets/img/segmentation-overlay.png';
|
||||||
|
|
||||||
import segDisplayEditingTrue from '../../../assets/img/segDisplayEditingTrue.png';
|
import segDisplayEditingTrue from '../../../assets/img/segDisplayEditingTrue.png';
|
||||||
import segDisplayEditingFalse from '../../../assets/img/segDisplayEditingFalse.png';
|
import segDisplayEditingFalse from '../../../assets/img/segDisplayEditingFalse.png';
|
||||||
@ -784,6 +785,57 @@ window.config = {
|
|||||||
};
|
};
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'viewportActionMenu.windowLevelActionMenu',
|
||||||
|
description:
|
||||||
|
'Configures the display and location of the window level action menu in the viewport.',
|
||||||
|
image: windowLevelActionMenu,
|
||||||
|
default: null,
|
||||||
|
configuration: `
|
||||||
|
window.config = {
|
||||||
|
// rest of window config
|
||||||
|
customizationService: [
|
||||||
|
{
|
||||||
|
'viewportActionMenu.windowLevelActionMenu': {
|
||||||
|
$set: {
|
||||||
|
enabled: true,
|
||||||
|
location: 1, // Set the location of the menu in the viewport.
|
||||||
|
// 0: topLeft
|
||||||
|
// 1: topRight
|
||||||
|
// 2: bottomLeft
|
||||||
|
// 3: bottomRight
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'viewportActionMenu.segmentationOverlay',
|
||||||
|
description: 'Configures the display and location of the segmentation overlay in the viewport.',
|
||||||
|
image: segmentationOverlay,
|
||||||
|
default: null,
|
||||||
|
configuration: `
|
||||||
|
window.config = {
|
||||||
|
// rest of window config
|
||||||
|
customizationService: [
|
||||||
|
{
|
||||||
|
'viewportActionMenu.segmentationOverlay': {
|
||||||
|
$set: {
|
||||||
|
enabled: true,
|
||||||
|
location: 1, // Set the location of the overlay in the viewport.
|
||||||
|
// 0: topLeft
|
||||||
|
// 1: topRight
|
||||||
|
// 2: bottomLeft
|
||||||
|
// 3: bottomRight
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const segmentationCustomizations = [
|
export const segmentationCustomizations = [
|
||||||
|
|||||||
@ -192,7 +192,6 @@ if auth headers are used, a preflight request is required.
|
|||||||
- `allowMultiSelectExport`: (default to false), if set to true, the user will be able to select the datasource to export the report to.
|
- `allowMultiSelectExport`: (default to false), if set to true, the user will be able to select the datasource to export the report to.
|
||||||
- `activateViewportBeforeInteraction`: (default to true), if set to false, tools can be used directly without the need to click and activate the viewport.
|
- `activateViewportBeforeInteraction`: (default to true), if set to false, tools can be used directly without the need to click and activate the viewport.
|
||||||
- `autoPlayCine`: (default to false), if set to true, data sets with the DICOM frame time tag (i.e. (0018,1063)) will auto play when displayed
|
- `autoPlayCine`: (default to false), if set to true, data sets with the DICOM frame time tag (i.e. (0018,1063)) will auto play when displayed
|
||||||
- `addWindowLevelActionMenu`: (default to true), if set to false, the window level action menu item is NOT added to the viewport action corners
|
|
||||||
- `dangerouslyUseDynamicConfig`: Dynamic config allows user to pass `configUrl` query string. This allows to load config without recompiling application. If the `configUrl` query string is passed, the worklist and modes will load from the referenced json rather than the default .env config. If there is no `configUrl` path provided, the default behaviour is used and there should not be any deviation from current user experience.<br/>
|
- `dangerouslyUseDynamicConfig`: Dynamic config allows user to pass `configUrl` query string. This allows to load config without recompiling application. If the `configUrl` query string is passed, the worklist and modes will load from the referenced json rather than the default .env config. If there is no `configUrl` path provided, the default behaviour is used and there should not be any deviation from current user experience.<br/>
|
||||||
Points to consider while using `dangerouslyUseDynamicConfig`:<br/>
|
Points to consider while using `dangerouslyUseDynamicConfig`:<br/>
|
||||||
- User have to enable this feature by setting `dangerouslyUseDynamicConfig.enabled:true`. By default it is `false`.
|
- User have to enable this feature by setting `dangerouslyUseDynamicConfig.enabled:true`. By default it is `false`.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user