ohif-viewer/docs/latest/extensions/index.md
2019-12-07 01:13:20 -05:00

6.6 KiB

Extensions

Overview

We use extensions to help us isolate and package groups of related features. Extensions provide functionality, ui components, and new behaviors.

Extensions Diagram
Diagram showing how extensions are configured and accessed.

The @ohif/viewer's application level configuration gives us the ability to add and configure extensions. When the application starts, extensions are registered with the ExtensionManager. Different portions of the @ohif/viewer project will use registered extensions to influence application behavior.

Extensions allow us to:

  • Wrap and integrate functionality of 3rd party dependencies in a reusable way
  • Change how application data is mapped and transformed
  • Display a consistent/cohesive UI
  • Inject custom components to override built-in components

Practical examples of extensions include:

Concepts

Extension Skeleton

An extension is a plain JavaScript object has an id property, and one or more "getModuleFunctions" and/or lifecycle hooks. You can read more about lifecycle hooks and modules further down.

// prettier-ignore
export default {
  /**
   * Only required property. Should be a unique value across all extensions.
   */
  id: 'example-extension',

  // Lifecyle
  preRegistration() { /* */ },
  // Modules
  getCommandsModule() { /* */ },
  getToolbarModule() { /* */ },
  getPanelModule() { /* */ },
  getSopClassHandler() { /* */ },
  getViewportModule() { /* */ },
}

Registering an Extension

There are two different ways to register and configure extensions: At runtime and at build time.

You can leverage one or both strategies. Which one(s) you choose depend on your application's requirements. Each module defined by the extension becomes available to the core application via the ExtensionManager.

// prettier-ignore
const config = {
  extensions: [
    MyFirstExtension,
    [
      MySecondExtension,
      { /* MySecondExtensions Configuration */ },
    ],
  ];
}

Registering at Runtime

The @ohif/viewer uses a configuration file at startup. The schema for that file includes an Extensions key that supports an array of extensions to register.

Registering at Build Time

The @ohif/viewer works best when built as a "Progressive Web Application" (PWA). If you know the extensions your application will need, you can specify them at "build time" to leverage advantages afforded to us by modern tooling:

  • Code Splitting
  • Tree Shaking
  • Dependency deduplication

You can update the list of bundled extensions by:

  1. Having your @ohif/viewer project depend on the extension
  2. Importing and adding it to the list of extensions in the <repo-root>/platform/src/index.js entrypoint.

Lifecycle Hooks

Currently, there is only a single lifecycle hook for extensions: preRegistration

If an extension defines the preRegistration lifecycle hook, it is called before any modules are registered in the ExtensionManager. It's most commonly used to wire up extensions to services and commands, and to bootstrap 3rd party libraries.

Modules

Modules are the meat of extensions. They provide "definitions", components, and filtering/mapping logic that are then made available by various managers and services.

Each module type has a special purpose, and is consumed by our viewer differently.

Type Description Examples
Commands Adds named commands, scoped to a context, to the CommandsManager setToolActive(), nextSeries()
Panel Adds left or right hand side panels <ThumbnailList />, <MeasurementsTable />
SOPClassHandler Determines how retrieved study data is split into "DisplaySets" getDisplaySetFromSeries()
Toolbar Adds buttons or custom components to the toolbar Toolbar button, nested buttons, custom
Viewport Adds a component responsible for rendering a "DisplaySet" <CornerstoneViewport />, <DicomPdfViewport />

Contexts

The @ohif/viewer tracks "active contexts" that extensions can use to scope their functionality. Some example contexts being:

  • Route: ROUTE:VIEWER, ROUTE:STUDY_LIST
  • Active Viewport: ACTIVE_VIEWPORT:CORNERSTONE, ACTIVE_VIEWPORT:VTK

An extension module can use these to say "Only show this Toolbar Button if the active viewport is a Cornerstone viewport." This helps us use the appropriate UI and behaviors depending on the current contexts.

Consuming Extensions

...

Maintained Extensions

A small number of powerful extensions for popular use cases are maintained by OHIF. They're co-located in the OHIF/Viewers repository, in the top level extensions/ directory.

{% include "./_maintained-extensions-table.md" %}