Docs reorganization

This commit is contained in:
Erik Ziegler 2021-07-15 09:54:01 +02:00
parent d6877cfcf9
commit c0df334233
152 changed files with 872 additions and 886 deletions

View File

@ -179,7 +179,7 @@ Check out these helpful links:
-->
<!-- prettier-ignore-start -->
[ohif-org]: http://www.ohif.org
[ohif-org]: https://www.ohif.org
[ohif-demo]: http://viewer.ohif.org/
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
[gh-issues]: https://github.com/OHIF/Viewers/issues

View File

@ -0,0 +1,4 @@
{
"label": "Configuration",
"position": 4
}

View File

@ -1,21 +1,20 @@
---
sidebar_position: 1
sidebar_label: Config
sidebar_position: 3
sidebar_label: Configuration
---
# Viewer: Configuration
The OHIF Viewing Platform strives to be highly configurable and extensible. This
The OHIF Viewer Platform strives to be highly configurable and extensible. This
makes it easier for our community members to keep their "secret sauce" private,
and incentives contributions back to the platform. The `@ohif/viewer` project
of the platform is the lynchpin that combines everything to create our
application.
and incentives contributions back to the platform. The `@ohif/viewer` project of
the platform is the lynchpin that combines everything to create our application.
We maintain a number of common viewer application configurations at
[`<root>/platform/viewer/public/configs`][config-dir].
You can take a look at how to use different configs in the [Environment Variables](../configuring/index.md#environment-variables)
You can take a look at how to use different configs in the
[Environment Variables](../platform/environment-variables)
```js title="<root>/platform/viewer/public/configs"
window.config = {

View File

@ -1,13 +1,12 @@
---
sidebar_position: 2
sidebar_label: Data Source
sidebar_label: Data Sources
---
# Data Source
# Data Sources
## Set up a local DICOM server
ATTENTION! Already have a remote or local server? Skip to the
[configuration section](#configuration-learn-more) below.
@ -37,11 +36,10 @@ in command prompt or terminal_
> the ip docker-machine ip throws. This is the value [`WebPack`][webpack-proxy]
> uses to proxy requests
## Open Source DICOM Image Archives
There are a lot of options available to you to use as a local DICOM server. Here are some of the more popular ones:
There are a lot of options available to you to use as a local DICOM server. Here
are some of the more popular ones:
| Archive | Installation |
| --------------------------------------------- | ---------------------------------- |
@ -53,11 +51,8 @@ There are a lot of options available to you to use as a local DICOM server. Here
_Feel free to make a Pull Request if you want to add to this list._
Below, we will focus on `DCM4CHEE` and `Orthanc` usage:
### Running Orthanc
_Start Orthanc:_
@ -105,8 +100,8 @@ yarn run dev:orthanc
> [Essentials Configuration](./index.md) guide.
Let's take a look at what's going on under the hood here. `yarn run dev:orthanc`
is running the `dev:orthanc` script in our project's `package.json` (inside `platform/viewer`). That script
is:
is running the `dev:orthanc` script in our project's `package.json` (inside
`platform/viewer`). That script is:
```js
cross-env NODE_ENV=development PROXY_TARGET=/dicom-web PROXY_DOMAIN=http://localhost:8042 APP_CONFIG=config/docker_nginx-orthanc.js webpack-dev-server --config .webpack/webpack.pwa.js -w
@ -161,35 +156,36 @@ window.config = {
To learn more about how you can configure the OHIF Viewer, check out our
[Configuration Guide](./index.md).
### Running DCM4CHEE
dcm4che is a collection of open source applications for healthcare enterprise written in Java programming language
which implements DICOM standard. dcm4chee (extra 'e' at the end) is dcm4che project
for an Image Manager/Image Archive which provides storage, retrieval and other functionalities.
You can read more about dcm4chee in their website [here](https://www.dcm4che.org/)
dcm4che is a collection of open source applications for healthcare enterprise
written in Java programming language which implements DICOM standard. dcm4chee
(extra 'e' at the end) is dcm4che project for an Image Manager/Image Archive
which provides storage, retrieval and other functionalities. You can read more
about dcm4chee in their website [here](https://www.dcm4che.org/)
DCM4chee installation is out of scope for these tutorials and can be found [here](https://github.com/dcm4che/dcm4chee-arc-light/wiki/Run-minimum-set-of-archive-services-on-a-single-host)
An overview of steps for running OHIF Viewer using a local DCM4CHEE is shown below:
DCM4chee installation is out of scope for these tutorials and can be found
[here](https://github.com/dcm4che/dcm4chee-arc-light/wiki/Run-minimum-set-of-archive-services-on-a-single-host)
An overview of steps for running OHIF Viewer using a local DCM4CHEE is shown
below:
<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
<iframe src="https://player.vimeo.com/video/557570043?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>
[dcm4chee]: https://github.com/dcm4che/dcm4chee-arc-light
[dcm4chee-docker]: https://github.com/dcm4che/dcm4chee-arc-light/wiki/Running-on-Docker
[dcm4chee-docker]:
https://github.com/dcm4che/dcm4chee-arc-light/wiki/Running-on-Docker
[orthanc]: https://www.orthanc-server.com/
[orthanc-docker]: http://book.orthanc-server.com/users/docker.html
[dicomcloud]: https://github.com/DICOMcloud/DICOMcloud
[dicomcloud-install]: https://github.com/DICOMcloud/DICOMcloud#running-the-code
[osirix]: http://www.osirix-viewer.com/
[horos]: https://www.horosproject.org/
[default-config]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/config/default.js
[html-templates]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/public/html-templates
[config-files]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/public/config
[default-config]:
https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/config/default.js
[html-templates]:
https://github.com/OHIF/Viewers/tree/master/platform/viewer/public/html-templates
[config-files]:
https://github.com/OHIF/Viewers/tree/master/platform/viewer/public/config

View File

@ -15,7 +15,6 @@ nice folks over at [dcmjs.org][dcmjs-org]. While convenient for getting started,
the time may come when you want to develop using your own data either locally or
remotely.
## Configuration Files
The configuration for our viewer is in the `<root>platform/viewer/public/config`
@ -26,7 +25,6 @@ and registered extension's features, are configured using this file.
The simplest way is to update the existing default config:
```js title="platform/viewer/public/config/default.js"
window.config = {
routerBasename: '/',
@ -55,24 +53,18 @@ window.config = {
],
defaultDataSourceName: 'dicomweb',
};
```
> As you can see a new change in `OHIF-v3` is the addition of `dataSources`.
> You can build your own datasource and map it to the internal data structure of OHIFs > metadata and enjoy using other peoples developed mode on your own data!
>
> You can read more about data sources at [Data Source section in Modes](../modes/index.md)
> As you can see a new change in `OHIF-v3` is the addition of `dataSources`. You
> can build your own datasource and map it to the internal data structure of
> OHIFs > metadata and enjoy using other peoples developed mode on your own
> data!
>
> You can read more about data sources at
> [Data Source section in Modes](../modes/index.md)
The configuration can also be written as a JS Function in case you need to inject dependencies like external services:
The configuration can also be written as a JS Function in case you need to
inject dependencies like external services:
```js
window.config = ({ servicesManager } = {}) => {
@ -135,12 +127,6 @@ alternative data source (or even specify different default hotkeys).
| `PROXY_TARGET` | When developing, proxy requests that match this pattern to `PROXY_DOMAIN` | `undefined` |
| `PROXY_DOMAIN` | When developing, proxy requests from `PROXY_TARGET` to `PROXY_DOMAIN` | `undefined` |
You can also create a new config file and specify its path relative to the build
output's root by setting the `APP_CONFIG` environment variable. You can set the
value of this environment variable a few different ways:
@ -157,8 +143,6 @@ value of this environment variable a few different ways:
After updating the configuration, `yarn run build` to generate updated build
output.
<!--
Links
-->
@ -166,17 +150,17 @@ output.
<!-- prettier-ignore-start -->
[dcmjs-org]: https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
[storescu]: http://support.dcmtk.org/docs/storescu.html
[storescu]: https://support.dcmtk.org/docs/storescu.html
[webpack-proxy]: https://webpack.js.org/configuration/dev-server/#devserverproxy
[orthanc-docker-compose]: https://github.com/OHIF/Viewers/tree/master/.docker/Nginx-Orthanc
<!-- Archives -->
[dcm4chee]: https://github.com/dcm4che/dcm4chee-arc-light
[dcm4chee-docker]: https://github.com/dcm4che/dcm4chee-arc-light/wiki/Running-on-Docker
[orthanc]: https://www.orthanc-server.com/
[orthanc-docker]: http://book.orthanc-server.com/users/docker.html
[orthanc-docker]: https://book.orthanc-server.com/users/docker.html
[dicomcloud]: https://github.com/DICOMcloud/DICOMcloud
[dicomcloud-install]: https://github.com/DICOMcloud/DICOMcloud#running-the-code
[osirix]: http://www.osirix-viewer.com/
[osirix]: https://www.osirix-viewer.com/
[horos]: https://www.horosproject.org/
[default-config]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/config/default.js
[html-templates]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/public/html-templates

View File

@ -1,4 +0,0 @@
{
"label": "Configuring",
"position": 5
}

View File

@ -1,4 +1,4 @@
{
"label": "Deployment",
"position": 13
"position": 3
}

View File

@ -4,7 +4,6 @@ sidebar_position: 2
# Build for Production
### Build Machine Requirements
- [Node.js & NPM](https://nodejs.org/en/download/)
@ -25,7 +24,7 @@ More on: _[`git clone`](https://git-scm.com/docs/git-clone),
_From .zip:_
[OHIF/Viewers: react.zip](https://github.com/OHIF/Viewers/archive/master.zip)
[OHIF/Viewers: master.zip](https://github.com/OHIF/Viewers/archive/master.zip)
### Restore Dependencies & Build
@ -33,18 +32,18 @@ Open your terminal, and navigate to the directory containing the source files.
Next run these commands:
```bash
// If you haven't already, enable yarn workspaces
# If you haven't already, enable yarn workspaces
yarn config set workspaces-experimental true
// Restore dependencies
# Restore dependencies
yarn install
// Build source code for production
# Build source code for production
yarn run build
```
If everything worked as expected, you should have a new `dist/` directory in the
project's folder. It should roughly resemble the following:
`platform/viewer/dist` folder. It should roughly resemble the following:
```bash title="<root>platform/viewer/dist/"
├── app-config.js
@ -99,17 +98,16 @@ You can do this by running the following commands in the `dist/` output
directory:
```bash
// Install http-server as a globally available package
# Install http-server as a globally available package
yarn global add http-server
// Change the directory to the platform/viewer
# Change the directory to the platform/viewer
// Serve the files in our current directory
// Accessible at: `http://localhost:8080`
# Serve the files in our current directory
# Accessible at: `http://localhost:8080`
npx http-server ./dist
```
<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
<iframe src="https://player.vimeo.com/video/551957266?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>
@ -125,8 +123,6 @@ web application. For a starting point, check out this repository's own use of:
- [Netlify][netlify]: [netlify.toml][netlify.toml] |
[build-deploy-preview.sh][build-deploy-preview.sh]
<!-- prettier-ignore-start -->
[circleci]: https://circleci.com/gh/OHIF/Viewers
[circleci-config]: https://github.com/OHIF/Viewers/blob/master/.circleci/config.yml

View File

@ -2,6 +2,7 @@
sidebar_position: 1
sidebar_label: Overview
---
# Deployment
The OHIF Viewer can be embedded in other web applications via it's [packaged
@ -21,9 +22,11 @@ applications. If you find yourself a little lost, please don't hesitate to
## Deployment Scenarios
### Embedded Viewer (deprecated)
`OHIF-v3` has deprecated deploying the viewer as an embedded viewer the number of underlying
libraries that run web workers are increasing for OHIF. An example of these libraries is
OHIF's 3D rendering functionality that is provided by `vtk-js`.
`OHIF-v3` has deprecated deploying the viewer as an embedded viewer the number
of underlying libraries that run web workers are increasing for OHIF. An example
of these libraries is OHIF's 3D rendering functionality that is provided by
`vtk-js`.
### Stand-alone Viewer
@ -32,7 +35,8 @@ benefits, but comes at the cost of time and complexity. Some benefits include:
_Today:_
- Leverage [extensions](/extensions/index.md) and [modes](/modes/index.md) to drop-in powerful new features
- Leverage [extensions](../platform/extensions/index.md) and
[modes](../platform/modes/index.md) to drop-in powerful new features
- Add routes and customize the viewer's workflow
- Finer control over styling and whitelabeling
@ -93,14 +97,14 @@ support it yet, but it is gaining wider adoption.
If you have an existing archive and intend to host the OHIF Viewer at the same
domain name as your archive, then connecting the two is as simple as following
the steps layed out in our
[Configuration Essentials Guide](./../configuring/index.md).
[Configuration Essentials Guide](./../configuration/index.md).
#### What if I don't have an imaging archive?
We provide some guidance on configuring a local image archive in our
[Data Source Essentials](./../configuring/index.md#set-up-a-local-DICOM-server) guide. Hosting an
archive remotely is a little trickier. You can check out some of our
[advanced recipes](#recipes) for modeled setups that may work for you.
[Data Source Essentials](./../configuration/index.md#set-up-a-local-DICOM-server)
guide. Hosting an archive remotely is a little trickier. You can check out some
of our [advanced recipes](#recipes) for modeled setups that may work for you.
#### What if I intend to host the OHIF Viewer at a different domain?
@ -124,91 +128,108 @@ appropriate headers. You can find an example of this setup in our
#### What if my archive doesn't support DicomWeb?
It's possible to supply all Study data via JSON format, in the event you do not have a DicomWeb endpoint.
You can host all of the relevant files on any web accessible server (Amazon S3, Azure Blob Storage, Local file server etc.)
It's possible to supply all Study data via JSON format, in the event you do not
have a DicomWeb endpoint. You can host all of the relevant files on any web
accessible server (Amazon S3, Azure Blob Storage, Local file server etc.)
This JSON is supplied via the '?url=' query parameter.
It should reference an endpoint that returns **application/json** formatted text.
This JSON is supplied via the '?url=' query parameter. It should reference an
endpoint that returns **application/json** formatted text.
If you do not have an API, you can simply return a text file containing the JSON from any web server.
If you do not have an API, you can simply return a text file containing the JSON
from any web server.
You tell the OHIF viewer to use JSON by using the `dicomjson` datasource and
appending `'?url='` query to your mode's route:
You tell the OHIF viewer to use JSON by using the `dicomjson` datasource and appending `'?url='` query to your mode's route:
e.g.
`https://my-test-ohif-server/myMode/dicomjson?url=https://my-json-server/study-uid.json`
eg. `https://my-test-ohif-server/myMode/dicomjson?url=https://my-json-server/study-uid.json`
The returned JSON object must contain a single root object with a 'studies'
array.
You can read more about using different data sources for mode's routes
[here](../platform/modes/routes.md#route-path)
The returned JSON object must contain a single root object with a 'studies' array.
_Sample JSON format:_
You can read more about using different data sources for mode's routes [here](../modes/routes.md#route-path)
*Sample JSON format:*
```json
{
"studies": [
{
"StudyInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.78",
"StudyDescription": "BRAIN SELLA",
"StudyDate": "20010108",
"StudyTime": "120022",
"PatientName": "MISTER^MR",
"PatientId": "832040",
"series": [
{
"SeriesDescription": "SAG T-1",
"SeriesInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.121",
"SeriesNumber": 2,
"SeriesDate": "20010108",
"SeriesTime": "120318",
"Modality": "MR",
"instances": [
{
"metadata": {
"Columns": 512,
"Rows": 512,
"InstanceNumber": 3,
"AcquisitionNumber": 0,
"PhotometricInterpretation": "MONOCHROME2",
"BitsAllocated": 16,
"BitsStored": 16,
"PixelRepresentation": 1,
"SamplesPerPixel": 1,
"PixelSpacing": [0.390625, 0.390625],
"HighBit": 15,
"ImageOrientationPatient": [0,1,0,0,0,-1],
"ImagePositionPatient": [11.600000,-92.500000, 98.099998],
"FrameOfReferenceUID": "1.2.840.113619.2.5.1762583153.223134.978956938.470",
"ImageType": ["ORIGINAL","PRIMARY","OTHER"],
"Modality": "MR",
"SOPInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.124",
"SeriesInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.121",
"StudyInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.78"
},
"url": "dicomweb://s3.amazonaws.com/lury/MRStudy/1.2.840.113619.2.5.1762583153.215519.978957063.124.dcm"
}
]
}
]
}
]
"studies": [
{
"StudyInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.78",
"StudyDescription": "BRAIN SELLA",
"StudyDate": "20010108",
"StudyTime": "120022",
"PatientName": "MISTER^MR",
"PatientId": "832040",
"series": [
{
"SeriesDescription": "SAG T-1",
"SeriesInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.121",
"SeriesNumber": 2,
"SeriesDate": "20010108",
"SeriesTime": "120318",
"Modality": "MR",
"instances": [
{
"metadata": {
"Columns": 512,
"Rows": 512,
"InstanceNumber": 3,
"AcquisitionNumber": 0,
"PhotometricInterpretation": "MONOCHROME2",
"BitsAllocated": 16,
"BitsStored": 16,
"PixelRepresentation": 1,
"SamplesPerPixel": 1,
"PixelSpacing": [0.390625, 0.390625],
"HighBit": 15,
"ImageOrientationPatient": [0, 1, 0, 0, 0, -1],
"ImagePositionPatient": [11.6, -92.5, 98.099998],
"FrameOfReferenceUID": "1.2.840.113619.2.5.1762583153.223134.978956938.470",
"ImageType": ["ORIGINAL", "PRIMARY", "OTHER"],
"Modality": "MR",
"SOPInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.124",
"SeriesInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.121",
"StudyInstanceUID": "1.2.840.113619.2.5.1762583153.215519.978957063.78"
},
"url": "dicomweb://s3.amazonaws.com/lury/MRStudy/1.2.840.113619.2.5.1762583153.215519.978957063.124.dcm"
}
]
}
]
}
]
}
```
More info on this JSON format can be found here [Issue #1500](https://github.com/OHIF/Viewers/issues/1500)
More info on this JSON format can be found here
[Issue #1500](https://github.com/OHIF/Viewers/issues/1500)
**Implementation Notes:**
<!-- 1. When hosting the viewer, you will also need to host a /viewer route on the server - or the browser may not be able to find the route. -->
1. For each instance url (dicom object) in the returned JSON, you must prefix the `url` with `dicomjson:` in order for the cornerstone image loader to retrieve it correctly.
eg. `https://image-server/my-image.dcm` ---> `dicomjson:https://image-server/my-image.dcm`
2. The JSON format above is compatible with >= v3.7.8 of the application in `V2` version. Older versions of the viewer used a different JSON format. As of 20/04/20 the public [https://viewer.ohif.org/] is a pre 3.0 version that does not support this format yet.
3. The JSON format is case-sensitive. Please ensure you have matched casing with the naturalised Dicom format referenced in [Issue #1500](https://github.com/OHIF/Viewers/issues/1500).
*CORS Issues (Cross-Origin Resource Sharing)*
1. For each instance url (dicom object) in the returned JSON, you must prefix
the `url` with `dicomjson:` in order for the cornerstone image loader to
retrieve it correctly. eg. `https://image-server/my-image.dcm` --->
`dicomjson:https://image-server/my-image.dcm`
2. The JSON format above is compatible with >= v3.7.8 of the application in `V2`
version. Older versions of the viewer used a different JSON format. As of
20/04/20 the public [https://viewer.ohif.org/] is a pre 3.0 version that does
not support this format yet.
3. The JSON format is case-sensitive. Please ensure you have matched casing with
the naturalised Dicom format referenced in
[Issue #1500](https://github.com/OHIF/Viewers/issues/1500).
If you host a JSON API or Images on a different domain from the the app itself, you will likely have CORS issues. This will also happen when testing from Localhost and reaching out to remote servers.
Even if the domain is the same, different ports, subdomains or protocols (https vs http) will also cause CORS errors.
You will to need add a configuration on each server hosting these assets to allow your App server origin.
_CORS Issues (Cross-Origin Resource Sharing)_
If you host a JSON API or Images on a different domain from the the app itself,
you will likely have CORS issues. This will also happen when testing from
Localhost and reaching out to remote servers. Even if the domain is the same,
different ports, subdomains or protocols (https vs http) will also cause CORS
errors. You will to need add a configuration on each server hosting these assets
to allow your App server origin.
For example:
@ -218,17 +239,26 @@ Your JSON API is hosted on `https://my-json-api.aws.com`
And your images are stored on Amazon S3 at `https://my-s3-bucket.aws.com`
When you first start your application, browsing to `https://my-ohif-server.com/myMode/dicomjson?url=https://my-json-api.aws.com/api/my-json-study-info.json`, you will likely get a CORS error in the browser console as it tries to connect to `https://my-json-api.aws.com`.
When you first start your application, browsing to
`https://my-ohif-server.com/myMode/dicomjson?url=https://my-json-api.aws.com/api/my-json-study-info.json`,
you will likely get a CORS error in the browser console as it tries to connect
to `https://my-json-api.aws.com`.
Adding a setting on the JSON server to allow the CORS origin = `https://my-ohif-server.com` should solve this.
Adding a setting on the JSON server to allow the CORS origin =
`https://my-ohif-server.com` should solve this.
Next, you will likely get a similar CORS error, as the browser tries to go to `https://my-s3-bucket.aws.com`.
You will need to go to the S3 bucket configuration, and add a CORS setting to allow origin = `https://my-ohif-server.com`.
Essentially, whenever the application connects to a remote resource, you will need to add the applications url to the allowed CORS Origins on that resource. Adding an origin similar to https://localhost:3000 will also allow for local testing.
Next, you will likely get a similar CORS error, as the browser tries to go to
`https://my-s3-bucket.aws.com`. You will need to go to the S3 bucket
configuration, and add a CORS setting to allow origin =
`https://my-ohif-server.com`.
Essentially, whenever the application connects to a remote resource, you will
need to add the applications url to the allowed CORS Origins on that resource.
Adding an origin similar to https://localhost:3000 will also allow for local
testing.
### Securing Your Data
Coming soon
<!--
@ -240,7 +270,7 @@ The OHIF Viewer can be configured to work with authorization servers that
support one or more of the OpenID-Connect authorization flows. The Viewer finds
it's OpenID-Connect settings on the `oidc` configuration key. You can set these
values following the instructions laid out in the
[Configuration Essentials Guide](./../configuring/index.md).
[Configuration Essentials Guide](./../configuration/index.md).
_Example OpenID-Connect Settings:_
@ -282,7 +312,6 @@ We've included a few recipes for common deployment scenarios. There are many,
many possible configurations, so please don't feel limited to these setups.
Please feel free to suggest or contribute your own recipes.
- [Build for Production](./build-for-production.md)
- [Static](./static-assets.md)
- [Nginx + Image Archive](./nginx--image-archive.md)

View File

@ -1,4 +1,4 @@
{
"label": "Development",
"position": 4
"position": 5
}

View File

@ -1,20 +1,18 @@
---
sidebar_position: 7
sidebar_position: 2
sidebar_label: Architecture
---
# Architecture
In order to achieve a platform that can support various workflows and be
extensible for the foreseeable future we went through extensive planning of
possible use cases and decided to significantly change and improve the
architecture.
>New `OHIF-v3` architecture has made OHIF a general purpose extensible medical imaging **platform**, as opposed to a somewhat highly configurable viewer.
In order to achieve a platform that can support various workflows and be extensible for the foreseeable future we went through extensive planning of possible use cases and decided to significantly change and improve the architecture.
Below, we aim to demystify that complexity by providing insight into how `OHIF Platform` is
architected, and the role each of it's dependent libraries plays.
Below, we aim to demystify that complexity by providing insight into how
`OHIF Platform` is architected, and the role each of it's dependent libraries
plays.
## Overview
@ -48,63 +46,53 @@ you'll see the following:
└── README.md
```
OHIF v3 is comprised of the following components, described in detail in further sections:
- `@ohif/viewer`: The core framework that controls extension registration, mode composition and routing.
- `@ohif/core`: A library of useful and reusable medical imaging functionality for the web.
- `@ohif/ui`: A library of reusable components to build OHIF-styled applications with.
- `Extensions`: A set of building blocks for building applications. The OHIF org maintains a few core libraries.
- `Modes`: Configuration objects that tell @ohif/viewer how to compose extensions to build applications on different routes of the platform.
OHIF v3 is comprised of the following components, described in detail in further
sections:
- `@ohif/viewer`: The core framework that controls extension registration, mode
composition and routing.
- `@ohif/core`: A library of useful and reusable medical imaging functionality
for the web.
- `@ohif/ui`: A library of reusable components to build OHIF-styled applications
with.
- `Extensions`: A set of building blocks for building applications. The OHIF org
maintains a few core libraries.
- `Modes`: Configuration objects that tell @ohif/viewer how to compose
extensions to build applications on different routes of the platform.
## Extensions
The `extensions` directory contains many packages that provides essential
functionalities such as rendering, study/series browsers, measurement tracking that modes
can consume to enable a certain workflow. Extensions have had their behavior changed
in `OHIF-v3` and their api is expanded. In summary:
>In `OHIF-v3`, extensions no longer automatically hook themselves to the app. Now,
>registering an extension makes its component available to `modes` that wish to use them.
> Basically, extensions in `OHIF-v3` are **building blocks** for building applications.
functionalities such as rendering, study/series browsers, measurement tracking
that modes can consume to enable a certain workflow. Extensions have had their
behavior changed in `OHIF-v3` and their api is expanded. In summary:
> In `OHIF-v3`, extensions no longer automatically hook themselves to the app.
> Now, registering an extension makes its component available to `modes` that
> wish to use them. Basically, extensions in `OHIF-v3` are **building blocks**
> for building applications.
OHIF team maintains several high value and commonly used functionalities in its
own extensions. For a list of extensions maintained by OHIF,
[check out this helpful table](./extensions/index.md#maintained-extensions).
As an example `default` extension provides a default viewer layout,
a study/series browser and a datasource that maps to a DICOMWeb compliant backend.
[Click here to read more about extensions!](./extensions/index.md)
[check out this helpful table](../platform/extensions/index.md#maintained-extensions).
As an example `default` extension provides a default viewer layout, a
study/series browser and a datasource that maps to a DICOMWeb compliant backend.
[Click here to read more about extensions!](../platform/extensions/index.md)
## Modes
The `modes` directory contains workflows that can be registered with OHIF
within certain `routes`. The mode will get used once the user opens the viewer
on the registered route.
The `modes` directory contains workflows that can be registered with OHIF within
certain `routes`. The mode will get used once the user opens the viewer on the
registered route.
OHIF extensions were designed to provide certain core functionalities for building
your viewer. However, often in medical imaging we face a specific use case
in which we are using some core functionalities, adding our specific UI, and
use it in our workflows. Previously, to achieve this you had to create an
OHIF extensions were designed to provide certain core functionalities for
building your viewer. However, often in medical imaging we face a specific use
case in which we are using some core functionalities, adding our specific UI,
and use it in our workflows. Previously, to achieve this you had to create an
extension to add have such feature. `OHIF-v3` introduces `Modes` to enable
building such workflows by re-using the core functionalities from the extensions.
building such workflows by re-using the core functionalities from the
extensions.
Some common workflows may include:
@ -112,69 +100,77 @@ Some common workflows may include:
- Segmentation of brain abnormalities
- AI probe mode for detecting prostate cancer
In the mentioned modes above, they will share the same core rendering module that
the `default` extension provides. However, segmentation mode will require
segmentation tools which is not needed for the other two.
As you can see, modes are a layer on top of extensions, that you
can configure in order to achieve certain workflows.
In the mentioned modes above, they will share the same core rendering module
that the `default` extension provides. However, segmentation mode will require
segmentation tools which is not needed for the other two. As you can see, modes
are a layer on top of extensions, that you can configure in order to achieve
certain workflows.
To summarize the difference between extensions and modes in `OHIF-v3` and extensions in `OHIF-v2`
To summarize the difference between extensions and modes in `OHIF-v3` and
extensions in `OHIF-v2`
> - `Modes` are configuration objects that tell *@ohif/viewer* how to compose extensions to build applications on different routes of the platform.
> - `Modes` are configuration objects that tell _@ohif/viewer_ how to compose
> extensions to build applications on different routes of the platform.
> - In v2 extensions are “plugins” that add functionality to a core viewer.
> - In v3 extensions are building blocks that a mode uses to build an entire viewer layout.
[Click here to read more about modes!](./modes/index.md)
> - In v3 extensions are building blocks that a mode uses to build an entire
> viewer layout.
[Click here to read more about modes!](../platform/modes/index.md)
## Platform
### `@ohif/viewer`
This library is the core library which consumes modes and extensions and builds an application. Extensions can be passed in as app configuration and will be consumed and initialized at the appropriate time by the application. Upon initialization the viewer will consume extensions and modes and build up the route desired, these can then be accessed via the study list, or directly via url parameters.
This library is the core library which consumes modes and extensions and builds
an application. Extensions can be passed in as app configuration and will be
consumed and initialized at the appropriate time by the application. Upon
initialization the viewer will consume extensions and modes and build up the
route desired, these can then be accessed via the study list, or directly via
url parameters.
Upon release modes will also be plugged into the app via configuration, but this is still an area which is under development/discussion, and they are currently pulled from the window in beta.
Upon release modes will also be plugged into the app via configuration, but this
is still an area which is under development/discussion, and they are currently
pulled from the window in beta.
Future ideas for this framework involve only adding modes and fetching the required extension versions at either runtime or build time, but this decision is still up for discussion.
Future ideas for this framework involve only adding modes and fetching the
required extension versions at either runtime or build time, but this decision
is still up for discussion.
### `@ohif/core`
OHIF core is a carefully maintained and tested set of web-based medical imaging functions and classes. This library includes managers and services used from within the viewer app.
OHIF core is largely similar to the @ohif/core library in v2, however a lot of logic has been moved to extensions:
however all logic about DICOMWeb and other data fetching mechanisms have been pulled out, as these now live in extensions, described later.
OHIF core is a carefully maintained and tested set of web-based medical imaging
functions and classes. This library includes managers and services used from
within the viewer app.
OHIF core is largely similar to the @ohif/core library in v2, however a lot of
logic has been moved to extensions: however all logic about DICOMWeb and other
data fetching mechanisms have been pulled out, as these now live in extensions,
described later.
### `@ohif/ui`
Firstly, a large time-consumer/barrier for entry we discovered was building new UI in a timely manner that fit OHIFs theme. For this reason we have built a new UI component library which contains all the components one needs to build their own viewer.
These components are presentational only, so you can reuse them with whatever logic you desire. As the components are presentational, you may swap out @ohif/ui for a custom UI library with conforming API if you wish to white label the viewer. The UI library is here to make development easier and quicker, but it is not mandatory for extension components to use.
Firstly, a large time-consumer/barrier for entry we discovered was building new
UI in a timely manner that fit OHIFs theme. For this reason we have built a new
UI component library which contains all the components one needs to build their
own viewer.
These components are presentational only, so you can reuse them with whatever
logic you desire. As the components are presentational, you may swap out
@ohif/ui for a custom UI library with conforming API if you wish to white label
the viewer. The UI library is here to make development easier and quicker, but
it is not mandatory for extension components to use.
[Check out our component library!](https://react.ohif.org/)
## Overview of the architecture
OHIF-v3 architecture can be seen in the following figure. We will explore each
piece in more detail.
![mode-archs](./assets/img/mode-archs.png)
![mode-archs](../assets/img/mode-archs.png)
## Common Questions
> Can I create my own Viewer using Vue.js or Angular.js?
You can, but you will not be able to leverage as much of the existing code and
@ -182,13 +178,14 @@ components. `@ohif/core` could still be used for business logic, and to provide
a model for extensions. `@ohif/ui` would then become a guide for the components
you would need to recreate.
> When I want to implement a functionality, should it be in the mode or in an
> extension?
> When I want to implement a functionality, should it be in the mode or in an extension?
This is a great question. Modes are designed to consume extensions, so you should implement
your functionality in one of the modules of your new extension, and let the mode to consume it.
This way, in future, if you needed another mode that utilizes the same functionality, you can easily
hook the extension to the new mode as well.
This is a great question. Modes are designed to consume extensions, so you
should implement your functionality in one of the modules of your new extension,
and let the mode to consume it. This way, in future, if you needed another mode
that utilizes the same functionality, you can easily hook the extension to the
new mode as well.
<!--
Links
@ -199,8 +196,8 @@ your functionality in one of the modules of your new extension, and let the mod
[viewers-project]: https://github.com/OHIF/Viewers
[viewer-npm]: https://www.npmjs.com/package/@ohif/viewer
[pwa]: https://developers.google.com/web/progressive-web-apps/
[configuration]: ./configuring/index.md
[extensions]: ./extensions/index.md
[configuration]: ../configuration/index.md
[extensions]: ../platform/extensions/index.md
[core-github]: https://github.com/OHIF/viewers/platform/core
[ui-github]: https://github.com/OHIF/Viewers/tree/master/platform/ui
<!-- prettier-ignore-end -->

View File

@ -1,7 +1,8 @@
---
sidebar_position: 3
sidebar_position: 6
sidebar_label: Continous Integration
---
# Continous Integration (CI)
This repository uses `CircleCI` and `Netlify` for continous integration.
@ -29,7 +30,6 @@ The PR_CHECKS workflow (Pull Request Checks) runs our automated unit and
end-to-end tests for every code check-in. These tests must all pass before code
can be merged to our `master` branch.
![PR_CHECKS](../assets/img/WORKFLOW_PR_CHECKS.png)
### Workflow: PR_OPTIONAL_DOCKER_PUBLISH
@ -38,8 +38,6 @@ The PR_OPTIONAL_DOCKER_PUBLISH workflow allows for "manual approval" to publish
the pull request as a tagged docker image. This is helpful when changes need to
be tested with the Google Adapter before merging to `master`.
![PR_Workflow](../assets/img/WORKFLOW_PR_OPTIONAL_DOCKER_PUBLISH.png)
> NOTE: This workflow will fail unless it's for a branch on our `upstream`
@ -53,10 +51,8 @@ It uses the Netlify CLI to deploy assets created as part of the repository's PWA
Build process (`yarn run build`). The workflow allows for "Manual Approval" to
promote the build to `STAGING` and `PRODUCTION` environments.
![WORKFLOW_DEPLOY](../assets/img/WORKFLOW_DEPLOY.png)
| Environment | Description | URL |
| ----------- | ---------------------------------------------------------------------------------- | --------------------------------------------- |
| Development | Always reflects latest changes on `master` branch. | [Netlify][netlify-dev] / [OHIF][ohif-dev] |
@ -76,12 +72,8 @@ GitHub hosts the `gh-pages` branch with GitHub Pages.
- Extension Packages: https://github.com/ohif/viewers/#extensions
- Documentation: https://docs.ohif.org/
![WORKFLOW_RELEASE](../assets/img/WORKFLOW_RELEASE.png)
<!--
LINKS
-->

View File

@ -1,7 +1,8 @@
---
sidebar_position: 2
sidebar_position: 3
sidebar_label: Contributing
---
# Contributing
## How can I help?
@ -12,7 +13,7 @@ should be implemented, please don't hesitate to create a new issue. At a
minimum, you may want to read the following documentation:
- [Getting Started](/development/getting-started.md)
- [Architecture](../architecture.md)
- [Architecture](./architecture.md)
Pull requests that are:
@ -49,9 +50,8 @@ On your local file system:
- [`yarn link`](https://yarnpkg.com/en/docs/cli/link)
- `yarn run dev`
- Open a new terminal/shell
- Navigate to `ohif/viewers` (the root of ohif project)
* Open a new terminal/shell
* Navigate to `ohif/viewers` (the root of ohif project)
- `yarn install`
- [`yarn link cornerstone-tools`](https://yarnpkg.com/en/docs/cli/link)
- `yarn run dev`
@ -59,12 +59,8 @@ On your local file system:
As you make changed to `cornerstone-tools`, and it's output is rebuilt, you
should see the following behavior:
![tools](..//assets/img/cornerstone-tools-link.gif)
If you wish to stop using your local package, run the following commands in the
`ohif/viewers` repository root:
@ -101,9 +97,10 @@ there are a lot of factors that can influence the behavior of our development
server and bundler. If you encounter issues not addressed here, please don't
hesitate to reach out on GitHub.
Sometimes you might encounter a situation where the linking doesn't work as expected.
This might happen when there are multiple linked packages with the same name.
You can [remove][unlink] the linked packages inside yarn and try again.
Sometimes you might encounter a situation where the linking doesn't work as
expected. This might happen when there are multiple linked packages with the
same name. You can [remove][unlink] the linked packages inside yarn and try
again.
## Any guidance on submitting changes?

View File

@ -2,6 +2,7 @@
sidebar_position: 1
sidebar_label: Getting Started
---
# Getting Started
## Setup
@ -74,12 +75,10 @@ You should see the following output:
### 🎉 Celebrate 🎉
<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
<iframe src="https://player.vimeo.com/video/545988245?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>
### Building for Production
> More comprehensive guides for building and publishing can be found in our
@ -97,7 +96,7 @@ yarn run build:package
- If you receive a _"No Studies Found"_ message and do not see your studies, try
changing the Study Date filters to a wider range.
- If you see a 'Loading' message which never resolves, check your browser
- If you see a 'Loading' message which never resolves, check your browser's
JavaScript console inside the Developer Tools to identify any errors.
<!--

View File

@ -1,6 +1,8 @@
---
sidebar_position: 2
sidebar_label: Issue & PR Triage Process
---
# Our Process
Our process is a living, breathing thing. We strive to have regular
@ -18,13 +20,11 @@ and suggest changes to the OHIF Viewer's core team. Community issues generally
fall into one of three categories, and are marked with a `triage` label when
created.
| Issue Template Name | Description |
| ---------------------- | ---------------------------------------------------------------------------------------- |
| Community: Report 🐛 | Describe a new issue; Provide steps to reproduce; Expected versus actual result? |
| Community: Request ✋ | Describe a proposed new feature. Why should it be implemented? What is the impact/value? |
| Community: Question ❓ | Seek clarification or assistance relevant to the repository. |
| Issue Template Name | Description |
| ---------------------- | ---------------------------------------------------------------------------------------- |
| Community: Report 🐛 | Describe a new issue; Provide steps to reproduce; Expected versus actual result? |
| Community: Request ✋ | Describe a proposed new feature. Why should it be implemented? What is the impact/value? |
| Community: Question ❓ | Seek clarification or assistance relevant to the repository. |
_table 1. issue template names and descriptions_
@ -38,10 +38,10 @@ accomplish this by:
3. Provide clear guidance and next steps (when applicable)
4. Regularly clean up old (stale) issues
> 🖋 Less obviously, patterns in the issues being reported can highlight
> areas that need improvement. For example, users often have difficulty
> navigating CORS issues when deploying the OHIF Viewer -- how do we best reduce
> our ticket volume for this issue?
> 🖋 Less obviously, patterns in the issues being reported can highlight areas
> that need improvement. For example, users often have difficulty navigating
> CORS issues when deploying the OHIF Viewer -- how do we best reduce our ticket
> volume for this issue?
### Backlogged Issues

View File

@ -1,31 +1,35 @@
---
sidebar_position: 4
sidebar_position: 5
sidebar_label: Testing
---
# Running Tests for OHIF
We introduce here various test types that is available
for OIHF, and how to run each test in order to make sure your contribution
hasn't broken any existing functionalities. Idea and philosophy of each testing category is discussed in the second
part of this page.
We introduce here various test types that is available for OHIF, and how to run
each test in order to make sure your contribution hasn't broken any existing
functionalities. Idea and philosophy of each testing category is discussed in
the second part of this page.
## Unit test
To run the unit test:
```bash
yarn run test:unit:ci
```
Note: You should have already installed all the packages with `yarn install`.
Running unit test will generate a report at the end showing the successful and
unsuccessful tests with detailed explanations.
## End-to-end test
For running the OHIF e2e test you need to run the following steps:
- Create a mini-pacs for OHIF to access the images for testing. We download
and run our lightweight implementation which provides a collection of DICOM studies ([source code][mini-pacs]).
- Create a mini-pacs for OHIF to access the images for testing. We download and
run our lightweight implementation which provides a collection of DICOM
studies ([source code][mini-pacs]).
```bash
docker run -p 5985:5985 -p 5984:5984 -e USE_POUCHDB=true -e DB_SERVER=http://0.0.0.0 ohif/viewer-testdata:0.1-test
@ -35,7 +39,8 @@ and run our lightweight implementation which provides a collection of DICOM stud
![](../assets/img/docker-pacs.png)
- Open a new terminal, navigate to the OHIF project, and run OHIF with the dicom-server config
- Open a new terminal, navigate to the OHIF project, and run OHIF with the
dicom-server config
```bash
APP_CONFIG=config/dicomweb-server.js yarn start
@ -45,7 +50,7 @@ and run our lightweight implementation which provides a collection of DICOM stud
![OHIF-e2e-test-studies](../assets/img/OHIF-e2e-test-studies.png)
- Open a new terminal inside the OIHF project, and run the e2e cypress test
- Open a new terminal inside the OHIF project, and run the e2e cypress test
```bash
yarn run test:e2e
@ -62,11 +67,6 @@ and run our lightweight implementation which provides a collection of DICOM stud
![e2e-cypress-final](../assets/img/e2e-cypress-final.png)
## Testing Philosiphy
> Testing is an opinionated topic. Here is a rough overview of our testing

View File

@ -1,4 +0,0 @@
{
"label": "LifeCycle",
"position": 1
}

View File

@ -1,33 +0,0 @@
---
sidebar_position: 2
sidebar_label: Mode Enter
---
# Lifecycle Hook: onModeEnter
If an extension defines the `onModeEnter` lifecycle hook, it is called
when a new mode is enters, or a mode's data or datasource is switched.
For instance, in DICOM structured report extension (`dicom-sr`), we are using
`onModeEnter` to re-create the displaySets after a new mode is entered.
_Example `onModeEnter` hook implementation_
```js
export default {
id: 'org.ohif.dicom-sr',
onModeEnter({ servicesManager}) {
const { DisplaySetService } = servicesManager.services;
const displaySetCache = DisplaySetService.getDisplaySetCache();
const srDisplaySets = displaySetCache.filter(
ds => ds.SOPClassHandlerId === SOPClassHandlerId
);
srDisplaySets.forEach(ds => {
// New mode route, allow SRs to be hydrated again
ds.isHydrated = false;
});
},
};
```

View File

@ -1,21 +0,0 @@
---
sidebar_position: 3
sidebar_label: Mode Exit
---
# Lifecycle Hook: onModeExit
If an extension defines the `onModeExit` lifecycle hook, it is called when navigating
away from a mode. This hook can be used to clean up data tasks such as unregistering services,
removing annotations that do not need to be persisted.
_Example `onModeExit` hook implementation_
```js
export default {
id: 'myExampleExtension',
onModeExit({ servicesManager, commandsManager}) {
myCacheServie.purge()
},
};
```

View File

@ -1,5 +1,6 @@
---
sidebar_position: 4
sidebar_position: 8
sidebar_label: FAQ
---
# Frequently Asked Questions
@ -25,12 +26,12 @@ to communicate this to the community. If your requested feature is on the
roadmap, then it will most likely be built at some point. If it is not, you are
welcome to build it yourself and [contribute it](development/contributing.md).
If you have resources and would like to fund the development of a feature,
please [contact us](http://www.ohif.org) or work with community members that
please [contact us](https://www.ohif.org) or work with community members that
offer [consulting services][commercial-support].
### Who should I contact about Academic Collaborations?
[Gordon J. Harris](http://www.dfhcc.harvard.edu/insider/member-detail/member/gordon-j-harris-phd/)
[Gordon J. Harris](https://www.dfhcc.harvard.edu/insider/member-detail/member/gordon-j-harris-phd/)
at Massachusetts General Hospital is the primary contact for any academic
collaborators. We are always happy to hear about new groups interested in using
the OHIF framework, and may be able to provide development support if the
@ -42,7 +43,7 @@ The Open Health Imaging Foundation does not offer commercial support, however,
some community members do offer consulting services. The following contacts may
be useful:
- Rob Lewis ([Radical Imaging](http://radicalimaging.com/))
- Rob Lewis ([Radical Imaging](https://radicalimaging.com/))
**Please file a Pull Request if you wish to add your name or organization to
this list.**

View File

@ -1,4 +0,0 @@
{
"label": "FAQ",
"position": 14
}

View File

@ -1,6 +1,7 @@
---
sidebar_position: 15
sidebar_position: 7
---
# Help
We all need a little help sometimes. Don't let a few roadblocks stand in the way
@ -29,7 +30,7 @@ persue paid support.
The Open Health Imaging Foundation does not offer commercial support, however,
some community members do offer consulting services:
- Rob Lewis ([Radical Imaging](http://radicalimaging.com/))
- Rob Lewis ([Radical Imaging](https://radicalimaging.com/))
**Please file a Pull Request if you wish to add your name or organization to
this list.**

View File

@ -0,0 +1,7 @@
---
sidebar_position: 9
sidebar_label: Migration to v3
---
> New `OHIF-v3` architecture has made OHIF a general purpose extensible medical
> imaging **platform**, as opposed to a configurable viewer.

View File

@ -0,0 +1,4 @@
{
"label": "Platform",
"position": 6
}

View File

@ -1,6 +1,6 @@
---
name: Colors
route: system/colors
sidebar_position: 2
sidebar_label: Colors
---
import { BackgroundColor } from '@ohif/ui';

View File

@ -0,0 +1,4 @@
{
"label": "UI Component Library",
"position": 5
}

View File

@ -5,7 +5,7 @@ route: components/button
---
import { Button, IconButton, Icon } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Button

View File

@ -5,7 +5,7 @@ route: components/buttonGroup
---
import { ButtonGroup, Button, IconButton, Icon } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# ButtonGroup

View File

@ -5,9 +5,7 @@ route: components/CinePlayer
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { CinePlayer } from '@ohif/ui';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
## Import

View File

@ -5,7 +5,7 @@ route: components/contextMenu
---
import { ContextMenu } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Context Menu

View File

@ -5,7 +5,7 @@ route: components/date-range
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { DateRange } from '@ohif/ui';

View File

@ -5,7 +5,7 @@ route: components/dropdown
---
import { Dropdown, IconButton, Icon } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Dropdown

View File

@ -5,7 +5,7 @@ route: components/empty-studies
---
import { EmptyStudies } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Empty Studies

View File

@ -5,7 +5,7 @@ route: components/errorBoundary
---
import { ErrorBoundary } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Error Boundary

View File

@ -5,7 +5,7 @@ route: components/expandableToolbarButton
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { ExpandableToolbarButton, ListMenu } from '@ohif/ui';
# Toolbar Button

View File

@ -5,7 +5,7 @@ route: components/input
---
import { Input } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Input

View File

@ -5,7 +5,7 @@ route: components/InputDateRange
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { InputDateRange } from '@ohif/ui';

View File

@ -5,7 +5,7 @@ route: components/InputGroup
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { InputGroup } from '@ohif/ui';

View File

@ -5,7 +5,7 @@ route: components/InputMultiSelect
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { InputMultiSelect } from '@ohif/ui';

View File

@ -5,7 +5,7 @@ route: components/InputText
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { InputText } from '@ohif/ui';

View File

@ -5,7 +5,7 @@ route: components/label
---
import { Label } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Label

View File

@ -5,7 +5,7 @@ route: components/listMenu
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { ListMenu, ToolbarButton } from '@ohif/ui';

View File

@ -5,7 +5,7 @@ route: components/measurementTable
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { MeasurementTable } from '@ohif/ui';

View File

@ -5,7 +5,7 @@ route: components/navBar
---
import { NavBar, Typography } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# NavBar

View File

@ -5,7 +5,7 @@ route: components/notification
---
import { Notification } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Notification

View File

@ -5,7 +5,7 @@ route: components/segmentationTable
---
import { SegmentationTable } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Segmentation Table

View File

@ -5,7 +5,7 @@ route: components/select
---
import { Select } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Select

View File

@ -7,7 +7,7 @@ route: components/splitButton
import { useState } from 'react';
import { SplitButton, WindowLevelMenuItem } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Split Button

View File

@ -5,7 +5,7 @@ route: components/studyBrowser
---
import { StudyBrowser } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# StudyBrowser

View File

@ -5,7 +5,7 @@ route: components/studyListFilter
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { StudyListFilter, Modal } from '@ohif/ui';
import { ModalProvider } from '@ohif/ui';

View File

@ -5,7 +5,7 @@ route: components/studyListPagination
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { StudyListPagination } from '@ohif/ui';

View File

@ -5,7 +5,7 @@ route: components/studyListTable
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { StudyListTable } from '@ohif/ui';

View File

@ -5,7 +5,7 @@ route: components/table
---
import { Table, TableHead, TableBody, TableRow, TableCell } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Table
@ -76,4 +76,3 @@ passing a `className` or `style`.
### TableCell Props
<ComponentPropsTable componentName={'TableCell'} />
```

View File

@ -6,7 +6,7 @@ route: components/ThumbnailTracked
import { ThumbnailTracked } from '../';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# ThumbnailTracked

View File

@ -5,7 +5,7 @@ route: components/toolbarButton
---
import { useState, useCallback } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { ToolbarButton } from '@ohif/ui';

View File

@ -5,7 +5,7 @@ route: components/tooltip
---
import { Tooltip, Typography } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Tooltip

View File

@ -5,7 +5,7 @@ route: components/tooltipClipboard
---
import { TooltipClipboard } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Tooltip Clipboard

View File

@ -5,7 +5,7 @@ route: components/typography
---
import { Typography } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Typography

View File

@ -5,7 +5,7 @@ route: components/viewport
---
import { Viewport } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Viewport

View File

@ -5,7 +5,7 @@ route: components/viewportActionBar
---
import { ViewportActionBar } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Viewport Action Bar

View File

@ -5,7 +5,7 @@ route: components/viewportGrid
---
import { DragAndDropProvider, ViewportGrid } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# ViewportGrid

View File

@ -6,7 +6,7 @@ route: components/viewport-pane
import { ViewportGrid, ViewportPane, DragAndDropProvider } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# ViewportPane

View File

@ -5,7 +5,7 @@ route: components/windowLevelMenuItem
---
import { useState } from 'react';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
import { ListMenu, WindowLevelMenuItem } from '@ohif/ui';

View File

@ -0,0 +1,4 @@
{
"label": "Components",
"position": 5
}

View File

@ -5,7 +5,7 @@ route: components/icon
---
import { Icon, ICONS } from '@ohif/ui';
import { ComponentPropsTable } from '../../../src/components/ComponentPropsTable.jsx';
import { ComponentPropsTable } from '../../../../src/components/ComponentPropsTable.jsx';
# Icon

View File

@ -0,0 +1,4 @@
{
"label": "Context Providers",
"position": 5
}

View File

@ -1,6 +1,6 @@
---
name: Getting Started
route: /
sidebar_position: 1
sidebar_label: Getting Started
---
import { Button } from '@ohif/ui';
@ -18,10 +18,10 @@ It's maintained in a monorepo, in the
Install `@ohif/ui` from your terminal:
```bash
// with npm
# with npm
npm i @ohif/ui --save-exact
// with yarn
# with yarn
yarn add @ohif/ui --exact
```
@ -42,5 +42,3 @@ import { Button } from '@ohif/ui';
In the **Examples** section you can check many examples on how to build your
application using `@ohif/ui` components.
...

View File

@ -4,18 +4,23 @@ sidebar_label: Introduction
---
# Introduction
We have re-designed the architecture of the `OHIF-v3` to enable building applications
that are easily extensible to various use cases (modes) that behind the scene would utilize desired functionalities (extensions) to reach the goal of the use case.
Previously, extensions were “additive” and could not easily be mixed and matched within the same viewer for different use cases. Previous `OHIF-v2` architecture meant that
any minor extension alteration usually would require the user to hard fork. E.g. removing some of the tools from the toolbar of the cornerstone extension meant you had to hard fork it, which was frustrating if the implementation was otherwise the same as master.
> - Developers should make packages of *reusable* functionality as extensions, and can consume
> publicly available extensions.
> - Any conceivable radiological workflow or viewer setup will be able to be built with the platform through *modes*.
We have re-designed the architecture of the `OHIF-v3` to enable building
applications that are easily extensible to various use cases (modes) that behind
the scene would utilize desired functionalities (extensions) to reach the goal
of the use case.
Previously, extensions were “additive” and could not easily be mixed and matched
within the same viewer for different use cases. Previous `OHIF-v2` architecture
meant that any minor extension alteration usually would require the user to hard
fork. E.g. removing some of the tools from the toolbar of the cornerstone
extension meant you had to hard fork it, which was frustrating if the
implementation was otherwise the same as master.
> - Developers should make packages of _reusable_ functionality as extensions,
> and can consume publicly available extensions.
> - Any conceivable radiological workflow or viewer setup will be able to be
> built with the platform through _modes_.
Practical examples of extensions include:
@ -23,8 +28,6 @@ Practical examples of extensions include:
- A set of rendering functionalities to volume render the data
- [See our maintained extensions for more examples of what's possible](#maintained-extensions)
**Diagram showing how extensions are configured and accessed.**
<!--
@ -35,8 +38,6 @@ Practical examples of extensions include:
<div><i>Diagram showing how extensions are configured and accessed.</i></div>
</div> -->
## Extension Skeleton
An extension is a plain JavaScript object that has an `id` property, and one or
@ -68,11 +69,11 @@ export default {
```
## OHIF-Maintained Extensions
A small number of powerful extensions for popular use cases are maintained by
OHIF. They're co-located in the [`OHIF/Viewers`][viewers-repo] repository, in
the top level [`extensions/`][ext-source] directory.
<table>
<thead>
<tr>
@ -137,49 +138,47 @@ the top level [`extensions/`][ext-source] directory.
## Registering an Extension
Extensions are building blocks that need to be registered. There are two different ways to register and configure extensions: At
Extensions are building blocks that need to be registered. There are two
different ways to register and configure extensions: At
[runtime](#registering-at-runtime) and at
[build time](#registering-at-build-time).
You can leverage one or both strategies. Which one(s) you choose depend on your
application's requirements.
Each [module](#modules) defined by the extension
becomes available to the modes via the `ExtensionManager` by requesting it via
its id. [Read more about Extension Manager](#extension-manager)
[build time](#registering-at-build-time). You can leverage one or both
strategies. Which one(s) you choose depend on your application's requirements.
Each [module](#modules) defined by the extension becomes available to the modes
via the `ExtensionManager` by requesting it via its id.
[Read more about Extension Manager](#extension-manager)
### Registering at Runtime
The `@ohif/viewer` uses a [configuration file](../viewer/configuration.md) at
The `@ohif/viewer` uses a [configuration file](../../configuration/index.md) at
startup. The schema for that file includes an `extensions` key that supports an
array of extensions to register.
```js
import MyFirstExtension from '@ohif/extension-first'
import MySecondExtension from '@ohif/extension-second'
import MyFirstExtension from '@ohif/extension-first';
import MySecondExtension from '@ohif/extension-second';
const extensionConfig = {/* extension configuration */}
const extensionConfig = {
/* extension configuration */
};
const config = {
routerBasename: '/',
extensions: [
MyFirstExtension,
[
MySecondExtension,
extensionConfig
],
extensions: [MyFirstExtension, [MySecondExtension, extensionConfig]],
modes: [
/* modes */
],
modes: [/* modes */],
showStudyList: true,
dataSources: [ /* data source config */]
}
dataSources: [
/* data source config */
],
};
```
Then, behind the scene, the runtime-added extensions will get merged with the
default app extensions (note: default app extensions include: `OHIFDefaultExtension`,
`OHIFCornerstoneExtension`, `OHIFDICOMSRExtension`,
`OHIFMeasurementTrackingExtension`)
default app extensions (note: default app extensions include:
`OHIFDefaultExtension`, `OHIFCornerstoneExtension`, `OHIFDICOMSRExtension`,
`OHIFMeasurementTrackingExtension`)
### Registering at Build Time
@ -194,56 +193,59 @@ them at "build time" to leverage advantages afforded to us by modern tooling:
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
entrypoint:
2. Importing and adding it to the list of extensions in the entrypoint:
```js title="<repo-root>/platform/src/index.js"
import OHIFDefaultExtension from '@ohif/extension-default';
import OHIFCornerstoneExtension from '@ohif/extension-cornerstone';
import OHIFMeasurementTrackingExtension from '@ohif/extension-measurement-tracking';
import OHIFDICOMSRExtension from '@ohif/extension-dicom-sr';
import MyFirstExtension from '@ohif/extension-first'
```js title="<repo-root>/platform/src/index.js"
import OHIFDefaultExtension from '@ohif/extension-default';
import OHIFCornerstoneExtension from '@ohif/extension-cornerstone';
import OHIFMeasurementTrackingExtension from '@ohif/extension-measurement-tracking';
import OHIFDICOMSRExtension from '@ohif/extension-dicom-sr';
import MyFirstExtension from '@ohif/extension-first';
/** Combine our appConfiguration and "baked-in" extensions */
const appProps = {
config: window ? window.config : {},
defaultExtensions: [
OHIFDefaultExtension,
OHIFCornerstoneExtension,
OHIFMeasurementTrackingExtension,
OHIFDICOMSRExtension,
MyFirstExtension
],
};
```
/** Combine our appConfiguration and "baked-in" extensions */
const appProps = {
config: window ? window.config : {},
defaultExtensions: [
OHIFDefaultExtension,
OHIFCornerstoneExtension,
OHIFMeasurementTrackingExtension,
OHIFDICOMSRExtension,
MyFirstExtension,
],
};
```
## Lifecycle Hooks
Currently, there are three lifecycle hook for extensions:
[`preRegistration`](./lifecycle/pre-registration.md)
This hook is called once on initialization of the entire viewer application, used to initialize the extensions state, and consume user defined extension configuration. If an extension defines the [`preRegistration`](./lifecycle/pre-registration.md)
[`preRegistration`](./lifecycle/#preRegistration) This hook is called once on
initialization of the entire viewer application, used to initialize the
extensions state, and consume user defined extension configuration. If an
extension defines the [`preRegistration`](./lifecycle/#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](./../services/index.md) and [commands](./modules/commands.md), and to
bootstrap 3rd party libraries.
[`onModeEnter`](./lifecycle#onModeEnter): This hook is called whenever a new
mode is entered, or a modes data or datasource is switched. This hook can be
used to initialize data.
[`onModeEnter`](./lifecycle/on-mode-enter.md): This hook is called whenever a new mode is entered, or a modes data or datasource is switched. This hook can be used to initialize data.
[`onModeExit`](./lifecycle/on-mode-exit.md): Similarly to onModeEnter, this hook is called when navigating away from a mode, or before a modes data or datasource is changed. This can be used to clean up data (e.g. remove annotations that do not need to be persisted)
[`onModeExit`](./lifecycle#onModeExit): Similarly to onModeEnter, this hook is
called when navigating away from a mode, or before a modes data or datasource
is changed. This can be used to clean up data (e.g. remove annotations that do
not need to be persisted)
## Modules
Modules are the meat of extensions, the `blocks` that we have been talking about a lot.
They provide "definitions", components, and filtering/mapping logic that are then made available to modes and services.
Modules are the meat of extensions, the `blocks` that we have been talking about
a lot. They provide "definitions", components, and filtering/mapping logic that
are then made available to modes and services.
Each module type has a special purpose, and is consumed by our viewer
differently.
<table>
<thead>
<tr>
@ -329,12 +331,9 @@ differently.
</tbody>
</table>
<span style={{"textAlign": 'center', 'fontStyle': 'italic'}}>Tbl. Module types with abridged descriptions and examples. Each module links to a dedicated documentation page.</span>
<span style={{"textAlign": 'center', 'fontStyle': 'italic'}}>Tbl. Module types
with abridged descriptions and examples. Each module links to a dedicated
documentation page.</span>
### Contexts
@ -353,12 +352,6 @@ module that supports this behavior can add a command with the same name, scoped
to the appropriate context. When the `command` is fired, the "active contexts"
are used to determine the appropriate implementation of the rotate behavior.
<!--
LINKS
-->

View File

@ -1,8 +1,19 @@
---
sidebar_position: 1
sidebar_label: Pre Registration
sidebar_position: 3
sidebar_label: Lifecycle Hooks
---
# Lifecylce Hook: preRegistration
# Extensions: Lifecycle Hooks
## Overview
Extensions can implement specific lifecycle methods.
- preRegistration
- onModeEnter
- onModeExit
## preRegistration
If an extension defines the `preRegistration` lifecycle hook, it is called
before any modules are registered in the `ExtensionManager`. This hook can be
@ -18,8 +29,8 @@ The `preRegistration` hook receives an object containing the
`configuration` that was provided with the extension at time of registration.
Example `preRegistration` implementation that register a new service and make it
available in the app. We will talk more in details for creating a new service for
`OHIF-v3`.
available in the app. We will talk more in details for creating a new service
for `OHIF-v3`.
```js
// new service inside new extension
@ -66,3 +77,52 @@ export default {
},
};
```
## onModeEnter
If an extension defines the `onModeEnter` lifecycle hook, it is called when a
new mode is enters, or a mode's data or datasource is switched.
For instance, in DICOM structured report extension (`dicom-sr`), we are using
`onModeEnter` to re-create the displaySets after a new mode is entered.
_Example `onModeEnter` hook implementation_
```js
export default {
id: 'org.ohif.dicom-sr',
onModeEnter({ servicesManager }) {
const { DisplaySetService } = servicesManager.services;
const displaySetCache = DisplaySetService.getDisplaySetCache();
const srDisplaySets = displaySetCache.filter(
ds => ds.SOPClassHandlerId === SOPClassHandlerId
);
srDisplaySets.forEach(ds => {
// New mode route, allow SRs to be hydrated again
ds.isHydrated = false;
});
},
};
```
## onModeExit
If an extension defines the `onModeExit` lifecycle hook, it is called when
navigating away from a mode. This hook can be used to clean up data tasks such
as unregistering services, removing annotations that do not need to be
persisted.
_Example `onModeExit` hook implementation_
```js
export default {
id: 'myExampleExtension',
onModeExit({ servicesManager, commandsManager }) {
myCacheService.purge();
},
};
```

View File

@ -2,17 +2,27 @@
sidebar_position: 3
sidebar_label: Data Source
---
# Module: Data Source
## Overview
The internal data structure of OHIFs metadata follows naturalized DICOM JSON, A format pioneered by `dcmjs`. In short DICOM metadata headers with DICOM Keywords instead of tags and sequences as arrays, for easy development and clear code.
We have built a standard for fetching and mapping data into OHIFs native format, which we call DataSources, and have provided one implementation of this standard.
The internal data structure of OHIFs metadata follows naturalized DICOM JSON, A
format pioneered by `dcmjs`. In short DICOM metadata headers with DICOM Keywords
instead of tags and sequences as arrays, for easy development and clear code.
You can make another datasource implementation which communicates to your backend and maps to OHIFs native format, then use any existing mode on your platform. Your data doesnt even need to be DICOM if you can map some proprietary data to the correct format.
We have built a standard for fetching and mapping data into OHIFs native
format, which we call DataSources, and have provided one implementation of this
standard.
The DataSource is also a place to add easy helper methods that platform-specific extensions can call in order to interact with the backend, meaning proprietary data interactions can be wrapped in extensions.
You can make another datasource implementation which communicates to your
backend and maps to OHIFs native format, then use any existing mode on your
platform. Your data doesnt even need to be DICOM if you can map some
proprietary data to the correct format.
The DataSource is also a place to add easy helper methods that platform-specific
extensions can call in order to interact with the backend, meaning proprietary
data interactions can be wrapped in extensions.
```js
const getDataSourcesModule = () => [
@ -26,16 +36,13 @@ const getDataSourcesModule = () => [
];
```
Default extension provides two main data sources that are commonly used: `dicomweb` and `dicomjson`
Default extension provides two main data sources that are commonly used:
`dicomweb` and `dicomjson`
```js
import { createDicomWebApi } from './DicomWebDataSource/index.js';
import { createDicomJSONApi } from './DicomJSONDataSource/index.js';
function getDataSourcesModule() {
return [
{
@ -52,13 +59,14 @@ function getDataSourcesModule() {
}
```
## Custom DataSource
You can add your custom datasource by creating the implementation using `IWebApiDataSource.create` from `@ohif/core`. This factory function creates a new "Web API" data source that fetches data over HTTP.
You need to make sure, you implement the following functions for the data source.
You can add your custom datasource by creating the implementation using
`IWebApiDataSource.create` from `@ohif/core`. This factory function creates a
new "Web API" data source that fetches data over HTTP.
You need to make sure, you implement the following functions for the data
source.
```js title="platform/core/src/DataSources/IWebApiDataSource.js"
function create({
@ -79,8 +87,9 @@ function create({
You can take a look at `dicomweb` data source implementation to get an idea
`extensions/default/src/DicomWebDataSource/index.js`
## DicomMetadataStore
In `OHIF-v3` we have a central location for the metadata of studies and they are located
in `DicomMetadataStore`. Your custom datasource can communicate with `DicomMetadataStore` to store, and fetch Study/Series/Instance metadata. We will learn more about `DicomMetadataStore` in services.
In `OHIF-v3` we have a central location for the metadata of studies and they are
located in `DicomMetadataStore`. Your custom datasource can communicate with
`DicomMetadataStore` to store, and fetch Study/Series/Instance metadata. We will
learn more about `DicomMetadataStore` in services.

View File

@ -2,22 +2,21 @@
sidebar_position: 6
sidebar_label: Panel
---
# Module: Panel
## Overview
The default LayoutTemplate has panels on the left and right sides, however one could make a template with panels at the top or bottom and make extensions with panels intended for such slots.
The default LayoutTemplate has panels on the left and right sides, however one
could make a template with panels at the top or bottom and make extensions with
panels intended for such slots.
An extension can register a Panel Module by defining a `getPanelModule` method.
The panel module provides the ability to define `menuOptions` and `components`
that can be used by the consuming application. `components` are React Components
that can be displayed in the consuming application's "Panel" Component.
![panel-module-v3](../../assets/img/panel-module-v3.png)
![panel-module-v3](../../../assets/img/panel-module-v3.png)
The `menuOptions`'s `target` key, points to a registered `components`'s `id`. A
`defaultContext` is applied to all `menuOption`s; however, each `menuOption` can
@ -29,7 +28,6 @@ associated `ServicesManager` and `CommandsManager`.
```jsx
import PanelMeasurementTable from './PanelMeasurementTable.js';
function getPanelModule({
commandsManager,
extensionManager,
@ -57,35 +55,33 @@ function getPanelModule({
}
```
## Consuming Panels Inside Modes
As explained earlier, extensions make the functionalities and components available and
`modes` utilize them to build an app. So, as seen above, we are not actually defining
which side the panel should be opened. Our extension is providing the component with
its.
New: You can easily add multiple panels to the left/right side of the viewer using the mode
configuration. As seen below, the `leftPanels` and `rightPanels` accept an `Array` of
the `IDs`.
As explained earlier, extensions make the functionalities and components
available and `modes` utilize them to build an app. So, as seen above, we are
not actually defining which side the panel should be opened. Our extension is
providing the component with its.
New: You can easily add multiple panels to the left/right side of the viewer
using the mode configuration. As seen below, the `leftPanels` and `rightPanels`
accept an `Array` of the `IDs`.
```js
export default function mode({ modeConfiguration }) {
return {
id: "viewer",
id: 'viewer',
routes: [
{
path: "longitudinal",
path: 'longitudinal',
layoutTemplate: ({ location, servicesManager }) => {
return {
id,
props: {
leftPanels: [
"org.ohif.measurement-tracking.panelModule.seriesList",
'org.ohif.measurement-tracking.panelModule.seriesList',
],
rightPanels: [
"org.ohif.measurement-tracking.panelModule.trackedMeasurements",
'org.ohif.measurement-tracking.panelModule.trackedMeasurements',
],
viewports,
},
@ -94,10 +90,10 @@ export default function mode({ modeConfiguration }) {
},
],
extensions: [
"org.ohif.default",
"org.ohif.cornerstone",
"org.ohif.measurement-tracking",
"org.ohif.dicom-sr",
'org.ohif.default',
'org.ohif.cornerstone',
'org.ohif.measurement-tracking',
'org.ohif.dicom-sr',
],
};
}

View File

@ -2,24 +2,22 @@
sidebar_position: 1
sidebar_label: Toolbar
---
# Module: Toolbar
An extension can register a Toolbar Module by defining a `getToolbarModule`
method. `OHIF-v3`'s `default` extension (`"ohif.org.default"`) provides 5 main toolbar button types:
![toolbarModule](../../assets/img/toolbarModule.png)
method. `OHIF-v3`'s `default` extension (`"ohif.org.default"`) provides 5 main
toolbar button types:
![toolbarModule](../../../assets/img/toolbarModule.png)
## Example Toolbar Module
The Toolbar Module should return an array of `objects`. There are currently a few different variations of definitions,
each one is detailed further down.
The Toolbar Module should return an array of `objects`. There are currently a
few different variations of definitions, each one is detailed further down.
```js
export default function getToolbarModule({ commandsManager, servicesManager }) {
return [
{
name: 'ohif.divider',
@ -45,17 +43,17 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
name: 'ohif.layoutSelector',
defaultComponent: ToolbarLayoutSelector,
clickHandler: (evt, clickedBtn, btnSectionName) => {},
}
]
},
];
}
```
## Toolbar buttons consumed in modes
Below we can see a simplified version of the `longitudinal` mode that shows how
a mode can add buttons to the toolbar by calling `ToolBarService.addButtons(toolbarButtons)`.
`toolbarButtons` is an array of `toolDefinitions` which we will learn next.
Below we can see a simplified version of the `longitudinal` mode that shows how
a mode can add buttons to the toolbar by calling
`ToolBarService.addButtons(toolbarButtons)`. `toolbarButtons` is an array of
`toolDefinitions` which we will learn next.
```js
export default function mode({ modeConfiguration }) {
@ -73,7 +71,9 @@ export default function mode({ modeConfiguration }) {
{
path: 'longitudinal',
layoutTemplate: ({ location, servicesManager }) => {
return {/* */};
return {
/* */
};
},
},
],
@ -85,17 +85,13 @@ export default function mode({ modeConfiguration }) {
],
};
}
```
## Button Definitions
The simplest toolbarButtons definition has the following properties:
![toolbarModule-zoom](../../assets/img/toolbarModule-zoom.png)
![toolbarModule-zoom](../../../assets/img/toolbarModule-zoom.png)
```js
{
@ -110,40 +106,36 @@ The simplest toolbarButtons definition has the following properties:
},
```
| property | description | values |
| ---------------- | ----------------------------------------------------------------- | ----------------------------------------- |
| `id` | Unique string identifier for the definition | \* |
| `label` | User/display friendly to show in UI | \* |
| `icon` | A string name for an icon supported by the consuming application. | \* |
| `type` | Used to determine the button's behaviour | "tool", "toggle", "action" |
| property | description | values |
| ---------------- | ----------------------------------------------------------------- | ------------------------------------------- |
| `id` | Unique string identifier for the definition | \* |
| `label` | User/display friendly to show in UI | \* |
| `icon` | A string name for an icon supported by the consuming application. | \* |
| `type` | Used to determine the button's behaviour | "tool", "toggle", "action" |
| `commandName` | (optional) The command to run when the button is used. | Any command registered by a `CommandModule` |
| `commandOptions` | (optional) Options to pass the target `commandName` | \* |
| `commandOptions` | (optional) Options to pass the target `commandName` | \* |
There are three main types of toolbar buttons:
- `tool`: buttons that enable a tool by running the `setToolActive` command with the `commandOptions`
- `tool`: buttons that enable a tool by running the `setToolActive` command with
the `commandOptions`
- `toggle`: buttons that acts as a toggle: e.g., linking viewports
- `action`: buttons that executes an action: e.g., capture button to save screenshot
- `action`: buttons that executes an action: e.g., capture button to save
screenshot
## Nested Buttons
You can use the `ohif.splitButton` type to build a button with extra tools in the dropdown.
You can use the `ohif.splitButton` type to build a button with extra tools in
the dropdown.
- First you need to give your `primary` tool definition to the split button
- the `secondary` properties can be a simple arrow down (`chevron-down` icon)
- For adding the extra tools add them to the `items` list.
You can see below how `longitudinal` mode is using the available toolbarModule to create
`MeasurementTools` nested button
You can see below how `longitudinal` mode is using the available toolbarModule
to create `MeasurementTools` nested button
![toolbarModule-nested-buttons](../../assets/img/toolbarModule-nested-buttons.png)
![toolbarModule-nested-buttons](../../../assets/img/toolbarModule-nested-buttons.png)
```js title="modes/longitudinal/src/toolbarButtons.js"
{
@ -203,19 +195,18 @@ You can see below how `longitudinal` mode is using the available toolbarModule t
}
```
<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
<iframe src="https://player.vimeo.com/video/547957214?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
</div>
## Layout Template
Layout selector button and logic is also provided by the OHIF-v3 `default` extension.
To use it, you can just add the following definition to the list of `toolDefinitions`
![toolbarModule-layout](../../assets/img/toolbarModule-layout.png)
Layout selector button and logic is also provided by the OHIF-v3 `default`
extension. To use it, you can just add the following definition to the list of
`toolDefinitions`
![toolbarModule-layout](../../../assets/img/toolbarModule-layout.png)
```js
{
id: 'Layout',
@ -228,30 +219,28 @@ To use it, you can just add the following definition to the list of `toolDefinit
</div>
## Custom Button
You can also create your own extension, and add your new custom tool appearance (e.g., split horizantlly instead of vertically for split tool).
Simply add `getToolbarModule` to your extension, and pass your tool react component to its
`defaultComponent` property in the returned object.
You can use `@ohif/ui` components such as `IconButton, Icon, Tooltip, ToolbarButton` to
build your own component.
You can also create your own extension, and add your new custom tool appearance
(e.g., split horizantlly instead of vertically for split tool). Simply add
`getToolbarModule` to your extension, and pass your tool react component to its
`defaultComponent` property in the returned object. You can use `@ohif/ui`
components such as `IconButton, Icon, Tooltip, ToolbarButton` to build your own
component.
```js
import myToolComponent from './myToolComponent'
import myToolComponent from './myToolComponent';
export default function getToolbarModule({ commandsManager, servicesManager }) {
return [
{
name: 'new-tool-type',
defaultComponent: myToolComponent,
clickHandler: () => {},
},
]
];
}
```
## Custom tool
**I want to create a new tool**

View File

@ -2,10 +2,13 @@
sidebar_position: 5
sidebar_label: Viewport
---
# Module: Viewport
## Overview
Viewports consume a displaySet and display/allow the user to interact with data. An extension can register a Viewport Module by defining a `getViewportModule`
Viewports consume a displaySet and display/allow the user to interact with data.
An extension can register a Viewport Module by defining a `getViewportModule`
method that returns a React component. Currently, we use viewport components to
add support for:
@ -16,10 +19,9 @@ add support for:
- Whole Slide Microscopy Viewing (whole slide ext.)
- etc.
The general pattern is that a mode can define which `Viewport` to use for which specific
`SOPClassHandlerUID`, so if you want to fork just a single Viewport component for a specialized mode, this is possible.
The general pattern is that a mode can define which `Viewport` to use for which
specific `SOPClassHandlerUID`, so if you want to fork just a single Viewport
component for a specialized mode, this is possible.
```jsx
// displaySet, viewportIndex, dataSource
@ -39,13 +41,10 @@ const getViewportModule = () => {
};
```
## Example Viewport Component
A simplified version of the tracked CornerstoneViewport is shown below, which creates
a cornerstone viewport and and action bar on top of it.
A simplified version of the tracked CornerstoneViewport is shown below, which
creates a cornerstone viewport and and action bar on top of it.
```jsx
function TrackedCornerstoneViewport({
@ -60,15 +59,15 @@ function TrackedCornerstoneViewport({
const renderViewport = () => {
const { component: Component } = extensionManager.getModuleEntry(
'org.ohif.cornerstone.viewportModule.cornerstone'
)
);
return (
<Component
onElementEnabled={onElementEnabled}
element={element}
{...props}
></Component>
)
}
);
};
return (
<>
@ -77,13 +76,12 @@ function TrackedCornerstoneViewport({
{renderViewport()}
</div>
</>
)
);
}
```
![viewportModule](../../../assets/img/viewportModule.png)
![viewportModule](../../assets/img/viewportModule.png)
### `@ohif/viewer`
Viewport components are managed by the `ViewportGrid` Component. Which Viewport
@ -93,6 +91,6 @@ component is used depends on:
- The Layout Configuration
- Registered SopClassHandlers
![viewportModule-layout](../../../assets/img/viewportModule-layout.png)
![viewportModule-layout](../../assets/img/viewportModule-layout.png)
<center><i>An example of three cornerstone Viewports</i></center>

Some files were not shown because too many files have changed in this diff Show More