feat(hp): Add displayArea option for Hanging protocols and example with Mamo(#3808)

This commit is contained in:
Bill Wallace 2024-05-29 11:31:09 -04:00 committed by GitHub
parent cb30b97610
commit 18ac08ed86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 771 additions and 27 deletions

View File

@ -51,7 +51,6 @@ provided by the <a href="https://ohif.org/">Open Health Imaging Foundation (OHIF
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-video.webp?raw=true" alt="VIDEO" width="350"/> | Video | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.96975534054447904995905761963464388233) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/microscopy.webp?raw=true" alt="microscopy" width="350"/> | Slide Microscopy | [Demo](https://viewer.ohif.org/microscopy?StudyInstanceUIDs=2.25.141277760791347900862109212450152067508) |
## About
The OHIF Viewer can retrieve

View File

@ -32,6 +32,7 @@ module.exports = {
'@babel/transform-destructuring',
'@babel/plugin-transform-runtime',
'@babel/plugin-transform-typescript',
'@babel/plugin-transform-class-static-block',
],
},
production: {

View File

@ -573,6 +573,8 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
initialImageIndexToUse = this._getInitialImageIndexForViewport(viewportInfo, imageIds) || 0;
}
const { rotation, flipHorizontal, displayArea } = viewportInfo.getViewportOptions();
const properties = { ...presentations.lutPresentation?.properties };
if (!presentations.lutPresentation?.properties) {
const { voi, voiInverted, colormap } = displaySetOptions[0];
@ -598,6 +600,15 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
return viewport.setStack(imageIds, initialImageIndexToUse).then(() => {
viewport.setProperties({ ...properties });
this.setPresentations(viewport.id, presentations);
if (displayArea) {
viewport.setDisplayArea(displayArea);
}
if (rotation) {
viewport.setProperties({ rotation });
}
if (flipHorizontal) {
viewport.setCamera({ flipHorizontal: true });
}
});
}

View File

@ -41,7 +41,7 @@
"react-dom": "^18.3.1",
"react-i18next": "^12.2.2",
"react-window": "^1.8.9",
"webpack": "^5.50.0",
"webpack": "^5.89.0",
"webpack-merge": "^5.7.3"
},
"dependencies": {

View File

@ -1,5 +1,7 @@
import hpMNGrid from './hpMNGrid';
import hpMNCompare from './hpCompare';
import hpMNGrid from './hangingprotocols/hpMNGrid';
import hpMNCompare from './hangingprotocols/hpCompare';
import hpMammography from './hangingprotocols/hpMammo';
import hpScale from './hangingprotocols/hpScale';
const defaultProtocol = {
id: 'default',
@ -114,6 +116,14 @@ function getHangingProtocolModule() {
name: hpMNCompare.id,
protocol: hpMNCompare,
},
{
name: hpMammography.id,
protocol: hpMammography,
},
{
name: hpScale.id,
protocol: hpScale,
},
];
}

View File

@ -120,9 +120,9 @@ const hpMNCompare: Types.HangingProtocol.Protocol = {
{
id: 'Two Studies',
weight: 1000,
// is there a second study or in another work the attribute
// studyInstanceUIDsIndex that we get from prior should not be null
attribute: 'StudyInstanceUID',
// The 'from' attribute says where to get the 'attribute' value from. In this case
// prior means the second study in the study list.
from: 'prior',
required: true,
constraint: {

View File

@ -0,0 +1,201 @@
import {
RCC,
RMLO,
LCC,
LMLO,
RCCPrior,
LCCPrior,
RMLOPrior,
LMLOPrior,
} from './mammoDisplaySetSelector';
const rightDisplayArea = {
storeAsInitialCamera: true,
imageArea: [0.8, 0.8],
imageCanvasPoint: {
imagePoint: [0, 0.5],
canvasPoint: [0, 0.5],
},
};
const leftDisplayArea = {
storeAsInitialCamera: true,
imageArea: [0.8, 0.8],
imageCanvasPoint: {
imagePoint: [1, 0.5],
canvasPoint: [1, 0.5],
},
};
const hpMammography = {
id: '@ohif/hpMammo',
hasUpdatedPriorsInformation: false,
name: 'Mammography Breast Screening',
protocolMatchingRules: [
{
id: 'Mammography',
weight: 150,
attribute: 'ModalitiesInStudy',
constraint: {
contains: 'MG',
},
required: true,
},
{
id: 'numberOfImages',
attribute: 'numberOfDisplaySetsWithImages',
constraint: {
greaterThan: 2,
},
required: true,
},
],
toolGroupIds: ['default'],
displaySetSelectors: {
RCC,
LCC,
RMLO,
LMLO,
RCCPrior,
LCCPrior,
RMLOPrior,
LMLOPrior,
},
stages: [
{
name: 'CC/MLO',
viewportStructure: {
type: 'grid',
layoutType: 'grid',
properties: {
rows: 2,
columns: 2,
},
},
viewports: [
{
viewportOptions: {
toolGroupId: 'default',
displayArea: leftDisplayArea,
// flipHorizontal: true,
// rotation: 180,
allowUnmatchedView: true,
},
displaySets: [
{
id: 'RCC',
},
],
},
{
viewportOptions: {
toolGroupId: 'default',
// flipHorizontal: true,
displayArea: rightDisplayArea,
allowUnmatchedView: true,
},
displaySets: [
{
id: 'LCC',
},
],
},
{
viewportOptions: {
toolGroupId: 'default',
displayArea: leftDisplayArea,
// rotation: 180,
// flipHorizontal: true,
allowUnmatchedView: true,
},
displaySets: [
{
id: 'RMLO',
},
],
},
{
viewportOptions: {
toolGroupId: 'default',
displayArea: rightDisplayArea,
// flipHorizontal: true,
allowUnmatchedView: true,
},
displaySets: [
{
id: 'LMLO',
},
],
},
],
},
// Compare CC current/prior top/bottom
{
name: 'CC compare',
viewportStructure: {
type: 'grid',
layoutType: 'grid',
properties: {
rows: 2,
columns: 2,
},
},
viewports: [
{
viewportOptions: {
toolGroupId: 'default',
displayArea: leftDisplayArea,
flipHorizontal: true,
rotation: 180,
},
displaySets: [
{
id: 'RCC',
},
],
},
{
viewportOptions: {
toolGroupId: 'default',
flipHorizontal: true,
displayArea: rightDisplayArea,
},
displaySets: [
{
id: 'LCC',
},
],
},
{
viewportOptions: {
toolGroupId: 'default',
displayArea: leftDisplayArea,
flipHorizontal: true,
},
displaySets: [
{
id: 'RCCPrior',
},
],
},
{
viewportOptions: {
toolGroupId: 'default',
displayArea: rightDisplayArea,
},
displaySets: [
{
id: 'LCCPrior',
},
],
},
],
},
],
// Indicates it is prior aware, but will work with no priors
numberOfPriorsReferenced: 0,
};
export default hpMammography;

View File

@ -0,0 +1,131 @@
import { Types } from '@ohif/core';
const displayAreaScale1: Types.HangingProtocol.DisplayArea = {
type: 'SCALE',
scale: 1,
storeAsInitialCamera: true,
};
const displayAreaScale15: Types.HangingProtocol.DisplayArea = { ...displayAreaScale1, scale: 15 };
/**
* This hanging protocol can be activated on the primary mode by directly
* referencing it in a URL or by directly including it within a mode, e.g.:
* `&hangingProtocolId=@ohif/mnGrid` added to the viewer URL
* It is not included in the viewer mode by default.
*/
const hpScale: Types.HangingProtocol.Protocol = {
id: '@ohif/hpScale',
description: 'Has various hanging protocol grid layouts',
name: 'Scale Images',
protocolMatchingRules: [
{
id: 'OneOrMoreSeries',
weight: 25,
attribute: 'numberOfDisplaySetsWithImages',
constraint: {
greaterThan: 0,
},
},
],
toolGroupIds: ['default'],
displaySetSelectors: {
defaultDisplaySetId: {
seriesMatchingRules: [
{
attribute: 'numImageFrames',
constraint: {
greaterThan: { value: 0 },
},
required: true,
},
// This display set will select the specified items by preference
// It has no affect if nothing is specified in the URL.
{
attribute: 'isDisplaySetFromUrl',
weight: 10,
constraint: {
equals: true,
},
},
],
},
},
defaultViewport: {
viewportOptions: {
viewportType: 'stack',
toolGroupId: 'default',
displayArea: displayAreaScale1,
allowUnmatchedView: true,
},
displaySets: [
{
id: 'defaultDisplaySetId',
matchedDisplaySetsIndex: -1,
},
],
},
stages: [
// A 1x1 stage - should be automatically activated if there is only 1 viewable instance
{
name: 'Scale 1:1',
stageActivation: {
enabled: {
minViewportsMatched: 1,
},
},
viewportStructure: {
layoutType: 'grid',
properties: {
rows: 1,
columns: 1,
},
},
viewports: [
{
viewportOptions: {
toolGroupId: 'default',
allowUnmatchedView: true,
displayArea: displayAreaScale1,
},
displaySets: [
{
id: 'defaultDisplaySetId',
},
],
},
],
},
{
name: 'Scale 1:15',
stageActivation: {
enabled: {
minViewportsMatched: 1,
},
},
viewportStructure: {
layoutType: 'grid',
properties: {
rows: 1,
columns: 1,
},
},
viewports: [
{
viewportOptions: {
toolGroupId: 'default',
allowUnmatchedView: true,
displayArea: displayAreaScale15,
},
displaySets: [
{
id: 'defaultDisplaySetId',
},
],
},
],
},
],
numberOfPriorsReferenced: -1,
};
export default hpScale;

View File

@ -0,0 +1,15 @@
import viewCodeAttribute from './viewCode';
import lateralityAttribute from './laterality';
import registerHangingProtocolAttributes from './registerHangingProtocolAttributes';
import hpMammography from './hpMammo';
import hpMNGrid from './hpMNGrid';
import hpCompare from './hpCompare';
export {
viewCodeAttribute,
lateralityAttribute,
hpMammography as hpMammo,
hpMNGrid,
hpCompare,
registerHangingProtocolAttributes,
};

View File

@ -0,0 +1,9 @@
export default displaySet => {
const frameAnatomy =
displaySet?.images?.[0]?.SharedFunctionalGroupsSequence?.[0]?.FrameAnatomySequence?.[0];
if (!frameAnatomy) {
return undefined;
}
const laterality = frameAnatomy?.FrameLaterality;
return laterality;
};

View File

@ -0,0 +1,214 @@
const priorStudyMatchingRules = [
{
// The priorInstance is a study counter that indicates what position this study is in
// and the value comes from the options parameter.
attribute: 'studyInstanceUIDsIndex',
from: 'options',
required: true,
constraint: {
equals: { value: 1 },
},
},
];
const currentStudyMatchingRules = [
{
// The priorInstance is a study counter that indicates what position this study is in
// and the value comes from the options parameter.
attribute: 'studyInstanceUIDsIndex',
from: 'options',
required: true,
constraint: {
equals: { value: 0 },
},
},
];
const LCCSeriesMatchingRules = [
{
weight: 10,
attribute: 'ViewCode',
constraint: {
contains: 'SCT:399162004',
},
},
{
weight: 5,
attribute: 'PatientOrientation',
constraint: {
contains: 'L',
},
},
{
weight: 20,
attribute: 'SeriesDescription',
constraint: {
contains: 'L CC',
},
},
];
const RCCSeriesMatchingRules = [
{
weight: 10,
attribute: 'ViewCode',
constraint: {
contains: 'SCT:399162004',
},
},
{
weight: 5,
attribute: 'PatientOrientation',
constraint: {
equals: ['P', 'L'],
},
},
{
attribute: 'PatientOrientation',
constraint: {
doesNotEqual: ['A', 'R'],
},
required: true,
},
{
weight: 20,
attribute: 'SeriesDescription',
constraint: {
contains: 'CC',
},
},
];
const LMLOSeriesMatchingRules = [
{
weight: 10,
attribute: 'ViewCode',
constraint: {
contains: 'SCT:399368009',
},
},
{
weight: 0,
attribute: 'ViewCode',
constraint: {
doesNotEqual: 'SCT:399162004',
},
required: true,
},
{
weight: 5,
attribute: 'PatientOrientation',
constraint: {
equals: ['A', 'R'],
},
},
{
weight: 20,
attribute: 'SeriesDescription',
constraint: {
contains: 'L MLO',
},
},
];
const RMLOSeriesMatchingRules = [
{
weight: 10,
attribute: 'ViewCode',
constraint: {
contains: 'SCT:399368009',
},
},
{
attribute: 'ViewCode',
constraint: {
doesNotEqual: 'SCT:399162004',
},
required: true,
},
{
attribute: 'PatientOrientation',
constraint: {
doesNotContain: ['P', 'FL'],
},
required: true,
},
{
weight: 5,
attribute: 'PatientOrientation',
constraint: {
equals: ['P', 'L'],
},
},
{
weight: 5,
attribute: 'PatientOrientation',
constraint: {
equals: ['A', 'FR'],
},
},
{
weight: 20,
attribute: 'SeriesDescription',
constraint: {
contains: 'R MLO',
},
},
{
attribute: 'SeriesDescription',
required: true,
constraint: {
doesNotContain: 'CC',
},
},
{
attribute: 'SeriesDescription',
required: true,
constraint: {
doesNotEqual: 'L MLO',
},
required: true,
},
];
const RCC = {
seriesMatchingRules: RCCSeriesMatchingRules,
studyMatchingRules: currentStudyMatchingRules,
};
const RCCPrior = {
seriesMatchingRules: RCCSeriesMatchingRules,
studyMatchingRules: priorStudyMatchingRules,
};
const LCC = {
seriesMatchingRules: LCCSeriesMatchingRules,
studyMatchingRules: currentStudyMatchingRules,
};
const LCCPrior = {
seriesMatchingRules: LCCSeriesMatchingRules,
studyMatchingRules: priorStudyMatchingRules,
};
const RMLO = {
seriesMatchingRules: RMLOSeriesMatchingRules,
studyMatchingRules: currentStudyMatchingRules,
};
const RMLOPrior = {
seriesMatchingRules: RMLOSeriesMatchingRules,
studyMatchingRules: priorStudyMatchingRules,
};
const LMLO = {
seriesMatchingRules: LMLOSeriesMatchingRules,
studyMatchingRules: currentStudyMatchingRules,
};
const LMLOPrior = {
seriesMatchingRules: LMLOSeriesMatchingRules,
studyMatchingRules: priorStudyMatchingRules,
};
export { RCC, LCC, RMLO, LMLO, RCCPrior, LCCPrior, RMLOPrior, LMLOPrior };

View File

@ -0,0 +1,8 @@
import viewCode from './viewCode';
import laterality from './laterality';
export default function registerHangingProtocolAttributes({ servicesManager }) {
const { hangingProtocolService } = servicesManager.services;
hangingProtocolService.addCustomAttribute('ViewCode', 'View Code Designator:Value', viewCode);
hangingProtocolService.addCustomAttribute('Laterality', 'Laterality of object', laterality);
}

View File

@ -0,0 +1,11 @@
export default displaySet => {
const ViewCodeSequence = displaySet?.images[0]?.ViewCodeSequence[0];
if (!ViewCodeSequence) {
return undefined;
}
const { CodingSchemeDesignator, CodeValue } = ViewCodeSequence;
if (!CodingSchemeDesignator || !CodeValue) {
return undefined;
}
return `${CodingSchemeDesignator}:${CodeValue}`;
};

View File

@ -2,6 +2,7 @@ import { DicomMetadataStore, classes } from '@ohif/core';
import { calculateSUVScalingFactors } from '@cornerstonejs/calculate-suv';
import getPTImageIdInstanceMetadata from './getPTImageIdInstanceMetadata';
import { registerHangingProtocolAttributes } from './hangingprotocols';
const metadataProvider = classes.MetadataProvider;
@ -60,6 +61,9 @@ export default function init({
// afterwards.
stateSyncService.register('viewportsByPosition', { clearOnModeExit: true });
// Adds extra custom attributes for use by hanging protocols
registerHangingProtocolAttributes({ servicesManager });
// Function to process and subscribe to events for a given set of commands and listeners
const subscribeToEvents = listeners => {
Object.entries(listeners).forEach(([event, commands]) => {

View File

@ -43,7 +43,7 @@
"i18next": "^17.0.3"
},
"devDependencies": {
"webpack": "^5.50.0",
"webpack": "^5.89.0",
"webpack-merge": "^5.7.3"
}
}

View File

@ -48,7 +48,7 @@
"i18next": "^17.0.3"
},
"devDependencies": {
"webpack": "^5.50.0",
"webpack": "^5.89.0",
"webpack-merge": "^5.7.3"
}
}

View File

@ -49,7 +49,7 @@
"i18next": "^17.0.3"
},
"devDependencies": {
"webpack": "^5.50.0",
"webpack": "^5.89.0",
"webpack-merge": "^5.7.3"
}
}

View File

@ -70,7 +70,7 @@
"dotenv": "^14.1.0",
"eslint": "^5.0.1",
"eslint-loader": "^2.0.0",
"webpack": "^5.50.0",
"webpack": "^5.89.0",
"webpack-cli": "^4.7.2",
"webpack-merge": "^5.7.3"
}

View File

@ -47,7 +47,7 @@
"i18next": "^17.0.3"
},
"devDependencies": {
"webpack": "^5.50.0",
"webpack": "^5.89.0",
"webpack-merge": "^5.7.3"
}
}

