/** @type {AppTypes.Config} */ window.config = { routerBasename: '/', // whiteLabeling: {}, extensions: [], modes: [], customizationService: {}, showStudyList: true, // some windows systems have issues with more than 3 web workers maxNumberOfWebWorkers: 3, // below flag is for performance reasons, but it might not work for all servers showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, experimentalStudyBrowserSort: false, strictZSpacingForVolumeViewport: true, groupEnabledModesFirst: true, maxNumRequests: { interaction: 100, thumbnail: 75, // Prefetch number is dependent on the http protocol. For http 2 or // above, the number of requests can be go a lot higher. prefetch: 25, }, expertise: false, //* Tambahan untuk enable expertise (CustomizableViewportOverlay) expertise_host: `http://152.42.173.210`, //* Tambahan untuk fetch data Expertise) pacs_document_host: `${window.location.hostname}`, pacs_document_port: 8080, // filterQueryParam: false, // defaultDataSourceName: 'dicomweb', defaultDataSourceName: 'local-proxy', /* Dynamic config allows user to pass "configUrl" query string this allows to load config without recompiling application. The regex will ensure valid configuration source */ // dangerouslyUseDynamicConfig: { // enabled: true, // // regex will ensure valid configuration source and default is /.*/ which matches any character. To use this, setup your own regex to choose a specific source of configuration only. // // Example 1, to allow numbers and letters in an absolute or sub-path only. // // regex: /(0-9A-Za-z.]+)(\/[0-9A-Za-z.]+)*/ // // Example 2, to restricts to either hosptial.com or othersite.com. // // regex: /(https:\/\/hospital.com(\/[0-9A-Za-z.]+)*)|(https:\/\/othersite.com(\/[0-9A-Za-z.]+)*)/ // regex: /.*/, // }, dataSources: [ { namespace: '@ohif/extension-default.dataSourcesModule.dicomweb', sourceName: 'local-proxy', configuration: { friendlyName: 'Static WADO Local Data', name: 'DCM4CHEE', qidoRoot: `http://152.42.173.210:5000/rs`, wadoRoot: `http://152.42.173.210:5000/rs`, qidoSupportsIncludeField: false, supportsReject: true, supportsStow: true, imageRendering: 'wadors', thumbnailRendering: 'wadors', enableStudyLazyLoad: true, supportsFuzzyMatching: false, supportsWildcard: true, staticWado: true, singlepart: 'video', bulkDataURI: { enabled: true, relativeResolution: 'studies', }, }, }, { namespace: '@ohif/extension-default.dataSourcesModule.dicomwebproxy', sourceName: 'dicomwebproxy', configuration: { friendlyName: 'dicomweb delegating proxy', name: 'dicomwebproxy', }, }, { namespace: '@ohif/extension-default.dataSourcesModule.dicomjson', sourceName: 'dicomjson', configuration: { friendlyName: 'dicom json', name: 'json', }, }, { namespace: '@ohif/extension-default.dataSourcesModule.dicomlocal', sourceName: 'dicomlocal', configuration: { friendlyName: 'dicom local', }, }, ], httpErrorHandler: error => { // This is 429 when rejected from the public idc sandbox too often. console.warn(error.status); // Could use services manager here to bring up a dialog/modal if needed. console.warn('test, navigate to https://ohif.org/'); }, // whiteLabeling: { // /* Optional: Should return a React component to be rendered in the "Logo" section of the application's Top Navigation bar */ // createLogoComponentFn: function (React) { // return React.createElement( // 'a', // { // target: '_self', // rel: 'noopener noreferrer', // className: 'text-purple-600 line-through', // href: '/', // }, // React.createElement('img', // { // src: './assets/customLogo.svg', // className: 'w-8 h-8', // } // )) // }, // }, hotkeys: [ { commandName: 'incrementActiveViewport', label: 'Next Viewport', keys: ['right'], }, { commandName: 'decrementActiveViewport', label: 'Previous Viewport', keys: ['left'], }, { commandName: 'rotateViewportCW', label: 'Rotate Right', keys: ['r'] }, { commandName: 'rotateViewportCCW', label: 'Rotate Left', keys: ['l'] }, { commandName: 'invertViewport', label: 'Invert', keys: ['i'] }, { commandName: 'flipViewportHorizontal', label: 'Flip Horizontally', keys: ['h'], }, { commandName: 'flipViewportVertical', label: 'Flip Vertically', keys: ['v'], }, { commandName: 'scaleUpViewport', label: 'Zoom In', keys: ['+'] }, { commandName: 'scaleDownViewport', label: 'Zoom Out', keys: ['-'] }, { commandName: 'fitViewportToWindow', label: 'Zoom to Fit', keys: ['='] }, { commandName: 'resetViewport', label: 'Reset', keys: ['space'] }, { commandName: 'nextImage', label: 'Next Image', keys: ['down'] }, { commandName: 'previousImage', label: 'Previous Image', keys: ['up'] }, // { // commandName: 'previousViewportDisplaySet', // label: 'Previous Series', // keys: ['pagedown'], // }, // { // commandName: 'nextViewportDisplaySet', // label: 'Next Series', // keys: ['pageup'], // }, { commandName: 'setToolActive', commandOptions: { toolName: 'Zoom' }, label: 'Zoom', keys: ['z'], }, // ~ Window level presets { commandName: 'windowLevelPreset1', label: 'W/L Preset 1', keys: ['1'], }, { commandName: 'windowLevelPreset2', label: 'W/L Preset 2', keys: ['2'], }, { commandName: 'windowLevelPreset3', label: 'W/L Preset 3', keys: ['3'], }, { commandName: 'windowLevelPreset4', label: 'W/L Preset 4', keys: ['4'], }, { commandName: 'windowLevelPreset5', label: 'W/L Preset 5', keys: ['5'], }, { commandName: 'windowLevelPreset6', label: 'W/L Preset 6', keys: ['6'], }, { commandName: 'windowLevelPreset7', label: 'W/L Preset 7', keys: ['7'], }, { commandName: 'windowLevelPreset8', label: 'W/L Preset 8', keys: ['8'], }, { commandName: 'windowLevelPreset9', label: 'W/L Preset 9', keys: ['9'], }, ], tours: [ { id: 'basicViewerTour', route: '/viewer', steps: [ { id: 'scroll', title: 'Scrolling Through Images', text: 'You can scroll through the images using the mouse wheel or scrollbar.', attachTo: { element: '.viewport-element', on: 'top', }, advanceOn: { selector: '.cornerstone-viewport-element', event: 'CORNERSTONE_TOOLS_MOUSE_WHEEL', }, beforeShowPromise: () => waitForElement('.viewport-element'), }, { id: 'zoom', title: 'Zooming In and Out', text: 'You can zoom the images using the right click.', attachTo: { element: '.viewport-element', on: 'left', }, advanceOn: { selector: '.cornerstone-viewport-element', event: 'CORNERSTONE_TOOLS_MOUSE_UP', }, beforeShowPromise: () => waitForElement('.viewport-element'), }, { id: 'pan', title: 'Panning the Image', text: 'You can pan the images using the middle click.', attachTo: { element: '.viewport-element', on: 'top', }, advanceOn: { selector: '.cornerstone-viewport-element', event: 'CORNERSTONE_TOOLS_MOUSE_UP', }, beforeShowPromise: () => waitForElement('.viewport-element'), }, { id: 'windowing', title: 'Adjusting Window Level', text: 'You can modify the window level using the left click.', attachTo: { element: '.viewport-element', on: 'left', }, advanceOn: { selector: '.cornerstone-viewport-element', event: 'CORNERSTONE_TOOLS_MOUSE_UP', }, beforeShowPromise: () => waitForElement('.viewport-element'), }, { id: 'length', title: 'Using the Measurement Tools', text: 'You can measure the length of a region using the Length tool.', attachTo: { element: '[data-cy="MeasurementTools-split-button-primary"]', on: 'bottom', }, advanceOn: { selector: '[data-cy="MeasurementTools-split-button-primary"]', event: 'click', }, beforeShowPromise: () => waitForElement('[data-cy="MeasurementTools-split-button-primary]'), }, { id: 'drawAnnotation', title: 'Drawing Length Annotations', text: 'Use the length tool on the viewport to measure the length of a region.', attachTo: { element: '.viewport-element', on: 'right', }, advanceOn: { selector: 'body', event: 'event::measurement_added', }, beforeShowPromise: () => waitForElement('.viewport-element'), }, { id: 'trackMeasurement', title: 'Tracking Measurements in the Panel', text: 'Click yes to track the measurements in the measurement panel.', attachTo: { element: '[data-cy="prompt-begin-tracking-yes-btn"]', on: 'bottom', }, advanceOn: { selector: '[data-cy="prompt-begin-tracking-yes-btn"]', event: 'click', }, beforeShowPromise: () => waitForElement('[data-cy="prompt-begin-tracking-yes-btn"]'), }, { id: 'openMeasurementPanel', title: 'Opening the Measurements Panel', text: 'Click the measurements button to open the measurements panel.', attachTo: { element: '#trackedMeasurements-btn', on: 'left-start', }, advanceOn: { selector: '#trackedMeasurements-btn', event: 'click', }, beforeShowPromise: () => waitForElement('#trackedMeasurements-btn'), }, { id: 'scrollAwayFromMeasurement', title: 'Scrolling Away from a Measurement', text: 'Scroll the images using the mouse wheel away from the measurement.', attachTo: { element: '.viewport-element', on: 'left', }, advanceOn: { selector: '.cornerstone-viewport-element', event: 'CORNERSTONE_TOOLS_MOUSE_WHEEL', }, beforeShowPromise: () => waitForElement('.viewport-element'), }, { id: 'jumpToMeasurement', title: 'Jumping to Measurements in the Panel', text: 'Click the measurement in the measurement panel to jump to it.', attachTo: { element: '[data-cy="data-row"]', on: 'left-start', }, advanceOn: { selector: '[data-cy="data-row"]', event: 'click', }, beforeShowPromise: () => waitForElement('[data-cy="data-row"]'), }, { id: 'changeLayout', title: 'Changing Layout', text: 'You can change the layout of the viewer using the layout button.', attachTo: { element: '[data-cy="Layout"]', on: 'bottom', }, advanceOn: { selector: '[data-cy="Layout"]', event: 'click', }, beforeShowPromise: () => waitForElement('[data-cy="Layout"]'), }, { id: 'selectLayout', title: 'Selecting the MPR Layout', text: 'Select the MPR layout to view the images in MPR mode.', attachTo: { element: '[data-cy="MPR"]', on: 'left-start', }, advanceOn: { selector: '[data-cy="MPR"]', event: 'click', }, beforeShowPromise: () => waitForElement('[data-cy="MPR"]'), }, ], tourOptions: { useModalOverlay: true, defaultStepOptions: { buttons: [ { text: 'Skip all', action() { this.complete(); }, secondary: true, }, ], }, }, }, ], }; function waitForElement(selector, maxAttempts = 20, interval = 25) { return new Promise(resolve => { let attempts = 0; const checkForElement = setInterval(() => { const element = document.querySelector(selector); if (element || attempts >= maxAttempts) { clearInterval(checkForElement); resolve(); } attempts++; }, interval); }); }