2019-10-09 16:23:14 +02:00
|
|
|
import OHIF from '@ohif/core';
|
2020-09-15 03:18:46 +02:00
|
|
|
import { ContextMenuMeasurements } from '@ohif/ui';
|
2022-07-27 18:39:04 +02:00
|
|
|
|
|
|
|
|
import * as cornerstone from '@cornerstonejs/core';
|
|
|
|
|
import * as cornerstoneTools from '@cornerstonejs/tools';
|
|
|
|
|
import {
|
|
|
|
|
init as cs3DInit,
|
|
|
|
|
eventTarget,
|
|
|
|
|
EVENTS,
|
|
|
|
|
metaData,
|
|
|
|
|
volumeLoader,
|
|
|
|
|
imageLoader,
|
|
|
|
|
imageLoadPoolManager,
|
|
|
|
|
Settings,
|
|
|
|
|
} from '@cornerstonejs/core';
|
|
|
|
|
import { Enums, utilities } from '@cornerstonejs/tools';
|
|
|
|
|
import {
|
|
|
|
|
cornerstoneStreamingImageVolumeLoader,
|
|
|
|
|
sharedArrayBufferImageLoader,
|
|
|
|
|
} from '@cornerstonejs/streaming-image-volume-loader';
|
|
|
|
|
|
|
|
|
|
import initWADOImageLoader from './initWADOImageLoader';
|
|
|
|
|
import initCornerstoneTools from './initCornerstoneTools';
|
|
|
|
|
|
|
|
|
|
import { connectToolsToMeasurementService } from './initMeasurementService';
|
|
|
|
|
import callInputDialog from './utils/callInputDialog';
|
|
|
|
|
import initCineService from './initCineService';
|
|
|
|
|
import interleaveCenterLoader from './utils/interleaveCenterLoader';
|
|
|
|
|
import interleaveTopToBottom from './utils/interleaveTopToBottom';
|
|
|
|
|
import initSegmentationService from './initSegmentationService';
|
|
|
|
|
|
|
|
|
|
const cs3DToolsEvents = Enums.Events;
|
2020-08-05 14:56:02 +02:00
|
|
|
|
|
|
|
|
let CONTEXT_MENU_OPEN = false;
|
2020-09-15 03:18:46 +02:00
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
// TODO: Cypress tests are currently grabbing this from the window?
|
|
|
|
|
window.cornerstone = cornerstone;
|
|
|
|
|
window.cornerstoneTools = cornerstoneTools;
|
2019-10-09 16:23:14 +02:00
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
*/
|
2022-07-27 18:39:04 +02:00
|
|
|
export default async function init({
|
2020-08-05 14:56:02 +02:00
|
|
|
servicesManager,
|
|
|
|
|
commandsManager,
|
|
|
|
|
configuration,
|
2022-07-27 18:39:04 +02:00
|
|
|
appConfig,
|
2020-08-05 14:56:02 +02:00
|
|
|
}) {
|
2022-07-27 18:39:04 +02:00
|
|
|
await cs3DInit();
|
|
|
|
|
|
|
|
|
|
// For debugging e2e tests that are failing on CI
|
|
|
|
|
//cornerstone.setUseCPURendering(true);
|
|
|
|
|
|
|
|
|
|
// For debugging large datasets
|
|
|
|
|
//cornerstone.cache.setMaxCacheSize(3000000000);
|
|
|
|
|
|
|
|
|
|
initCornerstoneTools();
|
|
|
|
|
|
|
|
|
|
// Don't use cursors in viewports
|
|
|
|
|
// Todo: this should come from extension/app configuration
|
|
|
|
|
Settings.getRuntimeSettings().set('useCursors', false);
|
|
|
|
|
|
2020-07-22 19:40:40 +02:00
|
|
|
const {
|
2022-07-27 18:39:04 +02:00
|
|
|
UserAuthenticationService,
|
|
|
|
|
ToolGroupService,
|
2020-07-22 19:40:40 +02:00
|
|
|
MeasurementService,
|
|
|
|
|
DisplaySetService,
|
2022-07-27 18:39:04 +02:00
|
|
|
UIDialogService,
|
|
|
|
|
CineService,
|
|
|
|
|
CornerstoneViewportService,
|
|
|
|
|
HangingProtocolService,
|
|
|
|
|
SegmentationService,
|
2020-07-22 19:40:40 +02:00
|
|
|
} = servicesManager.services;
|
2020-09-15 03:18:46 +02:00
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
const metadataProvider = OHIF.classes.MetadataProvider;
|
|
|
|
|
|
|
|
|
|
volumeLoader.registerUnknownVolumeLoader(
|
|
|
|
|
cornerstoneStreamingImageVolumeLoader
|
|
|
|
|
);
|
|
|
|
|
volumeLoader.registerVolumeLoader(
|
|
|
|
|
'cornerstoneStreamingImageVolume',
|
|
|
|
|
cornerstoneStreamingImageVolumeLoader
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
HangingProtocolService.registerImageLoadStrategy(
|
|
|
|
|
'interleaveCenter',
|
|
|
|
|
interleaveCenterLoader
|
|
|
|
|
);
|
|
|
|
|
HangingProtocolService.registerImageLoadStrategy(
|
|
|
|
|
'interleaveTopToBottom',
|
|
|
|
|
interleaveTopToBottom
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
imageLoader.registerImageLoader(
|
|
|
|
|
'streaming-wadors',
|
|
|
|
|
sharedArrayBufferImageLoader
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
metaData.addProvider(metadataProvider.get.bind(metadataProvider), 9999);
|
|
|
|
|
|
|
|
|
|
imageLoadPoolManager.maxNumRequests = {
|
|
|
|
|
interaction: appConfig?.maxNumRequests?.interaction || 100,
|
|
|
|
|
thumbnail: appConfig?.maxNumRequests?.thumbnail || 75,
|
|
|
|
|
prefetch: appConfig?.maxNumRequests?.prefetch || 10,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
initWADOImageLoader(UserAuthenticationService, appConfig);
|
2019-12-09 18:47:23 +01:00
|
|
|
|
2020-08-05 14:56:02 +02:00
|
|
|
/* Measurement Service */
|
2022-07-27 18:39:04 +02:00
|
|
|
const measurementServiceSource = connectToolsToMeasurementService(
|
2020-08-05 14:56:02 +02:00
|
|
|
MeasurementService,
|
2022-07-27 18:39:04 +02:00
|
|
|
DisplaySetService,
|
|
|
|
|
CornerstoneViewportService
|
2020-08-05 14:56:02 +02:00
|
|
|
);
|
|
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
initSegmentationService(SegmentationService, CornerstoneViewportService);
|
|
|
|
|
|
|
|
|
|
initCineService(CineService);
|
|
|
|
|
|
|
|
|
|
const _getDefaultPosition = event => ({
|
|
|
|
|
x: (event && event.currentPoints.client[0]) || 0,
|
|
|
|
|
y: (event && event.currentPoints.client[1]) || 0,
|
|
|
|
|
});
|
|
|
|
|
|
2020-08-05 14:56:02 +02:00
|
|
|
const onRightClick = event => {
|
|
|
|
|
if (!UIDialogService) {
|
|
|
|
|
console.warn('Unable to show dialog; no UI Dialog Service available.');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const onGetMenuItems = defaultMenuItems => {
|
|
|
|
|
const { element, currentPoints } = event.detail;
|
2022-07-27 18:39:04 +02:00
|
|
|
|
|
|
|
|
const nearbyToolData = utilities.getAnnotationNearPoint(
|
2020-08-05 14:56:02 +02:00
|
|
|
element,
|
2022-07-27 18:39:04 +02:00
|
|
|
currentPoints.canvas
|
|
|
|
|
);
|
2020-08-05 14:56:02 +02:00
|
|
|
|
|
|
|
|
let menuItems = [];
|
|
|
|
|
if (nearbyToolData) {
|
|
|
|
|
defaultMenuItems.forEach(item => {
|
|
|
|
|
item.value = nearbyToolData;
|
2022-07-27 18:39:04 +02:00
|
|
|
item.element = element;
|
2020-08-05 14:56:02 +02:00
|
|
|
menuItems.push(item);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return menuItems;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
CONTEXT_MENU_OPEN = true;
|
|
|
|
|
|
|
|
|
|
UIDialogService.dismiss({ id: 'context-menu' });
|
|
|
|
|
UIDialogService.create({
|
|
|
|
|
id: 'context-menu',
|
|
|
|
|
isDraggable: false,
|
|
|
|
|
preservePosition: false,
|
|
|
|
|
defaultPosition: _getDefaultPosition(event.detail),
|
|
|
|
|
content: ContextMenuMeasurements,
|
|
|
|
|
onClickOutside: () => {
|
|
|
|
|
UIDialogService.dismiss({ id: 'context-menu' });
|
|
|
|
|
CONTEXT_MENU_OPEN = false;
|
|
|
|
|
},
|
|
|
|
|
contentProps: {
|
|
|
|
|
onGetMenuItems,
|
|
|
|
|
eventData: event.detail,
|
|
|
|
|
onDelete: item => {
|
2022-07-27 18:39:04 +02:00
|
|
|
const { annotationUID } = item.value;
|
2020-10-06 05:40:58 +02:00
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
const uid = annotationUID;
|
2020-10-06 05:40:58 +02:00
|
|
|
// Sync'd w/ Measurement Service
|
2022-07-27 18:39:04 +02:00
|
|
|
if (uid) {
|
|
|
|
|
measurementServiceSource.remove(uid, {
|
|
|
|
|
element: item.element,
|
2020-10-06 05:40:58 +02:00
|
|
|
});
|
|
|
|
|
}
|
2020-08-05 14:56:02 +02:00
|
|
|
CONTEXT_MENU_OPEN = false;
|
|
|
|
|
},
|
|
|
|
|
onClose: () => {
|
|
|
|
|
CONTEXT_MENU_OPEN = false;
|
|
|
|
|
UIDialogService.dismiss({ id: 'context-menu' });
|
|
|
|
|
},
|
|
|
|
|
onSetLabel: item => {
|
2022-07-27 18:39:04 +02:00
|
|
|
const { annotationUID } = item.value;
|
2020-08-05 14:56:02 +02:00
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
const measurement = MeasurementService.getMeasurement(annotationUID);
|
2020-08-05 14:56:02 +02:00
|
|
|
|
|
|
|
|
callInputDialog(
|
2020-09-15 03:18:46 +02:00
|
|
|
UIDialogService,
|
2020-08-05 14:56:02 +02:00
|
|
|
measurement,
|
|
|
|
|
(label, actionId) => {
|
|
|
|
|
if (actionId === 'cancel') {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const updatedMeasurement = Object.assign({}, measurement, {
|
|
|
|
|
label,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
MeasurementService.update(
|
2022-07-27 18:39:04 +02:00
|
|
|
updatedMeasurement.uid,
|
2020-08-05 14:56:02 +02:00
|
|
|
updatedMeasurement,
|
|
|
|
|
true
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
false
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CONTEXT_MENU_OPEN = false;
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const resetContextMenu = () => {
|
|
|
|
|
if (!UIDialogService) {
|
|
|
|
|
console.warn('Unable to show dialog; no UI Dialog Service available.');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CONTEXT_MENU_OPEN = false;
|
|
|
|
|
|
|
|
|
|
UIDialogService.dismiss({ id: 'context-menu' });
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
// When a custom image load is performed, update the relevant viewports
|
|
|
|
|
HangingProtocolService.subscribe(
|
|
|
|
|
HangingProtocolService.EVENTS.CUSTOM_IMAGE_LOAD_PERFORMED,
|
|
|
|
|
volumeInputArrayMap => {
|
|
|
|
|
for (const entry of volumeInputArrayMap.entries()) {
|
|
|
|
|
const [viewportId, volumeInputArray] = entry;
|
|
|
|
|
const viewport = CornerstoneViewportService.getCornerstoneViewport(
|
|
|
|
|
viewportId
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CornerstoneViewportService.setVolumesForViewport(
|
|
|
|
|
viewport,
|
|
|
|
|
volumeInputArray
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
2020-08-05 14:56:02 +02:00
|
|
|
/*
|
|
|
|
|
* Because click gives us the native "mouse up", buttons will always be `0`
|
|
|
|
|
* Need to fallback to event.which;
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
const contextMenuHandleClick = evt => {
|
|
|
|
|
const mouseUpEvent = evt.detail.event;
|
|
|
|
|
const isRightClick = mouseUpEvent.which === 3;
|
|
|
|
|
|
|
|
|
|
const clickMethodHandler = isRightClick ? onRightClick : resetContextMenu;
|
|
|
|
|
clickMethodHandler(evt);
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
// const cancelContextMenuIfOpen = evt => {
|
|
|
|
|
// if (CONTEXT_MENU_OPEN) {
|
|
|
|
|
// resetContextMenu();
|
|
|
|
|
// }
|
|
|
|
|
// };
|
2020-08-05 14:56:02 +02:00
|
|
|
|
2022-09-16 05:23:17 +02:00
|
|
|
const newStackCallback = evt => {
|
|
|
|
|
const { element } = evt.detail;
|
|
|
|
|
utilities.stackPrefetch.enable(element);
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
function elementEnabledHandler(evt) {
|
|
|
|
|
const { element } = evt.detail;
|
2020-09-15 03:18:46 +02:00
|
|
|
|
2020-08-05 14:56:02 +02:00
|
|
|
element.addEventListener(
|
2022-07-27 18:39:04 +02:00
|
|
|
cs3DToolsEvents.MOUSE_CLICK,
|
2020-08-05 14:56:02 +02:00
|
|
|
contextMenuHandleClick
|
|
|
|
|
);
|
2022-07-27 18:39:04 +02:00
|
|
|
|
2022-09-16 05:23:17 +02:00
|
|
|
eventTarget.addEventListener(
|
|
|
|
|
EVENTS.STACK_VIEWPORT_NEW_STACK,
|
|
|
|
|
newStackCallback
|
|
|
|
|
);
|
2020-08-05 14:56:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function elementDisabledHandler(evt) {
|
2022-07-27 18:39:04 +02:00
|
|
|
const { viewportId, element } = evt.detail;
|
|
|
|
|
|
|
|
|
|
const viewportInfo = CornerstoneViewportService.getViewportInfo(viewportId);
|
|
|
|
|
ToolGroupService.disable(viewportInfo);
|
|
|
|
|
|
2020-08-05 14:56:02 +02:00
|
|
|
element.removeEventListener(
|
2022-07-27 18:39:04 +02:00
|
|
|
cs3DToolsEvents.MOUSE_CLICK,
|
2020-08-05 14:56:02 +02:00
|
|
|
contextMenuHandleClick
|
|
|
|
|
);
|
2020-06-25 18:13:31 +02:00
|
|
|
|
2022-09-16 05:23:17 +02:00
|
|
|
// TODO - consider removing the callback when all elements are gone
|
|
|
|
|
// eventTarget.removeEventListener(
|
|
|
|
|
// EVENTS.STACK_VIEWPORT_NEW_STACK,
|
|
|
|
|
// newStackCallback
|
|
|
|
|
// );
|
2022-07-27 18:39:04 +02:00
|
|
|
}
|
2020-07-03 19:18:59 +02:00
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
eventTarget.addEventListener(
|
|
|
|
|
EVENTS.ELEMENT_ENABLED,
|
|
|
|
|
elementEnabledHandler.bind(null)
|
2020-08-04 11:11:23 +02:00
|
|
|
);
|
2020-07-03 18:39:41 +02:00
|
|
|
|
2022-07-27 18:39:04 +02:00
|
|
|
eventTarget.addEventListener(
|
|
|
|
|
EVENTS.ELEMENT_DISABLED,
|
|
|
|
|
elementDisabledHandler.bind(null)
|
2020-09-15 03:18:46 +02:00
|
|
|
);
|
|
|
|
|
}
|