diff --git a/src/commands/README.md b/src/commands/README.md new file mode 100644 index 000000000..61c515e7b --- /dev/null +++ b/src/commands/README.md @@ -0,0 +1 @@ +# Commands diff --git a/src/commands/cornerstone.js b/src/commands/cornerstone.js new file mode 100644 index 000000000..ab8974ea4 --- /dev/null +++ b/src/commands/cornerstone.js @@ -0,0 +1,169 @@ +import cornerstone from 'cornerstone-core'; + +const definitions = { + rotateViewportCW: { + commandFn: actions.rotateViewport, + storeContexts: ['viewports'], + options: { rotation: 90 }, + }, + rotateViewportCCW: { + commandFn: actions.rotateViewport, + storeContexts: ['viewports'], + options: { rotation: -90 }, + }, + invertViewport: { + commandFn: actions.invertViewport, + storeContexts: ['viewports'], + options: {}, + }, + flipViewportVertical: { + commandFn: actions.flipViewportVertical, + storeContexts: ['viewports'], + options: {}, + }, + flipViewportHorizontal: { + commandFn: actions.flipViewportHorizontal, + storeContexts: ['viewports'], + options: {}, + }, + scaleUpViewport: { + keys: '', + commandFn: actions.scaleViewport, + storeContexts: ['viewports'], + options: { direction: 1 }, + }, + scaleDownViewport: { + keys: '', + commandFn: actions.scaleViewport, + storeContexts: ['viewports'], + options: { direction: -1 }, + }, + fitViewportToWindow: { + commandFn: actions.scaleViewport, + storeContexts: ['viewports'], + options: { direction: 0 }, + }, + resetViewport: { + commandFn: actions.resetViewport, + storeContexts: ['viewports'], + options: {}, + }, + // TODO: Clear Annotations + // TODO: Next/Previous image + // TODO: First/Last image + // Next/Previous series/DisplaySet + nextViewportDisplaySet: { + commandFn: actions.updateViewportDisplaySet, + storeContexts: [], + options: { direction: 1 }, + }, + previousViewportDisplaySet: { + commandFn: actions.updateViewportDisplaySet, + storeContexts: [], + options: { direction: 1 }, + }, +}; + +const actions = { + rotateViewport: ({ viewports, rotation }) => { + const enabledElement = _getActiveViewportEnabledElement( + viewports.viewportSpecificData, + viewports.activeViewportIndex + ); + + if (enabledElement) { + let viewport = cornerstone.getViewport(enabledElement); + viewport.rotation += rotation; + cornerstone.setViewport(enabledElement, viewport); + } + }, + flipViewportHorizontal: ({ viewports }) => { + const enabledElement = _getActiveViewportEnabledElement( + viewports.viewportSpecificData, + viewports.activeViewportIndex + ); + + if (enabledElement) { + let viewport = cornerstone.getViewport(enabledElement); + viewport.hflip = !viewport.hflip; + cornerstone.setViewport(enabledElement, viewport); + } + }, + flipViewportVertical: ({ viewports }) => { + const enabledElement = _getActiveViewportEnabledElement( + viewports.viewportSpecificData, + viewports.activeViewportIndex + ); + + if (enabledElement) { + let viewport = cornerstone.getViewport(enabledElement); + viewport.vflip = !viewport.vflip; + cornerstone.setViewport(enabledElement, viewport); + } + }, + scaleViewport: ({ viewports, direction }) => { + const enabledElement = _getActiveViewportEnabledElement( + viewports.viewportSpecificData, + viewports.activeViewportIndex + ); + const step = direction * 0.15; + + if (enabledElement) { + if (step) { + let viewport = cornerstone.getViewport(enabledElement); + viewport.scale += step; + cornerstone.setViewport(enabledElement, viewport); + } else { + cornerstone.fitToWindow(enabledElement); + } + } + }, + resetViewport: ({ viewports }) => { + const enabledElement = _getActiveViewportEnabledElement( + viewports.viewportSpecificData, + viewports.activeViewportIndex + ); + + if (enabledElement) { + cornerstone.reset(enabledElement); + } + }, + + invertViewport: ({ viewports }) => { + const enabledElement = _getActiveViewportEnabledElement( + viewports.viewportSpecificData, + viewports.activeViewportIndex + ); + + if (enabledElement) { + let viewport = cornerstone.getViewport(enabledElement); + viewport.invert = !viewport.invert; + cornerstone.setViewport(enabledElement, viewport); + } + }, + updateViewportDisplaySet: ({ direction }) => { + // TODO + console.warn('updateDisplaySet: ', direction); + }, + clearAnnotations: () => { + console.warn('clearAnnotations: not yet implemented'); + // const toolState = + // cornerstoneTools.globalImageIdSpecificToolStateManager.toolState; + // if (!toolState) return; + // Object.keys(toolState).forEach(imageId => { + // if (!cornerstoneImageId || cornerstoneImageId === imageId) + // delete toolState[imageId]; + // }); + }, +}; + +/** + * Grabs `dom` reference for the enabledElement of + * the active viewport + */ +function _getActiveViewportEnabledElement(viewports, activeIndex) { + const activeViewport = viewports[activeIndex] || {}; + return activeViewport.dom; +} + +export default definitions; diff --git a/src/commands/index.js b/src/commands/index.js new file mode 100644 index 000000000..b577eb2b8 --- /dev/null +++ b/src/commands/index.js @@ -0,0 +1,52 @@ +import { CommandsManager } from 'ohif-core'; +import cornerstoneCommandDefinitions from 'cornerstone.js'; +import viewerCommandDefinitions from 'viewer.js'; + +const CONTEXTS = { + viewer: 'VIEWER', + cornerstone: 'VIEWER::CORNERSTONE', +}; + +/** + * Register all commands + */ +function init() { + _registerViewerCommands(); + _registerCornerstoneCommands(); +} + +/** + * Register all Viewer commands + * + * @private + */ +function _registerViewerCommands() { + const commandContext = CONTEXTS.viewer; + + CommandsManager.createContext(commandContext); + Object.keys(viewerCommandDefinitions).forEach(commandName => { + const commandDefinition = viewerCommandDefinitions[commandName]; + + CommandsManager.register(commandContext, commandName, commandDefinition); + }); +} + +/** + * Register all Cornerstone commands + * + * @private + */ +function _registerCornerstoneCommands() { + const commandContext = CONTEXTS.cornerstone; + + CommandsManager.createContext(commandContext); + Object.keys(cornerstoneCommandDefinitions).forEach(commandName => { + const commandDefinition = cornerstoneCommandDefinitions[commandName]; + + CommandsManager.register(commandContext, commandName, commandDefinition); + }); +} + +export default { + init, +}; diff --git a/src/commands/viewer.js b/src/commands/viewer.js new file mode 100644 index 000000000..7f0bc0f4d --- /dev/null +++ b/src/commands/viewer.js @@ -0,0 +1,36 @@ +import { redux } from 'ohif-core'; +import store from './store'; +const { setViewportActive } = redux.actions; + +const definitions = { + // Next/Previous active viewport + incrementActiveViewport: { + commandFn: actions.updateActiveViewport, + storeContexts: ['viewports'], + options: { direction: 1 }, + }, + decrementActiveViewport: { + commandFn: actions.updateActiveViewport, + storeContexts: ['viewports'], + options: { direction: -1 }, + }, +}; + +const actions = { + updateViewportDisplaySet: ({ direction }) => { + // TODO + console.warn('updateDisplaySet: ', direction); + }, + updateActiveViewport: ({ viewports, direction }) => { + const { viewportSpecificData, activeViewportIndex } = viewports; + const maxIndex = Object.keys(viewportSpecificData).length - 1; + + let newIndex = activeViewportIndex + direction; + newIndex = newIndex > maxIndex ? 0 : newIndex; + newIndex = newIndex < 0 ? maxIndex : newIndex; + + store.dispatch(setViewportActive(newIndex)); + }, +}; + +export default definitions;