diff --git a/extensions/cornerstone-dynamic-volume/src/panels/DynamicDataPanel.tsx b/extensions/cornerstone-dynamic-volume/src/panels/DynamicDataPanel.tsx
index 6be93c1d3..d885d2e95 100644
--- a/extensions/cornerstone-dynamic-volume/src/panels/DynamicDataPanel.tsx
+++ b/extensions/cornerstone-dynamic-volume/src/panels/DynamicDataPanel.tsx
@@ -4,7 +4,7 @@ import PanelGenerateImage from './PanelGenerateImage';
function DynamicDataPanel({ servicesManager, commandsManager }) {
return (
{
+ const { cornerstoneViewportService, toolbarService, segmentationService } =
+ servicesManager.services;
+ toolbarService.registerEventForToolbarUpdate(cornerstoneViewportService, [
+ cornerstoneViewportService.EVENTS.VIEWPORT_DATA_CHANGED,
+ ]);
+
+ toolbarService.registerEventForToolbarUpdate(segmentationService, [
+ segmentationService.EVENTS.SEGMENTATION_ADDED,
+ segmentationService.EVENTS.SEGMENTATION_REMOVED,
+ segmentationService.EVENTS.SEGMENTATION_UPDATED,
+ ]);
+
+ toolbarService.registerEventForToolbarUpdate(cornerstone.eventTarget, [
+ cornerstoneTools.Enums.Events.TOOL_ACTIVATED,
+ ]);
+ },
+
onModeExit: ({ servicesManager }): void => {
const { cineService } = servicesManager.services;
// Empty out the image load and retrieval pools to prevent memory leaks
diff --git a/extensions/cornerstone/src/init.tsx b/extensions/cornerstone/src/init.tsx
index b7ec7abde..9e5f2c38c 100644
--- a/extensions/cornerstone/src/init.tsx
+++ b/extensions/cornerstone/src/init.tsx
@@ -99,26 +99,10 @@ export default async function init({
uiNotificationService,
cornerstoneViewportService,
hangingProtocolService,
- toolbarService,
viewportGridService,
stateSyncService,
- segmentationService,
} = servicesManager.services as CornerstoneServices;
- toolbarService.registerEventForToolbarUpdate(cornerstoneViewportService, [
- cornerstoneViewportService.EVENTS.VIEWPORT_DATA_CHANGED,
- ]);
-
- toolbarService.registerEventForToolbarUpdate(segmentationService, [
- segmentationService.EVENTS.SEGMENTATION_ADDED,
- segmentationService.EVENTS.SEGMENTATION_REMOVED,
- segmentationService.EVENTS.SEGMENTATION_UPDATED,
- ]);
-
- toolbarService.registerEventForToolbarUpdate(eventTarget, [
- cornerstoneTools.Enums.Events.TOOL_ACTIVATED,
- ]);
-
window.services = servicesManager.services;
window.extensionManager = extensionManager;
window.commandsManager = commandsManager;
diff --git a/extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts b/extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts
index a8d40b3d0..74f5d7ac3 100644
--- a/extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts
+++ b/extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts
@@ -98,7 +98,21 @@ class CornerstoneCacheService {
const volume = cs3DCache.getVolume(volumeId);
if (volume) {
- cs3DCache.removeVolumeLoadObject(volumeId);
+ if (volume.imageIds) {
+ // also for each imageId in the volume, remove the imageId from the cache
+ // since that will hold the old metadata as well
+
+ volume.imageIds.forEach(imageId => {
+ if (cs3DCache.getImageLoadObject(imageId)) {
+ cs3DCache.removeImageLoadObject(imageId);
+ }
+ });
+ }
+
+ // this shouldn't be via removeVolumeLoadObject, since that will
+ // remove the texture as well, but here we really just need a remove
+ // from registry so that we load it again
+ cs3DCache._volumeCache.delete(volumeId);
this.volumeImageIds.delete(volumeId);
}
diff --git a/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts b/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts
index 579dc93bd..355bcd0f5 100644
--- a/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts
+++ b/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts
@@ -1147,6 +1147,10 @@ class SegmentationService extends PubSubService {
displaySet.isHydrated = isHydrated;
displaySetService.setDisplaySetMetadataInvalidated(displaySetUID, false);
+
+ this._broadcastEvent(this.EVENTS.SEGMENTATION_UPDATED, {
+ segmentation: this.getSegmentation(displaySetUID),
+ });
}
private _highlightLabelmap(
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/CircleROI.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/CircleROI.ts
index c995fb171..88ca76862 100644
--- a/extensions/cornerstone/src/utils/measurementServiceMappings/CircleROI.ts
+++ b/extensions/cornerstone/src/utils/measurementServiceMappings/CircleROI.ts
@@ -2,6 +2,7 @@ import SUPPORTED_TOOLS from './constants/supportedTools';
import { getDisplayUnit } from './utils';
import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes';
import { utils } from '@ohif/core';
+import { getStatisticDisplayString } from './utils/getValueDisplayString';
const CircleROI = {
toAnnotation: measurement => {},
@@ -193,11 +194,7 @@ function getDisplayText(mappedAnnotations, displaySet, customizationService) {
mappedAnnotations.forEach(mappedAnnotation => {
const { unit, max, SeriesNumber } = mappedAnnotation;
- let maxStr = '';
- if (max) {
- const roundedMax = utils.roundNumber(max, 2);
- maxStr = `Max: ${roundedMax} ${getDisplayUnit(unit)} `;
- }
+ const maxStr = getStatisticDisplayString(max, unit, 'max');
const str = `${maxStr}(S:${SeriesNumber}${instanceText}${frameText})`;
if (!displayText.includes(str)) {
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/EllipticalROI.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/EllipticalROI.ts
index 30a925dd1..c406b9972 100644
--- a/extensions/cornerstone/src/utils/measurementServiceMappings/EllipticalROI.ts
+++ b/extensions/cornerstone/src/utils/measurementServiceMappings/EllipticalROI.ts
@@ -2,6 +2,7 @@ import SUPPORTED_TOOLS from './constants/supportedTools';
import { getDisplayUnit } from './utils';
import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes';
import { utils } from '@ohif/core';
+import { getStatisticDisplayString } from './utils/getValueDisplayString';
const EllipticalROI = {
toAnnotation: measurement => {},
@@ -192,12 +193,7 @@ function getDisplayText(mappedAnnotations, displaySet, customizationService) {
mappedAnnotations.forEach(mappedAnnotation => {
const { unit, max, SeriesNumber } = mappedAnnotation;
- let maxStr = '';
- if (max) {
- const roundedMax = utils.roundNumber(max, 2);
- maxStr = `Max: ${roundedMax} ${getDisplayUnit(unit)} `;
- }
-
+ const maxStr = getStatisticDisplayString(max, unit, 'max');
const str = `${maxStr}(S:${SeriesNumber}${instanceText}${frameText})`;
if (!displayText.includes(str)) {
displayText.push(str);
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/RectangleROI.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/RectangleROI.ts
index 943822de7..4718e617a 100644
--- a/extensions/cornerstone/src/utils/measurementServiceMappings/RectangleROI.ts
+++ b/extensions/cornerstone/src/utils/measurementServiceMappings/RectangleROI.ts
@@ -2,6 +2,7 @@ import SUPPORTED_TOOLS from './constants/supportedTools';
import { getDisplayUnit } from './utils';
import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes';
import { utils } from '@ohif/core';
+import { getStatisticDisplayString } from './utils/getValueDisplayString';
const RectangleROI = {
toAnnotation: measurement => {},
@@ -193,11 +194,7 @@ function getDisplayText(mappedAnnotations, displaySet, customizationService) {
mappedAnnotations.forEach(mappedAnnotation => {
const { unit, max, SeriesNumber } = mappedAnnotation;
- let maxStr = '';
- if (max) {
- const roundedMax = utils.roundNumber(max, 2);
- maxStr = `Max: ${roundedMax} ${getDisplayUnit(unit)} `;
- }
+ const maxStr = getStatisticDisplayString(max, unit, 'max');
const str = `${maxStr}(S:${SeriesNumber}${instanceText}${frameText})`;
if (!displayText.includes(str)) {
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/SplineROI.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/SplineROI.ts
index 05ed5b1dc..b1bac9f54 100644
--- a/extensions/cornerstone/src/utils/measurementServiceMappings/SplineROI.ts
+++ b/extensions/cornerstone/src/utils/measurementServiceMappings/SplineROI.ts
@@ -1,6 +1,5 @@
import SUPPORTED_TOOLS from './constants/supportedTools';
import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes';
-import { getDisplayUnit } from './utils';
import { utils } from '@ohif/core';
/**
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/utils/getValueDisplayString.js b/extensions/cornerstone/src/utils/measurementServiceMappings/utils/getValueDisplayString.js
new file mode 100644
index 000000000..aa0fe316c
--- /dev/null
+++ b/extensions/cornerstone/src/utils/measurementServiceMappings/utils/getValueDisplayString.js
@@ -0,0 +1,12 @@
+import { utils } from '@ohif/core';
+import getDisplayUnit from './getDisplayUnit';
+
+export const getStatisticDisplayString = (numbers, unit, key) => {
+ if (Array.isArray(numbers) && numbers.length > 0) {
+ const results = numbers.map(number => utils.roundNumber(number, 2));
+ return `${key.charAt(0).toUpperCase() + key.slice(1)}: ${results.join(', ')} ${getDisplayUnit(unit)}`;
+ }
+
+ const result = utils.roundNumber(numbers, 2);
+ return `${key.charAt(0).toUpperCase() + key.slice(1)}: ${result} ${getDisplayUnit(unit)}`;
+};
diff --git a/modes/segmentation/src/initToolGroups.ts b/modes/segmentation/src/initToolGroups.ts
index 8b2c28da9..540edf01d 100644
--- a/modes/segmentation/src/initToolGroups.ts
+++ b/modes/segmentation/src/initToolGroups.ts
@@ -55,10 +55,13 @@ function createTools(utilityModule) {
parentTool: 'Brush',
configuration: {
activeStrategy: 'THRESHOLD_INSIDE_CIRCLE',
- preview: {
- enabled: true,
- },
+ // preview: {
+ // enabled: true,
+ // },
strategySpecificConfiguration: {
+ // to use the use the center segment index to determine
+ // if inside -> same segment, if outside -> eraser
+ // useCenterSegmentIndex: true,
THRESHOLD: {
isDynamic: true,
dynamicRadius: 3,
diff --git a/modes/segmentation/src/segmentationButtons.ts b/modes/segmentation/src/segmentationButtons.ts
index cb096a9c6..800ea99fd 100644
--- a/modes/segmentation/src/segmentationButtons.ts
+++ b/modes/segmentation/src/segmentationButtons.ts
@@ -112,21 +112,15 @@ const toolbarButtons: Button[] = [
commands: {
commandName: 'setBrushSize',
commandOptions: {
- toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
+ toolNames: [
+ 'ThresholdCircularBrush',
+ 'ThresholdSphereBrush',
+ 'ThresholdCircularBrushDynamic',
+ ],
},
},
},
- {
- name: 'Shape',
- type: 'radio',
- id: 'eraser-mode',
- value: 'ThresholdCircularBrush',
- values: [
- { value: 'ThresholdCircularBrush', label: 'Circle' },
- { value: 'ThresholdSphereBrush', label: 'Sphere' },
- ],
- commands: 'setToolActiveToolbar',
- },
+
{
name: 'Threshold',
type: 'radio',
@@ -148,6 +142,19 @@ const toolbarButtons: Button[] = [
}
},
},
+ {
+ name: 'Shape',
+ type: 'radio',
+ id: 'eraser-mode',
+ value: 'ThresholdCircularBrush',
+ values: [
+ { value: 'ThresholdCircularBrush', label: 'Circle' },
+ { value: 'ThresholdSphereBrush', label: 'Sphere' },
+ ],
+ condition: ({ options }) =>
+ options.find(option => option.id === 'dynamic-mode').value === 'ThresholdRange',
+ commands: 'setToolActiveToolbar',
+ },
{
name: 'ThresholdRange',
type: 'double-range',
diff --git a/modes/tmtv/src/index.js b/modes/tmtv/src/index.js
index 7acca7c92..da318a527 100644
--- a/modes/tmtv/src/index.js
+++ b/modes/tmtv/src/index.js
@@ -1,7 +1,7 @@
import { hotkeys, classes } from '@ohif/core';
import toolbarButtons from './toolbarButtons.js';
import { id } from './id.js';
-import initToolGroups, { toolGroupIds } from './initToolGroups.js';
+import initToolGroups from './initToolGroups.js';
import setCrosshairsConfiguration from './utils/setCrosshairsConfiguration.js';
import setFusionActiveVolume from './utils/setFusionActiveVolume.js';
import i18n from 'i18next';
@@ -112,19 +112,6 @@ function modeFactory({ modeConfiguration }) {
},
]);
- // This is a hack and we need to find a better way to enable
- // some tools that require the viewport to be ready
- const { unsubscribe: unsub1 } = viewportGridService.subscribe(
- viewportGridService.EVENTS.VIEWPORTS_READY,
- () => {
- commandsManager.run('setToolEnabled', {
- toolName: 'OrientationMarker',
- toolGroupId: 'mipToolGroup',
- });
- unsub1();
- }
- );
-
// For the hanging protocol we need to decide on the window level
// based on whether the SUV is corrected or not, hence we can't hard
// code the window level in the hanging protocol but we add a custom
diff --git a/platform/app/src/routes/Mode/Mode.tsx b/platform/app/src/routes/Mode/Mode.tsx
index 53b881e51..791927455 100644
--- a/platform/app/src/routes/Mode/Mode.tsx
+++ b/platform/app/src/routes/Mode/Mode.tsx
@@ -242,7 +242,7 @@ export default function ModeRoute({
const lowerVal = val.toLowerCase();
if (lowerVal !== 'studyinstanceuids') {
// Not sure why the case matters here - it doesn't in the URL
- if (lowerVal === 'seriesinstanceuid') {
+ if (lowerVal === 'seriesinstanceuids') {
const seriesUIDs = getSplitParam(lowerVal, query);
return {
...acc,
diff --git a/platform/app/src/routes/Mode/defaultRouteInit.ts b/platform/app/src/routes/Mode/defaultRouteInit.ts
index 975ac4d8b..863cb1946 100644
--- a/platform/app/src/routes/Mode/defaultRouteInit.ts
+++ b/platform/app/src/routes/Mode/defaultRouteInit.ts
@@ -4,7 +4,7 @@ import isSeriesFilterUsed from '../../utils/isSeriesFilterUsed';
import { utils, Enums } from '@ohif/core';
-const { sortingCriteria } = utils;
+const { sortingCriteria, getSplitParam } = utils;
/**
* Initialize the route.
@@ -95,6 +95,18 @@ export async function defaultRouteInit(
});
});
+ // is displaysets from URL and has initialSOPInstanceUID or initialSeriesInstanceUID
+ // then we need to wait for all display sets to be retrieved before applying the hanging protocol
+ const params = new URLSearchParams(window.location.search);
+
+ const initialSeriesInstanceUID = getSplitParam('initialseriesinstanceuid', params);
+ const initialSOPInstanceUID = getSplitParam('initialsopinstanceuid', params);
+
+ let displaySetFromUrl = false;
+ if (initialSeriesInstanceUID || initialSOPInstanceUID) {
+ displaySetFromUrl = true;
+ }
+
await Promise.allSettled(allRetrieves).then(async promises => {
log.timeEnd(Enums.TimingEnum.STUDY_TO_DISPLAY_SETS);
log.time(Enums.TimingEnum.DISPLAY_SETS_TO_FIRST_IMAGE);
@@ -109,7 +121,16 @@ export async function defaultRouteInit(
promises.forEach(promise => {
const retrieveSeriesMetadataPromise = promise.value;
- if (Array.isArray(retrieveSeriesMetadataPromise)) {
+ if (!Array.isArray(retrieveSeriesMetadataPromise)) {
+ return;
+ }
+
+ if (displaySetFromUrl) {
+ const requiredSeriesPromises = retrieveSeriesMetadataPromise.map(promise =>
+ promise.start()
+ );
+ allPromises.push(Promise.allSettled(requiredSeriesPromises));
+ } else {
const { requiredSeries, remaining } = hangingProtocolService.filterSeriesRequiredForRun(
hangingProtocolId,
retrieveSeriesMetadataPromise
diff --git a/platform/core/src/services/HangingProtocolService/HangingProtocolService.ts b/platform/core/src/services/HangingProtocolService/HangingProtocolService.ts
index 90c19c458..524a45615 100644
--- a/platform/core/src/services/HangingProtocolService/HangingProtocolService.ts
+++ b/platform/core/src/services/HangingProtocolService/HangingProtocolService.ts
@@ -1314,19 +1314,18 @@ export default class HangingProtocolService extends PubSubService {
);
// Use the display set provided instead
- // Todo: find out what is wrong here
- // if (reuseDisplaySetUID) {
- // if (viewportOptions.allowUnmatchedView !== true) {
- // this.validateDisplaySetSelectMatch(viewportDisplaySet, id, reuseDisplaySetUID);
- // }
- // const displaySetInfo: HangingProtocol.DisplaySetInfo = {
- // displaySetInstanceUID: reuseDisplaySetUID,
- // displaySetOptions,
- // };
+ if (reuseDisplaySetUID) {
+ if (viewportOptions.allowUnmatchedView !== true) {
+ this.validateDisplaySetSelectMatch(viewportDisplaySet, id, reuseDisplaySetUID);
+ }
+ const displaySetInfo: HangingProtocol.DisplaySetInfo = {
+ displaySetInstanceUID: reuseDisplaySetUID,
+ displaySetOptions,
+ };
- // displaySetsInfo.push(displaySetInfo);
- // return;
- // }
+ displaySetsInfo.push(displaySetInfo);
+ return;
+ }
// Use the display set index to allow getting the "next" match, eg
// matching all display sets, and get the matchedDisplaySetsIndex'th item
diff --git a/platform/core/src/services/HangingProtocolService/custom-attribute/isDisplaySetFromUrl.ts b/platform/core/src/services/HangingProtocolService/custom-attribute/isDisplaySetFromUrl.ts
index 20ebb76fe..0689e0c05 100644
--- a/platform/core/src/services/HangingProtocolService/custom-attribute/isDisplaySetFromUrl.ts
+++ b/platform/core/src/services/HangingProtocolService/custom-attribute/isDisplaySetFromUrl.ts
@@ -13,15 +13,16 @@ const isDisplaySetFromUrl = (displaySet): boolean => {
if (!initialSeriesInstanceUID && !initialSOPInstanceUID) {
return false;
}
- const isSeriesMatch =
- !initialSeriesInstanceUID ||
- initialSeriesInstanceUID.some(seriesUID => displaySet.SeriesInstanceUID === seriesUID);
- const isSopMatch =
- !initialSOPInstanceUID ||
- displaySet.instances?.some?.(instance =>
- initialSOPInstanceUID.some(sopUID => sopUID === instance.SOPInstanceUID)
- );
- return isSeriesMatch && isSopMatch;
+
+ const isSeriesMatch = initialSeriesInstanceUID?.some(
+ seriesUID => displaySet.SeriesInstanceUID === seriesUID
+ );
+
+ const isSopMatch = initialSOPInstanceUID?.some(sopUID =>
+ displaySet.instances?.some(instance => sopUID === instance.SOPInstanceUID)
+ );
+
+ return isSeriesMatch || isSopMatch;
};
/** Returns the index location of the requested image, or the defaultValue in this.
diff --git a/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js b/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js
index 9e8425a15..0941136c5 100644
--- a/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js
+++ b/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js
@@ -28,7 +28,6 @@ export default function getPixelSpacingInformation(instance) {
PixelSpacingCalibrationType,
PixelSpacingCalibrationDescription,
EstimatedRadiographicMagnificationFactor,
- SequenceOfUltrasoundRegions,
} = instance;
const isProjection = projectionRadiographSOPClassUIDs.includes(SOPClassUID);
@@ -90,21 +89,6 @@ export default function getPixelSpacingInformation(instance) {
PixelSpacing: CorrectedImagerPixelSpacing,
isProjection,
};
- } else if (SequenceOfUltrasoundRegions && typeof SequenceOfUltrasoundRegions === 'object') {
- const { PhysicalDeltaX, PhysicalDeltaY } = SequenceOfUltrasoundRegions;
- const USPixelSpacing = [PhysicalDeltaX * 10, PhysicalDeltaY * 10];
-
- return {
- PixelSpacing: USPixelSpacing,
- };
- } else if (
- SequenceOfUltrasoundRegions &&
- Array.isArray(SequenceOfUltrasoundRegions) &&
- SequenceOfUltrasoundRegions.length > 1
- ) {
- log.warn(
- 'Sequence of Ultrasound Regions > one entry. This is not yet implemented, all measurements will be shown in pixels.'
- );
} else if (isProjection === false && !ImagerPixelSpacing) {
// If only Pixel Spacing is present, and this is not a projection radiograph,
// we can stop here
diff --git a/platform/docs/docs/configuration/url.md b/platform/docs/docs/configuration/url.md
index c81464e2f..cac7e5ad4 100644
--- a/platform/docs/docs/configuration/url.md
+++ b/platform/docs/docs/configuration/url.md
@@ -120,47 +120,74 @@ values.
:::
-### SeriesInstanceUID, SeriesInstanceUIDs and initialSeriesInstanceUID
+### SeriesInstanceUIDs
Sometimes you need to only retrieve a specific series in a study, you can do
that by providing series level QIDO query parameters in the URL such as
-SeriesInstanceUID or SeriesNumber. This does NOT work with instance or study
+SeriesInstanceUIDs. This does NOT work with instance or study
level parameters. For example:
```js
-http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1&SeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125113545.4
+http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8
```
This will only open the viewer with one series (one displaySet) loaded, and no
queries made for any other series.
Sometimes you need to only retrieve a subset of series in a study, you can do
-that by providing study level wado query parameters in the URL such as
-SeriesInstanceUIDs. For example:
+that by providing more than one series, separated by commas. For example:
```js
-http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113545.4,1.3.6.1.4.1.25403.345050719074.3824.20170125113545.5
+http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8,1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10
```
This will only open the viewer with two series (two displaySets) loaded, and no
queries made for any other series.
-Alternatively, sometimes you want to just open the study on a specified series
-and/or display a particular sop instance, which you can accomplish using:
-`initialSeriesInstanceUID` and/or `initialSOPInstanceUID`
-to select the series to open on, but allowing other
-series to be present in the study browser panel. This is the same behaviour
-as in OHIF 2.0, albeit on different URL parameters. For example:
+### initialSeriesInstanceUID
+
+Alternatively, sometimes you want to just open the study on a specified series, but allowing other
+series to be present too. This is the same behavior can be
+achieved by using the `initialSeriesInstanceUID` parameter. For example:
```js
-http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125113545.4
+http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8
```
+This will open all the series in the study, but the viewer will start with the
+series specified by the `initialSeriesInstanceUID` parameter.
+
+
Note that you can combine these, if you want to load a specific set of series
plus show an initial one as the first one selected, for example:
```js
-http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1&SeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125113545.4&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125113546.1
+http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8,1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10
+```
+
+### initialSopInstanceUID
+
+You can also specify the initial SOP Instance to be displayed by using the
+`initialSopInstanceUID` parameter. For example:
+
+```js
+http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095501.9
+```
+
+This will open the study with the filtered series, and navigate to the slice 101
+which happens to be the SOP Instance specified by the `initialSopInstanceUID`
+
+Note: again you can mix and match
+
+```js
+http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8,1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095510.8
+```
+
+You can even load the whole study and only specify the initial SOP Instance to be displayed. Although
+it will take more time to match, but it works as expected.
+
+```js
+http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095510.8
```
### hangingProtocolId
@@ -169,6 +196,11 @@ You can select the initial hanging protocol to apply by using the
hangingProtocolId parameter. The selected parameter must be available in a
hangingProtocolModule registration, but does not have to be active.
+For instance for loading a specific study in mpr mode from start you can use:
+
+```js
+http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&hangingProtocolId=@ohif/mnGrid
+```
### token