From fc4e1ff06f9ae5850fa4f1810c6efc52d025d511 Mon Sep 17 00:00:00 2001 From: James Petts Date: Thu, 3 Oct 2019 16:36:59 +0100 Subject: [PATCH] feat(init.js): Allow app to configure internal modules other than globalConfig via init. (#1094) --- docs/latest/index.md | 21 ++++++++++- index.html | 15 +++++++- netlify-example/brush/index.html | 36 +++++++++---------- .../imageRenderedEventDispatcher.js | 3 +- .../internals/renderSegmentation.js | 6 +++- .../internals/renderSegmentationFill.js | 4 ++- .../internals/renderSegmentationOutline.js | 4 ++- .../onImageRenderedBrushEventHandler.js | 3 +- src/init.js | 33 ++++++++++++----- src/store/modules/cursorModule.js | 3 ++ .../segmentationModule/activeSegmentIndex.js | 5 ++- .../modules/segmentationModule/colorLUT.js | 3 +- ...nfiguration.js => defaultConfiguration.js} | 4 +-- src/store/modules/segmentationModule/index.js | 10 ++---- .../segmentationModule/setLabelmap3D.js | 1 - .../modules/segmentationModule/setRadius.js | 10 ++++++ src/tools/base/BaseBrushTool.js | 6 +++- src/tools/segmentation/BrushTool.js | 3 +- src/tools/segmentation/SphericalBrushTool.js | 5 ++- 19 files changed, 127 insertions(+), 48 deletions(-) rename src/store/modules/segmentationModule/{configuration.js => defaultConfiguration.js} (85%) create mode 100644 src/store/modules/segmentationModule/setRadius.js diff --git a/docs/latest/index.md b/docs/latest/index.md index 51ced93d8..cf3d1ccbf 100644 --- a/docs/latest/index.md +++ b/docs/latest/index.md @@ -79,7 +79,7 @@ cornerstoneTools.external.cornerstoneMath = cornerstoneMath; cornerstoneTools.init(); ``` -The `cornerstoneTools.init();` call accepts a configuration object if you would like to deviate from default behaviors: +The `cornerstoneTools.init();` call accepts a configuration object if you would like to deviate from default behaviors of `cornerstoneTool`'s `globalConfiguration`: ```js cornerstoneTools.init({ @@ -108,6 +108,25 @@ cornerstoneTools.init({ }); ``` +If you wish to change modules other than the `globalConfiguration` module, you may pass an array of named module configuration like so: + +```js +cornerstoneTools.init([ + { + moduleName: 'globalConfiguration', + configuration: { + showSVGCursors: true, + }, + }, + { + moduleName: 'segmentation', + configuration: { + outlineWidth: 2, + }, + }, +]); +``` + You can go further and configure textStyle, toolStyle, toolColors, etc: ```js diff --git a/index.html b/index.html index 3efb72966..4ceb0dc86 100644 --- a/index.html +++ b/index.html @@ -166,7 +166,20 @@ diff --git a/src/eventDispatchers/imageRenderedEventDispatcher.js b/src/eventDispatchers/imageRenderedEventDispatcher.js index 14b4e53ea..0d9ddb34b 100644 --- a/src/eventDispatchers/imageRenderedEventDispatcher.js +++ b/src/eventDispatchers/imageRenderedEventDispatcher.js @@ -4,7 +4,6 @@ import onImageRenderedBrushEventHandler from '../eventListeners/onImageRenderedB import external from './../externalModules.js'; const segmentationModule = getModule('segmentation'); -const segmentationConfiguration = segmentationModule.configuration; const onImageRendered = function(evt) { const eventData = evt.detail; @@ -22,6 +21,8 @@ const onImageRendered = function(evt) { // Must be using stacks in order to use segmentation tools. const stackToolState = getToolState(element, 'stack'); + const segmentationConfiguration = segmentationModule.configuration; + if ( stackToolState && (segmentationConfiguration.renderFill || diff --git a/src/eventListeners/internals/renderSegmentation.js b/src/eventListeners/internals/renderSegmentation.js index 592298cc7..546aed1b5 100644 --- a/src/eventListeners/internals/renderSegmentation.js +++ b/src/eventListeners/internals/renderSegmentation.js @@ -2,7 +2,7 @@ import { getModule } from '../../store/index.js'; import renderSegmentationFill from './renderSegmentationFill'; import renderSegmentationOutline from './renderSegmentationOutline'; -const { configuration } = getModule('segmentation'); +const segmentationModule = getModule('segmentation'); /** * Renders the segmentation based on the brush configuration and @@ -50,6 +50,8 @@ export default function renderSegmentation( * @returns {boolean} True if the segmentation should be filled. */ function shouldRenderFill(isActiveLabelMap) { + const { configuration } = segmentationModule; + return ( configuration.renderFill && ((isActiveLabelMap && configuration.fillAlpha !== 0) || @@ -65,6 +67,8 @@ function shouldRenderFill(isActiveLabelMap) { * @returns {boolean} True if the segmentation should be outlined. */ function shouldRenderOutline(isActiveLabelMap) { + const { configuration } = segmentationModule; + return ( configuration.renderOutline && ((isActiveLabelMap && configuration.outlineAlpha !== 0) || diff --git a/src/eventListeners/internals/renderSegmentationFill.js b/src/eventListeners/internals/renderSegmentationFill.js index 48d72df28..ae57151c8 100644 --- a/src/eventListeners/internals/renderSegmentationFill.js +++ b/src/eventListeners/internals/renderSegmentationFill.js @@ -6,7 +6,7 @@ import { } from '../../drawing/index.js'; import external from '../../externalModules'; -const { state, configuration } = getModule('segmentation'); +const segmentationModule = getModule('segmentation'); export default function renderSegmentationFill( evt, @@ -31,6 +31,7 @@ export default function renderSegmentationFill( * @returns {HTMLCanvasElement} */ export function getLabelmapCanvas(evt, labelmap3D, labelmap2D) { + const { state } = segmentationModule; const eventData = evt.detail; const { image } = eventData; const cols = image.width; @@ -77,6 +78,7 @@ export function getLabelmapCanvas(evt, labelmap3D, labelmap2D) { * @returns {null} */ export function renderFill(evt, labelmapCanvas, isActiveLabelMap) { + const { configuration } = segmentationModule; const eventData = evt.detail; const context = getNewContext(eventData.canvasContext.canvas); diff --git a/src/eventListeners/internals/renderSegmentationOutline.js b/src/eventListeners/internals/renderSegmentationOutline.js index 0410005ed..379d6e050 100644 --- a/src/eventListeners/internals/renderSegmentationOutline.js +++ b/src/eventListeners/internals/renderSegmentationOutline.js @@ -3,7 +3,7 @@ import external from '../../externalModules.js'; import { getNewContext, draw, drawLines } from '../../drawing/index.js'; import { disableLogger } from '../../index.js'; -const { state, configuration } = getModule('segmentation'); +const segmentationModule = getModule('segmentation'); export default function renderSegmentationOutline( evt, @@ -12,6 +12,7 @@ export default function renderSegmentationOutline( labelmapIndex, isActiveLabelMap ) { + const { configuration } = segmentationModule; const outline = getOutline( evt, labelmap3D, @@ -37,6 +38,7 @@ export function renderOutline( colorLUTIndex, isActiveLabelMap = true ) { + const { configuration, state } = segmentationModule; const eventData = evt.detail; const { element, canvasContext } = eventData; diff --git a/src/eventListeners/onImageRenderedBrushEventHandler.js b/src/eventListeners/onImageRenderedBrushEventHandler.js index c2d433f60..4fbd1fa61 100644 --- a/src/eventListeners/onImageRenderedBrushEventHandler.js +++ b/src/eventListeners/onImageRenderedBrushEventHandler.js @@ -1,7 +1,7 @@ import { getModule } from '../store/index.js'; import renderSegmentation from './internals/renderSegmentation.js'; -const { configuration, getters } = getModule('segmentation'); +const segmentationModule = getModule('segmentation'); /** * Finds which segmentations need to be rendered based on the configuration and @@ -13,6 +13,7 @@ const { configuration, getters } = getModule('segmentation'); export default function(evt) { const eventData = evt.detail; const element = eventData.element; + const { configuration, getters } = segmentationModule; const { activeLabelmapIndex, diff --git a/src/init.js b/src/init.js index 96d795371..45cf79bed 100644 --- a/src/init.js +++ b/src/init.js @@ -12,21 +12,38 @@ import windowResizeHandler from './eventListeners/windowResizeHandler.js'; * @method * @name init * - * @param {Object} [configuration = {}] The global configuration to apply. + * @param {Object|Object[]} [defaultConfiguration = {}] The configuration to apply. Assumed globalConfiguration + * only one value, otherwise moduleName, configuration entires in an array. * @returns {Object} A configured CornerstoneTools instance with top level API members. */ -export default function(configuration = {}) { +export default function(defaultConfiguration = {}) { _addCornerstoneEventListeners(); _initModules(); - // Apply global configuration const globalConfigurationModule = getModule('globalConfiguration'); - globalConfigurationModule.configuration = Object.assign( - {}, - globalConfigurationModule.configuration, - configuration - ); + if (Array.isArray(defaultConfiguration)) { + defaultConfiguration.forEach(configurationEntry => { + const { moduleName, configuration } = configurationEntry; + + const module = getModule(moduleName); + + if (module) { + module.configuration = Object.assign( + {}, + module.configuration, + configuration + ); + } + }); + } else { + // defaultConfiguration is an object, default to assigning it to globalConfiguration. + globalConfigurationModule.configuration = Object.assign( + {}, + globalConfigurationModule.configuration, + defaultConfiguration + ); + } if (globalConfigurationModule.configuration.autoResizeViewports) { windowResizeHandler.enable(); diff --git a/src/store/modules/cursorModule.js b/src/store/modules/cursorModule.js index 70a92e7bc..64f4dae03 100644 --- a/src/store/modules/cursorModule.js +++ b/src/store/modules/cursorModule.js @@ -1,3 +1,5 @@ +import external from '../../externalModules'; + const configuration = { iconSize: 16, viewBox: { @@ -25,6 +27,7 @@ const getters = { }; export default { + configuration, getters, setters, }; diff --git a/src/store/modules/segmentationModule/activeSegmentIndex.js b/src/store/modules/segmentationModule/activeSegmentIndex.js index 871f39fd3..0eb058191 100644 --- a/src/store/modules/segmentationModule/activeSegmentIndex.js +++ b/src/store/modules/segmentationModule/activeSegmentIndex.js @@ -1,7 +1,7 @@ import getElement from './getElement'; import { getToolState } from '../../../stateManagement/toolState.js'; import state from './state'; -import configuration from './configuration'; +import { getModule } from '../../index.js'; /** * Returns the `activeSegmentIndex` for the active `Labelmap3D` for the `BrushStackState` displayed on the element. @@ -68,6 +68,8 @@ function setActiveSegmentIndex(elementOrEnabledElementUID, segmentIndex) { const activeLabelmapIndex = brushStackState.activeLabelmapIndex; const labelmap3D = brushStackState.labelmaps3D[activeLabelmapIndex]; + const { configuration } = getModule('segmentation'); + if (segmentIndex <= 0) { segmentIndex = 1; } else if (segmentIndex > configuration.segmentsPerLabelmap) { @@ -119,6 +121,7 @@ function decrementActiveSegmentIndex(elementOrEnabledElementUID) { * @returns {null} */ function _changeActiveSegmentIndex(element, increaseOrDecrease = 'increase') { + const { configuration } = getModule('segmentation'); const stackState = getToolState(element, 'stack'); const stackData = stackState.data[0]; const firstImageId = stackData.imageIds[0]; diff --git a/src/store/modules/segmentationModule/colorLUT.js b/src/store/modules/segmentationModule/colorLUT.js index 30eeae2cd..42154ae3a 100644 --- a/src/store/modules/segmentationModule/colorLUT.js +++ b/src/store/modules/segmentationModule/colorLUT.js @@ -1,7 +1,7 @@ import external from '../../../externalModules'; import { getLogger } from '../../../util/logger'; import state from './state'; -import configuration from './configuration'; +import { getModule } from '../../index.js'; const logger = getLogger('store:modules:segmentationModule:setColorLUT'); @@ -13,6 +13,7 @@ const logger = getLogger('store:modules:segmentationModule:setColorLUT'); * @returns {null} */ export default function setColorLUT(colorLUTIndex, colorLUT = []) { + const { configuration } = getModule('segmentation'); const segmentsPerLabelmap = configuration.segmentsPerLabelmap; if (colorLUT) { diff --git a/src/store/modules/segmentationModule/configuration.js b/src/store/modules/segmentationModule/defaultConfiguration.js similarity index 85% rename from src/store/modules/segmentationModule/configuration.js rename to src/store/modules/segmentationModule/defaultConfiguration.js index 1db227001..e26834142 100644 --- a/src/store/modules/segmentationModule/configuration.js +++ b/src/store/modules/segmentationModule/defaultConfiguration.js @@ -1,5 +1,5 @@ // Segmentation module configuration. -const configuration = { +const defaultConfiguration = { renderOutline: true, renderFill: true, shouldRenderInactiveLabelmaps: true, @@ -15,4 +15,4 @@ const configuration = { storeHistory: true, }; -export default configuration; +export default defaultConfiguration; diff --git a/src/store/modules/segmentationModule/index.js b/src/store/modules/segmentationModule/index.js index 4c62b731f..305c67351 100644 --- a/src/store/modules/segmentationModule/index.js +++ b/src/store/modules/segmentationModule/index.js @@ -36,8 +36,9 @@ import getSegmentsOnPixelData from './getSegmentsOnPixeldata'; import deleteSegment from './deleteSegment'; import state from './state'; -import configuration from './configuration'; +import configuration from './defaultConfiguration'; import { pushState, undo, redo } from './history'; +import setRadius from './setRadius'; /** * A map of `firstImageId` to associated `BrushStackState`, where @@ -127,12 +128,7 @@ export default { colorLUTIndexForLabelmap3D: setColorLUTIndexForLabelmap3D, colorForSegmentIndexOfColorLUT: setColorForSegmentIndexOfColorLUT, activeLabelmapIndex: setActiveLabelmapIndex, - radius: newRadius => { - configuration.radius = Math.min( - Math.max(newRadius, configuration.minRadius), - configuration.maxRadius - ); - }, + radius: setRadius, pushState, undo, redo, diff --git a/src/store/modules/segmentationModule/setLabelmap3D.js b/src/store/modules/segmentationModule/setLabelmap3D.js index f34c4417c..c84b5174f 100644 --- a/src/store/modules/segmentationModule/setLabelmap3D.js +++ b/src/store/modules/segmentationModule/setLabelmap3D.js @@ -2,7 +2,6 @@ import getElement from './getElement'; import { getToolState } from '../../../stateManagement/toolState.js'; import state from './state'; import getSegmentsOnPixelData from './getSegmentsOnPixeldata'; -import external from '../../../externalModules'; import { triggerLabelmapModifiedEvent } from '../../../util/segmentation'; /** diff --git a/src/store/modules/segmentationModule/setRadius.js b/src/store/modules/segmentationModule/setRadius.js new file mode 100644 index 000000000..0d7c52928 --- /dev/null +++ b/src/store/modules/segmentationModule/setRadius.js @@ -0,0 +1,10 @@ +import { getModule } from '../../index'; + +export default function setRadius(newRadius) { + const { configuration } = getModule('segmentation'); + + configuration.radius = Math.min( + Math.max(newRadius, configuration.minRadius), + configuration.maxRadius + ); +} diff --git a/src/tools/base/BaseBrushTool.js b/src/tools/base/BaseBrushTool.js index 895b53414..f7b227ed3 100644 --- a/src/tools/base/BaseBrushTool.js +++ b/src/tools/base/BaseBrushTool.js @@ -8,7 +8,7 @@ import { triggerLabelmapModifiedEvent, } from '../../util/segmentation'; -const { configuration, getters, setters } = getModule('segmentation'); +const segmentationModule = getModule('segmentation'); /** * @abstract @@ -118,6 +118,7 @@ class BaseBrushTool extends BaseTool { _startPainting(evt) { const eventData = evt.detail; const element = eventData.element; + const { configuration, getters } = segmentationModule; const { labelmap2D, @@ -153,6 +154,7 @@ class BaseBrushTool extends BaseTool { * @returns {void} */ _endPainting(evt) { + const { configuration, setters } = segmentationModule; const { labelmap2D, currentImageIdIndex } = this.paintEventData; // Grab the labels on the slice. @@ -319,6 +321,7 @@ class BaseBrushTool extends BaseTool { * @returns {void} */ increaseBrushSize() { + const { configuration, setters } = segmentationModule; const oldRadius = configuration.radius; let newRadius = Math.floor(oldRadius * 1.2); @@ -339,6 +342,7 @@ class BaseBrushTool extends BaseTool { * @returns {void} */ decreaseBrushSize() { + const { configuration, setters } = segmentationModule; const oldRadius = configuration.radius; const newRadius = Math.floor(oldRadius * 0.8); diff --git a/src/tools/segmentation/BrushTool.js b/src/tools/segmentation/BrushTool.js index 004fb90c3..049a23015 100644 --- a/src/tools/segmentation/BrushTool.js +++ b/src/tools/segmentation/BrushTool.js @@ -6,7 +6,7 @@ import { getLogger } from '../../util/logger.js'; const logger = getLogger('tools:BrushTool'); -const { configuration } = getModule('segmentation'); +const segmentationModule = getModule('segmentation'); /** * @public @@ -37,6 +37,7 @@ export default class BrushTool extends BaseBrushTool { * @returns {void} */ _paint(evt) { + const { configuration } = segmentationModule; const eventData = evt.detail; const element = eventData.element; const { rows, columns } = eventData.image; diff --git a/src/tools/segmentation/SphericalBrushTool.js b/src/tools/segmentation/SphericalBrushTool.js index c6cf0eca4..006f6c20f 100644 --- a/src/tools/segmentation/SphericalBrushTool.js +++ b/src/tools/segmentation/SphericalBrushTool.js @@ -12,7 +12,7 @@ import { getDiffBetweenPixelData } from '../../util/segmentation'; const logger = getLogger('tools:SphericalBrushTool'); -const { getters, setters, configuration } = getModule('segmentation'); +const segmentationModule = getModule('segmentation'); /** * @public @@ -44,6 +44,7 @@ export default class SphericalBrushTool extends BaseBrushTool { * @returns {void} */ _startPainting(evt) { + const { configuration, getters } = segmentationModule; const eventData = evt.detail; const { element, image } = eventData; const { cornerstone } = external; @@ -137,6 +138,7 @@ export default class SphericalBrushTool extends BaseBrushTool { * @returns {void} */ _paint(evt) { + const { getters } = segmentationModule; const eventData = evt.detail; const element = eventData.element; const image = eventData.image; @@ -290,6 +292,7 @@ export default class SphericalBrushTool extends BaseBrushTool { _endPainting(evt) { const { labelmap3D, imagesInRange } = this.paintEventData; const operations = []; + const { configuration, setters } = segmentationModule; for (let i = 0; i < imagesInRange.length; i++) { const { imageIdIndex } = imagesInRange[i];