From dbbcbe6e674a37d4b9f585f4fa65f7ae97655068 Mon Sep 17 00:00:00 2001 From: Bruno Alves de Faria Date: Mon, 24 Apr 2017 17:07:47 -0300 Subject: [PATCH] Creating ohif:commands package --- .../client/classes/CommandsManager.js | 60 +++++++++++++ Packages/ohif-commands/main.js | 15 ++++ Packages/ohif-commands/package.js | 22 +++++ .../client/classes/HotkeysManager.js | 2 +- Packages/ohif-hotkeys/main.js | 13 +-- .../ohif-viewerbase/client/lib/toolManager.js | 87 +++++++++++-------- 6 files changed, 151 insertions(+), 48 deletions(-) create mode 100644 Packages/ohif-commands/client/classes/CommandsManager.js create mode 100644 Packages/ohif-commands/main.js create mode 100644 Packages/ohif-commands/package.js diff --git a/Packages/ohif-commands/client/classes/CommandsManager.js b/Packages/ohif-commands/client/classes/CommandsManager.js new file mode 100644 index 000000000..179ba4d3e --- /dev/null +++ b/Packages/ohif-commands/client/classes/CommandsManager.js @@ -0,0 +1,60 @@ +import { ReactiveDict } from 'meteor/reactive-dict'; +import { Tracker } from 'meteor/tracker'; +import { OHIF } from 'meteor/ohif:core'; + +export class CommandsManager { + constructor() { + this.contexts = {}; + + Tracker.autorun(() => { + const currentContextName = OHIF.context.get(); + OHIF.log.info(currentContextName); + // TODO: initialize hotkeys context + }); + } + + getContext(contextName) { + const context = this.contexts[contextName]; + if (!context) { + OHIF.log.warn(`No context found with name "${contextName}"`); + } + + return context; + } + + getCurrentContext(contextName) { + return this.getContext(OHIF.context.get()); + } + + createContext(contextName) { + if (this.contexts[contextName]) { + return this.unsetCommands(contextName); + } + + this.contexts[contextName] = new ReactiveDict(); + } + + setCommands(contextName, definitions) { + if (typeof definitions !== 'object') return; + const context = this.getContext(contextName); + if (!context) return; + + this.unsetCommands(contextName); + Object.keys(definitions).forEach(key => context.set(key, definitions[key])); + } + + registerCommand(contextName, key, definition) { + if (typeof definition !== 'object') return; + const context = this.getContext(contextName); + if (!context) return; + + context.set(key, definition); + } + + unsetCommands(contextName) { + const context = this.getContext(contextName); + if (!context) return; + + context.clear(); + } +} diff --git a/Packages/ohif-commands/main.js b/Packages/ohif-commands/main.js new file mode 100644 index 000000000..e1328cf0a --- /dev/null +++ b/Packages/ohif-commands/main.js @@ -0,0 +1,15 @@ +import { ReactiveVar } from 'meteor/reactive-var'; +import { OHIF } from 'meteor/ohif:core'; +import { CommandsManager } from 'meteor/ohif:commands/client/classes/CommandsManager'; + +// Create context namespace using a ReactiveVar +const context = new ReactiveVar(null); + +// Create commands namespace using a CommandsManager class instance +const commands = new CommandsManager(context); + +// Append context namespace to OHIF namespace +OHIF.context = context; + +// Export relevant objects +export { context, commands }; diff --git a/Packages/ohif-commands/package.js b/Packages/ohif-commands/package.js new file mode 100644 index 000000000..aacd09aaf --- /dev/null +++ b/Packages/ohif-commands/package.js @@ -0,0 +1,22 @@ +Package.describe({ + name: 'ohif:commands', + summary: 'OHIF commands management', + version: '0.0.1' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.4'); + + // Meteor packages + api.use([ + 'ecmascript', + 'reactive-var', + 'reactive-dict' + ]); + + // OHIF dependencies + api.use('ohif:core'); + + // Main module definition + api.mainModule('main.js', 'client'); +}); diff --git a/Packages/ohif-hotkeys/client/classes/HotkeysManager.js b/Packages/ohif-hotkeys/client/classes/HotkeysManager.js index 591e3ef69..466e44859 100644 --- a/Packages/ohif-hotkeys/client/classes/HotkeysManager.js +++ b/Packages/ohif-hotkeys/client/classes/HotkeysManager.js @@ -2,7 +2,7 @@ import { ReactiveVar } from 'meteor/reactive-var'; import { HotkeysContext } from 'meteor/ohif:hotkeys/client/classes/HotkeysContext'; export class HotkeysManager { - constructor() { + constructor(retrieveFunction, storeFunction) { this.contexts = {}; this.currentContextName = null; this.enabled = new ReactiveVar(true); diff --git a/Packages/ohif-hotkeys/main.js b/Packages/ohif-hotkeys/main.js index 6d925f26c..c473b8b17 100644 --- a/Packages/ohif-hotkeys/main.js +++ b/Packages/ohif-hotkeys/main.js @@ -1,18 +1,11 @@ import { OHIF } from 'meteor/ohif:core'; import { HotkeysManager } from 'meteor/ohif:hotkeys/client/classes/HotkeysManager'; -/** - * Create hotkeys namespace using a HotkeysManager class instance - */ +// Create hotkeys namespace using a HotkeysManager class instance const hotkeys = new HotkeysManager(); -/** - * Append hotkeys namespace to OHIF namespace - */ - +// Append hotkeys namespace to OHIF namespace OHIF.hotkeys = hotkeys; -/** - * Export relevant objects - */ +// Export relevant objects export { hotkeys }; diff --git a/Packages/ohif-viewerbase/client/lib/toolManager.js b/Packages/ohif-viewerbase/client/lib/toolManager.js index 2ef992519..38b85e142 100644 --- a/Packages/ohif-viewerbase/client/lib/toolManager.js +++ b/Packages/ohif-viewerbase/client/lib/toolManager.js @@ -132,6 +132,7 @@ export const toolManager = { this.configureTools(); initialized = true; }, + configureTools() { // Get Cornerstone Tools const { panMultiTouch, textStyle, toolStyle, toolColors, @@ -171,29 +172,22 @@ export const toolManager = { const ellipticalRoiConfig = ellipticalRoi.getConfiguration(); // Add shadow to length tool - length.setConfiguration({ - ...lengthConfig, - ...shadowConfig, - drawHandlesOnHover: true - }); + length.setConfiguration(Object.assign({}, lengthConfig, shadowConfig, { drawHandlesOnHover: true })); // Add shadow to length tool - ellipticalRoi.setConfiguration({ - ...ellipticalRoiConfig, - ...shadowConfig - }); + ellipticalRoi.setConfiguration(Object.assign({}, ellipticalRoiConfig, shadowConfig)); // Set the configuration values for the Text Marker (Spine Labelling) tool - const startFrom = $('#startFrom'); - const ascending = $('#ascending'); + const $startFrom = $('#startFrom'); + const $ascending = $('#ascending'); const textMarkerConfig = { markers: [ 'L5', 'L4', 'L3', 'L2', 'L1', // Lumbar spine 'T12', 'T11', 'T10', 'T9', 'T8', 'T7', // Thoracic spine 'T6', 'T5', 'T4', 'T3', 'T2', 'T1', 'C7', 'C6', 'C5', 'C4', 'C3', 'C2', 'C1', // Cervical spine ], - current: startFrom.val(), - ascending: ascending.is(':checked'), + current: $startFrom.val(), + ascending: $ascending.is(':checked'), loop: true, changeTextCallback: textMarkerUtils.changeTextCallback, shadow: shadowConfig.shadow, @@ -236,12 +230,13 @@ export const toolManager = { // http://stackoverflow.com/questions/9907419/javascript-object-get-key-by-value return Object.keys(object).filter(key => object[key] === value); }, + configureLoadProcess() { // Whenever the CornerstoneImageLoadProgress is fired, identify which viewports // the "in-progress" image is to be displayed in. Then pass the percent complete // via the Meteor Session to the other templates to be displayed in the relevant viewports. $(cornerstone).on('CornerstoneImageLoadProgress', (e, eventData) => { - viewportIndices = this.getKeysByValue(window.ViewportLoading, eventData.imageId); + const viewportIndices = this.getKeysByValue(window.ViewportLoading, eventData.imageId); viewportIndices.forEach(viewportIndex => { Session.set('CornerstoneLoadProgress' + viewportIndex, eventData.percentComplete); }); @@ -250,24 +245,31 @@ export const toolManager = { Session.set('CornerstoneThumbnailLoadProgress' + encodedId, eventData.percentComplete); }); }, + setGestures(newGestures) { gestures = newGestures; }, + getGestures() { return gestures; }, + addTool(name, base) { tools[name] = base; }, + getTools() { return tools; }, + setToolDefaultStates(states) { toolDefaultStates = states; }, + getToolDefaultStates() { return toolDefaultStates; }, + setActiveToolForElement(tool, element) { const canvases = $(element).find('canvas'); if (element.classList.contains('empty') || !canvases.length) { @@ -276,22 +278,19 @@ export const toolManager = { // First, deactivate the current active tool tools[activeTool].mouse.deactivate(element, 1); -  + if (tools[activeTool].touch) { tools[activeTool].touch.deactivate(element); } // Enable tools based on their default states - Object.keys(toolDefaultStates).forEach( action => { + Object.keys(toolDefaultStates).forEach(action => { const relevantTools = toolDefaultStates[action]; - if (!relevantTools || !relevantTools.length || action === 'disabledToolButtons') { - return; - } - relevantTools.forEach( toolType => { + if (!relevantTools || !relevantTools.length || action === 'disabledToolButtons') return; + relevantTools.forEach(toolType => { // the currently active tool has already been deactivated and can be skipped - if (action === 'deactivate' && toolType === activeTool) { - return; - } + if (action === 'deactivate' && toolType === activeTool) return; + tools[toolType].mouse[action]( element, (action === 'activate' || action === 'deactivate' ? 1 : void 0) @@ -334,7 +333,7 @@ export const toolManager = { // scroll is the default tool for middle mouse wheel for stacks cornerstoneTools.stackScrollWheel.activate(element); - if (gestures['stackScrollMultiTouch'].enabled === true) { + if (gestures.stackScrollMultiTouch.enabled === true) { cornerstoneTools.stackScrollMultiTouch.activate(element); // Three finger scroll } @@ -385,37 +384,41 @@ export const toolManager = { tools[tool].touch.activate(element); } - if (gestures['zoomTouchPinch'].enabled === true) { + if (gestures.zoomTouchPinch.enabled === true) { cornerstoneTools.zoomTouchPinch.activate(element); // Two finger pinch } - if (gestures['panMultiTouch'].enabled === true) { + if (gestures.panMultiTouch.enabled === true) { cornerstoneTools.panMultiTouch.activate(element); // Two or >= Two finger pan } - if (gestures['doubleTapZoom'].enabled === true) { + if (gestures.doubleTapZoom.enabled === true) { cornerstoneTools.doubleTapZoom.activate(element); } }, + setActiveTool(tool, elements) { if (!initialized) { toolManager.init(); } + // Prevent changing if tool is already active + if (tool === toolManager.getActiveTool()) return; + /** * TODO: Add textMarkerDialogs template to OHIF's */ const dialog = document.getElementById('textMarkerOptionsDialog'); - if(dialog) { + if (dialog) { if (tool === 'spine' && activeTool !== 'spine' && dialog.getAttribute('open') !== 'open') { dialog.show(); - } else if(activeTool !== 'spine' && dialog.getAttribute("open") === "open") { + } else if (activeTool !== 'spine' && dialog.getAttribute('open') === 'open') { dialog.close(); } } - - /** - * TODO: Use Session variables to activate a button and use Helpers like in toolbarSectionButton.js from OHIF’s. + + /** + * TODO: Use Session variables to activate a button and use Helpers like in toolbarSectionButton.js from OHIF’s. */ // Set the div to active for the tool $('.imageViewerButton').removeClass('active'); @@ -428,19 +431,24 @@ export const toolManager = { tool = defaultTool; } + let $elements; if (!elements || !elements.length) { - elements = $('.imageViewerViewport'); + $elements = $('.imageViewerViewport'); + } else { + $elements = $(elements); } // Otherwise, set the active tool for all viewport elements - $(elements).each((index, element) => { + $elements.each((index, element) => { toolManager.setActiveToolForElement(tool, element); }); + activeTool = tool; // Store the active tool in the session in order to enable reactivity Session.set('ToolManagerActiveTool', tool); }, + getActiveTool() { if (!initialized) { toolManager.init(); @@ -453,30 +461,35 @@ export const toolManager = { return activeTool; }, + setDefaultTool(tool) { defaultTool = tool; }, + getDefaultTool() { return defaultTool; }, + setConfigureTools(configureTools) { - if(typeof configureTools === 'function') { + if (typeof configureTools === 'function') { this.configureTools = configureTools; } }, + activateCommandButton(button) { const activeCommandButtons = Session.get('ToolManagerActiveCommandButtons') || []; - if(activeCommandButtons.indexOf(button) === -1) { + if (activeCommandButtons.indexOf(button) === -1) { activeCommandButtons.push(button); Session.set('ToolManagerActiveCommandButtons', activeCommandButtons); } }, + deactivateCommandButton(button) { const activeCommandButtons = Session.get('ToolManagerActiveCommandButtons') || []; const index = activeCommandButtons.indexOf(button); - if(index !== -1) { + if (index !== -1) { activeCommandButtons.splice(index, 1); Session.set('ToolManagerActiveCommandButtons', activeCommandButtons); }