diff --git a/OHIFViewer/client/components/toolbarSection/toolbarSection.js b/OHIFViewer/client/components/toolbarSection/toolbarSection.js index cb4dc3eb8..1197cd998 100644 --- a/OHIFViewer/client/components/toolbarSection/toolbarSection.js +++ b/OHIFViewer/client/components/toolbarSection/toolbarSection.js @@ -97,7 +97,7 @@ Template.toolbarSection.helpers({ title: 'Previous', classes: 'imageViewerCommand', buttonTemplateName: 'displaySetNavigation', - isPrevious: true + isNext: false }); buttonData.push({ @@ -105,7 +105,7 @@ Template.toolbarSection.helpers({ title: 'Next', classes: 'imageViewerCommand', buttonTemplateName: 'displaySetNavigation', - isPrevious: false + isNext: true }); buttonData.push({ diff --git a/Packages/ohif-core/client/lib/viewer.js b/Packages/ohif-core/client/lib/viewer.js index 21ab195f5..70615985e 100644 --- a/Packages/ohif-core/client/lib/viewer.js +++ b/Packages/ohif-core/client/lib/viewer.js @@ -2,6 +2,107 @@ import { OHIF } from 'meteor/ohif:core'; OHIF.viewer = {}; +OHIF.viewer.getDisplaySetSequenceMap = () => { + // Get the viewport data list + const viewportDataList = window.layoutManager.viewportData; + + // Create a map to control the display set sequence + const sequenceMap = new Map(); + + // Iterate over each viewport and register its details on the sequence map + viewportDataList.forEach((viewportData, viewportIndex) => { + // Get the current study + const currentStudy = _.findWhere(window.layoutManager.studies, { + studyInstanceUid: viewportData.studyInstanceUid + }) || window.layoutManager.studies[0]; + + // Get the display sets + const displaySets = currentStudy.displaySets; + + // Get the current display set + const displaySet = _.findWhere(displaySets, { + displaySetInstanceUid: viewportData.displaySetInstanceUid + }); + + // Get the current instance index + let displaySetIndex = _.indexOf(displaySets, displaySet); + displaySetIndex = displaySetIndex < 0 ? 9999 : displaySetIndex; + + // Try to get a map entry for current study or create it if not present + let studyViewports = sequenceMap.get(currentStudy); + if (!studyViewports) { + studyViewports = []; + sequenceMap.set(currentStudy, studyViewports); + } + + // Register the viewport index and the display set index on the map + studyViewports.push({ + viewportIndex, + displaySetIndex + }); + }); + + // Return the generated sequence map + return sequenceMap; +}; + +OHIF.viewer.isDisplaySetsSequenced = definedSequenceMap => { + let isSequenced = true; + + // Get the studies and display sets sequence map + const sequenceMap = definedSequenceMap || OHIF.viewer.getDisplaySetSequenceMap(); + + sequenceMap.forEach((studyViewports, study) => { + let lastDisplaySetIndex = null; + let lastViewportIndex = null; + studyViewports.forEach(({ viewportIndex, displaySetIndex }, index) => { + // Check if the sequence is wrong + if ( + displaySetIndex !== 9999 && + lastViewportIndex !== null && + lastDisplaySetIndex !== null && + displaySetIndex !== null && + (viewportIndex - 1) !== lastViewportIndex && + (displaySetIndex - 1) !== lastDisplaySetIndex + ) { + // Set the sequenced flag as false; + isSequenced = false; + } + + // Update the last viewport index + lastViewportIndex = viewportIndex; + + // Update the last display set index + lastDisplaySetIndex = displaySetIndex; + }); + }); + + return isSequenced; +}; + +OHIF.viewer.canMoveDisplaySets = isNext => { + // Get the setting that defines if the display set navigation is multiple + const isMultiple = OHIF.uiSettings.displaySetNavigationMultipleViewports; + + // Get the setting that allow display set navigation looping over series + const allowLooping = OHIF.uiSettings.displaySetNavigationLoopOverSeries; + + // Return false if no layout manager is not defined yet + if (!window.layoutManager) { + return false; + } + + // Get the studies and display sets sequence map + const sequenceMap = OHIF.viewer.getDisplaySetSequenceMap(); + + // Return false for moving backward if display sets are not sequenced + if (isMultiple && !isNext && !OHIF.viewer.isDisplaySetsSequenced(sequenceMap)) { + return false; + } + + return true; +}; + // Move display sets forward or backward in the given viewport index OHIF.viewer.moveSingleViewportDisplaySets = (viewportIndex, isNext) => { // Get the setting that allow display set navigation looping over series @@ -59,47 +160,14 @@ OHIF.viewer.moveMultipleViewportDisplaySets = isNext => { // Get the setting that allow display set navigation looping over series const allowLooping = OHIF.uiSettings.displaySetNavigationLoopOverSeries; - // Get the viewport data list - const viewportDataList = window.layoutManager.viewportData; + // Create a map to control the display set sequence + const sequenceMap = new OHIF.viewer.getDisplaySetSequenceMap(); - // Create a map to control the display set movement - const moveMap = new Map(); - - // Iterate over each viewport and register its details on the movement map - viewportDataList.forEach((viewportData, viewportIndex) => { - // Get the current study - const currentStudy = _.findWhere(window.layoutManager.studies, { - studyInstanceUid: viewportData.studyInstanceUid - }) || window.layoutManager.studies[0]; - - // Get the display sets - const displaySets = currentStudy.displaySets; - - // Get the current display set - const displaySet = _.findWhere(displaySets, { - displaySetInstanceUid: viewportData.displaySetInstanceUid - }); - - // Get the current instance index - let displaySetIndex = _.indexOf(displaySets, displaySet); - displaySetIndex = displaySetIndex < 0 ? 9999 : displaySetIndex; - - // Try to get a map entry for current study or create it if not present - let studyViewports = moveMap.get(currentStudy); - if (!studyViewports) { - studyViewports = []; - moveMap.set(currentStudy, studyViewports); - } - - // Register the viewport index and the display set index on the map - studyViewports.push({ - viewportIndex, - displaySetIndex - }); - }); + // Check if the display sets are sequenced + const isSequenced = OHIF.viewer.isDisplaySetsSequenced(sequenceMap); // Iterate over the studies map and move its display sets - moveMap.forEach((studyViewports, study) => { + sequenceMap.forEach((studyViewports, study) => { // Sort the viewports on the study by the display set index studyViewports.sort((a, b) => a.displaySetIndex > b.displaySetIndex); @@ -114,13 +182,17 @@ OHIF.viewer.moveMultipleViewportDisplaySets = isNext => { const direction = isNext ? 1 : -1; baseIndex += amount * direction; - // Check if the base index will be outside the array bounds - if (baseIndex >= displaySets.length) { + // Check if the indexes are sequenced or will overflow the array bounds + if (!isSequenced) { + // Reset the sequence if indexes are not sequenced + baseIndex = 0; + } else if (baseIndex >= displaySets.length) { // Stop here if looping is not allowed if (!allowLooping) { return; } + // Start over the series if looping is allowed baseIndex = 0; } else if (baseIndex < 0) { // Stop here if looping is not allowed @@ -128,6 +200,7 @@ OHIF.viewer.moveMultipleViewportDisplaySets = isNext => { return; } + // Go to the series' end if looping is allowed baseIndex = (displaySets.length - 1) - ((displaySets.length - 1) % amount); } diff --git a/Packages/viewerbase/client/components/viewer/displaySetNavigation/displaySetNavigation.html b/Packages/viewerbase/client/components/viewer/displaySetNavigation/displaySetNavigation.html index 67880565c..0b8dacd56 100644 --- a/Packages/viewerbase/client/components/viewer/displaySetNavigation/displaySetNavigation.html +++ b/Packages/viewerbase/client/components/viewer/displaySetNavigation/displaySetNavigation.html @@ -1,16 +1,16 @@ diff --git a/Packages/viewerbase/client/components/viewer/displaySetNavigation/displaySetNavigation.js b/Packages/viewerbase/client/components/viewer/displaySetNavigation/displaySetNavigation.js index 505847af6..c4e05e241 100644 --- a/Packages/viewerbase/client/components/viewer/displaySetNavigation/displaySetNavigation.js +++ b/Packages/viewerbase/client/components/viewer/displaySetNavigation/displaySetNavigation.js @@ -3,16 +3,25 @@ import { Template } from 'meteor/templating'; Template.displaySetNavigation.events({ 'click .js-next'(event, instance) { + if ($(event.currentTarget).hasClass('disabled')) { + return; + } + OHIF.viewer.moveDisplaySets(true); }, 'click .js-prev'(event, instance) { + if ($(event.currentTarget).hasClass('disabled')) { + return; + } + OHIF.viewer.moveDisplaySets(false); } }); Template.displaySetNavigation.helpers({ - disableButton(isPrevious) { - + disableButton(isNext) { + Session.get('LayoutManagerUpdated'); + return !OHIF.viewer.canMoveDisplaySets(isNext); } }); diff --git a/Packages/viewerbase/lib/layoutManager.js b/Packages/viewerbase/lib/layoutManager.js index a38a423fa..1ba580413 100644 --- a/Packages/viewerbase/lib/layoutManager.js +++ b/Packages/viewerbase/lib/layoutManager.js @@ -25,68 +25,74 @@ LayoutManager = class LayoutManager { } setDefaultViewportData() { - var numViewports = this.getNumberOfViewports(); + const self = this; - var viewportIndex = 0; - var self = this; - var oldViewportData = self.viewportData; - var running = true; - self.viewportData = []; - this.studies.forEach(function(study) { - study.displaySets.forEach(function(displaySet) { - if (!displaySet.images.length || !running) { - return; - } + // Get the number of vieports to be rendered + const viewportsAmount = this.getNumberOfViewports(); - var currentViewportData; - var existingViewportData = oldViewportData[viewportIndex]; - if (oldViewportData[viewportIndex]) { - currentViewportData = { - viewportIndex: existingViewportData.viewportIndex, - studyInstanceUid: existingViewportData.studyInstanceUid, - seriesInstanceUid: existingViewportData.seriesInstanceUid, - displaySetInstanceUid: existingViewportData.displaySetInstanceUid, - sopInstanceUid: existingViewportData.sopInstanceUid, - viewport: existingViewportData.viewport, - imageId: existingViewportData.imageId, - currentImageIdIndex: existingViewportData.currentImageIdIndex // TODO Remove this once currentImageIdIndex is removed from imageViewerViewports - }; - } else { - // 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 = displaySet.images[0]; + // Store the old viewport data and reset the current + const oldViewportData = self.viewportData; - // All imaging modalities must have a valid value for sopClassUid or rows - if (!firstInstance || (!isImage(firstInstance.sopClassUid) && !firstInstance.rows)) { - currentViewportData = {}; - } else { - currentViewportData = { - viewportIndex: viewportIndex, - studyInstanceUid: study.studyInstanceUid, - seriesInstanceUid: displaySet.seriesInstanceUid, - displaySetInstanceUid: displaySet.displaySetInstanceUid, - sopInstanceUid: firstInstance.sopInstanceUid, - currentImageIdIndex: 0 // TODO Remove this once currentImageIdIndex is removed from imageViewerViewports - }; - } - } + // Get the studies and display sets sequence map + const sequenceMap = OHIF.viewer.getDisplaySetSequenceMap(); - self.viewportData.push(currentViewportData); + // Check if the display sets are sequenced + const isSequenced = OHIF.viewer.isDisplaySetsSequenced(sequenceMap); - viewportIndex++; + // Define the current viewport index and the viewport data array + let currentViewportIndex = 0; + if (viewportsAmount > oldViewportData.length && isSequenced) { + // Keep the displayed display sets + self.viewportData = oldViewportData; + currentViewportIndex = oldViewportData.length - 1; + } else if (viewportsAmount <= oldViewportData.length) { + // Reduce the original displayed display sets + self.viewportData = oldViewportData.slice(0, viewportsAmount); + return; + } else { + // Reset all display sets + self.viewportData = []; + } - if (viewportIndex === numViewports) { - running = false; - return false; - } + // Get all the display sets for the viewer studies + let displaySets = []; + this.studies.forEach(study => { + study.displaySets.forEach(displaySet => { + displaySet.images.length && displaySets.push(displaySet); }); - - if (viewportIndex === numViewports) { - running = false; - return false; - } }); + + // Get the display sets that will be appended to the current ones + let appendix; + const currentLength = self.viewportData.length; + if (currentLength) { + // TODO: isolate displaySets array by study (maybe a map?) + const endIndex = currentViewportIndex + (viewportsAmount - currentLength) + 1; + appendix = displaySets.slice(currentViewportIndex + 1, endIndex); + } else { + // Get available display sets from the first to the grid size + appendix = displaySets.slice(0, viewportsAmount - 1); + } + + // Generate the additional data based on the appendix + const additionalData = []; + appendix.forEach((displaySet, index) => { + additionalData.push({ + viewportIndex: currentViewportIndex + index, + studyInstanceUid: displaySet.studyInstanceUid, + seriesInstanceUid: displaySet.seriesInstanceUid, + displaySetInstanceUid: displaySet.displaySetInstanceUid, + sopInstanceUid: displaySet.images[0].sopInstanceUid + }); + }); + + // Append the additional data with the viewport data + self.viewportData = self.viewportData.concat(additionalData); + + // Push empty objects if the amount is lesser than the grid size + while (self.viewportData.length < viewportsAmount) { + self.viewportData.push({}); + } } updateViewports() {