diff --git a/OHIFViewer/client/components/viewer/viewer.js b/OHIFViewer/client/components/viewer/viewer.js
index 8af6dccbc..17762810d 100644
--- a/OHIFViewer/client/components/viewer/viewer.js
+++ b/OHIFViewer/client/components/viewer/viewer.js
@@ -1,7 +1,5 @@
import { OHIF } from 'meteor/ohif:core';
-//test2
-
OHIF.viewer = OHIF.viewer || {};
OHIF.viewer.loadIndicatorDelay = 500;
OHIF.viewer.defaultTool = 'wwwc';
@@ -58,6 +56,7 @@ Template.viewer.onCreated(() => {
ViewerData[contentId].studyInstanceUids = [];
instance.data.studies.forEach(study => {
study.selected = true;
+ study.displaySets = createStacks(study);
ViewerStudies.insert(study);
ViewerData[contentId].studyInstanceUids.push(study.studyInstanceUid);
});
diff --git a/Packages/dimseservice/server/DIMSE.js b/Packages/dimseservice/server/DIMSE.js
index d006a06cc..9c180b002 100755
--- a/Packages/dimseservice/server/DIMSE.js
+++ b/Packages/dimseservice/server/DIMSE.js
@@ -23,6 +23,7 @@ var getInstanceRetrievalParams = function(studyInstanceUID, seriesInstanceUID) {
0x00200011: '',
0x00080016: '', // sopClassUid
0x00080018: '', // sopInstanceUid
+ 0x00080060: '', // modality
0x00200013: '', // instanceNumber
0x00280010: '', // rows
0x00280011: '', // columns
diff --git a/Packages/hangingprotocols/client/components/protocolEditor/protocolEditor.js b/Packages/hangingprotocols/client/components/protocolEditor/protocolEditor.js
index 78523bee7..292f3cde8 100644
--- a/Packages/hangingprotocols/client/components/protocolEditor/protocolEditor.js
+++ b/Packages/hangingprotocols/client/components/protocolEditor/protocolEditor.js
@@ -2,6 +2,10 @@
* Updates the Hanging Protocol Select2 Input
*/
function updateProtocolSelect() {
+ if (!ProtocolEngine) {
+ return;
+ }
+
// Loop through the available HangingProtocols
// to create an array with the protocols that includes
// a property labelled 'text', so that Select2 has something
diff --git a/Packages/hangingprotocols/client/protocolEngine.js b/Packages/hangingprotocols/client/protocolEngine.js
index 70a38fc6f..c76ff1749 100644
--- a/Packages/hangingprotocols/client/protocolEngine.js
+++ b/Packages/hangingprotocols/client/protocolEngine.js
@@ -401,7 +401,7 @@ HP.ProtocolEngine = class ProtocolEngine {
if (!alreadyLoaded) {
getStudyMetadata(priorStudy.studyInstanceUid, study => {
study.abstractPriorValue = abstractPriorValue;
-
+ study.displaySets = createStacks(study);
ViewerStudies.insert(study);
this.studies.push(study);
this.matchImages(viewport);
@@ -586,6 +586,23 @@ HP.ProtocolEngine = class ProtocolEngine {
currentViewportData.currentImageIdIndex = details.bestMatch.currentImageIdIndex;
}
+ const study = ViewerStudies.findOne({
+ studyInstanceUid: details.bestMatch.studyInstanceUid
+ });
+
+ // Find the best matched display set. TODO: Fix this to actually
+ // find the most appropriate display set
+ study.displaySets.forEach(displaySet => {
+ if (displaySet.seriesInstanceUid === details.bestMatch.seriesInstanceUid) {
+ currentViewportData.displaySetInstanceUid = displaySet.displaySetInstanceUid;
+ return false;
+ }
+ })
+
+ if (!currentViewportData.displaySetInstanceUid) {
+ throw "No matching display set found?";
+ }
+
viewportData.push(currentViewportData);
});
@@ -594,7 +611,7 @@ HP.ProtocolEngine = class ProtocolEngine {
this.LayoutManager.viewportData = viewportData;
if (viewportIndex !== undefined && viewportData[viewportIndex]) {
- this.LayoutManager.rerenderViewportWithNewSeries(viewportIndex, viewportData[viewportIndex]);
+ this.LayoutManager.rerenderViewportWithNewDisplaySet(viewportIndex, viewportData[viewportIndex]);
} else {
this.LayoutManager.updateViewports();
}
diff --git a/Packages/lesiontracker/client/components/lesionTableRow/lesionTableRow.js b/Packages/lesiontracker/client/components/lesionTableRow/lesionTableRow.js
index 5b3799e43..816ca99a8 100644
--- a/Packages/lesiontracker/client/components/lesionTableRow/lesionTableRow.js
+++ b/Packages/lesiontracker/client/components/lesionTableRow/lesionTableRow.js
@@ -23,6 +23,7 @@ Template.lesionTableRow.events({
$row.closest('.lesionTableView').find('.lesionTableRow').not($row).removeClass('active');
$row.toggleClass('active');
},
+
'dblclick .location': function() {
log.info('Double clicked on Lesion Location cell');
@@ -33,6 +34,7 @@ Template.lesionTableRow.events({
changeLesionLocationCallback(measurementData, null, doneCallback);
},
+
'keydown .location': function(e) {
var keyCode = e.which;
@@ -45,8 +47,8 @@ Template.lesionTableRow.events({
text: 'Are you sure you would like to remove the entire measurement?'
};
- showConfirmDialog(function() {
- Meteor.call('removeMeasurement', currentMeasurement._id, function(error, response) {
+ showConfirmDialog(() => {
+ Meteor.call('removeMeasurement', currentMeasurement._id, (error, response) => {
if (error) {
log.warn(error);
}
diff --git a/Packages/lesiontracker/client/components/lesionTableView/lesionTableView.js b/Packages/lesiontracker/client/components/lesionTableView/lesionTableView.js
index 4df919501..628ed1a99 100644
--- a/Packages/lesiontracker/client/components/lesionTableView/lesionTableView.js
+++ b/Packages/lesiontracker/client/components/lesionTableView/lesionTableView.js
@@ -9,8 +9,8 @@ Template.lesionTableView.helpers({
}
});
},
+
nonTargets() {
- // All Targets shall be listed first followed by Non-Targets
return Measurements.find({
isTarget: false
}, {
@@ -19,8 +19,8 @@ Template.lesionTableView.helpers({
}
});
},
+
newLesions() {
- // All Targets shall be listed first followed by Non-Targets
return Measurements.find({
saved: false
}, {
diff --git a/Packages/lesiontracker/client/components/studySeriesQuickSwitch/studySeriesQuickSwitch.html b/Packages/lesiontracker/client/components/studySeriesQuickSwitch/studySeriesQuickSwitch.html
index 7cc722b93..ae0cf7444 100644
--- a/Packages/lesiontracker/client/components/studySeriesQuickSwitch/studySeriesQuickSwitch.html
+++ b/Packages/lesiontracker/client/components/studySeriesQuickSwitch/studySeriesQuickSwitch.html
@@ -18,7 +18,7 @@
{{#each thumbnail in thumbnailsList}}
{{#if lt @index 8}}
-
+
{{else}}
{{#if eq @index 8}}
{{thumbnailsList.length}}
diff --git a/Packages/lesiontracker/client/components/studyTimepointBrowser/studyTimepointStudy.js b/Packages/lesiontracker/client/components/studyTimepointBrowser/studyTimepointStudy.js
index b0552699a..7a095bfa7 100644
--- a/Packages/lesiontracker/client/components/studyTimepointBrowser/studyTimepointStudy.js
+++ b/Packages/lesiontracker/client/components/studyTimepointBrowser/studyTimepointStudy.js
@@ -66,6 +66,7 @@ Template.studyTimepointStudy.events({
if (!alreadyLoaded) {
$study.addClass('loading');
getStudyMetadata(studyInstanceUid, studyData => {
+ study.displaySets = createStacks(study);
ViewerStudies.insert(studyData);
instance.select(isQuickSwitch);
});
diff --git a/Packages/lesiontracker/client/components/viewer/viewer.js b/Packages/lesiontracker/client/components/viewer/viewer.js
index d2c526f51..079e7fdef 100644
--- a/Packages/lesiontracker/client/components/viewer/viewer.js
+++ b/Packages/lesiontracker/client/components/viewer/viewer.js
@@ -72,6 +72,7 @@ Template.viewer.onCreated(() => {
instance.data.studies.forEach(study => {
study.selected = true;
+ study.displaySets = createStacks(study);
ViewerStudies.insert(study);
});
diff --git a/Packages/viewerbase/assets/sprites.svg b/Packages/viewerbase/assets/sprites.svg
deleted file mode 100644
index 426f99ade..000000000
--- a/Packages/viewerbase/assets/sprites.svg
+++ /dev/null
@@ -1,699 +0,0 @@
-
\ No newline at end of file
diff --git a/Packages/viewerbase/client/components/studyBrowser/imageThumbnail/imageThumbnail.js b/Packages/viewerbase/client/components/studyBrowser/imageThumbnail/imageThumbnail.js
index 36a3291cf..0e00de0f8 100644
--- a/Packages/viewerbase/client/components/studyBrowser/imageThumbnail/imageThumbnail.js
+++ b/Packages/viewerbase/client/components/studyBrowser/imageThumbnail/imageThumbnail.js
@@ -16,7 +16,7 @@ Template.imageThumbnail.onRendered(() => {
cornerstone.enable(element);
// Get the image ID
- const imageInstance = instance.data.thumbnail.stack.instances[0];
+ const imageInstance = instance.data.thumbnail.stack.images[0];
const imageId = getImageId(imageInstance);
// Activate the loading state
@@ -50,7 +50,7 @@ Template.imageThumbnail.onRendered(() => {
}
// Wait for the new data and reresh the image thumbnail
- Meteor.setTimeout(() => {
+ Meteor.defer(() => {
instance.refreshImage();
});
});
diff --git a/Packages/viewerbase/client/components/studyBrowser/thumbnailEntry/thumbnailEntry.html b/Packages/viewerbase/client/components/studyBrowser/thumbnailEntry/thumbnailEntry.html
index e890c6669..55d5d2220 100644
--- a/Packages/viewerbase/client/components/studyBrowser/thumbnailEntry/thumbnailEntry.html
+++ b/Packages/viewerbase/client/components/studyBrowser/thumbnailEntry/thumbnailEntry.html
@@ -1,5 +1,5 @@
-
+
{{>imageThumbnail (clone this)}}
@@ -14,7 +14,7 @@
diff --git a/Packages/viewerbase/client/components/studyBrowser/thumbnailEntry/thumbnailEntry.js b/Packages/viewerbase/client/components/studyBrowser/thumbnailEntry/thumbnailEntry.js
index 13fd27a6c..676ccb7e3 100644
--- a/Packages/viewerbase/client/components/studyBrowser/thumbnailEntry/thumbnailEntry.js
+++ b/Packages/viewerbase/client/components/studyBrowser/thumbnailEntry/thumbnailEntry.js
@@ -193,7 +193,7 @@ const thumbnailDragEndHandler = (event, data, handlers) => {
const viewportIndex = $('.imageViewerViewport').index(element);
// Rerender the viewport using the dragged thumbnail data
- layoutManager.rerenderViewportWithNewSeries(viewportIndex, data);
+ window.layoutManager.rerenderViewportWithNewDisplaySet(viewportIndex, data);
return false;
};
@@ -226,7 +226,7 @@ Template.thumbnailEntry.events({
const data = instance.data.thumbnail.stack;
// Rerender the viewport using the clicked thumbnail data
- layoutManager.rerenderViewportWithNewSeries(instance.data.viewportIndex, data);
+ window.layoutManager.rerenderViewportWithNewDisplaySet(instance.data.viewportIndex, data);
}
});
diff --git a/Packages/viewerbase/client/components/viewer/imageViewerViewport/imageViewerViewport.js b/Packages/viewerbase/client/components/viewer/imageViewerViewport/imageViewerViewport.js
index 5949ba016..04d71960c 100644
--- a/Packages/viewerbase/client/components/viewer/imageViewerViewport/imageViewerViewport.js
+++ b/Packages/viewerbase/client/components/viewer/imageViewerViewport/imageViewerViewport.js
@@ -11,11 +11,12 @@ var allCornerstoneEvents = 'CornerstoneToolsMouseDown CornerstoneToolsMouseDownA
*
* @param data {object} Object containing the study, series, and viewport element to be used
*/
-function loadSeriesIntoViewport(data, templateData) {
- log.info('imageViewerViewport loadSeriesIntoViewport');
+function loadDisplaySetIntoViewport(data, templateData) {
+ log.info('imageViewerViewport loadDisplaySetIntoViewport');
// Make sure we have all the data required to render the series
- if (!data.study || !data.series || !data.element) {
+ if (!data.study || !data.displaySet || !data.element) {
+ log.warn('loadDisplaySetIntoViewport: No Study, Display Set, or Element provided');
return;
}
@@ -53,30 +54,30 @@ function loadSeriesIntoViewport(data, templateData) {
// Loop through the current series and add metadata to the
// Cornerstone meta data provider. This will be used to fill information
// into the viewport overlays, and to calculate reference lines and orientation markers
- var series = data.series;
- var numImages = series.instances.length;
+ var displaySet = data.displaySet;
+ var numImages = displaySet.images.length;
var imageId;
- series.instances.forEach(function(instance, imageIndex) {
+ displaySet.images.forEach(function(image, imageIndex) {
var metaData = {
- instance: instance,
- series: series,
+ instance: image,
+ series: displaySet, // TODO: Check this
study: data.study,
numImages: numImages,
imageIndex: imageIndex + 1
};
- var numFrames = instance.numFrames;
+ var numFrames = image.numImageFrames;
if (numFrames > 1) {
log.info('Multiframe image detected');
for (var i = 0; i < numFrames; i++) {
metaData.frame = i;
- imageId = getImageId(instance, i);
+ imageId = getImageId(image, i);
imageIds.push(imageId);
addMetaData(imageId, metaData);
}
} else {
- imageId = getImageId(instance);
+ imageId = getImageId(image);
imageIds.push(imageId);
addMetaData(imageId, metaData);
}
@@ -161,11 +162,11 @@ function loadSeriesIntoViewport(data, templateData) {
enabledElement.viewport = cornerstone.getDefaultViewport(enabledElement.canvas, image);
// Check if there are default viewport settings for this sopClassUid
- if (!series.instances || !series.instances.length) {
+ if (!displaySet.images || !displaySet.images.length) {
return;
}
- var instance = series.instances[0];
+ var instance = displaySet.images[0];
var instanceClassViewport = getInstanceClassDefaultViewport(instance, enabledElement, image.imageId);
// If there are sopClassUid-specific viewport settings, apply them
@@ -227,7 +228,7 @@ function loadSeriesIntoViewport(data, templateData) {
cornerstoneTools.addToolState(element, 'stack', stack);
// Set the default CINE settings
- var frameRate = 1000 / series.instances[0].frameTime;
+ var frameRate = 1000 / displaySet.images[0].frameTime;
var cineToolData = {
loop: OHIF.viewer.cine.loop,
framesPerSecond: frameRate || OHIF.viewer.cine.framesPerSecond
@@ -415,22 +416,23 @@ function loadSeriesIntoViewport(data, templateData) {
}
/**
- * This function sets series for the study and calls LoadSeriesIntoViewport function
+ * This function sets the display set for the study and calls LoadDisplaySetIntoViewport function
*
* @param data includes study data
- * @param seriesInstanceUid series information which is loaded in Template
+ * @param displaySetInstanceUid Display set information which is loaded in Template
* @param templateData currentData of Template
*
*/
-function setSeries(data, seriesInstanceUid, templateData) {
+function setDisplaySet(data, displaySetInstanceUid, templateData) {
var study = data.study;
- if (!study || !study.seriesList) {
+ if (!study || !study.displaySets) {
+ throw "Study does not exist or has no display sets";
return;
}
- study.seriesList.every(function(series) {
- if (series.seriesInstanceUid === seriesInstanceUid) {
- data.series = series;
+ study.displaySets.every(displaySet => {
+ if (displaySet.displaySetInstanceUid === displaySetInstanceUid) {
+ data.displaySet = displaySet;
return false;
}
@@ -438,12 +440,13 @@ function setSeries(data, seriesInstanceUid, templateData) {
});
// If we didn't find anything, stop here
- if (!data.series) {
+ if (!data.displaySet) {
+ throw "Display set not found in specified study!";
return;
}
// Otherwise, load pass the data object into loadSeriesIntoViewport
- loadSeriesIntoViewport(data, templateData);
+ loadDisplaySetIntoViewport(data, templateData);
}
/**
@@ -490,10 +493,6 @@ Meteor.startup(function() {
cornerstoneTools.magnify.setConfiguration(config);
});
-Template.imageViewerViewport.onCreated(function() {
- log.info('imageViewerViewport onCreated');
-});
-
Template.imageViewerViewport.onRendered(function() {
var templateData = Template.currentData();
log.info('imageViewerViewport onRendered');
@@ -513,15 +512,16 @@ Template.imageViewerViewport.onRendered(function() {
element: element,
viewport: this.data.viewport,
currentImageIdIndex: this.data.currentImageIdIndex,
+ displaySetInstanceUid: this.data.displaySetInstanceUid,
studyInstanceUid: this.data.studyInstanceUid,
seriesInstanceUid: this.data.seriesInstanceUid,
renderedCallback: this.data.renderedCallback,
activeViewport: activeViewport
};
- // If no seriesInstanceUid or studyInstanceUid were supplied, display the drag/drop
+ // If no displaySetInstanceUid was supplied, display the drag/drop
// instructions and then stop here since we don't know what to display in the viewport.
- if (!this.data.seriesInstanceUid || !this.data.studyInstanceUid) {
+ if (!this.data.displaySetInstanceUid) {
element.classList.add('empty');
$(element).siblings('.imageViewerLoadingIndicator').css('display', 'none');
$(element).siblings('.viewportInstructions').show();
@@ -533,10 +533,10 @@ Template.imageViewerViewport.onRendered(function() {
var study = ViewerStudies.findOne({
studyInstanceUid: this.data.studyInstanceUid
});
- var seriesInstanceUid = this.data.seriesInstanceUid;
+ var displaySetInstanceUid = this.data.displaySetInstanceUid;
data.study = study;
- setSeries(data, seriesInstanceUid, templateData);
+ setDisplaySet(data, displaySetInstanceUid, templateData);
});
Template.imageViewerViewport.onDestroyed(function() {
diff --git a/Packages/viewerbase/client/components/viewer/viewportOverlay/viewportOverlay.js b/Packages/viewerbase/client/components/viewer/viewportOverlay/viewportOverlay.js
index 286e2ca91..9b119756e 100644
--- a/Packages/viewerbase/client/components/viewer/viewportOverlay/viewportOverlay.js
+++ b/Packages/viewerbase/client/components/viewer/viewportOverlay/viewportOverlay.js
@@ -24,6 +24,27 @@ function getElementIfNotEmpty(viewportIndex) {
return element;
}
+function getStackDataIfNotEmpty(viewportIndex) {
+ const element = getElementIfNotEmpty(viewportIndex);
+ if (!element) {
+ return;
+ }
+
+ const stackToolData = cornerstoneTools.getToolState(element, 'stack');
+ if (!stackToolData ||
+ !stackToolData.data ||
+ !stackToolData.data.length) {
+ return;
+ }
+
+ const stack = stackToolData.data[0];
+ if (!stack) {
+ return;
+ }
+
+ return stack;
+}
+
function getPatient(property) {
Session.get('CornerstoneNewImage' + this.viewportIndex);
if (!this.imageId) {
@@ -201,6 +222,24 @@ Template.viewportOverlay.helpers({
numImages: function() {
return getSeries.call(this, 'numImages');
},
+ imageIndex: function() {
+ Session.get('CornerstoneNewImage' + this.viewportIndex);
+ var stack = getStackDataIfNotEmpty(this.viewportIndex);
+ if (!stack || stack.currentImageIdIndex === undefined) {
+ return;
+ }
+
+ return stack.currentImageIdIndex + 1;
+ },
+ numImages: function() {
+ Session.get('CornerstoneNewImage' + this.viewportIndex);
+ var stack = getStackDataIfNotEmpty(this.viewportIndex);
+ if (!stack || !stack.imageIds) {
+ return;
+ }
+
+ return stack.imageIds.length;
+ },
prior: function() {
// This helper is updated whenever a new image is displayed in the viewport
Session.get('CornerstoneNewImage' + this.viewportIndex);
diff --git a/Packages/viewerbase/lib/createStacks.js b/Packages/viewerbase/lib/createStacks.js
index 1fe8999e4..bedde4e91 100644
--- a/Packages/viewerbase/lib/createStacks.js
+++ b/Packages/viewerbase/lib/createStacks.js
@@ -11,32 +11,93 @@
* @returns {Array} An array of series to be placed in the Study Browser
*/
createStacks = function(study) {
- // Define an empty array of stacks
- var stacks = [];
+ // Define an empty array of display sets
+ var displaySets = [];
if (!study || !study.seriesList) {
- return stacks;
+ return displaySets;
}
- // TODO: Split by multi-frame, modality, image size, etc
- study.seriesList.forEach(function(series) {
+ study.seriesList.forEach(series => {
// If the series has no instances, skip it
if (!series.instances) {
return;
}
- // Don't display thumbnails for non-image modalities
- // All imaging modalities must have a valid value for rows (or columns)
- var anInstance = series.instances[0];
- if (!anInstance || !anInstance.rows) {
- return;
+ // Search through the instances of this series
+ // Split Multi-frame instances and Single-image modalities
+ // into their own specific display sets. Place the rest of each
+ // series into another display set.
+ let stackableInstances = [];
+ series.instances.forEach(instance => {
+ // All imaging modalities must have a valid value for rows (or columns)
+ if (!instance.rows) {
+ return;
+ }
+
+ let displaySet;
+ if (isMultiFrame(instance)) {
+ displaySet = makeDisplaySet(series, [ instance ]);
+ displaySet.isClip = true;
+
+ // Include the study instance Uid for drag/drop purposes
+ displaySet.studyInstanceUid = study.studyInstanceUid;
+
+ // Override the default value of instances.length
+ displaySet.numImageFrames = instance.numFrames;
+
+ displaySets.push(displaySet);
+ } else if (isSingleImageModality(instance.modality)) {
+ displaySet = makeDisplaySet(series, [ instance ]);
+ displaySet.studyInstanceUid = study.studyInstanceUid;
+ displaySets.push(displaySet);
+ } else {
+ stackableInstances.push(instance);
+ }
+ });
+
+ if (stackableInstances.length) {
+ let displaySet = makeDisplaySet(series, stackableInstances);
+ displaySet.studyInstanceUid = study.studyInstanceUid;
+ displaySets.push(displaySet);
}
-
- // Include the study instance Uid for drag/drop purposes
- series.studyInstanceUid = study.studyInstanceUid;
-
- // Add this series to the list of stacks
- stacks.push(series);
});
- return stacks;
-};
\ No newline at end of file
+
+ return displaySets;
+};
+
+function makeDisplaySet(series, instances) {
+ const instance = instances[0];
+
+ let displaySet = {
+ seriesInstanceUid: series.seriesInstanceUid,
+ seriesNumber: series.seriesNumber,
+ seriesDescription: series.seriesDescription,
+ numImageFrames: instances.length,
+ frameRate: instance.frameTime,
+ images: instances
+ };
+
+ // Sort the images in this series
+ displaySet.images.sort(function(a, b) {
+ if (a.instanceNumber && b.instanceNumber &&
+ a.instanceNumber !== b.instanceNumber) {
+ return a.instanceNumber - b.instanceNumber;
+ }
+ });
+
+ // Create a unique ID for this stack so we can reference it
+ displaySet.displaySetInstanceUid = Random.id();
+
+ return displaySet;
+}
+
+function isSingleImageModality(modality) {
+ return (modality === 'CR' ||
+ modality === 'MG' ||
+ modality === 'DX');
+}
+
+function isMultiFrame(instance) {
+ return instance.numFrames > 1;
+}
\ No newline at end of file
diff --git a/Packages/viewerbase/lib/helpers/isSeriesActive.js b/Packages/viewerbase/lib/helpers/isDisplaySetActive.js
similarity index 78%
rename from Packages/viewerbase/lib/helpers/isSeriesActive.js
rename to Packages/viewerbase/lib/helpers/isDisplaySetActive.js
index 18ac31522..251e0ecc6 100644
--- a/Packages/viewerbase/lib/helpers/isSeriesActive.js
+++ b/Packages/viewerbase/lib/helpers/isDisplaySetActive.js
@@ -1,7 +1,7 @@
/**
* Boolean helper to identify if a series instance is active in some viewport
*/
-Template.registerHelper('isSeriesActive', (seriesInstanceUid, viewportIndex) => {
+Template.registerHelper('isDisplaySetActive', (displaySetInstanceUid, viewportIndex) => {
// Run this computation every time the viewports are updated
Session.get('LayoutManagerUpdated');
@@ -19,7 +19,7 @@ Template.registerHelper('isSeriesActive', (seriesInstanceUid, viewportIndex) =>
let result = false;
_.each(viewportData, data => {
- if (data && data.seriesInstanceUid === seriesInstanceUid) {
+ if (data && data.displaySetInstanceUid === displaySetInstanceUid) {
result = true;
}
});
diff --git a/Packages/viewerbase/lib/helpers/studyThumbnails.js b/Packages/viewerbase/lib/helpers/studyThumbnails.js
index 94aeb920f..ad7a97ac6 100644
--- a/Packages/viewerbase/lib/helpers/studyThumbnails.js
+++ b/Packages/viewerbase/lib/helpers/studyThumbnails.js
@@ -2,8 +2,8 @@
* A global Blaze UI helper to get the thumbnails for the given study
*/
Template.registerHelper('studyThumbnails', study => {
- // Creates the series stacks
- const stacks = createStacks(study);
+ // Find the study's stacks
+ const stacks = study.displaySets;
// Defines the resulting thumbnails list
const thumbnails = [];
diff --git a/Packages/viewerbase/lib/layoutManager.js b/Packages/viewerbase/lib/layoutManager.js
index 85fb2da00..0877a56b9 100644
--- a/Packages/viewerbase/lib/layoutManager.js
+++ b/Packages/viewerbase/lib/layoutManager.js
@@ -27,8 +27,8 @@ LayoutManager = class LayoutManager {
var viewportIndex = 0;
var self = this;
this.studies.forEach(function(study) {
- study.seriesList.forEach(function(series) {
- if (!series.instances.length) {
+ study.displaySets.forEach(function(displaySet) {
+ if (!displaySet.images.length) {
return;
}
@@ -39,6 +39,7 @@ LayoutManager = class LayoutManager {
viewportIndex: existingViewportData.viewportIndex,
studyInstanceUid: existingViewportData.studyInstanceUid,
seriesInstanceUid: existingViewportData.seriesInstanceUid,
+ displaySetInstanceUid: existingViewportData.displaySetInstanceUid,
sopInstanceUid: existingViewportData.sopInstanceUid,
viewport: existingViewportData.viewport,
imageId: existingViewportData.imageId,
@@ -50,7 +51,7 @@ LayoutManager = class LayoutManager {
// This tests to make sure there is actually image data in this instance
// TODO: Change this when we add PDF and MPEG support
// See https://ohiforg.atlassian.net/browse/LT-227
- var firstInstance = series.instances[0];
+ var firstInstance = displaySet.images[0];
// All imaging modalities must have a valid value for sopClassUid or rows
if (!firstInstance || (!isImage(firstInstance.sopClassUid) && !firstInstance.rows)) {
@@ -59,7 +60,8 @@ LayoutManager = class LayoutManager {
currentViewportData = {
viewportIndex: viewportIndex,
studyInstanceUid: study.studyInstanceUid,
- seriesInstanceUid: series.seriesInstanceUid,
+ seriesInstanceUid: displaySet.seriesInstanceUid,
+ displaySetInstanceUid: displaySet.displaySetInstanceUid,
sopInstanceUid: firstInstance.sopInstanceUid,
currentImageIdIndex: 0 // TODO Remove this once currentImageIdIndex is removed from imageViewerViewports
};
@@ -114,13 +116,12 @@ LayoutManager = class LayoutManager {
/**
* This function destroys and re-renders the imageViewerViewport template.
- * It uses the data provided (object containing seriesIndex and studyIndex) to
- * load a new series into the produced viewport.
+ * It uses the data provided to load a new display set into the produced viewport.
*
* @param viewportIndex
- * @param data An object containing a seriesIndex and studyIndex for a study to load into this viewport
+ * @param data
*/
- rerenderViewportWithNewSeries(viewportIndex, data) {
+ rerenderViewportWithNewDisplaySet(viewportIndex, data) {
// The parent container is identified because it is later removed from the DOM
var element = $('.imageViewerViewport').eq(viewportIndex);
var container = element.parents('.viewportContainer').get(0);
@@ -128,9 +129,10 @@ LayoutManager = class LayoutManager {
// Record the current viewportIndex so this can be passed into the re-rendering call
data.viewportIndex = viewportIndex;
- // Update the dictionary of loaded series for the specified viewport
+ // Update the dictionary of loaded displaySet for the specified viewport
this.viewportData[viewportIndex] = {
viewportIndex: viewportIndex,
+ displaySetInstanceUid: data.displaySetInstanceUid,
seriesInstanceUid: data.seriesInstanceUid,
studyInstanceUid: data.studyInstanceUid,
renderedCallback: data.renderedCallback,
diff --git a/Packages/viewerbase/package.js b/Packages/viewerbase/package.js
index be5badc7d..dac78c86b 100644
--- a/Packages/viewerbase/package.js
+++ b/Packages/viewerbase/package.js
@@ -143,8 +143,7 @@ Package.onUse(function(api) {
api.addFiles('lib/resizeViewportElements.js', 'client');
api.addFiles('lib/setFocusToActiveViewport.js', 'client');
api.addFiles('lib/updateAllViewports.js', 'client');
- api.addFiles('lib/queryStudies.js', 'client');
- api.addFiles('lib/importStudies.js', 'client');
+
//api.addFiles('lib/validators.js', 'client');
api.addFiles('lib/instanceClassSpecificViewport.js', 'client');
api.addFiles('lib/setMammogramViewportAlignment.js', 'client');
@@ -197,7 +196,7 @@ Package.onUse(function(api) {
'lib/helpers/formatTM.js',
'lib/helpers/inlineIf.js',
'lib/helpers/inc.js',
- 'lib/helpers/isSeriesActive.js',
+ 'lib/helpers/isDisplaySetActive.js',
'lib/helpers/getUsername.js',
'lib/helpers/capitalizeFirstLetter.js',
'lib/helpers/objectToPairs.js',
@@ -219,14 +218,4 @@ Package.onUse(function(api) {
api.export('clearTools', 'client');
api.export('resetViewport', 'client');
api.export('invert', 'client');
-
- api.addFiles('server/methods/importStudies.js', 'server');
-
- api.export('importStudies', 'server');
- api.export('importSupported', 'server');
-
- // Collections
- api.addFiles('both/collections.js', [ 'client', 'server' ]);
- api.addFiles('server/collections.js', 'server');
- api.export('StudyImportStatus', [ 'client', 'server' ]);
});
diff --git a/Packages/viewerbase/both/collections.js b/Packages/worklist/both/collections.js
similarity index 100%
rename from Packages/viewerbase/both/collections.js
rename to Packages/worklist/both/collections.js
diff --git a/Packages/worklist/client/components/worklist.styl b/Packages/worklist/client/components/worklist.styl
index ccd8eb337..9096c4ff5 100644
--- a/Packages/worklist/client/components/worklist.styl
+++ b/Packages/worklist/client/components/worklist.styl
@@ -14,6 +14,8 @@ body
background-color: $primaryBackgroundColor
margin: 0 auto
color: white
+ float: left;
+ width: 100%;
.tab-content
width: 100%
diff --git a/Packages/viewerbase/lib/importStudies.js b/Packages/worklist/client/lib/importStudies.js
similarity index 100%
rename from Packages/viewerbase/lib/importStudies.js
rename to Packages/worklist/client/lib/importStudies.js
diff --git a/Packages/viewerbase/lib/queryStudies.js b/Packages/worklist/client/lib/queryStudies.js
similarity index 100%
rename from Packages/viewerbase/lib/queryStudies.js
rename to Packages/worklist/client/lib/queryStudies.js
diff --git a/Packages/worklist/client/lib/switchToTab.js b/Packages/worklist/client/lib/switchToTab.js
index 9158c1f32..487fafc47 100644
--- a/Packages/worklist/client/lib/switchToTab.js
+++ b/Packages/worklist/client/lib/switchToTab.js
@@ -20,7 +20,6 @@ switchToTab = function(contentId) {
} else {
$('.tab-content .tab-pane#' + contentId).addClass('active');
}
-
// Remove any previous Viewers from the DOM
$('.viewerContainer').remove();
diff --git a/Packages/worklist/package.js b/Packages/worklist/package.js
index cba14a0f6..bfd48e455 100644
--- a/Packages/worklist/package.js
+++ b/Packages/worklist/package.js
@@ -73,11 +73,15 @@ Package.onUse(function (api) {
api.addFiles('client/lib/switchToTab.js', 'client');
api.addFiles('client/lib/exportStudies.js', 'client');
api.addFiles('client/lib/worklist.js', 'client');
+ api.addFiles('client/lib/queryStudies.js', 'client');
+ api.addFiles('client/lib/importStudies.js', 'client');
// Server-side functions
+ api.addFiles('server/collections.js', 'server');
api.addFiles('server/lib/namespace.js', 'server');
api.addFiles('server/lib/encodeQueryData.js', 'server');
api.addFiles('server/methods/getStudyMetadata.js', 'server');
+ api.addFiles('server/methods/importStudies.js', 'server');
api.addFiles('server/methods/worklistSearch.js', 'server');
// DICOMWeb instance, study, and metadata retrieval
@@ -95,6 +99,8 @@ Package.onUse(function (api) {
api.addFiles('server/services/remote/studies.js', 'server');
api.addFiles('server/services/remote/retrieveMetadata.js', 'server');
+ api.addFiles('both/collections.js', [ 'client', 'server' ]);
+
api.export('Services', 'server');
// Export Worklist helper functions for usage in Routes
@@ -113,5 +119,5 @@ Package.onUse(function (api) {
// Export the Collections
api.export('WorklistTabs', 'client');
api.export('WorklistStudies', 'client');
- api.export('WorklistSelectedStudies', 'client');
+ api.export('WorklistSelectedStudies', 'client')
});
\ No newline at end of file
diff --git a/Packages/viewerbase/server/collections.js b/Packages/worklist/server/collections.js
similarity index 100%
rename from Packages/viewerbase/server/collections.js
rename to Packages/worklist/server/collections.js
diff --git a/Packages/viewerbase/server/methods/importStudies.js b/Packages/worklist/server/methods/importStudies.js
similarity index 100%
rename from Packages/viewerbase/server/methods/importStudies.js
rename to Packages/worklist/server/methods/importStudies.js
diff --git a/Packages/worklist/server/services/dimse/retrieveMetadata.js b/Packages/worklist/server/services/dimse/retrieveMetadata.js
index 7a34be612..7fe163dd8 100755
--- a/Packages/worklist/server/services/dimse/retrieveMetadata.js
+++ b/Packages/worklist/server/services/dimse/retrieveMetadata.js
@@ -72,6 +72,7 @@ function resultDataToStudyMetadata(studyInstanceUid, resultData) {
var instanceSummary = {
imageType: instance[0x00080008],
sopClassUid: instance[0x00080016],
+ modality: instance[0x00080060],
sopInstanceUid: sopInstanceUid,
instanceNumber: parseFloat(instance[0x00200013]),
imagePositionPatient: instance[0x00200032],
diff --git a/Packages/worklist/server/services/wado/retrieveMetadata.js b/Packages/worklist/server/services/wado/retrieveMetadata.js
index e2b3c783b..e0d8bb864 100644
--- a/Packages/worklist/server/services/wado/retrieveMetadata.js
+++ b/Packages/worklist/server/services/wado/retrieveMetadata.js
@@ -82,6 +82,7 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
var instanceSummary = {
imageType: DICOMWeb.getString(instance['00080008']),
sopClassUid: DICOMWeb.getString(instance['00080016']),
+ modality: DICOMWeb.getString(instance['00080060']),
sopInstanceUid: sopInstanceUid,
instanceNumber: DICOMWeb.getNumber(instance['00200013']),
imagePositionPatient: DICOMWeb.getString(instance['00200032']),
diff --git a/config/dcm4cheeDIMSE.json b/config/dcm4cheeDIMSE.json
index e37a91fd4..4e9615ac9 100644
--- a/config/dcm4cheeDIMSE.json
+++ b/config/dcm4cheeDIMSE.json
@@ -36,5 +36,11 @@
]
}]
},
- "defaultServiceType": "dimse"
+ "defaultServiceType": "dimse",
+ "public": {
+ "verifyEmail": false,
+ "ui": {
+ "studyListFunctionsEnabled": true
+ }
+ }
}
diff --git a/config/orthancDIMSE.json b/config/orthancDIMSE.json
index eaf0ffcf9..8d713c603 100644
--- a/config/orthancDIMSE.json
+++ b/config/orthancDIMSE.json
@@ -36,5 +36,11 @@
]
}]
},
- "defaultServiceType": "dimse"
+ "defaultServiceType": "dimse",
+ "public": {
+ "verifyEmail": false,
+ "ui": {
+ "studyListFunctionsEnabled": true
+ }
+ }
}