From e12fb0de35d8d684107b6244e717174da9284c61 Mon Sep 17 00:00:00 2001 From: Bruno Alves de Faria Date: Thu, 16 Mar 2017 22:39:41 -0300 Subject: [PATCH] Final adjustments to routing behaviors --- LesionTracker/client/components/app/app.html | 2 +- LesionTracker/client/components/app/app.js | 77 ++++++++-------- LesionTracker/client/components/app/app.styl | 9 -- .../client/components/viewer/viewer.html | 18 ++-- .../client/components/viewer/viewer.js | 17 ++-- LesionTracker/client/routes.js | 13 ++- .../components/ohifViewer/ohifViewer.js | 75 +++++++++------ .../components/ohifViewer/ohifViewer.styl | 9 -- OHIFViewer/client/components/viewer/viewer.js | 4 +- .../ohif-lesiontracker/client/lib/index.js | 1 - .../lib/studylist/openNewTabWithTimepoint.js | 92 ------------------- .../lib/studylist/studylistModification.js | 25 +---- .../components/caseProgress/caseProgress.js | 2 +- .../components/longitudinal/dropdown.js | 13 +-- .../studylistResult/studylistResult.js | 11 ++- .../studylistStudy/studylistStudy.js | 1 + .../ohif-study-list/client/lib/studylist.js | 44 +++------ Packages/ohif-study-list/package.js | 6 -- .../imageViewerViewport.js | 41 +++------ .../viewer/viewerMain/viewerMain.styl | 9 ++ .../lib/classes/ResizeViewportManager.js | 72 +++++++-------- .../client/lib/renderViewer.js | 4 +- .../standaloneViewer/standaloneViewer.styl | 9 -- .../client/components/viewer/viewer.js | 34 ++++--- 24 files changed, 226 insertions(+), 362 deletions(-) delete mode 100644 Packages/ohif-lesiontracker/client/lib/studylist/openNewTabWithTimepoint.js diff --git a/LesionTracker/client/components/app/app.html b/LesionTracker/client/components/app/app.html index 0410e9d30..ad36371ca 100644 --- a/LesionTracker/client/components/app/app.html +++ b/LesionTracker/client/components/app/app.html @@ -8,7 +8,7 @@ {{/section}} {{#section 'headerAfterBrand'}} {{#if studyListToggleText}} - + {{studyListToggleText}} {{/if}} diff --git a/LesionTracker/client/components/app/app.js b/LesionTracker/client/components/app/app.js index 0450bb9f6..a51185ae4 100644 --- a/LesionTracker/client/components/app/app.js +++ b/LesionTracker/client/components/app/app.js @@ -4,16 +4,10 @@ import { Router } from 'meteor/iron:router'; import { ReactiveVar } from 'meteor/reactive-var'; import { OHIF } from 'meteor/ohif:core'; -const studylistContentId = 'studylistTab'; -const viewerContentId = 'viewerTab'; - -// Define the OHIF.viewer.data global object Template.app.onCreated(() => { const instance = Template.instance(); instance.headerClasses = new ReactiveVar(''); - OHIF.viewer.data = instance.data.viewerData || {}; - OHIF.header.dropdown.setItems([{ action: OHIF.user.audit, text: 'View Audit Log', @@ -50,6 +44,9 @@ Template.app.onCreated(() => { const routeName = currentRoute.route.getName(); const isViewer = routeName.indexOf('viewer') === 0; + // Define the OHIF.viewer.data global object + OHIF.viewer.data = OHIF.viewer.data || Session.get('ViewerData') || {}; + // Add or remove the strech class from body $(document.body)[isViewer ? 'addClass' : 'removeClass']('stretch'); @@ -62,23 +59,41 @@ Template.app.onCreated(() => { }); Template.app.events({ - 'click .js-toggle-studyList'(event) { - OHIF.ui.unsavedChanges.presentProactiveDialog('viewer.*', (hasChanges, userChoice) => { - if (hasChanges) { - - switch (userChoice) { - case 'abort-action': - return; - case 'save-changes': - OHIF.ui.unsavedChanges.trigger('viewer', 'save', false); - OHIF.ui.unsavedChanges.clear('viewer.*'); - break; - case 'abandon-changes': - OHIF.ui.unsavedChanges.clear('viewer.*'); - break; - } + 'click .js-toggle-studyList'(event, instance) { + event.preventDefault(); + event.stopPropagation(); + const isViewer = Session.get('ViewerOpened'); + if (!isViewer) { + const timepointId = OHIF.viewer.data.currentTimepointId; + if (timepointId) { + Router.go('viewerTimepoint', { timepointId }); + } else { + const { studyInstanceUids } = OHIF.viewer.data; + Router.go('viewerStudies', { studyInstanceUids }); } + + return; + } + + OHIF.ui.unsavedChanges.presentProactiveDialog('viewer.*', (hasChanges, userChoice) => { + if (!hasChanges) { + return Router.go('studylist'); + } + + switch (userChoice) { + case 'abort-action': + return; + case 'save-changes': + OHIF.ui.unsavedChanges.trigger('viewer', 'save', false); + OHIF.ui.unsavedChanges.clear('viewer.*'); + break; + case 'abandon-changes': + OHIF.ui.unsavedChanges.clear('viewer.*'); + break; + } + + Router.go('studylist'); }, { position: { x: event.clientX + 15, @@ -92,24 +107,12 @@ Template.app.helpers({ userName: OHIF.user.getName, studyListToggleText() { - const contentId = Session.get('activeContentId'); + const isViewer = Session.get('ViewerOpened'); - // If the Viewer has not been opened yet, 'Back to viewer' should - // not be displayed - const viewerContentExists = !!Object.keys(OHIF.viewer.data).length; - if (!viewerContentExists) { - return; - } + // Return empty if viewer was not opened yet + if (!OHIF.viewer.data.studyInstanceUids) return; - if (contentId === studylistContentId) { - return 'Back to viewer'; - } else if (contentId === viewerContentId) { - return 'Study list'; - } - }, - - onStudyList() { - return (Session.get('activeContentId') === 'studylistTab'); + return isViewer ? 'Study list' : 'Back to viewer'; }, dasherize(text) { diff --git a/LesionTracker/client/components/app/app.styl b/LesionTracker/client/components/app/app.styl index 8527ea9cf..30edb631f 100644 --- a/LesionTracker/client/components/app/app.styl +++ b/LesionTracker/client/components/app/app.styl @@ -86,12 +86,3 @@ body>.header padding: 0 position: absolute top: 0 - -#studylistTabs - height: "calc(100% - %s)" % $topBarHeight - - .tab-pane - .viewerContainer - .loadingTextDiv - theme('color', '$textSecondaryColor') - font-size: 30px diff --git a/LesionTracker/client/components/viewer/viewer.html b/LesionTracker/client/components/viewer/viewer.html index 9bb5da765..5a7ac6fd1 100644 --- a/LesionTracker/client/components/viewer/viewer.html +++ b/LesionTracker/client/components/viewer/viewer.html @@ -1,15 +1,17 @@ diff --git a/LesionTracker/client/components/viewer/viewer.js b/LesionTracker/client/components/viewer/viewer.js index 4703cfecf..d5d3c7200 100644 --- a/LesionTracker/client/components/viewer/viewer.js +++ b/LesionTracker/client/components/viewer/viewer.js @@ -36,7 +36,8 @@ Template.viewer.onCreated(() => { const instance = Template.instance(); const { TimepointApi, MeasurementApi, ConformanceCriteria } = OHIF.measurements; - const currentTimepointId = instance.data.currentTimepointId; + + const currentTimepointId = OHIF.viewer.data.currentTimepointId; const timepointApi = new TimepointApi(currentTimepointId); const measurementApi = new MeasurementApi(timepointApi); const conformanceCriteria = new ConformanceCriteria(measurementApi, timepointApi); @@ -88,6 +89,9 @@ Template.viewer.onCreated(() => { OHIF.viewer.data.loadedSeriesData = {}; } + // Store the viewer data in session for further user + Session.setPersistent('ViewerData', OHIF.viewer.data); + Session.set('activeViewport', OHIF.viewer.data.activeViewport || false); // Set lesion tool buttons as disabled if pixel spacing is not available for active element @@ -156,13 +160,8 @@ Template.viewer.onCreated(() => { measurementApi.priorTimepointId = prior.timepointId; } - if (instance.data.currentTimepointId) { - // Enable Lesion Tracker Tools if the opened study is associated - OHIF.lesiontracker.toggleLesionTrackerToolsButtons(true); - } else { - // Disable Lesion Tracker Tools if the opened study is not associated - OHIF.lesiontracker.toggleLesionTrackerToolsButtons(false); - } + // Enable/Disable Lesion Tracker Tools if the opened study is associated or not + OHIF.lesiontracker.toggleLesionTrackerToolsButtons(!!currentTimepointId); let firstMeasurementActivated = false; instance.autorun(() => { @@ -311,7 +310,7 @@ const initHangingProtocol = () => { const layoutManager = OHIF.viewerbase.layoutManager; // Instantiate StudyMetadataSource: necessary for Hanging Protocol to get study metadata - const studyMetadataSource = new StudyList.classes.OHIFStudyMetadataSource(); + const studyMetadataSource = new OHIF.studylist.classes.OHIFStudyMetadataSource(); // Creates Protocol Engine object with required arguments const ProtocolEngine = new HP.ProtocolEngine(layoutManager, studyMetadataList, [], studyMetadataSource); diff --git a/LesionTracker/client/routes.js b/LesionTracker/client/routes.js index b3d2665a9..098ae15dc 100644 --- a/LesionTracker/client/routes.js +++ b/LesionTracker/client/routes.js @@ -2,9 +2,6 @@ import { Meteor } from 'meteor/meteor'; import { Router } from 'meteor/iron:router'; import { OHIF } from 'meteor/ohif:core'; -// TODO: remove the line below -window.Router = Router; - Router.configure({ layoutTemplate: 'layout', loadingTemplate: 'layout' @@ -30,11 +27,17 @@ Router.onBeforeAction(function() { }); Router.route('/', function() { - this.redirect('/studylist'); + Router.go('studylist', {}, { replaceState: true }); }, { name: 'home' }); Router.route('/studylist', function() { - this.render('app', { data: { template: 'studylist' } }); + // Retrieve the timepoints data to display in studylist + const promise = OHIF.studylist.timepointApi.retrieveTimepoints({}).then(() => { + this.render('app', { data: { template: 'studylist' } }); + }); + + // Show loading state while preparing the studylist data + OHIF.ui.showDialog('dialogLoading', { promise }); }, { name: 'studylist' }); Router.route('/viewer/timepoints/:timepointId', function() { diff --git a/OHIFViewer/client/components/ohifViewer/ohifViewer.js b/OHIFViewer/client/components/ohifViewer/ohifViewer.js index 57ba70066..98295fd88 100644 --- a/OHIFViewer/client/components/ohifViewer/ohifViewer.js +++ b/OHIFViewer/client/components/ohifViewer/ohifViewer.js @@ -1,46 +1,65 @@ import { Template } from 'meteor/templating'; import { Session } from 'meteor/session'; +import { Router } from 'meteor/iron:router'; +import { ReactiveVar } from 'meteor/reactive-var'; import { OHIF } from 'meteor/ohif:core'; -const studylistContentId = 'studylistTab'; -let lastContentId; +Template.ohifViewer.onCreated(() => { + const instance = Template.instance(); + instance.headerClasses = new ReactiveVar(''); + + // Define the OHIF.viewer.data global object + OHIF.viewer.data = instance.data.viewerData || {}; + + OHIF.header.dropdown.setItems([{ + action: () => OHIF.ui.showDialog('serverInformationModal'), + text: 'Server Information', + icon: 'fa fa-server fa-lg', + separatorAfter: true + }, { + action: () => $('#aboutModal').show(), + text: 'About', + icon: 'fa fa-info' + }]); + + instance.autorun(() => { + const currentRoute = Router.current(); + if (!currentRoute) return; + const routeName = currentRoute.route.getName(); + const isViewer = routeName.indexOf('viewer') === 0; + + // Add or remove the strech class from body + $(document.body)[isViewer ? 'addClass' : 'removeClass']('stretch'); + + // Set the header on its bigger version if the viewer is not opened + instance.headerClasses.set(isViewer ? '' : 'header-big'); + + // Set the viewer open state on session + Session.set('ViewerOpened', isViewer); + }); +}); Template.ohifViewer.events({ - 'click .js-toggle-studyList'() { - const contentId = Session.get('activeContentId'); + 'click .js-toggle-studyList'(event, instance) { + event.preventDefault(); + const isViewer = Session.get('ViewerOpened'); - if (contentId !== studylistContentId) { - switchToTab(studylistContentId); + if (isViewer) { + Router.go('studylist'); } else { - switchToTab(lastContentId); + const { studyInstanceUids } = OHIF.viewer.data; + Router.go('viewerStudies', { studyInstanceUids }); } - }, - - 'click #serverInformation'() { - OHIF.ui.showDialog('serverInformationModal'); } }); Template.ohifViewer.helpers({ studyListToggleText() { - const contentId = Session.get('activeContentId'); + const isViewer = Session.get('ViewerOpened'); - // If the Viewer has not been opened yet, 'Back to viewer' should - // not be displayed - const viewerContentExists = !!Object.keys(OHIF.viewer.data).length; - if (!viewerContentExists) { - return; - } + // Return empty if viewer was not opened yet + if (!OHIF.viewer.data.studyInstanceUids) return; - if (contentId === studylistContentId) { - return 'Back to viewer'; - } else { - lastContentId = contentId; - return 'Study list'; - } - }, - - onStudyList() { - return (Session.get('activeContentId') === 'studylistTab'); + return isViewer ? 'Study list' : 'Back to viewer'; } }); diff --git a/OHIFViewer/client/components/ohifViewer/ohifViewer.styl b/OHIFViewer/client/components/ohifViewer/ohifViewer.styl index 0fd51d190..8f7395275 100644 --- a/OHIFViewer/client/components/ohifViewer/ohifViewer.styl +++ b/OHIFViewer/client/components/ohifViewer/ohifViewer.styl @@ -76,12 +76,3 @@ $expandedHeight = 160px padding: 0 position: absolute top: 0 - -#studylistTabs - height: "calc(100% - %s)" % $topBarHeight - - .tab-pane - .viewerContainer - .loadingTextDiv - theme('color', '$textSecondaryColor') - font-size: 30px diff --git a/OHIFViewer/client/components/viewer/viewer.js b/OHIFViewer/client/components/viewer/viewer.js index cdbca4bec..0c7202ac2 100644 --- a/OHIFViewer/client/components/viewer/viewer.js +++ b/OHIFViewer/client/components/viewer/viewer.js @@ -25,10 +25,10 @@ const initHangingProtocol = () => { const layoutManager = OHIF.viewerbase.layoutManager; // Instantiate StudyMetadataSource: necessary for Hanging Protocol to get study metadata - const studyMetadataSource = new StudyList.classes.OHIFStudyMetadataSource(); + const studyMetadataSource = new OHIF.studylist.classes.OHIFStudyMetadataSource(); // Get prior studies map - const studyPriorsMap = StudyList.functions.getStudyPriorsMap(studyMetadataList); + const studyPriorsMap = OHIF.studylist.functions.getStudyPriorsMap(studyMetadataList); // Creates Protocol Engine object with required arguments const ProtocolEngine = new HP.ProtocolEngine(layoutManager, studyMetadataList, studyPriorsMap, studyMetadataSource); diff --git a/Packages/ohif-lesiontracker/client/lib/index.js b/Packages/ohif-lesiontracker/client/lib/index.js index 29c58da4d..80f3ac5ff 100644 --- a/Packages/ohif-lesiontracker/client/lib/index.js +++ b/Packages/ohif-lesiontracker/client/lib/index.js @@ -1,5 +1,4 @@ // StudyList-related functions -import './studylist/openNewTabWithTimepoint.js'; import './studylist/studylistModification.js'; // Library functions diff --git a/Packages/ohif-lesiontracker/client/lib/studylist/openNewTabWithTimepoint.js b/Packages/ohif-lesiontracker/client/lib/studylist/openNewTabWithTimepoint.js deleted file mode 100644 index c34e1a026..000000000 --- a/Packages/ohif-lesiontracker/client/lib/studylist/openNewTabWithTimepoint.js +++ /dev/null @@ -1,92 +0,0 @@ -import { OHIF } from 'meteor/ohif:core'; - -/** - * Opens a new tab in the tabbed studylist environment using - * a given timepoint and new tab title. - * - * @param timepointId The UID of the Timepoint to be opened - * @param title The title to be used for the tab heading - */ -OHIF.lesiontracker.openNewTabWithTimepoint = timepointId => { - const Timepoints = OHIF.studylist.timepointApi.timepoints; - const timepoint = Timepoints.findOne({ - timepointId: timepointId - }); - - if (!timepoint) { - throw 'No such timepoint exists'; - } - - // Get the relevant studyInstanceUids given the timepoints - const data = getDataFromTimepoint(timepoint); - if (!data.studyInstanceUids) { - throw 'No studies found that are related to this timepoint'; - } - - // Update the OHIF.viewer.data global object - OHIF.viewer.data = { - studyInstanceUids: data.studyInstanceUids, - timepointIds: data.timepointIds, - currentTimepointId: timepointId - }; - - // Switch to the new tab - switchToTab(contentId); -}; - -/** - * Retrieves related studies given a Baseline or Follow-up Timepoint - * - * @param timepoint - * @returns {Array} - */ -function getDataFromTimepoint(timepoint) { - let relatedStudies = [timepoint.studyInstanceUids[0]]; - - // If this is the baseline, we should stop here and return the relevant studies - if (isBaseline(timepoint)) { - return { - studyInstanceUids: relatedStudies, - timepointIds: [timepoint.timepointId] - }; - } - - // Otherwise, this is a follow-up exam, so we should also find the baseline timepoint, - // and all studies related to it. We also enforce that the Baseline should have a studyDate - // prior to the latest studyDate in the current (Follow-up) Timepoint. - const Timepoints = OHIF.studylist.timepointApi.timepoints; - const baseline = Timepoints.findOne({ - timepointType: 'baseline', - patientId: timepoint.patientId, - latestDate: { - $lte: timepoint.latestDate - } - }); - - let timepointIds = []; - if (baseline) { - // NOTE: Temporarily added [0], since we only need one study per timepoint to load immediately? - relatedStudies = relatedStudies.concat(baseline.studyInstanceUids[0]); - timepointIds.push(baseline.timepointId); - } else { - OHIF.log.warn('No Baseline found while opening a Follow-up Timepoint'); - } - - timepointIds.push(timepoint.timepointId); - - return { - studyInstanceUids: relatedStudies, - timepointIds: timepointIds - }; -} - -/** - * Checks if a Timepoints is a baseline or not - * (abstracting this for later use, since I expect it to get more complex) - * - * @param timepoint a document from the Timepoints Collection - * @returns {boolean} Whether or not the timepoint is stored as a Baseline - */ -function isBaseline(timepoint) { - return (timepoint.timepointType === 'baseline'); -} diff --git a/Packages/ohif-lesiontracker/client/lib/studylist/studylistModification.js b/Packages/ohif-lesiontracker/client/lib/studylist/studylistModification.js index e757c9ca0..edbf00d5a 100644 --- a/Packages/ohif-lesiontracker/client/lib/studylist/studylistModification.js +++ b/Packages/ohif-lesiontracker/client/lib/studylist/studylistModification.js @@ -1,4 +1,5 @@ import { Meteor } from 'meteor/meteor'; +import { Router } from 'meteor/iron:router'; import { OHIF } from 'meteor/ohif:core'; Meteor.startup(function() { @@ -22,28 +23,8 @@ const dblClickOnStudy = data => { const timepoint = timepointApi.study(data.studyInstanceUid)[0]; if (timepoint) { - OHIF.lesiontracker.openNewTabWithTimepoint(timepoint.timepointId); + Router.go('viewerTimepoint', { timepointId: timepoint.timepointId }); } else { - openTab(data.studyInstanceUid); + Router.go('viewerStudies', { studyInstanceUids: data.studyInstanceUid }); } }; - -/** - * Opens a study - * - * @param studyInstanceUid The UID of the Study to be opened - * @param title The title to be used for the tab heading - */ -const openTab = studyInstanceUid => { - const contentId = 'viewerTab'; - - // Update the OHIF.viewer.data global object - OHIF.viewer.data = { - contentId: contentId, - isUnassociatedStudy: true, - studyInstanceUids: [studyInstanceUid] - }; - - // Switch to the new tab - switchToTab(contentId); -}; diff --git a/Packages/ohif-measurements/client/components/caseProgress/caseProgress.js b/Packages/ohif-measurements/client/components/caseProgress/caseProgress.js index 624173adc..3b36da0b1 100644 --- a/Packages/ohif-measurements/client/components/caseProgress/caseProgress.js +++ b/Packages/ohif-measurements/client/components/caseProgress/caseProgress.js @@ -181,6 +181,6 @@ Template.caseProgress.events({ return; } - instance.saveData().then(() => switchToTab('studylistTab')); + instance.saveData(); } }); diff --git a/Packages/ohif-measurements/client/components/longitudinal/dropdown.js b/Packages/ohif-measurements/client/components/longitudinal/dropdown.js index c940ac853..23f0e8e4e 100644 --- a/Packages/ohif-measurements/client/components/longitudinal/dropdown.js +++ b/Packages/ohif-measurements/client/components/longitudinal/dropdown.js @@ -1,4 +1,5 @@ import { Meteor } from 'meteor/meteor'; +import { Router } from 'meteor/iron:router'; import { OHIF } from 'meteor/ohif:core'; /** @@ -43,17 +44,9 @@ const viewStudies = () => { return; } - const studyInstanceUids = selectedStudies.map(study => study.studyInstanceUid); - const contentId = 'viewerTab'; + const studyInstanceUids = selectedStudies.map(study => study.studyInstanceUid).join(';'); - // Update the OHIF.viewer.data global object - OHIF.viewer.data = { - contentId: contentId, - studyInstanceUids: studyInstanceUids - }; - - // Switch to the new tab - switchToTab(contentId); + Router.go('viewerStudies', { studyInstanceUids }); }; /** diff --git a/Packages/ohif-study-list/client/components/studylist/studylistResult/studylistResult.js b/Packages/ohif-study-list/client/components/studylist/studylistResult/studylistResult.js index 0eb7b8c1d..990802fed 100644 --- a/Packages/ohif-study-list/client/components/studylist/studylistResult/studylistResult.js +++ b/Packages/ohif-study-list/client/components/studylist/studylistResult/studylistResult.js @@ -245,7 +245,7 @@ Template.studylistResult.onRendered(() => { endDate = today; } - const datePicker = $studyDate.daterangepicker({ + instance.datePicker = $studyDate.daterangepicker({ maxDate: today, autoUpdateInput: true, startDate: startDate, @@ -258,7 +258,7 @@ Template.studylistResult.onRendered(() => { }).data('daterangepicker'); if (startDate && endDate) { - datePicker.updateInputText(); + instance.datePicker.updateInputText(); $studyDate.trigger('change'); } else { // Retrieve all studies @@ -266,6 +266,13 @@ Template.studylistResult.onRendered(() => { } }); +Template.studylistResult.onDestroyed(() => { + const instance = Template.instance(); + + // Destroy the daterangepicker to prevent residual elements on DOM + instance.datePicker.remove(); +}); + function resetSortingColumns(instance, sortingColumn) { Object.keys(instance.sortingColumns.keys).forEach(key => { if (key !== sortingColumn) { diff --git a/Packages/ohif-study-list/client/components/studylist/studylistStudy/studylistStudy.js b/Packages/ohif-study-list/client/components/studylist/studylistStudy/studylistStudy.js index b3a74b8cc..fd8d70543 100644 --- a/Packages/ohif-study-list/client/components/studylist/studylistStudy/studylistStudy.js +++ b/Packages/ohif-study-list/client/components/studylist/studylistStudy/studylistStudy.js @@ -1,5 +1,6 @@ import { Template } from 'meteor/templating'; import { Blaze } from 'meteor/blaze'; +import * as Hammer from 'hammerjs'; import { OHIF } from 'meteor/ohif:core'; // Clear all selected studies diff --git a/Packages/ohif-study-list/client/lib/studylist.js b/Packages/ohif-study-list/client/lib/studylist.js index 92fa7f16b..7a387758f 100644 --- a/Packages/ohif-study-list/client/lib/studylist.js +++ b/Packages/ohif-study-list/client/lib/studylist.js @@ -1,41 +1,27 @@ import { OHIF } from 'meteor/ohif:core'; -import { Viewerbase } from 'meteor/ohif:viewerbase'; +import { Router } from 'meteor/iron:router'; + // Classes import { OHIFStudyMetadataSource } from './OHIFStudyMetadataSource'; import { OHIFStudySummary } from './OHIFStudySummary'; + // Functions import { getStudyPriors } from './getStudyPriors'; import { getStudyPriorsMap } from './getStudyPriorsMap'; -StudyList = { - functions: { - getStudyPriors, - getStudyPriorsMap - }, - classes: { - OHIFStudyMetadataSource, - OHIFStudySummary - } +OHIF.studylist.functions = { + getStudyPriors, + getStudyPriorsMap +}; + +OHIF.studylist.classes = { + OHIFStudyMetadataSource, + OHIFStudySummary +}; + +const dblClickOnStudy = data => { + Router.go('viewerStudies', { studyInstanceUids: data.studyInstanceUid }); }; OHIF.studylist.callbacks.dblClickOnStudy = dblClickOnStudy; OHIF.studylist.callbacks.middleClickOnStudy = dblClickOnStudy; - -function dblClickOnStudy(data) { - openNewTab(data.studyInstanceUid); -} - -let currentServerChangeHandlerFirstRun = true; -const currentServerChangeHandler = () => { - if (currentServerChangeHandlerFirstRun) { - currentServerChangeHandlerFirstRun = false; - return; - } - - switchToTab('studylistTab'); -}; - -CurrentServer.find().observe({ - added: currentServerChangeHandler, - changed: currentServerChangeHandler -}); diff --git a/Packages/ohif-study-list/package.js b/Packages/ohif-study-list/package.js index 498677e0a..820ed2336 100644 --- a/Packages/ohif-study-list/package.js +++ b/Packages/ohif-study-list/package.js @@ -52,10 +52,4 @@ Package.onUse(function(api) { api.export('getCurrentServer', ['client', 'server']); api.export('Services', 'server'); - - // Export StudyList helper functions for usage in Routes - api.export('StudyList'); - - // Export the Collections - api.export('StudyListSelectedStudies', 'client'); }); diff --git a/Packages/ohif-viewerbase/client/components/viewer/imageViewerViewport/imageViewerViewport.js b/Packages/ohif-viewerbase/client/components/viewer/imageViewerViewport/imageViewerViewport.js index 4e09d8d9f..61ce052b7 100644 --- a/Packages/ohif-viewerbase/client/components/viewer/imageViewerViewport/imageViewerViewport.js +++ b/Packages/ohif-viewerbase/client/components/viewer/imageViewerViewport/imageViewerViewport.js @@ -46,20 +46,11 @@ const loadDisplaySetIntoViewport = (data, templateData) => { layoutManager.viewportData[viewportIndex] = layoutManager.viewportData[viewportIndex] || {}; layoutManager.viewportData[viewportIndex].viewportIndex = viewportIndex; - // Get the contentID of the current study list tab, if the viewport is running - // alongside the study list package - const contentId = Session.get('activeContentId'); + // Stop here if no data was defined for the viewer + if (!OHIF.viewer.data) return; - // If the viewer is inside a tab, create an object related to the specified viewport - // This data will be saved so that the tab can be reloaded to the same state after tabs - // are switched - if (contentId) { - if (!OHIF.viewer.data) { - return; - } - - OHIF.viewer.data.loadedSeriesData[viewportIndex] = {}; - } + // This data will be saved so that the viewport can be reloaded to the same state later + OHIF.viewer.data.loadedSeriesData[viewportIndex] = {}; // Create shortcut to displaySet const displaySet = data.displaySet; @@ -67,7 +58,7 @@ const loadDisplaySetIntoViewport = (data, templateData) => { // Get stack from Stack Manager let stack = StackManager.findStack(displaySet.displaySetInstanceUid); // Make sure if the stack is already loaded in the stack manager, otherwise create it - if(!stack || !stack.imageIds) { + if (!stack || !stack.imageIds) { stack = StackManager.makeAndAddStack(data.study, displaySet); } @@ -144,7 +135,7 @@ const loadDisplaySetIntoViewport = (data, templateData) => { try { imagePromise = cornerstone.loadAndCacheImage(imageId); } catch (error) { - console.log(error); + OHIF.log.info(error); if (!imagePromise) { errorLoadingHandler(element, imageId, error); return; @@ -163,7 +154,7 @@ const loadDisplaySetIntoViewport = (data, templateData) => { const callbacks = imageViewerViewportData.callbacks; // Check if it has before loadAndCacheImage callback - if(typeof callbacks.before === 'function') { + if (typeof callbacks.before === 'function') { OHIF.log.info('imageViewerViewport before loadAndCacheImage callback'); callbacks.before(imagePromise, templateData); } @@ -262,8 +253,7 @@ const loadDisplaySetIntoViewport = (data, templateData) => { let fps; if (multiframeMetadata && multiframeMetadata.averageFrameRate > 0) { fps = multiframeMetadata.averageFrameRate; - } - else { + } else { fps = OHIF.viewer.cine.framesPerSecond; } @@ -431,7 +421,6 @@ const loadDisplaySetIntoViewport = (data, templateData) => { // Check if image plane (orientation / location) data is present for the current image const imagePlane = cornerstoneTools.metaData.get('imagePlane', image.imageId); if (imagePlane && imagePlane.frameOfReferenceUID) { - // If it is, add this element to the global synchronizer... OHIF.viewer.updateImageSynchronizer.add(element); @@ -449,7 +438,6 @@ const loadDisplaySetIntoViewport = (data, templateData) => { } } - // Set the active viewport based on the Session variable // This is done to ensure that the active element has the current // focus, so that keyboard events are triggered. @@ -465,8 +453,8 @@ const loadDisplaySetIntoViewport = (data, templateData) => { // Update the LayoutManagerUpdated session key layoutManager.updateSession(); - // Check if it has after loadAndCacheImage callback - if(typeof callbacks.after === 'function') { + // Check if it has after loadAndCacheImage callback + if (typeof callbacks.after === 'function') { OHIF.log.info('imageViewerViewport after callback'); callbacks.after(image, templateData, element); } @@ -531,7 +519,7 @@ Template.imageViewerViewport.onRendered(function() { let { currentImageIdIndex } = templateData; const { viewport, studyInstanceUid, seriesInstanceUid, renderedCallback, displaySetInstanceUid } = templateData; - if(!currentImageIdIndex) { + if (!currentImageIdIndex) { currentImageIdIndex = 0; } @@ -570,8 +558,9 @@ Template.imageViewerViewport.onDestroyed(function() { OHIF.log.info('imageViewerViewport onDestroyed'); // When a viewport element is being destroyed - var element = this.find('.imageViewerViewport'); - if (!element || $(element).hasClass('empty') || !$(element).find('canvas').length) { + const element = this.find('.imageViewerViewport'); + const $element = $(element); + if (!element || $element.hasClass('empty') || !$element.find('canvas').length) { return; } @@ -600,7 +589,7 @@ Template.imageViewerViewport.onDestroyed(function() { // Trigger custom Destroy Viewport event // for compatibility with other systems - $(element).trigger('OHIFDestroyedViewport'); + $element.trigger('OHIFDestroyedViewport'); // Disable the viewport element with Cornerstone // This also triggers the removal of the element from all available diff --git a/Packages/ohif-viewerbase/client/components/viewer/viewerMain/viewerMain.styl b/Packages/ohif-viewerbase/client/components/viewer/viewerMain/viewerMain.styl index 9f09bc1a1..a0a0c042e 100644 --- a/Packages/ohif-viewerbase/client/components/viewer/viewerMain/viewerMain.styl +++ b/Packages/ohif-viewerbase/client/components/viewer/viewerMain/viewerMain.styl @@ -1,5 +1,14 @@ @import "{ohif:design}/app" +#viewer + height: "calc(100% - %s)" % $topBarHeight + + &>.loadingTextDiv + theme('color', '$textSecondaryColor') + font-size: 30px + height: 100% + line-height: "calc(100vh - %s)" % $topBarHeight + .viewerMain width: 100% height: 100% diff --git a/Packages/ohif-viewerbase/client/lib/classes/ResizeViewportManager.js b/Packages/ohif-viewerbase/client/lib/classes/ResizeViewportManager.js index 0c9f45ddc..bb0922b50 100644 --- a/Packages/ohif-viewerbase/client/lib/classes/ResizeViewportManager.js +++ b/Packages/ohif-viewerbase/client/lib/classes/ResizeViewportManager.js @@ -14,65 +14,65 @@ export class ResizeViewportManager { repositionStudySeriesQuickSwitch() { OHIF.log.info('ResizeViewportManager repositionStudySeriesQuickSwitch'); - const activeTab = Session.get('activeContentId'); - if(activeTab === 'viewerTab') { - const nViewports = OHIF.viewerbase.layoutManager.viewportData.length; + // Stop here if viewer is not displayed + const isViewer = Session.get('ViewerOpened'); + if (!isViewer) return; - if(nViewports && nViewports > 1) { - const viewer = $('#viewer'); - const leftSidebar = viewer.find('.sidebar-left.sidebar-open'); - const rightSidebar = viewer.find('.sidebar-right.sidebar-open'); + // Stop here if there is no one or only one viewport + const nViewports = OHIF.viewerbase.layoutManager.viewportData.length; + if (!nViewports || nViewports <= 1) return; - const leftQuickSwitch = $('.quickSwitchWrapper.left'); - const rightQuickSwitch = $('.quickSwitchWrapper.right'); + const $viewer = $('#viewer'); + const leftSidebar = $viewer.find('.sidebar-left.sidebar-open'); + const rightSidebar = $viewer.find('.sidebar-right.sidebar-open'); - const hasLeftSidebar = leftSidebar.length > 0; - const hasRightSidebar = rightSidebar.length > 0; + const $leftQuickSwitch = $('.quickSwitchWrapper.left'); + const $rightQuickSwitch = $('.quickSwitchWrapper.right'); - rightQuickSwitch.removeClass('left-sidebar-only'); - leftQuickSwitch.removeClass('right-sidebar-only'); + const hasLeftSidebar = leftSidebar.length > 0; + const hasRightSidebar = rightSidebar.length > 0; - let leftOffset = 0; + $rightQuickSwitch.removeClass('left-sidebar-only'); + $leftQuickSwitch.removeClass('right-sidebar-only'); - if(hasLeftSidebar) { - leftOffset = ( leftSidebar.width()/$(window).width() ) * 100; + let leftOffset = 0; - if(!hasRightSidebar) { - rightQuickSwitch.addClass('left-sidebar-only'); - } - } + if (hasLeftSidebar) { + leftOffset = (leftSidebar.width() / $(window).width()) * 100; - if(hasRightSidebar && !hasLeftSidebar) { - leftQuickSwitch.addClass('right-sidebar-only'); - } - - const leftPosition = ( ($('#imageViewerViewports').width() / nViewports) / $(window).width() ) * 100 + leftOffset; - const rightPosition = 100 - leftPosition; - - leftQuickSwitch.css('right', rightPosition + '%'); - rightQuickSwitch.css('left', leftPosition + '%'); + if (!hasRightSidebar) { + $rightQuickSwitch.addClass('left-sidebar-only'); } - } + + if (hasRightSidebar && !hasLeftSidebar) { + $leftQuickSwitch.addClass('right-sidebar-only'); + } + + const leftPosition = (($('#imageViewerViewports').width() / nViewports) / $(window).width()) * 100 + leftOffset; + const rightPosition = 100 - leftPosition; + + $leftQuickSwitch.css('right', rightPosition + '%'); + $rightQuickSwitch.css('left', leftPosition + '%'); } // Relocate dialogs positions relocateDialogs(){ OHIF.log.info('ResizeViewportManager relocateDialogs'); - const bottomRightDialogs = $('#cineDialog, #annotationDialog, #textMarkerOptionsDialog'); - bottomRightDialogs.css({ + const $bottomRightDialogs = $('#cineDialog, #annotationDialog, #textMarkerOptionsDialog'); + $bottomRightDialogs.css({ top: '', // This removes the CSS property completely left: '', bottom: 0, right: 0 }); - const centerDialogs = $('.draggableDialog').not(bottomRightDialogs); + const centerDialogs = $('.draggableDialog').not($bottomRightDialogs); centerDialogs.css({ top: 0, - left:0, + left: 0, bottom: 0, right: 0 }); @@ -83,7 +83,6 @@ export class ResizeViewportManager { OHIF.log.info('ResizeViewportManager resizeScrollbars'); const currentOverlay = $(element).siblings('.imageViewerViewportOverlay'); - const imageControls = currentOverlay.find('.imageControls'); currentOverlay.find('.imageControls').height($(element).height()); // Set it's width to its parent's height @@ -125,7 +124,7 @@ export class ResizeViewportManager { resizeViewportElements() { this.relocateDialogs(); - const viewportResizeTimer = setTimeout(() => { + setTimeout(() => { this.repositionStudySeriesQuickSwitch(); const elements = $('.imageViewerViewport').not('.empty'); @@ -162,6 +161,7 @@ export class ResizeViewportManager { resizeHandler = this.handleResize.bind(this); this._resizeHandler = resizeHandler; } + return resizeHandler; } } diff --git a/Packages/ohif-viewerbase/client/lib/renderViewer.js b/Packages/ohif-viewerbase/client/lib/renderViewer.js index 90851f043..9ffdbf4cd 100644 --- a/Packages/ohif-viewerbase/client/lib/renderViewer.js +++ b/Packages/ohif-viewerbase/client/lib/renderViewer.js @@ -15,11 +15,11 @@ export const renderViewer = (context, params) => { // Render the viewer when the data is ready promise.then(({ studies, viewerData }) => { + OHIF.viewer.data = viewerData; context.render('app', { data: { template: 'viewer', - studies, - viewerData + studies } }); }); diff --git a/StandaloneViewer/StandaloneViewer/client/components/standaloneViewer/standaloneViewer.styl b/StandaloneViewer/StandaloneViewer/client/components/standaloneViewer/standaloneViewer.styl index 0fd51d190..8f7395275 100644 --- a/StandaloneViewer/StandaloneViewer/client/components/standaloneViewer/standaloneViewer.styl +++ b/StandaloneViewer/StandaloneViewer/client/components/standaloneViewer/standaloneViewer.styl @@ -76,12 +76,3 @@ $expandedHeight = 160px padding: 0 position: absolute top: 0 - -#studylistTabs - height: "calc(100% - %s)" % $topBarHeight - - .tab-pane - .viewerContainer - .loadingTextDiv - theme('color', '$textSecondaryColor') - font-size: 30px diff --git a/StandaloneViewer/StandaloneViewer/client/components/viewer/viewer.js b/StandaloneViewer/StandaloneViewer/client/components/viewer/viewer.js index 603aac48b..473c335ac 100644 --- a/StandaloneViewer/StandaloneViewer/client/components/viewer/viewer.js +++ b/StandaloneViewer/StandaloneViewer/client/components/viewer/viewer.js @@ -1,3 +1,7 @@ +import { Template } from 'meteor/templating'; +import { Session } from 'meteor/session'; +import { Tracker } from 'meteor/tracker'; +import { ReactiveDict } from 'meteor/reactive-dict'; import { OHIF } from 'meteor/ohif:core'; import 'meteor/ohif:viewerbase'; import 'meteor/ohif:metadata'; @@ -12,8 +16,6 @@ OHIF.viewer.functionList = { invert: viewportUtils.invert }; -Session.set('activeContentId', 'standalone'); - Session.setDefault('activeViewport', false); Session.setDefault('leftSidebar', false); Session.setDefault('rightSidebar', false); @@ -34,7 +36,7 @@ const initHangingProtocol = () => { const layoutManager = OHIF.viewerbase.layoutManager; // Instantiate StudyMetadataSource: necessary for Hanging Protocol to get study metadata - const studyMetadataSource = new StudyList.classes.OHIFStudyMetadataSource(); + const studyMetadataSource = new OHIF.studylist.classes.OHIFStudyMetadataSource(); // Creates Protocol Engine object with required arguments const ProtocolEngine = new HP.ProtocolEngine(layoutManager, studyMetadataList, [], studyMetadataSource); @@ -52,39 +54,35 @@ Template.viewer.onCreated(() => { instance.data.state.set('leftSidebar', Session.get('leftSidebar')); instance.data.state.set('rightSidebar', Session.get('rightSidebar')); - const contentId = instance.data.contentId; - - if (ViewerData[contentId] && ViewerData[contentId].loadedSeriesData) { + if (OHIF.viewer.data && OHIF.viewer.data.loadedSeriesData) { OHIF.log.info('Reloading previous loadedSeriesData'); - OHIF.viewer.loadedSeriesData = ViewerData[contentId].loadedSeriesData; + OHIF.viewer.loadedSeriesData = OHIF.viewer.data.loadedSeriesData; } else { - OHIF.log.info('Setting default ViewerData'); + OHIF.log.info('Setting default viewer data'); OHIF.viewer.loadedSeriesData = {}; - ViewerData[contentId] = {}; - ViewerData[contentId].loadedSeriesData = OHIF.viewer.loadedSeriesData; + OHIF.viewer.data = {}; + OHIF.viewer.data.loadedSeriesData = OHIF.viewer.loadedSeriesData; // Update the viewer data object - ViewerData[contentId].viewportColumns = 1; - ViewerData[contentId].viewportRows = 1; - ViewerData[contentId].activeViewport = 0; + OHIF.viewer.data.viewportColumns = 1; + OHIF.viewer.data.viewportRows = 1; + OHIF.viewer.data.activeViewport = 0; } - Session.set('activeViewport', ViewerData[contentId].activeViewport || 0); + Session.set('activeViewport', OHIF.viewer.data.activeViewport || 0); // @TypeSafeStudies // Update the OHIF.viewer.Studies collection with the loaded studies OHIF.viewer.Studies.removeAll(); - ViewerData[contentId].studyInstanceUids = []; + OHIF.viewer.data.studyInstanceUids = []; instance.data.studies.forEach(study => { study.selected = true; const studyMetadata = new OHIF.metadata.StudyMetadata(study); study.displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(studyMetadata); OHIF.viewer.Studies.insert(study); - ViewerData[contentId].studyInstanceUids.push(study.studyInstanceUid); + OHIF.viewer.data.studyInstanceUids.push(study.studyInstanceUid); }); - - Session.set('ViewerData', ViewerData); }); Template.viewer.onRendered(function() {