View File

@ -20,6 +20,7 @@ const PUBLIC_URL = process.env.PUBLIC_URL || '/';
const APP_CONFIG = process.env.APP_CONFIG || 'config/default.js';
const PROXY_TARGET = process.env.PROXY_TARGET;
const PROXY_DOMAIN = process.env.PROXY_DOMAIN;
const OHIF_PORT = Number(process.env.OHIF_PORT || 3000);
const ENTRY_TARGET = process.env.ENTRY_TARGET || `${SRC_DIR}/index.js`;
const Dotenv = require('dotenv-webpack');
const writePluginImportFile = require('./writePluginImportsFile.js');
@ -143,7 +144,7 @@ module.exports = (env, argv) => {
// http2: true,
// https: true,
open: true,
port: 3000,
port: OHIF_PORT,
client: {
overlay: { errors: true, warnings: false },
},

View File

@ -0,0 +1,86 @@
import { utilities } from '@cornerstonejs/core';
/**
* Add tests to ensure image consistency and quality
*/
const testPixel = (dx, dy, expectedPixel) => {
cy.get('.cornerstone-canvas').then(v => {
const canvas = v[0];
cy.log(
'testPixel canvas',
dx,
dy,
expectedPixel,
canvas.width,
canvas.height,
canvas.style.width,
canvas.style.height
);
const ctx = canvas.getContext('2d');
cy.window()
.its('cornerstone')
.then(cornerstone => {
const { viewport } = cornerstone.getEnabledElements()[0];
const imageData = viewport.getImageData();
// cy.log("imageData", imageData);
const origin = viewport.worldToCanvas(imageData.origin);
const orX = origin[0] * devicePixelRatio;
const orY = origin[1] * devicePixelRatio;
const x = Math.round(orX + dx);
const y = Math.round(orY + dy);
cy.log('testPixel origin x,y point x,y', orX, orY, x, y);
// cy.log('world origin', imageData.origin);
// cy.log('focal', viewport.getCamera().focalPoint,
// viewport.worldToCanvas(viewport.getCamera().focalPoint));
const pixelData = ctx.getImageData(x, y, 1, 1);
expect(pixelData.data[0]).closeTo(expectedPixel, 1);
});
});
};
describe('CS3D Image Consistency and Quality', () => {
const setupStudySeries = (studyUID, seriesUID) => {
cy.checkStudyRouteInViewer(
studyUID,
`&seriesInstanceUID=${seriesUID}&hangingProtocolId=@ohif/hpScale`
);
cy.initCornerstoneToolsAliases();
cy.initCommonElementsAliases();
};
it('TG18 Resolution Test Displayed 1:1', () => {
setupStudySeries(
'2.16.124.113543.6004.101.103.20021117.061159.1',
'2.16.124.113543.6004.101.103.20021117.061159.1.004'
);
testPixel(1018, 1028, 255);
// Horizontal and vertical delta from this should not be contaminated
// by values from center
testPixel(1019, 1028, 0);
testPixel(1018, 1029, 0);
testPixel(1017, 1028, 0);
testPixel(1018, 1027, 0);
});
// Missing test data - todo
it.skip('8 bit image displayable', () => {
setupStudySeries('1.3.46.670589.17.1.7.1.1.7', '1.3.46.670589.17.1.7.2.1.7');
// Compare with dcm2jpg generated values or by manually computing WL values
testPixel(258, 257, 171);
testPixel(259, 257, 166);
});
it.skip('12 bit image displayable and zoom with pixel spacing', () => {
setupStudySeries(
'1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1',
'1.3.6.1.4.1.25403.345050719074.3824.20170125113608.5'
);
// Compare with dcm2jpg generated values or by manually computing WL values
testPixel(258, 277, 120);
testPixel(259, 277, 122);
});
});

View File

@ -111,6 +111,34 @@ window.config = {
},
},
},
{
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
sourceName: 'dicomweb2',
configuration: {
friendlyName: 'AWS S3 Static wado secondary server',
name: 'aws',
wadoUriRoot: 'https://d28o5kq0jsoob5.cloudfront.net/dicomweb',
qidoRoot: 'https://d28o5kq0jsoob5.cloudfront.net/dicomweb',
wadoRoot: 'https://d28o5kq0jsoob5.cloudfront.net/dicomweb',
qidoSupportsIncludeField: false,
supportsReject: false,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
enableStudyLazyLoad: true,
supportsFuzzyMatching: false,
supportsWildcard: true,
staticWado: true,
singlepart: 'bulkdata,video',
// whether the data source should use retrieveBulkData to grab metadata,
// and in case of relative path, what would it be relative to, options
// are in the series level or study level (some servers like series some study)
bulkDataURI: {
enabled: true,
relativeResolution: 'studies',
},
omitQuotationForMultipartRequest: true,
},
},
{
friendlyName: 'StaticWado default data',
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',

View File

@ -24,6 +24,18 @@ export type DisplaySetAndViewportOptions = {
displaySetOptions: DisplaySetOptions;
};
export type DisplayArea = {
type?: 'SCALE' | 'FIT';
scale?: number;
interpolationType?: any;
imageArea?: [number, number]; // areaX, areaY
imageCanvasPoint?: {
imagePoint: [number, number]; // imageX, imageY
canvasPoint?: [number, number]; // canvasX, canvasY
};
storeAsInitialCamera?: boolean;
};
export type SetProtocolOptions = {
/** Used to provide a mapping of what keys are provided for which viewport.
* For example, a Chest XRay might use have the display set selector id of
@ -155,6 +167,7 @@ export type ViewportOptions = {
id?: string;
orientation?: CustomOption<string>;
viewportId?: string;
displayArea?: DisplayArea;
initialImageOptions?: CustomOption<initialImageOptions>;
syncGroups?: CustomOption<SyncGroup>[];
customViewportProps?: Record<string, unknown>;

View File

@ -293,6 +293,7 @@ alternative data source (or even specify different default hotkeys).
| `APP_CONFIG` | Which [configuration file][config-file] to copy to output as `app-config.js` | `config/default.js` |
| `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` |
| `OHIF_PORT` | The port to run the webpack server on for PWA builds. | `3000` |
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

View File

@ -281,21 +281,22 @@ A list of criteria for the protocol along with the provided points for ranking.
},
```
### `from` attribute
The from attribute allows getting the attribute to test from some other object
such as the prior study, the list of studies overall or another module provided
value. Some of the possible attributes are:
### `from` attribute (optional)
The `from` attribute allows you to retrieve the attribute to test from another object, such as the previous study, the overall list of studies, or another provided value from a module.
* `prior`: To get the value from the prior study.
* `activeStudy`: To match the active study
* `studies`: To match the list of studies to display
* `displaySets`: The display sets for the current study
* `allDisplaySets`: Alll available display sets
* `instance`: An instance from the current display set being tested
* `options`: Gets the options object itself, eg if you want a simple top level
value.
The values provided by OHIF which you can use are:
### displaySetSelectors
- `activeStudy`: to use the metadata of the active study to match
- `studies`: to use the metadata of the list of studies (all studies) to match
- `allDisplaySets`: all available display sets
- `displaySets`: if the selector has matched a study, these are the display sets for that study
- `prior`: the metadata of the first study in the list of studies that is not the active study
- `options`: during matching, we also provide an options object with the following information that you can use as the `from` value:
- `studyInstanceUIDsIndex`: the index of the study in the list of studies
- `instance`: the metadata of the instance being matched, which is exactly the displaySet.instance metadata.
### displaySetSelectors (mandatory)
Defines the display sets that the protocol will use for arrangement.
```js

View File

@ -60,7 +60,7 @@
"react-window": "^1.8.9",
"react-with-direction": "^1.3.1",
"swiper": "^8.4.2",
"webpack": "^5.81.0"
"webpack": "^5.89.0"
},
"devDependencies": {
"@babel/core": "^7.23.2",

View File

@ -22557,7 +22557,7 @@ webpack-virtual-modules@^0.6.1:
resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.1.tgz#ac6fdb9c5adb8caecd82ec241c9631b7a3681b6f"
integrity sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg==
webpack@5, webpack@^5.50.0, webpack@^5.73.0, webpack@^5.81.0, webpack@^5.90.3:
webpack@5, webpack@^5.50.0, webpack@^5.73.0, webpack@^5.89.0, webpack@^5.90.3:
version "5.91.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.91.0.tgz#ffa92c1c618d18c878f06892bbdc3373c71a01d9"
integrity sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==