fix(bugs): and replace seriesInstanceUID and seriesInstanceUIDs URL with seriesInstanceUIDs (#4049)
This commit is contained in:
parent
058da93863
commit
da7c1a5d8c
@ -4,7 +4,7 @@ import PanelGenerateImage from './PanelGenerateImage';
|
||||
function DynamicDataPanel({ servicesManager, commandsManager }) {
|
||||
return (
|
||||
<div
|
||||
className="flex flex-auto flex-col text-white"
|
||||
className="flex flex-col text-white"
|
||||
data-cy={'dynamic-volume-panel'}
|
||||
>
|
||||
<PanelGenerateImage
|
||||
|
||||
@ -61,6 +61,24 @@ const cornerstoneExtension: Types.Extensions.Extension = {
|
||||
*/
|
||||
id,
|
||||
|
||||
onModeEnter: ({ servicesManager }): void => {
|
||||
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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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} <small>${getDisplayUnit(unit)}</small> `;
|
||||
}
|
||||
const maxStr = getStatisticDisplayString(max, unit, 'max');
|
||||
|
||||
const str = `${maxStr}(S:${SeriesNumber}${instanceText}${frameText})`;
|
||||
if (!displayText.includes(str)) {
|
||||
|
||||
@ -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} <small>${getDisplayUnit(unit)}</small> `;
|
||||
}
|
||||
|
||||
const maxStr = getStatisticDisplayString(max, unit, 'max');
|
||||
const str = `${maxStr}(S:${SeriesNumber}${instanceText}${frameText})`;
|
||||
if (!displayText.includes(str)) {
|
||||
displayText.push(str);
|
||||
|
||||
@ -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} <small>${getDisplayUnit(unit)}</small> `;
|
||||
}
|
||||
const maxStr = getStatisticDisplayString(max, unit, 'max');
|
||||
|
||||
const str = `${maxStr}(S:${SeriesNumber}${instanceText}${frameText})`;
|
||||
if (!displayText.includes(str)) {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import SUPPORTED_TOOLS from './constants/supportedTools';
|
||||
import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes';
|
||||
import { getDisplayUnit } from './utils';
|
||||
import { utils } from '@ohif/core';
|
||||
|
||||
/**
|
||||
|
||||
@ -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(', ')} <small>${getDisplayUnit(unit)}</small>`;
|
||||
}
|
||||
|
||||
const result = utils.roundNumber(numbers, 2);
|
||||
return `${key.charAt(0).toUpperCase() + key.slice(1)}: ${result} <small>${getDisplayUnit(unit)}</small>`;
|
||||
};
|
||||
@ -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,
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user