Third Party Functionality

Since 3.0, cornerstoneTools comes with third-party support so that one can easily drop new common functionality into cornerstoneTools, then construct new custom Tools which expand upon core and third-party functionality.

The third-party architecture comes with the advantage of not having to maintain a fork of the entire codebase, should you wish to include some custom/bespoke functionality. However, if you think something you have developed would be valued by the wider Cornerstone community, please consider submitting a pull request and contributing it back.

Item Types

The types typically registered by third-parties are:

  • base
  • mixins
  • manipulators
  • utils

Cornerstone Tools has these additional types (third-parties could expand these, but are unlikely to):

  • drawing (for drawing api functions)
  • stateManagement

Additionally, custom modules can be added to the store.

Base

A user can define a new abstract base Tool type, from which third-party Tools can inherit from. The new Tool type must inherit from either BaseTool, BaseAnnotationTool or BaseBrushTool. To create a new base Tool type simply import the base type you wish to extend and extend it as:

const BaseTool = cornerstoneTools.import('core/base/BaseTool');

export default class BaseNewTypeTool extends BaseTool {
  // implementation ...
}

Mixins

You may want to make custom mixins if you re-use some functionality between various custom Tools. Mixins are simply Objects consisting of functions that may assigned to any Tool as member functions, e.g.:

function evenMoreHelloWorld() {
  // Note this would need to be called from somewhere
  // Within the Tool's implementation.
  console.log('Hello World from the even more hello world mixin!');
}

export default {
  evenMoreHelloWorld,
};

Manipulators

BaseAnnotationTools use manipulators to interact with the annotation's handles data in a particular way. If you need to build a custom interaction mechanism you envision using more than once, you may want to make a custom manipulator. A manipulator is just a function. They have rather freeform structure, but principally take eventData and toolData and perform an operation, e.g.:

export default function(eventData, toolName, data, handle, someCallback) {
  // Implementation, Do something with the handle.
  // ...
  someCallback();
}

Utils

Utils are just functions that perform some generic common process, e.g.:

export default function() {
  console.log('Super important hello world util.');
}

Modules

Module are objects that store global data, which may be shared between multiple tools, effect multiple cornerstone elements, etc. Most modules will have getters and setters, unless they only contain primitives (e.g. the module's state is only comprised of boolean toggles). You can learn more about modules here. Here is a simple toy example of a module with state, setters and getters:

const configuration = {
  // Some app-level configuration for this module.
};

// The modules internal state.
const state = {
  isPolite: true,
  responses: {
    polite: 'Hello World!',
    rude: 'Go away, World.',
  },
};

const setters = {
  politeResponse: response => {
    state.responses.polite = response;
  },
  rudeResponse: response => {
    state.responses.rude = response;
  },
  moodSwitch: () => {
    state.isPolite = !state.isPolite;
  },
};

const getters = {
  response: () => {
    if (state.isPolite) {
      return state.responses.polite;
    } else {
      return state.responses.rude;
    }
  },
};

function onRegisterCallback() {
  console.log('Hello onRegisterCallback.');
}

function enabledElementCallback(enabledElement) {
  console.log(`hello element ${enabledElement.uuid}.`);
}

export default {
  state,
  getters,
  setters,
  onRegisterCallback,
  enabledElementCallback,
};

Registration

Registration is abstracted to a simple top-level register function, taking type, name and item as arguments e.g.:

cornerstoneTools.register('module', 'helloWorldModule', myModule);
cornerstoneTools.register('mixin', 'evenMoreHelloWorld', myMixin);

By default, trying to register an item that would occupy an already registered 'type/name' uri will log a warning and cancel registration. If you wish to overwrite a uri, you may do so by adding true to the end of the register call:

cornerstoneTools.register('mixin', 'evenMoreHelloWorld', mySuperiorMixin, true);

If a library has lots of items it would like to register at once, it can pack its items into an array such as:

const lotsOfItems = [
  {
    type, // String
    name, // String
    item  // Object/Function
  },
  // Etc...
];

These can then all be registered at once by calling:

cornerstoneTools.registerSome(lotsOfItems);

Again, you can toggle an overwrite by adding true as an additional argument:

cornerstoneTools.registerSome(lotsOfItems, true);

Imports

Helpful internal library methods and utilities can be retrieved by the top-level importInternal function, e.g.:

const evenMoreHelloWorldMixin = cornerstoneTools.importInternal(
  'mixins/evenMoreHelloWorld'
);

You can add to the list of methods and utilities that can be retrieved by registering them.

Store modules may also be retrieved with the top-level getModule function:

const { helloWorldModule } = cornerstoneTools.getModule('helloWorldModule');

Tools

Third-party tools may be easily created by importing the required base tool Type and extending it.

For instance, if we wanted to package the HelloWorldTool that we created in the Custom Tools section into a third-party tool:

const BaseTool = cornerstoneTools.importInternal('base/BaseTool');

export default class HelloWorldTool extends BaseTool {
  constructor(name = 'HelloWorld') {
    super({
      name,
      supportedInteractionTypes: ['mouse'],
      mixins: [
        'activeOrDisabledBinaryTool', // Mixin from cornerstoneTools source.
        'evenMoreHelloWorld', // Mixin from the plugin.
      ],
    });

    // Use a module from the plugin. It should be first accessed in constructor.
    this._helloWorldModule = cornerstoneTools.getModule('helloWorld);
  }

  // implementation ...
}

The array of mixins to add to the Tool may be from either the core library or registered functionality. You needn't import any mixin used, the heavy lifting is performed in the constructor of BaseTool.

Any other functionality imported must be done so in the constructor, to ensure it is already registered upon import. This includes accessing modules which might not be there when the file is loaded (e.g. the example above).

The tool can then be added to a cornerstoneTools instance that has the required functionality registered, e.g.:

// Register all custom functionality used by cornerstoneTools in this app.
cornerstoneTools.register('module', 'helloWorldModule', myModule);
cornerstoneTools.register('mixin', 'evenMoreHelloWorld', myMixin);

// Initialise cornerstoneTools.
cornerstoneTools.init();

// Add the custom tool!
cornerstoneTools.addTool(HelloWorldMouseTool);

results matching ""

    No results matching ""